10#include <botan/certstor_windows.h>
12#include <botan/ber_dec.h>
13#include <botan/hash.h>
14#include <botan/pkix_types.h>
25#define WINCRYPT_UNUSED_PARAM \
31const std::array<const char*, 2> cert_store_names{
"Root",
"CA"};
43 Handle_Guard(
T context) : m_context(context) {}
45 Handle_Guard(
const Handle_Guard<T>& rhs) =
delete;
47 Handle_Guard(Handle_Guard<T>&& rhs) : m_context(std::move(rhs.m_context)) { rhs.m_context =
nullptr; }
49 ~Handle_Guard() { close<T>(); }
51 operator bool()
const {
return m_context !=
nullptr; }
53 bool assign(
T context) {
55 return m_context !=
nullptr;
58 T& get() {
return m_context; }
60 const T& get()
const {
return m_context; }
62 T operator->() {
return m_context; }
65 template <
class T2 = T>
66 typename std::enable_if<std::is_same<T2, PCCERT_CONTEXT>::value>::type close() {
68 CertFreeCertificateContext(m_context);
72 template <
class T2 = T>
73 typename std::enable_if<std::is_same<T2, HCERTSTORE>::value>::type close() {
78 CertCloseStore(m_context, 0);
85HCERTSTORE open_cert_store(
const char* cert_store_name) {
88 throw Internal_Error(
"failed to open windows certificate store '" + std::string(cert_store_name) +
89 "' (Error Code: " + std::to_string(::GetLastError()) +
")");
94std::vector<X509_Certificate> search_cert_stores(
95 const _CRYPTOAPI_BLOB& blob,
96 const DWORD& find_type,
97 std::function<
bool(
const std::vector<X509_Certificate>& certs,
const X509_Certificate& cert)> filter,
98 bool return_on_first_found) {
99 std::vector<X509_Certificate> certs;
100 for(
const auto store_name : cert_store_names) {
101 Handle_Guard<HCERTSTORE> windows_cert_store = open_cert_store(store_name);
102 Handle_Guard<PCCERT_CONTEXT> cert_context =
nullptr;
103 while(cert_context.assign(CertFindCertificateInStore(windows_cert_store.get(),
104 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
108 cert_context.get()))) {
109 X509_Certificate cert(cert_context->pbCertEncoded, cert_context->cbCertEncoded);
110 if(filter(certs, cert)) {
111 if(return_on_first_found) {
114 certs.push_back(cert);
122bool already_contains_certificate(
const std::vector<X509_Certificate>& certs, X509_Certificate cert) {
123 return std::any_of(certs.begin(), certs.end(), [&](
const X509_Certificate& c) { return c == cert; });
126std::vector<X509_Certificate> find_cert_by_dn_and_key_id(
const X509_DN& subject_dn,
127 const std::vector<uint8_t>& key_id,
128 bool return_on_first_found) {
129 _CRYPTOAPI_BLOB blob;
131 std::vector<uint8_t> dn_data;
135 find_type = CERT_FIND_SUBJECT_NAME;
136 dn_data = subject_dn.DER_encode();
137 blob.cbData =
static_cast<DWORD
>(dn_data.size());
138 blob.pbData =
reinterpret_cast<BYTE*
>(dn_data.data());
140 find_type = CERT_FIND_KEY_IDENTIFIER;
141 blob.cbData =
static_cast<DWORD
>(key_id.size());
142 blob.pbData =
const_cast<BYTE*
>(key_id.data());
145 auto filter = [&](
const std::vector<X509_Certificate>& certs,
const X509_Certificate& cert) {
146 return !already_contains_certificate(certs, cert) && (key_id.empty() || cert.subject_dn() == subject_dn);
149 return search_cert_stores(blob, find_type, filter, return_on_first_found);
157 std::vector<X509_DN> subject_dns;
158 for(
const auto store_name : cert_store_names) {
159 Handle_Guard<HCERTSTORE> windows_cert_store = open_cert_store(store_name);
160 Handle_Guard<PCCERT_CONTEXT> cert_context =
nullptr;
164 while(cert_context.assign(CertEnumCertificatesInStore(windows_cert_store.get(), cert_context.get()))) {
165 BER_Decoder dec(cert_context->pCertInfo->Subject.pbData, cert_context->pCertInfo->Subject.cbData);
169 subject_dns.emplace_back(std::move(dn));
177 const std::vector<uint8_t>& key_id)
const {
178 const auto certs = find_cert_by_dn_and_key_id(subject_dn, key_id,
true);
182 return certs.front();
186 const std::vector<uint8_t>& key_id)
const {
187 return find_cert_by_dn_and_key_id(subject_dn, key_id,
false);
191 const std::vector<uint8_t>& key_hash)
const {
192 if(key_hash.size() != 20) {
193 throw Invalid_Argument(
"Certificate_Store_Windows::find_cert_by_pubkey_sha1 invalid hash");
196 CRYPT_HASH_BLOB blob;
197 blob.cbData =
static_cast<DWORD
>(key_hash.size());
198 blob.pbData =
const_cast<BYTE*
>(key_hash.data());
200 auto filter = [&](
const std::vector<X509_Certificate>&,
const X509_Certificate&) {
return true; };
205 const auto certs = search_cert_stores(blob, CERT_FIND_KEY_IDENTIFIER, filter,
true);
207 return certs.front();
211 return find_cert_by_pubkey_sha1_via_exhaustive_search(key_hash);
215 const std::vector<uint8_t>& subject_hash)
const {
217 throw Not_Implemented(
"Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256");
226std::optional<X509_Certificate> Certificate_Store_Windows::find_cert_by_pubkey_sha1_via_exhaustive_search(
227 const std::vector<uint8_t>& key_hash)
const {
228 if(
const auto cache_hit = m_non_rfc3289_certs.find(key_hash); cache_hit != m_non_rfc3289_certs.end()) {
229 return cache_hit->second;
233 for(
const auto store_name : cert_store_names) {
234 Handle_Guard<HCERTSTORE> windows_cert_store = open_cert_store(store_name);
235 Handle_Guard<PCCERT_CONTEXT> cert_context =
nullptr;
239 while(cert_context.assign(CertEnumCertificatesInStore(windows_cert_store.get(), cert_context.get()))) {
240 const auto pubkey_blob = cert_context->pCertInfo->SubjectPublicKeyInfo.PublicKey;
241 const auto key_hash_candidate = sha1->process(
static_cast<uint8_t*
>(pubkey_blob.pbData), pubkey_blob.cbData);
243 if(std::equal(key_hash.begin(), key_hash.end(), key_hash_candidate.begin())) {
244 X509_Certificate result(cert_context->pbCertEncoded, cert_context->cbCertEncoded);
245 m_non_rfc3289_certs[key_hash] = result;
252 m_non_rfc3289_certs[key_hash] = std::nullopt;
#define WINCRYPT_UNUSED_PARAM
Certificate_Store_Windows()
std::vector< X509_DN > all_subjects() const override
std::optional< X509_Certificate > find_cert_by_pubkey_sha1(const std::vector< uint8_t > &key_hash) const override
std::optional< X509_Certificate > find_cert(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const override
std::optional< X509_Certificate > find_cert_by_raw_subject_dn_sha256(const std::vector< uint8_t > &subject_hash) const override
std::optional< X509_CRL > find_crl_for(const X509_Certificate &subject) const override
std::vector< X509_Certificate > find_all_certs(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const override
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
void decode_from(BER_Decoder &) override