10#include <botan/certstor_windows.h>
12#include <botan/assert.h>
13#include <botan/ber_dec.h>
14#include <botan/hash.h>
15#include <botan/pkix_types.h>
27#define WINCRYPT_UNUSED_PARAM \
27#define WINCRYPT_UNUSED_PARAM \ …
33const std::array<const char*, 2> cert_store_names{
"Root",
"CA"};
45 Handle_Guard(T context) : m_context(context) {}
47 Handle_Guard(
const Handle_Guard<T>& rhs) =
delete;
49 Handle_Guard(Handle_Guard<T>&& rhs) : m_context(std::move(rhs.m_context)) { rhs.m_context =
nullptr; }
51 ~Handle_Guard() { close<T>(); }
53 operator bool()
const {
return m_context !=
nullptr; }
55 bool assign(T context) {
57 return m_context !=
nullptr;
60 T& get() {
return m_context; }
62 const T& get()
const {
return m_context; }
64 T operator->() {
return m_context; }
67 template <
class T2 = T>
68 typename std::enable_if<std::is_same<T2, PCCERT_CONTEXT>::value>::type close() {
70 CertFreeCertificateContext(m_context);
74 template <
class T2 = T>
75 typename std::enable_if<std::is_same<T2, HCERTSTORE>::value>::type close() {
80 CertCloseStore(m_context, 0);
87HCERTSTORE open_cert_store(
const char* cert_store_name) {
90 throw Internal_Error(
"failed to open windows certificate store '" + std::string(cert_store_name) +
91 "' (Error Code: " + std::to_string(::GetLastError()) +
")");
96std::vector<X509_Certificate> search_cert_stores(
97 const _CRYPTOAPI_BLOB& blob,
98 const DWORD& find_type,
99 std::function<
bool(
const std::vector<X509_Certificate>& certs,
const X509_Certificate& cert)> filter,
100 bool return_on_first_found) {
101 std::vector<X509_Certificate> certs;
102 for(
const auto store_name : cert_store_names) {
103 Handle_Guard<HCERTSTORE> windows_cert_store = open_cert_store(store_name);
104 Handle_Guard<PCCERT_CONTEXT> cert_context =
nullptr;
105 while(cert_context.assign(CertFindCertificateInStore(windows_cert_store.get(),
106 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
110 cert_context.get()))) {
111 X509_Certificate cert(cert_context->pbCertEncoded, cert_context->cbCertEncoded);
112 if(filter(certs, cert)) {
113 if(return_on_first_found) {
116 certs.push_back(cert);
124bool already_contains_certificate(
const std::vector<X509_Certificate>& certs, X509_Certificate cert) {
125 return std::any_of(certs.begin(), certs.end(), [&](
const X509_Certificate& c) { return c == cert; });
128std::vector<X509_Certificate> find_cert_by_dn_and_key_id(
const X509_DN& subject_dn,
129 const std::vector<uint8_t>& key_id,
130 bool return_on_first_found) {
131 _CRYPTOAPI_BLOB blob;
133 std::vector<uint8_t> dn_data;
137 find_type = CERT_FIND_SUBJECT_NAME;
138 dn_data = subject_dn.DER_encode();
139 blob.cbData =
static_cast<DWORD
>(dn_data.size());
140 blob.pbData =
reinterpret_cast<BYTE*
>(dn_data.data());
142 find_type = CERT_FIND_KEY_IDENTIFIER;
143 blob.cbData =
static_cast<DWORD
>(key_id.size());
144 blob.pbData =
const_cast<BYTE*
>(key_id.data());
147 auto filter = [&](
const std::vector<X509_Certificate>& certs,
const X509_Certificate& cert) {
148 return !already_contains_certificate(certs, cert) && (key_id.empty() || cert.subject_dn() == subject_dn);
151 return search_cert_stores(blob, find_type, filter, return_on_first_found);
159 std::vector<X509_DN> subject_dns;
160 for(
const auto store_name : cert_store_names) {
161 Handle_Guard<HCERTSTORE> windows_cert_store = open_cert_store(store_name);
162 Handle_Guard<PCCERT_CONTEXT> cert_context =
nullptr;
166 while(cert_context.assign(CertEnumCertificatesInStore(windows_cert_store.get(), cert_context.get()))) {
167 BER_Decoder dec(cert_context->pCertInfo->Subject.pbData, cert_context->pCertInfo->Subject.cbData);
171 subject_dns.emplace_back(std::move(dn));
179 const std::vector<uint8_t>& key_id)
const {
180 const auto certs = find_cert_by_dn_and_key_id(subject_dn, key_id,
true);
184 return certs.front();
188 const std::vector<uint8_t>& key_id)
const {
189 return find_cert_by_dn_and_key_id(subject_dn, key_id,
false);
193 const std::vector<uint8_t>& key_hash)
const {
194 if(key_hash.size() != 20) {
195 throw Invalid_Argument(
"Certificate_Store_Windows::find_cert_by_pubkey_sha1 invalid hash");
198 CRYPT_HASH_BLOB blob;
199 blob.cbData =
static_cast<DWORD
>(key_hash.size());
200 blob.pbData =
const_cast<BYTE*
>(key_hash.data());
202 auto filter = [&](
const std::vector<X509_Certificate>&,
const X509_Certificate&) {
return true; };
207 const auto certs = search_cert_stores(blob, CERT_FIND_KEY_IDENTIFIER, filter,
true);
209 return certs.front();
213 return find_cert_by_pubkey_sha1_via_exhaustive_search(key_hash);
217 const std::vector<uint8_t>& subject_hash)
const {
219 throw Not_Implemented(
"Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256");
228std::optional<X509_Certificate> Certificate_Store_Windows::find_cert_by_pubkey_sha1_via_exhaustive_search(
229 const std::vector<uint8_t>& key_hash)
const {
230 if(
const auto cache_hit = m_non_rfc3289_certs.find(key_hash); cache_hit != m_non_rfc3289_certs.end()) {
231 return cache_hit->second;
235 for(
const auto store_name : cert_store_names) {
236 Handle_Guard<HCERTSTORE> windows_cert_store = open_cert_store(store_name);
237 Handle_Guard<PCCERT_CONTEXT> cert_context =
nullptr;
241 while(cert_context.assign(CertEnumCertificatesInStore(windows_cert_store.get(), cert_context.get()))) {
242 const auto pubkey_blob = cert_context->pCertInfo->SubjectPublicKeyInfo.PublicKey;
243 const auto key_hash_candidate = sha1->process(
static_cast<uint8_t*
>(pubkey_blob.pbData), pubkey_blob.cbData);
245 if(std::equal(key_hash.begin(), key_hash.end(), key_hash_candidate.begin())) {
246 X509_Certificate result(cert_context->pbCertEncoded, cert_context->cbCertEncoded);
247 m_non_rfc3289_certs[key_hash] = result;
254 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