From 235228a06d933de592a5045b68ca9dd12bb23750 Mon Sep 17 00:00:00 2001 From: Matula Peter Date: Thu, 23 Jul 2020 16:17:54 +0200 Subject: [PATCH] fileformat/certificate: remove OpenSSL from headers --- .../types/certificate_table/certificate.h | 15 +- src/fileformat/file_format/pe/pe_format.cpp | 170 +++++++++++- .../types/certificate_table/certificate.cpp | 260 ------------------ 3 files changed, 169 insertions(+), 276 deletions(-) diff --git a/include/retdec/fileformat/types/certificate_table/certificate.h b/include/retdec/fileformat/types/certificate_table/certificate.h index 0cf7b3ff1..633998cee 100644 --- a/include/retdec/fileformat/types/certificate_table/certificate.h +++ b/include/retdec/fileformat/types/certificate_table/certificate.h @@ -9,9 +9,6 @@ #include -// Forward declare OpenSSL structures used in this header. -typedef struct x509_st X509; - namespace retdec { namespace fileformat { @@ -39,8 +36,7 @@ class Certificate std::string generationQualifier; std::string emailAddress; }; - private: - X509 *certImpl; + public: std::string validSince; std::string validUntil; std::string publicKey; @@ -54,16 +50,7 @@ class Certificate Attributes subject; Attributes issuer; - void load(); - void loadValidity(); - void loadPublicKey(); - void loadSignatureAlgorithm(); - void loadSerialNumber(); - void loadIssuerAndSubject(); - void calculateHashes(); public: - Certificate(X509 *cert); - /// @name Getters /// @{ const std::string& getValidSince() const; diff --git a/src/fileformat/file_format/pe/pe_format.cpp b/src/fileformat/file_format/pe/pe_format.cpp index f58382433..305c877ad 100644 --- a/src/fileformat/file_format/pe/pe_format.cpp +++ b/src/fileformat/file_format/pe/pe_format.cpp @@ -13,8 +13,9 @@ #include #include -#include #include +#include +#include #include "retdec/utils/container.h" #include "retdec/utils/conversion.h" @@ -628,6 +629,171 @@ bool verifySignature(const retdec::fileformat::PeFormat* peFile, PKCS7 *p7) return true; } +template +decltype(auto) managedPtr(T* ptr, Deleter deleter) +{ + return std::unique_ptr(ptr, deleter); +} + +std::string parseDateTime(ASN1_TIME* dateTime) +{ + if (ASN1_TIME_check(dateTime) == 0) + return {}; + + auto memBio = managedPtr(BIO_new(BIO_s_mem()), &BIO_free); + ASN1_TIME_print(memBio.get(), dateTime); + + BUF_MEM* bioMemPtr; + BIO_ctrl(memBio.get(), BIO_C_GET_BUF_MEM_PTR, 0, reinterpret_cast(&bioMemPtr)); + + return std::string(bioMemPtr->data, bioMemPtr->length); +} + +std::string parsePublicKey(BIO *bio) +{ + std::string key; + std::vector tmp(100); + + BIO_gets(bio, tmp.data(), 100); + if(std::string(tmp.data()) != "-----BEGIN PUBLIC KEY-----\n") + { + return key; + } + + while(true) + { + BIO_gets(bio, tmp.data(), 100); + if(std::string(tmp.data()) == "-----END PUBLIC KEY-----\n") + { + break; + } + + key += tmp.data(); + key.erase(key.length() - 1, 1); // Remove last character (whitespace) + } + + return key; +} + +void parseAttributes(Certificate::Attributes *attributes, X509_NAME *raw) +{ + std::size_t numEntries = X509_NAME_entry_count(raw); + for(std::size_t i = 0; i < numEntries; ++i) + { + auto nameEntry = X509_NAME_get_entry(raw, int(i)); + auto valueObj = X509_NAME_ENTRY_get_data(nameEntry); + + std::string key = OBJ_nid2sn( + OBJ_obj2nid(X509_NAME_ENTRY_get_object(nameEntry)) + ); + std::string value = std::string( + reinterpret_cast(valueObj->data), + valueObj->length + ); + + if (key == "C") attributes->country = value; + else if (key == "O") attributes->organization = value; + else if (key == "OU") attributes->organizationalUnit = value; + else if (key == "dnQualifier") attributes->nameQualifier = value; + else if (key == "ST") attributes->state = value; + else if (key == "CN") attributes->commonName = value; + else if (key == "serialNumber") attributes->serialNumber = value; + else if (key == "L") attributes->locality = value; + else if (key == "title") attributes->title = value; + else if (key == "SN") attributes->surname = value; + else if (key == "GN") attributes->givenName = value; + else if (key == "initials") attributes->initials = value; + else if (key == "pseudonym") attributes->pseudonym = value; + else if (key == "generationQualifier") attributes->generationQualifier = value; + else if (key == "emailAddress") attributes->emailAddress = value; + } +} + +retdec::fileformat::Certificate x509toCert(X509* cert) +{ + Certificate c; + + c.validSince = parseDateTime(X509_get_notBefore(cert)); + c.validUntil = parseDateTime(X509_get_notAfter(cert)); + + if (auto pubKey = managedPtr(X509_get_pubkey(cert), &EVP_PKEY_free)) + { + auto memBio = managedPtr(BIO_new(BIO_s_mem()), &BIO_free); + PEM_write_bio_PUBKEY(memBio.get(), pubKey.get()); + c.publicKey = parsePublicKey(memBio.get()); + c.publicKeyAlgo = OBJ_nid2sn(EVP_PKEY_base_id(pubKey.get())); + } + + c.signatureAlgo = OBJ_nid2sn(X509_get_signature_nid(cert)); + + if (auto sn = X509_get_serialNumber(cert)) + { + retdec::utils::bytesToHexString( + sn->data, + sn->length, + c.serialNumber, + 0, + 0, + false + ); + } + + if (auto subjectName = X509_get_subject_name(cert)) + { + auto subjectNameOneline = managedPtr( + X509_NAME_oneline(subjectName, nullptr, 0), + &free + ); + c.subjectRaw = subjectNameOneline.get(); + + parseAttributes(&c.subject, subjectName); + } + + if (auto issuerName = X509_get_issuer_name(cert)) + { + auto issuerNameOneline = managedPtr( + X509_NAME_oneline(issuerName, nullptr, 0), + &free + ); + c.issuerRaw = issuerNameOneline.get(); + + parseAttributes(&c.issuer, issuerName); + } + + std::vector tmp(0x2000); + auto memBio = managedPtr(BIO_new(BIO_s_mem()), &BIO_free); + + i2d_X509_bio(memBio.get(), cert); + std::size_t certLen = BIO_read(memBio.get(), tmp.data(), int(tmp.size())); + tmp.resize(certLen); + + std::vector sha1Bytes( + SHA_DIGEST_LENGTH), + sha256Bytes(SHA256_DIGEST_LENGTH + ); + SHA1(reinterpret_cast( + tmp.data()), + tmp.size(), + sha1Bytes.data() + ); + SHA256(reinterpret_cast( + tmp.data()), + tmp.size(), + sha256Bytes.data() + ); + + retdec::utils::bytesToHexString(sha1Bytes, c.sha1Digest, 0, 0, false); + retdec::utils::bytesToHexString( + sha256Bytes, + c.sha256Digest, + 0, + 0, + false + ); + + return c; +} + } // anonymous namespace /** @@ -2045,7 +2211,7 @@ void PeFormat::loadCertificates() certificateTable = new CertificateTable(); } - Certificate cert(xcert); + Certificate cert = x509toCert(xcert); certificateTable->addCertificate(cert); // Check if we are at signer or counter-signer certificate and let the certificate table known indices. diff --git a/src/fileformat/types/certificate_table/certificate.cpp b/src/fileformat/types/certificate_table/certificate.cpp index d0659a184..d6017c950 100644 --- a/src/fileformat/types/certificate_table/certificate.cpp +++ b/src/fileformat/types/certificate_table/certificate.cpp @@ -17,266 +17,6 @@ namespace retdec { namespace fileformat { -namespace -{ - -enum : std::uint8_t -{ - ATTRIBUTE_COUNTRY = 0, - ATTRIBUTE_ORGANIZATION, - ATTRIBUTE_ORGANIZATIONAL_UNIT, - ATTRIBUTE_NAME_QUALIFIER, - ATTRIBUTE_STATE, - ATTRIBUTE_COMMON_NAME, - ATTRIBUTE_SERIAL_NUMBER, - ATTRIBUTE_LOCALITY, - ATTRIBUTE_TITLE, - ATTRIBUTE_SURNAME, - ATTRIBUTE_GIVEN_NAME, - ATTRIBUTE_INITIALS, - ATTRIBUTE_PSEUDONYM, - ATTRIBUTE_GENERATION_QUALIFIER, - ATTRIBUTE_EMAIL_ADDRESS -}; - -static const std::unordered_map attrTable = -{ - { "C", ATTRIBUTE_COUNTRY }, - { "O", ATTRIBUTE_ORGANIZATION }, - { "OU", ATTRIBUTE_ORGANIZATIONAL_UNIT }, - { "dnQualifier", ATTRIBUTE_NAME_QUALIFIER }, - { "ST", ATTRIBUTE_STATE }, - { "CN", ATTRIBUTE_COMMON_NAME }, - { "serialNumber", ATTRIBUTE_SERIAL_NUMBER }, - { "L", ATTRIBUTE_LOCALITY }, - { "title", ATTRIBUTE_TITLE }, - { "SN", ATTRIBUTE_SURNAME }, - { "GN", ATTRIBUTE_GIVEN_NAME }, - { "initials", ATTRIBUTE_INITIALS }, - { "pseudonym", ATTRIBUTE_PSEUDONYM }, - { "generationQualifier", ATTRIBUTE_GENERATION_QUALIFIER }, - { "emailAddress", ATTRIBUTE_EMAIL_ADDRESS }, -}; - -template -decltype(auto) managedPtr(T* ptr, Deleter deleter) -{ - return std::unique_ptr(ptr, deleter); -} - -void assignAttribute(Certificate::Attributes *attributes, const std::string &key, const std::string &value) -{ - auto itr = attrTable.find(key); - if(itr == attrTable.end()) - { - return; - } - - switch(itr->second) - { - case ATTRIBUTE_COUNTRY: - attributes->country = value; - break; - case ATTRIBUTE_ORGANIZATION: - attributes->organization = value; - break; - case ATTRIBUTE_ORGANIZATIONAL_UNIT: - attributes->organizationalUnit = value; - break; - case ATTRIBUTE_NAME_QUALIFIER: - attributes->nameQualifier = value; - break; - case ATTRIBUTE_STATE: - attributes->state = value; - break; - case ATTRIBUTE_COMMON_NAME: - attributes->commonName = value; - break; - case ATTRIBUTE_SERIAL_NUMBER: - attributes->serialNumber = value; - break; - case ATTRIBUTE_LOCALITY: - attributes->locality = value; - break; - case ATTRIBUTE_TITLE: - attributes->title = value; - break; - case ATTRIBUTE_SURNAME: - attributes->surname = value; - break; - case ATTRIBUTE_GIVEN_NAME: - attributes->givenName = value; - break; - case ATTRIBUTE_INITIALS: - attributes->initials = value; - break; - case ATTRIBUTE_PSEUDONYM: - attributes->pseudonym = value; - break; - case ATTRIBUTE_GENERATION_QUALIFIER: - attributes->generationQualifier = value; - break; - case ATTRIBUTE_EMAIL_ADDRESS: - attributes->emailAddress = value; - break; - default: - break; - } -} - -void parseAttributes(Certificate::Attributes *attributes, X509_NAME *raw) -{ - std::size_t numEntries = X509_NAME_entry_count(raw); - for(std::size_t i = 0; i < numEntries; ++i) - { - auto nameEntry = X509_NAME_get_entry(raw, int(i)); - auto valueObj = X509_NAME_ENTRY_get_data(nameEntry); - - std::string key = OBJ_nid2sn(OBJ_obj2nid(X509_NAME_ENTRY_get_object(nameEntry))); - std::string value = std::string(reinterpret_cast(valueObj->data), valueObj->length); - - assignAttribute(attributes, key, value); - } -} - -std::string parsePublicKey(BIO *bio) -{ - std::string key; - std::vector tmp(100); - - BIO_gets(bio, tmp.data(), 100); - if(std::string(tmp.data()) != "-----BEGIN PUBLIC KEY-----\n") - { - return key; - } - - while(true) - { - BIO_gets(bio, tmp.data(), 100); - if(std::string(tmp.data()) == "-----END PUBLIC KEY-----\n") - { - break; - } - - key += tmp.data(); - key.erase(key.length() - 1, 1); // Remove last character (whitespace) - } - - return key; -} - -std::string parseDateTime(ASN1_TIME* dateTime) -{ - if (ASN1_TIME_check(dateTime) == 0) - return {}; - - auto memBio = managedPtr(BIO_new(BIO_s_mem()), &BIO_free); - ASN1_TIME_print(memBio.get(), dateTime); - - BUF_MEM* bioMemPtr; - BIO_ctrl(memBio.get(), BIO_C_GET_BUF_MEM_PTR, 0, reinterpret_cast(&bioMemPtr)); - - return std::string(bioMemPtr->data, bioMemPtr->length); -} - -} // anonymous namespace - -/** - * Constructor - */ -Certificate::Certificate(X509* cert) : certImpl(cert) -{ - load(); -} - -void Certificate::load() -{ - loadValidity(); - loadPublicKey(); - loadSignatureAlgorithm(); - loadSerialNumber(); - loadIssuerAndSubject(); - calculateHashes(); -} - -void Certificate::loadValidity() -{ - validSince = parseDateTime(X509_get_notBefore(certImpl)); - validUntil = parseDateTime(X509_get_notAfter(certImpl)); -} - -void Certificate::loadPublicKey() -{ - publicKey.clear(); - publicKeyAlgo.clear(); - - auto pubKey = managedPtr(X509_get_pubkey(certImpl), &EVP_PKEY_free); - if(!pubKey) - return; - - auto memBio = managedPtr(BIO_new(BIO_s_mem()), &BIO_free); - - PEM_write_bio_PUBKEY(memBio.get(), pubKey.get()); - publicKey = parsePublicKey(memBio.get()); - -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - publicKeyAlgo = OBJ_nid2sn(EVP_PKEY_base_id(pubKey.get())); -#else - publicKeyAlgo = OBJ_nid2sn(OBJ_obj2nid(certImpl->cert_info->key->algor->algorithm)); -#endif -} - -void Certificate::loadSignatureAlgorithm() -{ -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - signatureAlgo = OBJ_nid2sn(X509_get_signature_nid(certImpl)); -#else - signatureAlgo = OBJ_nid2sn(OBJ_obj2nid(certImpl->sig_alg->algorithm)); -#endif -} - -void Certificate::loadSerialNumber() -{ - if (auto sn = X509_get_serialNumber(certImpl)) - retdec::utils::bytesToHexString(sn->data, sn->length, serialNumber, 0, 0, false); -} - -void Certificate::loadIssuerAndSubject() -{ - if (auto subjectName = X509_get_subject_name(certImpl)) - { - auto subjectNameOneline = managedPtr(X509_NAME_oneline(subjectName, nullptr, 0), &free); - subjectRaw = subjectNameOneline.get(); - - parseAttributes(&subject, subjectName); - } - - if (auto issuerName = X509_get_issuer_name(certImpl)) - { - auto issuerNameOneline = managedPtr(X509_NAME_oneline(issuerName, nullptr, 0), &free); - issuerRaw = issuerNameOneline.get(); - - parseAttributes(&issuer, issuerName); - } -} - -void Certificate::calculateHashes() -{ - std::vector tmp(0x2000); - auto memBio = managedPtr(BIO_new(BIO_s_mem()), &BIO_free); - - i2d_X509_bio(memBio.get(), certImpl); - std::size_t certLen = BIO_read(memBio.get(), tmp.data(), int(tmp.size())); - tmp.resize(certLen); - - std::vector sha1Bytes(SHA_DIGEST_LENGTH), sha256Bytes(SHA256_DIGEST_LENGTH); - SHA1(reinterpret_cast(tmp.data()), tmp.size(), sha1Bytes.data()); - SHA256(reinterpret_cast(tmp.data()), tmp.size(), sha256Bytes.data()); - - retdec::utils::bytesToHexString(sha1Bytes, sha1Digest, 0, 0, false); - retdec::utils::bytesToHexString(sha256Bytes, sha256Digest, 0, 0, false); -} - /** * Get date since when is certificate valid * @return Date since when is certificate valid