mirror of
https://github.com/jakcron/nstool.git
synced 2024-12-22 18:55:29 +00:00
216 lines
6.4 KiB
C++
216 lines
6.4 KiB
C++
#include "PkiValidator.h"
|
|
|
|
#include <tc/crypto.h>
|
|
#include <pietendo/hac/define/types.h>
|
|
#include <pietendo/hac/es/SignUtils.h>
|
|
|
|
nstool::PkiValidator::PkiValidator() :
|
|
mModuleName("nstool::PkiValidator")
|
|
{
|
|
clearCertificates();
|
|
}
|
|
|
|
void nstool::PkiValidator::setKeyCfg(const KeyBag& keycfg)
|
|
{
|
|
// save a copy of the certificate bank
|
|
std::vector<pie::hac::es::SignedData<pie::hac::es::CertificateBody>> old_certs = mCertificateBank;
|
|
|
|
// clear the certificate bank
|
|
mCertificateBank.clear();
|
|
|
|
// overwrite the root key
|
|
mKeyCfg = keycfg;
|
|
|
|
// 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 nstool::PkiValidator::addCertificates(const std::vector<pie::hac::es::SignedData<pie::hac::es::CertificateBody>>& certs)
|
|
{
|
|
for (size_t i = 0; i < certs.size(); i++)
|
|
{
|
|
addCertificate(certs[i]);
|
|
}
|
|
}
|
|
|
|
void nstool::PkiValidator::addCertificate(const pie::hac::es::SignedData<pie::hac::es::CertificateBody>& cert)
|
|
{
|
|
std::string cert_ident;
|
|
pie::hac::es::sign::HashAlgo cert_hash_algo;
|
|
tc::ByteData cert_hash;
|
|
|
|
try
|
|
{
|
|
makeCertIdent(cert, cert_ident);
|
|
|
|
if (doesCertExist(cert_ident) == true)
|
|
{
|
|
throw tc::Exception(mModuleName, "Certificate already exists");
|
|
}
|
|
|
|
cert_hash_algo = pie::hac::es::sign::getHashAlgo(cert.getSignature().getSignType());
|
|
|
|
// get cert hash
|
|
switch (cert_hash_algo)
|
|
{
|
|
case (pie::hac::es::sign::HASH_ALGO_SHA1):
|
|
|
|
cert_hash = tc::ByteData(tc::crypto::Sha1Generator::kHashSize);
|
|
tc::crypto::GenerateSha1Hash(cert_hash.data(), cert.getBody().getBytes().data(), cert.getBody().getBytes().size());
|
|
break;
|
|
case (pie::hac::es::sign::HASH_ALGO_SHA256):
|
|
cert_hash = tc::ByteData(tc::crypto::Sha2256Generator::kHashSize);
|
|
tc::crypto::GenerateSha2256Hash(cert_hash.data(), cert.getBody().getBytes().data(), cert.getBody().getBytes().size());
|
|
break;
|
|
default:
|
|
throw tc::Exception(mModuleName, "Unrecognised hash type");
|
|
}
|
|
|
|
validateSignature(cert.getBody().getIssuer(), cert.getSignature().getSignType(), cert.getSignature().getSignature(), cert_hash);
|
|
|
|
mCertificateBank.push_back(cert);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(mModuleName, fmt::format("Failed to add certificate {:s} ({:s})", cert_ident, e.error()));
|
|
}
|
|
}
|
|
|
|
void nstool::PkiValidator::clearCertificates()
|
|
{
|
|
mCertificateBank.clear();
|
|
}
|
|
|
|
void nstool::PkiValidator::validateSignature(const std::string& issuer, pie::hac::es::sign::SignatureId signature_id, const tc::ByteData& signature, const tc::ByteData& hash) const
|
|
{
|
|
pie::hac::es::sign::SignatureAlgo sign_algo = pie::hac::es::sign::getSignatureAlgo(signature_id);
|
|
|
|
// validate signature
|
|
bool sig_valid = false;
|
|
|
|
// get public key
|
|
// tc::crypto::EccKey ecc_key;
|
|
tc::crypto::RsaKey rsa_key;
|
|
|
|
// special case if signed by Root (legacy nstool only defers to keybag for "Root", it did not store certificates)
|
|
if (issuer == "Root")
|
|
{
|
|
auto itr = mKeyCfg.broadon_signer.find(issuer);
|
|
|
|
if (itr == mKeyCfg.broadon_signer.end())
|
|
{
|
|
throw tc::Exception(mModuleName, fmt::format("Public key for issuer \"{:s}\" does not exist.", issuer));
|
|
}
|
|
|
|
if (sign_algo != itr->second.key_type)
|
|
{
|
|
throw tc::Exception(mModuleName, fmt::format("Public key for issuer \"{:s}\" cannot verify this signature.", issuer));
|
|
}
|
|
|
|
if (sign_algo == pie::hac::es::sign::SIGN_ALGO_ECDSA240)
|
|
{
|
|
throw tc::Exception(mModuleName, "ECDSA signatures are not supported");
|
|
}
|
|
|
|
rsa_key = itr->second.rsa_key;
|
|
}
|
|
else
|
|
{
|
|
// try to find issuer cert
|
|
const pie::hac::es::CertificateBody& issuer_cert = getCert(issuer).getBody();
|
|
pie::hac::es::cert::PublicKeyType issuer_pubk_type = issuer_cert.getPublicKeyType();
|
|
|
|
if (issuer_pubk_type == pie::hac::es::cert::RSA4096 && sign_algo == pie::hac::es::sign::SIGN_ALGO_RSA4096)
|
|
{
|
|
rsa_key = issuer_cert.getRsa4096PublicKey();
|
|
}
|
|
else if (issuer_pubk_type == pie::hac::es::cert::RSA2048 && sign_algo == pie::hac::es::sign::SIGN_ALGO_RSA2048)
|
|
{
|
|
rsa_key = issuer_cert.getRsa2048PublicKey();
|
|
}
|
|
else if (issuer_pubk_type == pie::hac::es::cert::ECDSA240 && sign_algo == pie::hac::es::sign::SIGN_ALGO_ECDSA240)
|
|
{
|
|
// ecc_key = issuer_cert.getEcdsa240PublicKey();
|
|
throw tc::Exception(mModuleName, "ECDSA signatures are not supported");
|
|
}
|
|
else
|
|
{
|
|
throw tc::Exception(mModuleName, "Mismatch between issuer public key and signature type");
|
|
}
|
|
}
|
|
|
|
// verify signature
|
|
switch (signature_id) {
|
|
case (pie::hac::es::sign::SIGN_ID_RSA4096_SHA1):
|
|
sig_valid = tc::crypto::VerifyRsa4096Pkcs1Sha1(signature.data(), hash.data(), rsa_key);
|
|
break;
|
|
case (pie::hac::es::sign::SIGN_ID_RSA2048_SHA1):
|
|
sig_valid = tc::crypto::VerifyRsa2048Pkcs1Sha1(signature.data(), hash.data(), rsa_key);
|
|
break;
|
|
case (pie::hac::es::sign::SIGN_ID_ECDSA240_SHA1):
|
|
sig_valid = false;
|
|
break;
|
|
case (pie::hac::es::sign::SIGN_ID_RSA4096_SHA256):
|
|
sig_valid = tc::crypto::VerifyRsa4096Pkcs1Sha2256(signature.data(), hash.data(), rsa_key);
|
|
break;
|
|
case (pie::hac::es::sign::SIGN_ID_RSA2048_SHA256):
|
|
sig_valid = tc::crypto::VerifyRsa2048Pkcs1Sha2256(signature.data(), hash.data(), rsa_key);
|
|
break;
|
|
case (pie::hac::es::sign::SIGN_ID_ECDSA240_SHA256):
|
|
sig_valid = false;
|
|
break;
|
|
}
|
|
|
|
if (sig_valid == false)
|
|
{
|
|
throw tc::Exception(mModuleName, "Incorrect signature");
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void nstool::PkiValidator::makeCertIdent(const pie::hac::es::SignedData<pie::hac::es::CertificateBody>& cert, std::string& ident) const
|
|
{
|
|
makeCertIdent(cert.getBody().getIssuer(), cert.getBody().getSubject(), ident);
|
|
}
|
|
|
|
void nstool::PkiValidator::makeCertIdent(const std::string& issuer, const std::string& subject, std::string& ident) const
|
|
{
|
|
ident = issuer + pie::hac::es::sign::kIdentDelimiter + subject;
|
|
ident = ident.substr(0, std::min<size_t>(ident.length(),64));
|
|
}
|
|
|
|
bool nstool::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 pie::hac::es::SignedData<pie::hac::es::CertificateBody>& nstool::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 tc::Exception(mModuleName, "Issuer certificate does not exist");
|
|
} |