[nstool|es] Add cert validation.

This commit is contained in:
jakcron 2018-07-30 03:18:02 +08:00
parent 6f5c7fd353
commit 0aebf43f4b
9 changed files with 184 additions and 61 deletions

View file

@ -0,0 +1,14 @@
#pragma once
#include <es/sign.h>
#include <crypto/sha.h>
namespace es
{
namespace sign
{
es::sign::SignatureAlgo getSignatureAlgo(es::sign::SignatureId sign_id);
es::sign::HashAlgo getHashAlgo(es::sign::SignatureId sign_id);
}
}

View file

@ -24,8 +24,8 @@ namespace es
// variables // variables
void clear(); void clear();
es::sign::SignType getSignType() const; es::sign::SignatureId getSignType() const;
void setSignType(es::sign::SignType type); void setSignType(es::sign::SignatureId type);
bool isLittleEndian() const; bool isLittleEndian() const;
void setLittleEndian(bool isLE); void setLittleEndian(bool isLE);
@ -41,7 +41,7 @@ namespace es
fnd::Vec<byte_t> mRawBinary; fnd::Vec<byte_t> mRawBinary;
// variables // variables
es::sign::SignType mSignType; es::sign::SignatureId mSignType;
bool mIsLittleEndian; bool mIsLittleEndian;
fnd::Vec<byte_t> mSignature; fnd::Vec<byte_t> mSignature;
}; };

View file

