Botan 2.13.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

certstor_windows.cpp
Go to the documentation of this file.
1 /*
2 * Certificate Store
3 * (C) 1999-2019 Jack Lloyd
4 * (C) 2018-2019 Patrik Fiedler, Tim Oesterreich
5 *
6 * Botan is released under the Simplified BSD License (see license.txt)
7 */
8
9 #include <botan/certstor_windows.h>
10 #include <botan/der_enc.h>
11
12 #include <array>
13 #include <vector>
14
15 #define NOMINMAX 1
16 #define _WINSOCKAPI_ // stop windows.h including winsock.h
17 #include <windows.h>
18 #include <wincrypt.h>
19
20 namespace Botan {
21 namespace {
22
23 using Cert_Pointer = std::shared_ptr<const Botan::X509_Certificate>;
24 using Cert_Vector = std::vector<Cert_Pointer>;
25 const std::array<const char*, 2> cert_store_names{"Root", "CA"};
26
27 /**
28 * Abstract RAII wrapper for PCCERT_CONTEXT and HCERTSTORE
29 * The Windows API partly takes care of those pointers destructions itself.
30 * Especially, iteratively calling `CertFindCertificateInStore` with the previous PCCERT_CONTEXT
31 * will free the context and return a new one. In this case, this guard takes care of freeing the context
32 * in case of an exception and at the end of the iterative process.
33 */
34 template<class T>
35 class Handle_Guard
36 {
37 public:
38 Handle_Guard(T context)
39 : m_context(context)
40 {
41 }
42
43 Handle_Guard(const Handle_Guard<T>& rhs) = delete;
44 Handle_Guard(Handle_Guard<T>&& rhs) :
45 m_context(std::move(rhs.m_context))
46 {
47 rhs.m_context = nullptr;
48 }
49
50 ~Handle_Guard()
51 {
52 close<T>();
53 }
54
55 operator bool() const
56 {
57 return m_context != nullptr;
58 }
59
60 bool assign(T context)
61 {
62 m_context = context;
63 return m_context != nullptr;
64 }
65
66 T& get()
67 {
68 return m_context;
69 }
70
71 const T& get() const
72 {
73 return m_context;
74 }
75
76 T operator->()
77 {
78 return m_context;
79 }
80
81 private:
82 template<class T2 = T>
83 typename std::enable_if<std::is_same<T2, PCCERT_CONTEXT>::value>::type close()
84 {
85 if(m_context)
86 {
87 CertFreeCertificateContext(m_context);
88 }
89 }
90
91 template<class T2 = T>
92 typename std::enable_if<std::is_same<T2, HCERTSTORE>::value>::type close()
93 {
94 if(m_context)
95 {
96 // second parameter is a flag that tells the store how to deallocate memory
97 // using the default "0", this function works like decreasing the reference counter
98 // in a shared_ptr
99 CertCloseStore(m_context, 0);
100 }
101 }
102
103 T m_context;
104 };
105
106 HCERTSTORE open_cert_store(const char* cert_store_name)
107 {
108 auto store = CertOpenSystemStore(NULL, cert_store_name);
109 if(!store)
110 {
111 throw Botan::Internal_Error(
112 "failed to open windows certificate store '" + std::string(cert_store_name) +
113 "' (Error Code: " +
114 std::to_string(::GetLastError()) + ")");
115 }
116 return store;
117 }
118
119 Cert_Vector search_cert_stores(const _CRYPTOAPI_BLOB& blob, const DWORD& find_type,
120 std::function<bool(const Cert_Vector& certs, Cert_Pointer cert)> filter,
121 bool return_on_first_found)
122 {
123 Cert_Vector certs;
124 for(const auto store_name : cert_store_names)
125 {
126 Handle_Guard<HCERTSTORE> windows_cert_store = open_cert_store(store_name);
127 Handle_Guard<PCCERT_CONTEXT> cert_context = nullptr;
128 while(cert_context.assign(CertFindCertificateInStore(
129 windows_cert_store.get(), PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
130 NULL, find_type,
131 &blob, cert_context.get())))
132 {
133 auto cert = std::make_shared<X509_Certificate>(cert_context->pbCertEncoded, cert_context->cbCertEncoded);
134 if(filter(certs, cert))
135 {
136 if(return_on_first_found)
137 {
138 return {cert};
139 }
140 certs.push_back(cert);
141 }
142 }
143 }
144
145 return certs;
146 }
147
148 bool already_contains_certificate(const Cert_Vector& certs, Cert_Pointer cert)
149 {
150 return std::any_of(certs.begin(), certs.end(), [&](std::shared_ptr<const Botan::X509_Certificate> c)
151 {
152 return *c == *cert;
153 });
154 }
155
156 Cert_Vector find_cert_by_dn_and_key_id(const Botan::X509_DN& subject_dn,
157 const std::vector<uint8_t>& key_id,
158 bool return_on_first_found)
159 {
160 _CRYPTOAPI_BLOB blob;
161 DWORD find_type;
162 std::vector<uint8_t> dn_data;
163
164 // if key_id is available, prefer searching that, as it should be "more unique" than the subject DN
165 if(key_id.empty())
166 {
167 find_type = CERT_FIND_SUBJECT_NAME;
168 DER_Encoder encoder(dn_data);
169 subject_dn.encode_into(encoder);
170 blob.cbData = static_cast<DWORD>(dn_data.size());
171 blob.pbData = reinterpret_cast<BYTE*>(dn_data.data());
172 }
173 else
174 {
175 find_type = CERT_FIND_KEY_IDENTIFIER;
176 blob.cbData = static_cast<DWORD>(key_id.size());
177 blob.pbData = const_cast<BYTE*>(key_id.data());
178 }
179
180 auto filter = [&](const Cert_Vector& certs, Cert_Pointer cert)
181 {
182 return !already_contains_certificate(certs, cert) && (key_id.empty() || cert->subject_dn() == subject_dn);
183 };
184
185 return search_cert_stores(blob, find_type, filter, return_on_first_found);
186 }
187 } // namespace
188
189 Certificate_Store_Windows::Certificate_Store_Windows() {}
190
191 std::vector<X509_DN> Certificate_Store_Windows::all_subjects() const
192 {
193 std::vector<X509_DN> subject_dns;
194 for(const auto store_name : cert_store_names)
195 {
196 Handle_Guard<HCERTSTORE> windows_cert_store = open_cert_store(store_name);
197 Handle_Guard<PCCERT_CONTEXT> cert_context = nullptr;
198
199 // Handle_Guard::assign exchanges the underlying pointer. No RAII is needed here, because the Windows API takes care of
200 // freeing the previous context.
201 while(cert_context.assign(CertEnumCertificatesInStore(windows_cert_store.get(), cert_context.get())))
202 {
203 X509_Certificate cert(cert_context->pbCertEncoded, cert_context->cbCertEncoded);
204 subject_dns.push_back(cert.subject_dn());
205 }
206 }
207
208 return subject_dns;
209 }
210
211 Cert_Pointer Certificate_Store_Windows::find_cert(const Botan::X509_DN& subject_dn,
212 const std::vector<uint8_t>& key_id) const
213 {
214 const auto certs = find_cert_by_dn_and_key_id(subject_dn, key_id, true);
215 return certs.empty() ? nullptr : certs.front();
216 }
217
218 Cert_Vector Certificate_Store_Windows::find_all_certs(
219 const X509_DN& subject_dn,
220 const std::vector<uint8_t>& key_id) const
221 {
222 return find_cert_by_dn_and_key_id(subject_dn, key_id, false);
223 }
224
225 Cert_Pointer Certificate_Store_Windows::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
226 {
227 if(key_hash.size() != 20)
228 {
229 throw Invalid_Argument("Certificate_Store_Windows::find_cert_by_pubkey_sha1 invalid hash");
230 }
231
232 CRYPT_HASH_BLOB blob;
233 blob.cbData = static_cast<DWORD>(key_hash.size());
234 blob.pbData = const_cast<BYTE*>(key_hash.data());
235
236 auto filter = [](const Cert_Vector&, Cert_Pointer) { return true; };
237
238 const auto certs = search_cert_stores(blob, CERT_FIND_KEY_IDENTIFIER, filter, true);
239 return certs.empty() ? nullptr : certs.front();
240 }
241
242 Cert_Pointer Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256(
243 const std::vector<uint8_t>& subject_hash) const
244 {
245 BOTAN_UNUSED(subject_hash);
246 throw Not_Implemented("Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256");
247 }
248
249 std::shared_ptr<const X509_CRL> Certificate_Store_Windows::find_crl_for(const X509_Certificate& subject) const
250 {
251 // TODO: this could be implemented by using the CertFindCRLInStore function
252 BOTAN_UNUSED(subject);
253 return {};
254 }
255 }
Botan::Certificate_Store_Windows::all_subjects
std::vector< X509_DN > all_subjects() const override
Definition: certstor_windows.cpp:191
Botan::Invalid_Argument
Definition: exceptn.h:136
Botan::Certificate_Store_Windows::find_all_certs
std::vector< std::shared_ptr< const X509_Certificate > > find_all_certs(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const override
Definition: certstor_windows.cpp:218
m_context
T m_context
Definition: certstor_windows.cpp:103
Botan::Certificate_Store_Windows::Certificate_Store_Windows
Certificate_Store_Windows()
Definition: certstor_windows.cpp:189
Botan::Internal_Error
Definition: exceptn.h:341
Botan::Not_Implemented
Definition: exceptn.h:355
Botan::ASN1::to_string
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
Botan::X509_DN::encode_into
void encode_into(class DER_Encoder &) const override
Definition: x509_dn.cpp:241
type
MechanismType type
Definition: p11_mechanism.cpp:44
Botan::Certificate_Store_Windows::find_cert_by_pubkey_sha1
std::shared_ptr< const X509_Certificate > find_cert_by_pubkey_sha1(const std::vector< uint8_t > &key_hash) const override
Definition: certstor_windows.cpp:225
Botan::Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256
std::shared_ptr< const X509_Certificate > find_cert_by_raw_subject_dn_sha256(const std::vector< uint8_t > &subject_hash) const override
Definition: certstor_windows.cpp:242
Botan::X509_Certificate
Definition: x509cert.h:40
Botan::X509_DN
Definition: x509_dn.h:24
Botan
Definition: alg_id.cpp:13
BOTAN_UNUSED
#define BOTAN_UNUSED(...)
Definition: assert.h:142
Botan::Certificate_Store_Windows::find_cert
std::shared_ptr< const X509_Certificate > find_cert(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const override
Definition: certstor_windows.cpp:211
T
fe T
Definition: ge.cpp:37
Botan::X509_Certificate::subject_dn
const X509_DN & subject_dn() const
Definition: x509cert.cpp:438
Botan::Certificate_Store_Windows::find_crl_for
std::shared_ptr< const X509_CRL > find_crl_for(const X509_Certificate &subject) const override
Definition: certstor_windows.cpp:249