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

View file

@ -9,14 +9,27 @@ namespace es
{
namespace sign
{
enum SignType
enum SignatureId
{
SIGN_RSA4096_SHA1 = 0x10000,
SIGN_RSA2048_SHA1,
SIGN_ECDSA240_SHA1,
SIGN_RSA4096_SHA256,
SIGN_RSA2048_SHA256,
SIGN_ECDSA240_SHA256,
SIGN_ID_RSA4096_SHA1 = 0x10000,
SIGN_ID_RSA2048_SHA1,
SIGN_ID_ECDSA240_SHA1,
SIGN_ID_RSA4096_SHA256,
SIGN_ID_RSA2048_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;

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

View file

@ -2,6 +2,7 @@
#include <iomanip>
#include <fnd/SimpleTextOutput.h>
#include <es/SignUtils.h>
#include "OffsetAdjustedIFile.h"
#include "EsCertProcess.h"
@ -84,24 +85,49 @@ void EsCertProcess::validateCert(const es::SignedData<es::CertificateBody>& cert
{
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
{
// special case if signed by Root
if (cert.getBody().getIssuer() == es::sign::kRootIssuerStr)
{
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");
}
@ -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");
}
if (sig_validate_res != 0)
{
throw fnd::Exception(kModuleName, "Incorrect signature");
}
}
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;
}
@ -194,27 +225,45 @@ const es::SignedData<es::CertificateBody>& EsCertProcess::getIssuerCert(const st
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;
switch (type)
{
case (es::sign::SIGN_RSA4096_SHA1):
case (es::sign::SIGN_ID_RSA4096_SHA1):
str = "RSA4096-SHA1";
break;
case (es::sign::SIGN_RSA2048_SHA1):
case (es::sign::SIGN_ID_RSA2048_SHA1):
str = "RSA2048-SHA1";
break;
case (es::sign::SIGN_ECDSA240_SHA1):
case (es::sign::SIGN_ID_ECDSA240_SHA1):
str = "ECDSA240-SHA1";
break;
case (es::sign::SIGN_RSA4096_SHA256):
case (es::sign::SIGN_ID_RSA4096_SHA256):
str = "RSA4096-SHA256";
break;
case (es::sign::SIGN_RSA2048_SHA256):
case (es::sign::SIGN_ID_RSA2048_SHA256):
str = "RSA2048-SHA256";
break;
case (es::sign::SIGN_ECDSA240_SHA256):
case (es::sign::SIGN_ID_ECDSA240_SHA256):
str = "ECDSA240-SHA256";
break;
default:

View file

@ -40,7 +40,9 @@ private:
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* getPublicKeyTypeStr(es::cert::PublicKeyType type) const;
};

View file

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

View file

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