mirror of
https://github.com/jakcron/nstool
synced 2024-11-15 02:06:40 +00:00
[nstool] Encapsulate nnpki validation in PkiValidator.
This commit is contained in:
parent
104fecde82
commit
24fa6da666
4 changed files with 232 additions and 109 deletions
|
@ -5,6 +5,7 @@
|
|||
#include <es/SignUtils.h>
|
||||
#include "OffsetAdjustedIFile.h"
|
||||
#include "EsCertProcess.h"
|
||||
#include "PkiValidator.h"
|
||||
|
||||
EsCertProcess::EsCertProcess() :
|
||||
mFile(nullptr),
|
||||
|
@ -75,84 +76,18 @@ void EsCertProcess::importCerts()
|
|||
|
||||
void EsCertProcess::validateCerts()
|
||||
{
|
||||
for (size_t i = 0; i < mCert.size(); i++)
|
||||
{
|
||||
EsCertProcess::validateCert(mCert[i]);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
PkiValidator pki;
|
||||
|
||||
try
|
||||
{
|
||||
// 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");
|
||||
}
|
||||
|
||||
// validate signature
|
||||
int sig_validate_res = -1;
|
||||
|
||||
// special case if signed by Root
|
||||
if (cert.getBody().getIssuer() == es::sign::kRootIssuerStr)
|
||||
{
|
||||
if (cert_sign_algo != es::sign::SIGN_ALGO_RSA4096)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Issued by Root, but does not have a RSA4096 signature");
|
||||
}
|
||||
sig_validate_res = crypto::rsa::pkcs::rsaVerify(mKeyset->pki.root_sign_key, getCryptoHashAlgoFromEsSignHashAlgo(cert_hash_algo), cert_hash, cert.getSignature().getSignature().data());
|
||||
}
|
||||
else
|
||||
{
|
||||
// try to find issuer cert
|
||||
const es::CertificateBody& issuer = getIssuerCert(cert.getBody().getIssuer()).getBody();
|
||||
es::cert::PublicKeyType issuer_pubk_type = issuer.getPublicKeyType();
|
||||
|
||||
if (issuer_pubk_type == es::cert::RSA4096 && cert_sign_algo == es::sign::SIGN_ALGO_RSA4096)
|
||||
{
|
||||
sig_validate_res = crypto::rsa::pkcs::rsaVerify(issuer.getRsa4098PublicKey(), getCryptoHashAlgoFromEsSignHashAlgo(cert_hash_algo), cert_hash, cert.getSignature().getSignature().data());
|
||||
}
|
||||
else if (issuer_pubk_type == es::cert::RSA2048 && cert_sign_algo == es::sign::SIGN_ALGO_RSA2048)
|
||||
{
|
||||
sig_validate_res = crypto::rsa::pkcs::rsaVerify(issuer.getRsa2048PublicKey(), getCryptoHashAlgoFromEsSignHashAlgo(cert_hash_algo), cert_hash, cert.getSignature().getSignature().data());
|
||||
}
|
||||
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");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Mismatch between issuer public key and signature type");
|
||||
}
|
||||
}
|
||||
|
||||
if (sig_validate_res != 0)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Incorrect signature");
|
||||
}
|
||||
pki.setRootKey(mKeyset->pki.root_sign_key);
|
||||
pki.addCertificates(mCert);
|
||||
}
|
||||
catch (const fnd::Exception& e)
|
||||
{
|
||||
std::cout << "[WARNING] Failed to validate " << cert_ident << " (" << e.error() << ")" << std::endl;
|
||||
std::cout << "[WARNING] " << e.error() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EsCertProcess::displayCerts()
|
||||
|
@ -216,39 +151,6 @@ void EsCertProcess::displayCert(const es::SignedData<es::CertificateBody>& cert)
|
|||
#undef _SPLIT_VER
|
||||
}
|
||||
|
||||
const es::SignedData<es::CertificateBody>& EsCertProcess::getIssuerCert(const std::string& issuer_name) const
|
||||
{
|
||||
std::string full_cert_name;
|
||||
for (size_t i = 0; i < mCert.size(); i++)
|
||||
{
|
||||
full_cert_name = mCert[i].getBody().getIssuer() + es::sign::kIdentDelimiter + mCert[i].getBody().getSubject();
|
||||
if (full_cert_name == issuer_name)
|
||||
{
|
||||
return mCert[i];
|
||||
}
|
||||
}
|
||||
|
||||
throw fnd::Exception(kModuleName, "Issuer certificate does not exist");
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -34,13 +34,9 @@ private:
|
|||
|
||||
void importCerts();
|
||||
void validateCerts();
|
||||
void validateCert(const es::SignedData<es::CertificateBody>& cert);
|
||||
void displayCerts();
|
||||
void displayCert(const es::SignedData<es::CertificateBody>& cert);
|
||||
|
||||
const es::SignedData<es::CertificateBody>& getIssuerCert(const std::string& issuer_name) 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;
|
||||
|
|
192
programs/nstool/source/PkiValidator.cpp
Normal file
192
programs/nstool/source/PkiValidator.cpp
Normal file
|
@ -0,0 +1,192 @@
|
|||
#include "PkiValidator.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <es/SignUtils.h>
|
||||
|
||||
PkiValidator::PkiValidator()
|
||||
{
|
||||
clearCertificates();
|
||||
}
|
||||
|
||||
void PkiValidator::setRootKey(const crypto::rsa::sRsa4096Key& root_key)
|
||||
{
|
||||
// save a copy of the certificate bank
|
||||
fnd::List<es::SignedData<es::CertificateBody>> old_certs = mCertificateBank;
|
||||
|
||||
// clear the certificate bank
|
||||
mCertificateBank.clear();
|
||||
|
||||
// overwrite the root key
|
||||
mRootKey = root_key;
|
||||
|
||||
// if there were certificates before, reimport them (so they are checked against the new root key)
|
||||
if (old_certs.size() > 0)
|
||||
{
|
||||
addCertificates(old_certs);
|
||||
}
|
||||
}
|
||||
|
||||
void PkiValidator::addCertificates(const fnd::List<es::SignedData<es::CertificateBody>>& certs)
|
||||
{
|
||||
std::string cert_ident;
|
||||
es::sign::SignatureAlgo cert_sign_algo;
|
||||
es::sign::HashAlgo cert_hash_algo;
|
||||
fnd::Vec<byte_t> cert_sign, cert_hash;
|
||||
|
||||
try
|
||||
{
|
||||
for (size_t i = 0; i < certs.size(); i++)
|
||||
{
|
||||
makeCertIdent(certs[i], cert_ident);
|
||||
|
||||
if (doesCertExist(cert_ident) == true)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Certificate already exists");
|
||||
}
|
||||
|
||||
cert_sign_algo = es::sign::getSignatureAlgo(certs[i].getSignature().getSignType());
|
||||
cert_hash_algo = es::sign::getHashAlgo(certs[i].getSignature().getSignType());
|
||||
|
||||
// get cert hash
|
||||
switch (cert_hash_algo)
|
||||
{
|
||||
case (es::sign::HASH_ALGO_SHA1):
|
||||
cert_hash.alloc(crypto::sha::kSha1HashLen);
|
||||
crypto::sha::Sha1(certs[i].getBody().getBytes().data(), certs[i].getBody().getBytes().size(), cert_hash.data());
|
||||
break;
|
||||
case (es::sign::HASH_ALGO_SHA256):
|
||||
cert_hash.alloc(crypto::sha::kSha256HashLen);
|
||||
crypto::sha::Sha256(certs[i].getBody().getBytes().data(), certs[i].getBody().getBytes().size(), cert_hash.data());
|
||||
break;
|
||||
default:
|
||||
throw fnd::Exception(kModuleName, "Unrecognised hash type");
|
||||
}
|
||||
|
||||
validateSignature(certs[i].getBody().getIssuer(), certs[i].getSignature().getSignType(), certs[i].getSignature().getSignature(), cert_hash);
|
||||
|
||||
mCertificateBank.addElement(certs[i]);
|
||||
}
|
||||
}
|
||||
catch (const fnd::Exception& e)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Failed to add certificate " << cert_ident << " (" << e.error() << ")";
|
||||
throw fnd::Exception(kModuleName, ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void PkiValidator::clearCertificates()
|
||||
{
|
||||
mCertificateBank.clear();
|
||||
}
|
||||
|
||||
void PkiValidator::validateSignature(const std::string& issuer, es::sign::SignatureId signature_id, const fnd::Vec<byte_t>& signature, const fnd::Vec<byte_t>& hash) const
|
||||
{
|
||||
es::sign::SignatureAlgo sign_algo = es::sign::getSignatureAlgo(signature_id);
|
||||
es::sign::HashAlgo hash_algo = es::sign::getHashAlgo(signature_id);
|
||||
|
||||
|
||||
// validate signature
|
||||
int sig_validate_res = -1;
|
||||
|
||||
// special case if signed by Root
|
||||
if (issuer == es::sign::kRootIssuerStr)
|
||||
{
|
||||
if (sign_algo != es::sign::SIGN_ALGO_RSA4096)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Issued by Root, but does not have a RSA4096 signature");
|
||||
}
|
||||
sig_validate_res = crypto::rsa::pkcs::rsaVerify(mRootKey, getCryptoHashAlgoFromEsSignHashAlgo(hash_algo), hash.data(), signature.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
// try to find issuer cert
|
||||
const es::CertificateBody& issuer_cert = getCert(issuer).getBody();
|
||||
es::cert::PublicKeyType issuer_pubk_type = issuer_cert.getPublicKeyType();
|
||||
|
||||
if (issuer_pubk_type == es::cert::RSA4096 && sign_algo == es::sign::SIGN_ALGO_RSA4096)
|
||||
{
|
||||
sig_validate_res = crypto::rsa::pkcs::rsaVerify(issuer_cert.getRsa4098PublicKey(), getCryptoHashAlgoFromEsSignHashAlgo(hash_algo), hash.data(), signature.data());
|
||||
}
|
||||
else if (issuer_pubk_type == es::cert::RSA2048 && sign_algo == es::sign::SIGN_ALGO_RSA2048)
|
||||
{
|
||||
sig_validate_res = crypto::rsa::pkcs::rsaVerify(issuer_cert.getRsa2048PublicKey(), getCryptoHashAlgoFromEsSignHashAlgo(hash_algo), hash.data(), signature.data());
|
||||
}
|
||||
else if (issuer_pubk_type == es::cert::ECDSA240 && sign_algo == es::sign::SIGN_ALGO_ECDSA240)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "ECDSA signatures are not supported");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Mismatch between issuer public key and signature type");
|
||||
}
|
||||
}
|
||||
|
||||
if (sig_validate_res != 0)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Incorrect signature");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void PkiValidator::makeCertIdent(const es::SignedData<es::CertificateBody>& cert, std::string& ident) const
|
||||
{
|
||||
makeCertIdent(cert.getBody().getIssuer(), cert.getBody().getSubject(), ident);
|
||||
}
|
||||
|
||||
void PkiValidator::makeCertIdent(const std::string& issuer, const std::string& subject, std::string& ident) const
|
||||
{
|
||||
ident = issuer + es::sign::kIdentDelimiter + subject;
|
||||
ident = ident.substr(0, _MIN(ident.length(),64));
|
||||
}
|
||||
|
||||
bool PkiValidator::doesCertExist(const std::string& ident) const
|
||||
{
|
||||
bool exists = false;
|
||||
std::string full_cert_name;
|
||||
for (size_t i = 0; i < mCertificateBank.size(); i++)
|
||||
{
|
||||
makeCertIdent(mCertificateBank[i], full_cert_name);
|
||||
if (full_cert_name == ident)
|
||||
{
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
const es::SignedData<es::CertificateBody>& PkiValidator::getCert(const std::string& ident) const
|
||||
{
|
||||
std::string full_cert_name;
|
||||
for (size_t i = 0; i < mCertificateBank.size(); i++)
|
||||
{
|
||||
makeCertIdent(mCertificateBank[i], full_cert_name);
|
||||
if (full_cert_name == ident)
|
||||
{
|
||||
return mCertificateBank[i];
|
||||
}
|
||||
}
|
||||
|
||||
throw fnd::Exception(kModuleName, "Issuer certificate does not exist");
|
||||
}
|
||||
|
||||
crypto::sha::HashType PkiValidator::getCryptoHashAlgoFromEsSignHashAlgo(es::sign::HashAlgo hash_algo) const
|
||||
{
|
||||
crypto::sha::HashType hash_type = crypto::sha::HASH_SHA1;
|
||||
|
||||
switch (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;
|
||||
}
|
33
programs/nstool/source/PkiValidator.h
Normal file
33
programs/nstool/source/PkiValidator.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/List.h>
|
||||
#include <fnd/Vec.h>
|
||||
#include <crypto/rsa.h>
|
||||
#include <es/SignedData.h>
|
||||
#include <es/CertificateBody.h>
|
||||
#include <string>
|
||||
|
||||
class PkiValidator
|
||||
{
|
||||
public:
|
||||
PkiValidator();
|
||||
|
||||
void setRootKey(const crypto::rsa::sRsa4096Key& root_key);
|
||||
void addCertificates(const fnd::List<es::SignedData<es::CertificateBody>>& certs);
|
||||
void clearCertificates();
|
||||
|
||||
void validateSignature(const std::string& issuer, es::sign::SignatureId signature_id, const fnd::Vec<byte_t>& signature, const fnd::Vec<byte_t>& hash) const;
|
||||
|
||||
private:
|
||||
const std::string kModuleName = "NNPkiValidator";
|
||||
|
||||
|
||||
crypto::rsa::sRsa4096Key mRootKey;
|
||||
fnd::List<es::SignedData<es::CertificateBody>> mCertificateBank;
|
||||
|
||||
void makeCertIdent(const es::SignedData<es::CertificateBody>& cert, std::string& ident) const;
|
||||
void makeCertIdent(const std::string& issuer, const std::string& subject, std::string& ident) const;
|
||||
bool doesCertExist(const std::string& ident) const;
|
||||
const es::SignedData<es::CertificateBody>& getCert(const std::string& ident) const;
|
||||
crypto::sha::HashType getCryptoHashAlgoFromEsSignHashAlgo(es::sign::HashAlgo hash_algo) const;
|
||||
};
|
Loading…
Reference in a new issue