@ -9,14 +9,27 @@ namespace es
{ {
namespace sign namespace sign
{ {
enum SignType enum SignatureId
{ {
SIGN_RSA4096_SHA1 = 0x10000, SIGN_ID_RSA4096_SHA1 = 0x10000,
SIGN_RSA2048_SHA1, SIGN_ID_RSA2048_SHA1,
SIGN_ECDSA240_SHA1, SIGN_ID_ECDSA240_SHA1,
SIGN_RSA4096_SHA256, SIGN_ID_RSA4096_SHA256,
SIGN_RSA2048_SHA256, SIGN_ID_RSA2048_SHA256,
SIGN_ECDSA240_SHA256, SIGN_ID_ECDSA240_SHA256,
};
enum SignatureAlgo
{
SIGN_ALGO_RSA4096,
SIGN_ALGO_RSA2048,
SIGN_ALGO_ECDSA240
};
enum HashAlgo
{
HASH_ALGO_SHA1,
HASH_ALGO_SHA256
}; };
static const size_t kEcdsaSigSize = 0x3C; static const size_t kEcdsaSigSize = 0x3C;

View file

@ -0,0 +1,45 @@
#include <es/SignUtils.h>
es::sign::SignatureAlgo es::sign::getSignatureAlgo(es::sign::SignatureId sign_id)
{
SignatureAlgo sign_algo = SIGN_ALGO_RSA4096;
switch (sign_id)
{
case (es::sign::SIGN_ID_RSA4096_SHA1):
case (es::sign::SIGN_ID_RSA4096_SHA256):
sign_algo = SIGN_ALGO_RSA4096;
break;
case (es::sign::SIGN_ID_RSA2048_SHA1):
case (es::sign::SIGN_ID_RSA2048_SHA256):
sign_algo = SIGN_ALGO_RSA2048;
break;
case (es::sign::SIGN_ID_ECDSA240_SHA1):
case (es::sign::SIGN_ID_ECDSA240_SHA256):
sign_algo = SIGN_ALGO_ECDSA240;
break;
};
return sign_algo;
}
es::sign::HashAlgo es::sign::getHashAlgo(es::sign::SignatureId sign_id)
{
HashAlgo hash_algo = HASH_ALGO_SHA1;
switch (sign_id)
{
case (es::sign::SIGN_ID_RSA4096_SHA1):
case (es::sign::SIGN_ID_RSA2048_SHA1):
case (es::sign::SIGN_ID_ECDSA240_SHA1):
hash_algo = HASH_ALGO_SHA1;
break;
case (es::sign::SIGN_ID_RSA4096_SHA256):
case (es::sign::SIGN_ID_RSA2048_SHA256):
case (es::sign::SIGN_ID_ECDSA240_SHA256):
hash_algo = HASH_ALGO_SHA256;
break;
};
return hash_algo;
}

View file

@ -37,18 +37,18 @@ void es::SignatureBlock::toBytes()
switch (mSignType) switch (mSignType)
{ {
case (sign::SIGN_RSA4096_SHA1): case (sign::SIGN_ID_RSA4096_SHA1):
case (sign::SIGN_RSA4096_SHA256): case (sign::SIGN_ID_RSA4096_SHA256):
totalSize = sizeof(sRsa4096SignBlock); totalSize = sizeof(sRsa4096SignBlock);
sigSize = crypto::rsa::kRsa4096Size; sigSize = crypto::rsa::kRsa4096Size;
break; break;
case (sign::SIGN_RSA2048_SHA1): case (sign::SIGN_ID_RSA2048_SHA1):
case (sign::SIGN_RSA2048_SHA256): case (sign::SIGN_ID_RSA2048_SHA256):
totalSize = sizeof(sRsa2048SignBlock); totalSize = sizeof(sRsa2048SignBlock);
sigSize = crypto::rsa::kRsa2048Size; sigSize = crypto::rsa::kRsa2048Size;
break; break;
case (sign::SIGN_ECDSA240_SHA1): case (sign::SIGN_ID_ECDSA240_SHA1):
case (sign::SIGN_ECDSA240_SHA256): case (sign::SIGN_ID_ECDSA240_SHA256):
totalSize = sizeof(sEcdsa240SignBlock); totalSize = sizeof(sEcdsa240SignBlock);
sigSize = sign::kEcdsaSigSize; sigSize = sign::kEcdsaSigSize;
break; break;
@ -80,18 +80,18 @@ void es::SignatureBlock::fromBytes(const byte_t* src, size_t size)
signType = ((be_uint32_t*)src)->get(); signType = ((be_uint32_t*)src)->get();
switch (signType) switch (signType)
{ {
case (sign::SIGN_RSA4096_SHA1): case (sign::SIGN_ID_RSA4096_SHA1):
case (sign::SIGN_RSA4096_SHA256): case (sign::SIGN_ID_RSA4096_SHA256):
totalSize = sizeof(sRsa4096SignBlock); totalSize = sizeof(sRsa4096SignBlock);
sigSize = crypto::rsa::kRsa4096Size; sigSize = crypto::rsa::kRsa4096Size;
break; break;
case (sign::SIGN_RSA2048_SHA1): case (sign::SIGN_ID_RSA2048_SHA1):
case (sign::SIGN_RSA2048_SHA256): case (sign::SIGN_ID_RSA2048_SHA256):
totalSize = sizeof(sRsa2048SignBlock); totalSize = sizeof(sRsa2048SignBlock);
sigSize = crypto::rsa::kRsa2048Size; sigSize = crypto::rsa::kRsa2048Size;
break; break;
case (sign::SIGN_ECDSA240_SHA1): case (sign::SIGN_ID_ECDSA240_SHA1):
case (sign::SIGN_ECDSA240_SHA256): case (sign::SIGN_ID_ECDSA240_SHA256):
totalSize = sizeof(sEcdsa240SignBlock); totalSize = sizeof(sEcdsa240SignBlock);
sigSize = sign::kEcdsaSigSize; sigSize = sign::kEcdsaSigSize;
break; break;
@ -103,18 +103,18 @@ void es::SignatureBlock::fromBytes(const byte_t* src, size_t size)
signType = ((le_uint32_t*)src)->get(); signType = ((le_uint32_t*)src)->get();
switch (signType) switch (signType)
{ {
case (sign::SIGN_RSA4096_SHA1): case (sign::SIGN_ID_RSA4096_SHA1):
case (sign::SIGN_RSA4096_SHA256): case (sign::SIGN_ID_RSA4096_SHA256):
totalSize = sizeof(sRsa4096SignBlock); totalSize = sizeof(sRsa4096SignBlock);
sigSize = crypto::rsa::kRsa4096Size; sigSize = crypto::rsa::kRsa4096Size;
break; break;
case (sign::SIGN_RSA2048_SHA1): case (sign::SIGN_ID_RSA2048_SHA1):
case (sign::SIGN_RSA2048_SHA256): case (sign::SIGN_ID_RSA2048_SHA256):
totalSize = sizeof(sRsa2048SignBlock); totalSize = sizeof(sRsa2048SignBlock);
sigSize = crypto::rsa::kRsa2048Size; sigSize = crypto::rsa::kRsa2048Size;
break; break;
case (sign::SIGN_ECDSA240_SHA1): case (sign::SIGN_ID_ECDSA240_SHA1):
case (sign::SIGN_ECDSA240_SHA256): case (sign::SIGN_ID_ECDSA240_SHA256):
totalSize = sizeof(sEcdsa240SignBlock); totalSize = sizeof(sEcdsa240SignBlock);
sigSize = sign::kEcdsaSigSize; sigSize = sign::kEcdsaSigSize;
break; break;
@ -133,7 +133,7 @@ void es::SignatureBlock::fromBytes(const byte_t* src, size_t size)
mRawBinary.alloc(totalSize); mRawBinary.alloc(totalSize);
memcpy(mRawBinary.data(), src, totalSize); memcpy(mRawBinary.data(), src, totalSize);
mSignType = (sign::SignType)signType; mSignType = (sign::SignatureId)signType;
mSignature.alloc(sigSize); mSignature.alloc(sigSize);
memcpy(mSignature.data(), mRawBinary.data() + 4, sigSize); memcpy(mSignature.data(), mRawBinary.data() + 4, sigSize);
} }
@ -146,17 +146,17 @@ const fnd::Vec<byte_t>& es::SignatureBlock::getBytes() const
void es::SignatureBlock::clear() void es::SignatureBlock::clear()
{ {
mRawBinary.clear(); mRawBinary.clear();
mSignType = sign::SIGN_RSA4096_SHA1; mSignType = sign::SIGN_ID_RSA4096_SHA1;
mIsLittleEndian = false; mIsLittleEndian = false;
mSignature.clear(); mSignature.clear();
} }
es::sign::SignType es::SignatureBlock::getSignType() const es::sign::SignatureId es::SignatureBlock::getSignType() const
{ {
return mSignType; return mSignType;
} }
void es::SignatureBlock::setSignType(es::sign::SignType type) void es::SignatureBlock::setSignType(es::sign::SignatureId type)
{ {
mSignType = type; mSignType = type;
} }

View file

@ -2,6 +2,7 @@
#include <iomanip> #include <iomanip>
#include <fnd/SimpleTextOutput.h> #include <fnd/SimpleTextOutput.h>
#include <es/SignUtils.h>
#include "OffsetAdjustedIFile.h" #include "OffsetAdjustedIFile.h"
#include "EsCertProcess.h" #include "EsCertProcess.h"
@ -83,25 +84,50 @@ void EsCertProcess::validateCerts()
void EsCertProcess::validateCert(const es::SignedData<es::CertificateBody>& cert) void EsCertProcess::validateCert(const es::SignedData<es::CertificateBody>& cert)
{ {
std::string cert_ident = cert.getBody().getIssuer() + es::sign::kIdentDelimiter + cert.getBody().getSubject(); std::string cert_ident = cert.getBody().getIssuer() + es::sign::kIdentDelimiter + cert.getBody().getSubject();
es::sign::SignatureAlgo cert_sign_algo = es::sign::getSignatureAlgo(cert.getSignature().getSignType());
es::sign::HashAlgo cert_hash_algo = es::sign::getHashAlgo(cert.getSignature().getSignType());
byte_t cert_hash[crypto::sha::kSha256HashLen];
memset(cert_hash, 0, crypto::sha::kSha256HashLen);
try try
{ {
// special case if signed by Root
if (cert.getBody().getIssuer() == es::sign::kRootIssuerStr) if (cert.getBody().getIssuer() == es::sign::kRootIssuerStr)
{ {
throw fnd::Exception(kModuleName, "Signed by Root"); throw fnd::Exception(kModuleName, "Signed by Root");
} }
const es::CertificateBody& issuer = getIssuerCert(cert.getBody().getIssuer()).getBody(); // get cert hash
switch (cert_hash_algo)
{
case (es::sign::HASH_ALGO_SHA1):
crypto::sha::Sha1(cert.getBody().getBytes().data(), cert.getBody().getBytes().size(), cert_hash);
break;
case (es::sign::HASH_ALGO_SHA256):
crypto::sha::Sha256(cert.getBody().getBytes().data(), cert.getBody().getBytes().size(), cert_hash);
break;
default:
throw fnd::Exception(kModuleName, "Unrecognised hash type");
}
if (issuer.getPublicKeyType() == es::cert::RSA4096 && (cert.getSignature().getSignType() == es::sign::SIGN_RSA4096_SHA1 || cert.getSignature().getSignType() == es::sign::SIGN_RSA4096_SHA256)) // try to find issuer cert
const es::CertificateBody& issuer = getIssuerCert(cert.getBody().getIssuer()).getBody();
es::cert::PublicKeyType issuer_pubk_type = issuer.getPublicKeyType();
// validate signature
int sig_validate_res = -1;
if (issuer_pubk_type == es::cert::RSA4096 && cert_sign_algo == es::sign::SIGN_ALGO_RSA4096)
{ {
throw fnd::Exception(kModuleName, "RSA4096 signatures are not supported"); sig_validate_res = crypto::rsa::pkcs::rsaVerify(issuer.getRsa4098PublicKey(), getCryptoHashAlgoFromEsSignHashAlgo(cert_hash_algo), cert_hash, cert.getSignature().getSignature().data());
} }
else if (issuer.getPublicKeyType() == es::cert::RSA2048 && (cert.getSignature().getSignType() == es::sign::SIGN_RSA2048_SHA1 || cert.getSignature().getSignType() == es::sign::SIGN_RSA2048_SHA256)) else if (issuer_pubk_type == es::cert::RSA2048 && cert_sign_algo == es::sign::SIGN_ALGO_RSA2048)
{ {
throw fnd::Exception(kModuleName, "RSA2048 signatures are not supported"); sig_validate_res = crypto::rsa::pkcs::rsaVerify(issuer.getRsa2048PublicKey(), getCryptoHashAlgoFromEsSignHashAlgo(cert_hash_algo), cert_hash, cert.getSignature().getSignature().data());
} }
else if (issuer.getPublicKeyType() == es::cert::ECDSA240 && (cert.getSignature().getSignType() == es::sign::SIGN_ECDSA240_SHA1 || cert.getSignature().getSignType() == es::sign::SIGN_ECDSA240_SHA256)) else if (issuer_pubk_type == es::cert::ECDSA240 && cert_sign_algo == es::sign::SIGN_ALGO_ECDSA240)
{ {
throw fnd::Exception(kModuleName, "ECDSA signatures are not supported"); throw fnd::Exception(kModuleName, "ECDSA signatures are not supported");
} }
@ -109,10 +135,15 @@ void EsCertProcess::validateCert(const es::SignedData<es::CertificateBody>& cert
{ {
throw fnd::Exception(kModuleName, "Mismatch between issuer public key and signature type"); throw fnd::Exception(kModuleName, "Mismatch between issuer public key and signature type");
} }
if (sig_validate_res != 0)
{
throw fnd::Exception(kModuleName, "Incorrect signature");
}
} }
catch (const fnd::Exception& e) catch (const fnd::Exception& e)
{ {
printf("[WARNING] Failed to validate %s (%s)\n", cert_ident.c_str(), e.error()); std::cout << "[WARNING] Failed to validate " << cert_ident << " (" << e.error() << ")" << std::endl;
return; return;
} }
@ -194,27 +225,45 @@ const es::SignedData<es::CertificateBody>& EsCertProcess::getIssuerCert(const st
throw fnd::Exception(kModuleName, "Issuer certificate does not exist"); throw fnd::Exception(kModuleName, "Issuer certificate does not exist");
} }
const char* EsCertProcess::getSignTypeStr(es::sign::SignType type) const crypto::sha::HashType EsCertProcess::getCryptoHashAlgoFromEsSignHashAlgo(es::sign::HashAlgo es_hash_algo) const
{
crypto::sha::HashType hash_type = crypto::sha::HASH_SHA1;
switch (es_hash_algo)
{
case (es::sign::HASH_ALGO_SHA1):
hash_type = crypto::sha::HASH_SHA1;
break;
case (es::sign::HASH_ALGO_SHA256):
hash_type = crypto::sha::HASH_SHA256;
break;
};
return hash_type;
}
const char* EsCertProcess::getSignTypeStr(es::sign::SignatureId type) const
{ {
const char* str; const char* str;
switch (type) switch (type)
{ {
case (es::sign::SIGN_RSA4096_SHA1): case (es::sign::SIGN_ID_RSA4096_SHA1):
str = "RSA4096-SHA1"; str = "RSA4096-SHA1";
break; break;
case (es::sign::SIGN_RSA2048_SHA1): case (es::sign::SIGN_ID_RSA2048_SHA1):
str = "RSA2048-SHA1"; str = "RSA2048-SHA1";
break; break;
case (es::sign::SIGN_ECDSA240_SHA1): case (es::sign::SIGN_ID_ECDSA240_SHA1):
str = "ECDSA240-SHA1"; str = "ECDSA240-SHA1";
break; break;
case (es::sign::SIGN_RSA4096_SHA256): case (es::sign::SIGN_ID_RSA4096_SHA256):
str = "RSA4096-SHA256"; str = "RSA4096-SHA256";
break; break;
case (es::sign::SIGN_RSA2048_SHA256): case (es::sign::SIGN_ID_RSA2048_SHA256):
str = "RSA2048-SHA256"; str = "RSA2048-SHA256";
break; break;
case (es::sign::SIGN_ECDSA240_SHA256): case (es::sign::SIGN_ID_ECDSA240_SHA256):
str = "ECDSA240-SHA256"; str = "ECDSA240-SHA256";
break; break;
default: default:

View file

@ -40,7 +40,9 @@ private:
const es::SignedData<es::CertificateBody>& getIssuerCert(const std::string& issuer_name) const; const es::SignedData<es::CertificateBody>& getIssuerCert(const std::string& issuer_name) const;
const char* getSignTypeStr(es::sign::SignType type) const; crypto::sha::HashType getCryptoHashAlgoFromEsSignHashAlgo(es::sign::HashAlgo hash_algo) const;
const char* getSignTypeStr(es::sign::SignatureId type) const;
const char* getEndiannessStr(bool isLittleEndian) const; const char* getEndiannessStr(bool isLittleEndian) const;
const char* getPublicKeyTypeStr(es::cert::PublicKeyType type) const; const char* getPublicKeyTypeStr(es::cert::PublicKeyType type) const;
}; };

View file

@ -132,23 +132,23 @@ const char* EsTikProcess::getSignTypeStr(uint32_t type) const
const char* str = nullptr; const char* str = nullptr;
switch(type) switch(type)
{ {
case (es::sign::SIGN_RSA4096_SHA1): case (es::sign::SIGN_ID_RSA4096_SHA1):
str = "RSA4096_SHA1"; str = "RSA4096-SHA1";
break; break;
case (es::sign::SIGN_RSA2048_SHA1): case (es::sign::SIGN_ID_RSA2048_SHA1):
str = "RSA2048_SHA1"; str = "RSA2048-SHA1";
break; break;
case (es::sign::SIGN_ECDSA240_SHA1): case (es::sign::SIGN_ID_ECDSA240_SHA1):
str = "ECDSA240_SHA1"; str = "ECDSA240-SHA1";
break; break;
case (es::sign::SIGN_RSA4096_SHA256): case (es::sign::SIGN_ID_RSA4096_SHA256):
str = "RSA4096_SHA256"; str = "RSA4096-SHA256";
break; break;
case (es::sign::SIGN_RSA2048_SHA256): case (es::sign::SIGN_ID_RSA2048_SHA256):
str = "RSA2048_SHA256"; str = "RSA2048-SHA256";
break; break;
case (es::sign::SIGN_ECDSA240_SHA256): case (es::sign::SIGN_ID_ECDSA240_SHA256):
str = "ECDSA240_SHA256"; str = "ECDSA240-SHA256";
break; break;
default: default:
str = "Unknown"; str = "Unknown";

View file

@ -882,7 +882,7 @@ bool UserSettings::determineValidEsCertFromSample(const fnd::Vec<byte_t>& sample
if (sign.isLittleEndian() == true) if (sign.isLittleEndian() == true)
return false; return false;
if (sign.getSignType() != es::sign::SIGN_RSA4096_SHA256 && sign.getSignType() != es::sign::SIGN_RSA2048_SHA256 && sign.getSignType() != es::sign::SIGN_ECDSA240_SHA256) if (sign.getSignType() != es::sign::SIGN_ID_RSA4096_SHA256 && sign.getSignType() != es::sign::SIGN_ID_RSA2048_SHA256 && sign.getSignType() != es::sign::SIGN_ID_ECDSA240_SHA256)
return false; return false;
return true; return true;
@ -904,7 +904,7 @@ bool UserSettings::determineValidEsTikFromSample(const fnd::Vec<byte_t>& sample)
if (sign.isLittleEndian() == false) if (sign.isLittleEndian() == false)
return false; return false;
if (sign.getSignType() != es::sign::SIGN_RSA2048_SHA256) if (sign.getSignType() != es::sign::SIGN_ID_RSA2048_SHA256)
return false; return false;
return true; return true;