From 85490ba683d75a6c554dd866d4e2bb262d3db373 Mon Sep 17 00:00:00 2001 From: Tim Oesterreich Date: Thu, 2 May 2019 16:32:19 +0200 Subject: add find_cert by key_id functionality --- .../certstor_system_windows/certstor_windows.cpp | 111 ++++++++++++++++----- 1 file changed, 84 insertions(+), 27 deletions(-) (limited to 'src/lib/x509') diff --git a/src/lib/x509/certstor_system_windows/certstor_windows.cpp b/src/lib/x509/certstor_system_windows/certstor_windows.cpp index 9bbe6ee31..7ad5d0263 100644 --- a/src/lib/x509/certstor_system_windows/certstor_windows.cpp +++ b/src/lib/x509/certstor_system_windows/certstor_windows.cpp @@ -43,44 +43,101 @@ std::vector Certificate_Store_Windows::all_subjects() const return subject_dns; } - std::vector certStoreNames{"MY", "Root", "Trust", "CA"}; - for (auto &storeName : certStoreNames) { - auto windowsCertStore = CertOpenSystemStore(0, storeName.c_str()); - if (!windowsCertStore) { - throw Decoding_Error( - "failed to open windows certificate store '" + storeName + - "' to find_cert (Error Code: " + - std::to_string(::GetLastError()) + ")"); - } - PCCERT_CONTEXT pCertContext = CertFindCertificateInStore( - windowsCertStore, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, - CERT_UNICODE_IS_RDN_ATTRS_FLAG, CERT_FIND_SUBJECT_STR_A, - certName.c_str(), nullptr); +PCCERT_CONTEXT lookup_cert_by_name(const std::string& cert_name, const std::string& cert_store_name, PCCERT_CONTEXT prevContext = nullptr) +{ + auto windows_cert_store = CertOpenSystemStore(0, cert_store_name.c_str()); + if (!windows_cert_store) { + throw Decoding_Error( + "failed to open windows certificate store '" + cert_store_name + + "' to find_cert (Error Code: " + + std::to_string(::GetLastError()) + ")"); + } + + PCCERT_CONTEXT cert_context = CertFindCertificateInStore( + windows_cert_store, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, + CERT_UNICODE_IS_RDN_ATTRS_FLAG, CERT_FIND_SUBJECT_STR_A, + cert_name.c_str(), prevContext); - CertCloseStore(windowsCertStore, 0); + CertCloseStore(windows_cert_store, 0); - if (pCertContext) { - X509_Certificate cert(pCertContext->pbCertEncoded, pCertContext->cbCertEncoded); - CertFreeCertificateContext(pCertContext); + return cert_context; +} - if (cert.subject_dn() == subject_dn) { - return std::shared_ptr(&cert); - } - } +PCCERT_CONTEXT lookup_cert_by_hash_blob(const CRYPT_HASH_BLOB& hash_blob, const std::string& cert_store_name, PCCERT_CONTEXT prevContext = nullptr) +{ + auto windows_cert_store = CertOpenSystemStore(0, cert_store_name.c_str()); + if (!windows_cert_store) { + throw Decoding_Error( + "failed to open windows certificate store '" + cert_store_name + + "' to find_cert (Error Code: " + + std::to_string(::GetLastError()) + ")"); } - return nullptr; + PCCERT_CONTEXT cert_context = CertFindCertificateInStore( + windows_cert_store, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, + 0, CERT_FIND_KEY_IDENTIFIER, + &hash_blob, prevContext); + + CertCloseStore(windows_cert_store, 0); + + return cert_context; +} + +std::shared_ptr +Certificate_Store_Windows::find_cert(const Botan::X509_DN & subject_dn, + const std::vector &key_id) const +{ + const auto certs = find_all_certs(subject_dn, key_id); + return certs.empty() ? nullptr : certs.front(); +} + +bool already_contains_key_id( + const std::vector>& certs, const std::vector& key_id) +{ + return std::any_of(certs.begin(), certs.end(), + [&](std::shared_ptr c) { + return c->subject_key_id() == key_id; + }); } std::vector> Certificate_Store_Windows::find_all_certs( - const X509_DN& subject_dn, - const std::vector& key_id) const + const X509_DN& subject_dn, + const std::vector& key_id) const { - BOTAN_UNUSED(subject_dn); - BOTAN_UNUSED(key_id); - return {}; + auto common_name = subject_dn.get_attribute("CN"); + + if (common_name.empty()) + { + return {}; // certificate not found + } + + if (common_name.size() != 1) + { + throw Lookup_Error("ambiguous certificate result"); + } + + const auto &cert_name = common_name[0]; + + std::vector> certs; + std::vector cert_store_names{"MY", "Root", "Trust", "CA"}; + for (auto &store_name : cert_store_names) { + PCCERT_CONTEXT cert_context = nullptr; + while (cert_context = lookup_cert_by_name(cert_name, store_name, cert_context)) { + if (cert_context) { + auto cert = std::make_shared(cert_context->pbCertEncoded, cert_context->cbCertEncoded); + if (cert->subject_dn() == subject_dn && + (key_id.empty() || (cert->subject_key_id() == key_id && !already_contains_key_id(certs, key_id)))) + { + certs.push_back(cert); + } + } + } + } + + return certs; } + std::shared_ptr Certificate_Store_Windows::find_cert_by_pubkey_sha1( const std::vector &key_hash) const -- cgit v1.2.3