Botan 3.12.0
Crypto and TLS for C&
certstor.cpp
Go to the documentation of this file.
1/*
2* Certificate Store
3* (C) 1999-2010,2013 Jack Lloyd
4* (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/certstor.h>
10
11#include <botan/asn1_time.h>
12#include <botan/assert.h>
13#include <botan/data_src.h>
14#include <botan/pkix_types.h>
15#include <botan/internal/filesystem.h>
16#include <algorithm>
17#include <map>
18#include <set>
19
20namespace Botan {
21
23
25 return contains(cert);
26}
27
28bool Certificate_Store::contains(const X509_Certificate& searching) const {
29 for(const auto& cert : find_all_certs(searching.subject_dn(), searching.subject_key_id())) {
30 if(cert == searching) {
31 return true;
32 }
33 }
34
35 return false;
36}
37
38std::optional<X509_Certificate> Certificate_Store::find_cert(const X509_DN& subject_dn,
39 const std::vector<uint8_t>& key_id) const {
40 const auto certs = find_all_certs(subject_dn, key_id);
41
42 if(certs.empty()) {
43 return std::nullopt;
44 }
45
46 // `count` might be greater than 1, but we'll just select the first match
47 return certs.front();
48}
49
50std::optional<X509_CRL> Certificate_Store::find_crl_for(const X509_Certificate& /*unused*/) const {
51 return std::nullopt;
52}
53
54class Certificate_Store_In_Memory::Impl final {
55 public:
56 std::vector<X509_Certificate> m_certs;
57 std::set<X509_Certificate::Tag> m_cert_tags;
58 std::map<X509_DN, std::vector<size_t>> m_dn_to_indices;
59 std::vector<X509_CRL> m_crls;
60 std::map<X509_DN, size_t> m_issuer_dn_to_crl_idx;
61};
62
63Certificate_Store_In_Memory::Certificate_Store_In_Memory() : m_impl(std::make_unique<Impl>()) {}
64
66 m_impl(std::make_unique<Impl>(other.impl())) {}
67
69
71 default;
72
74
75Certificate_Store_In_Memory::Impl& Certificate_Store_In_Memory::impl() {
76 BOTAN_STATE_CHECK(m_impl != nullptr);
77 return *m_impl;
78}
79
80const Certificate_Store_In_Memory::Impl& Certificate_Store_In_Memory::impl() const {
81 BOTAN_STATE_CHECK(m_impl != nullptr);
82 return *m_impl;
83}
84
86 auto& store = impl();
87 const auto tag = cert.tag();
88 if(!store.m_cert_tags.contains(tag)) {
89 store.m_cert_tags.insert(tag);
90 const size_t idx = store.m_certs.size();
91 store.m_certs.push_back(cert);
92 store.m_dn_to_indices[cert.subject_dn()].push_back(idx);
93 }
94}
95
96std::vector<X509_DN> Certificate_Store_In_Memory::all_subjects() const {
97 const auto& store = impl();
98 std::vector<X509_DN> subjects;
99 subjects.reserve(store.m_certs.size());
100 for(const auto& cert : store.m_certs) {
101 subjects.push_back(cert.subject_dn());
102 }
103 return subjects;
104}
105
106std::optional<X509_Certificate> Certificate_Store_In_Memory::find_cert(const X509_DN& subject_dn,
107 const std::vector<uint8_t>& key_id) const {
108 const auto& store = impl();
109 const auto it = store.m_dn_to_indices.find(subject_dn);
110 if(it == store.m_dn_to_indices.end()) {
111 return std::nullopt;
112 }
113
114 for(const size_t idx : it->second) {
115 const auto& cert = store.m_certs[idx];
116 BOTAN_ASSERT_NOMSG(cert.subject_dn() == subject_dn);
117
118 if(!key_id.empty()) {
119 const std::vector<uint8_t>& skid = cert.subject_key_id();
120 if(!skid.empty() && skid != key_id) { // no match
121 continue;
122 }
123 }
124
125 return cert;
126 }
127
128 return std::nullopt;
129}
130
131std::vector<X509_Certificate> Certificate_Store_In_Memory::find_all_certs(const X509_DN& subject_dn,
132 const std::vector<uint8_t>& key_id) const {
133 const auto& store = impl();
134 std::vector<X509_Certificate> matches;
135
136 const auto it = store.m_dn_to_indices.find(subject_dn);
137 if(it == store.m_dn_to_indices.end()) {
138 return matches;
139 }
140
141 for(const size_t idx : it->second) {
142 const auto& cert = store.m_certs[idx];
143 BOTAN_ASSERT_NOMSG(cert.subject_dn() == subject_dn);
144
145 if(!key_id.empty()) {
146 const std::vector<uint8_t>& skid = cert.subject_key_id();
147 if(!skid.empty() && skid != key_id) { // no match
148 continue;
149 }
150 }
151
152 matches.push_back(cert);
153 }
154
155 return matches;
156}
157
159 const std::vector<uint8_t>& key_hash) const {
160 if(key_hash.size() != 20) {
161 throw Invalid_Argument("Certificate_Store_In_Memory::find_cert_by_pubkey_sha1 invalid hash");
162 }
163
164 for(const auto& cert : impl().m_certs) {
165 if(key_hash == cert.subject_public_key_bitstring_sha1()) {
166 return cert;
167 }
168 }
169
170 return std::nullopt;
171}
172
174 const std::vector<uint8_t>& subject_hash) const {
175 if(subject_hash.size() != 32) {
176 throw Invalid_Argument("Certificate_Store_In_Memory::find_cert_by_raw_subject_dn_sha256 invalid hash");
177 }
178
179 for(const auto& cert : impl().m_certs) {
180 if(subject_hash == cert.raw_subject_dn_sha256()) {
181 return cert;
182 }
183 }
184
185 return std::nullopt;
186}
187
189 const X509_DN& issuer_dn, std::span<const uint8_t> serial_number) const {
190 for(const auto& cert : impl().m_certs) {
191 if(cert.issuer_dn() == issuer_dn && std::ranges::equal(cert.serial_number(), serial_number)) {
192 return cert;
193 }
194 }
195
196 return std::nullopt;
197}
198
200 auto& store = impl();
201 const X509_DN& crl_issuer = crl.issuer_dn();
202
203 if(const auto it = store.m_issuer_dn_to_crl_idx.find(crl_issuer); it != store.m_issuer_dn_to_crl_idx.end()) {
204 auto& current_crl = store.m_crls.at(it->second);
205
206 // Found an update of a previously existing one; replace it
207 if(current_crl.this_update() <= crl.this_update()) {
208 current_crl = crl;
209 }
210
211 return;
212 }
213
214 // Totally new CRL, add to the list
215 store.m_issuer_dn_to_crl_idx.emplace(crl_issuer, store.m_crls.size());
216 store.m_crls.push_back(crl);
217}
218
219std::optional<X509_CRL> Certificate_Store_In_Memory::find_crl_for(const X509_Certificate& subject) const {
220 const auto& store = impl();
221 const std::vector<uint8_t>& key_id = subject.authority_key_id();
222
223 const auto it = store.m_issuer_dn_to_crl_idx.find(subject.issuer_dn());
224 if(it == store.m_issuer_dn_to_crl_idx.end()) {
225 return std::nullopt;
226 }
227
228 const auto& crl = store.m_crls.at(it->second);
229
230 // Only compare key ids if set in both call and in the CRL
231 if(!key_id.empty()) {
232 const std::vector<uint8_t>& akid = crl.authority_key_id();
233
234 if(!akid.empty() && akid != key_id) {
235 return std::nullopt;
236 }
237 }
238
239 return crl;
240}
241
243 return impl().m_cert_tags.contains(cert.tag());
244}
245
249
255
256#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
258 if(dir.empty()) {
259 return;
260 }
261
262 std::vector<std::string> maybe_certs = get_files_recursive(dir);
263
264 if(maybe_certs.empty()) {
265 maybe_certs.push_back(std::string(dir));
266 }
267
268 for(auto&& cert_file : maybe_certs) {
269 try {
270 DataSource_Stream src(cert_file, true);
271 while(!src.end_of_data()) {
272 try {
273 add_certificate(X509_Certificate(src));
274 } catch(std::exception&) {
275 // stop searching for other certificate at first exception
276 break;
277 }
278 }
279 } catch(std::exception&) {}
280 }
281}
282#endif
283
284} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
Certificate_Store_In_Memory(const X509_Certificate &cert)
Definition certstor.cpp:246
std::optional< X509_Certificate > find_cert_by_issuer_dn_and_serial_number(const X509_DN &issuer_dn, std::span< const uint8_t > serial_number) const override
Definition certstor.cpp:188
std::vector< X509_Certificate > find_all_certs(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const override
Definition certstor.cpp:131
std::optional< X509_Certificate > find_cert_by_pubkey_sha1(const std::vector< uint8_t > &key_hash) const override
Definition certstor.cpp:158
std::optional< X509_Certificate > find_cert(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const override
Definition certstor.cpp:106
Certificate_Store_In_Memory & operator=(const Certificate_Store_In_Memory &other)=delete
void add_crl(const X509_CRL &crl)
Definition certstor.cpp:199
std::optional< X509_Certificate > find_cert_by_raw_subject_dn_sha256(const std::vector< uint8_t > &subject_hash) const override
Definition certstor.cpp:173
std::optional< X509_CRL > find_crl_for(const X509_Certificate &subject) const override
Definition certstor.cpp:219
bool contains(const X509_Certificate &cert) const override
Definition certstor.cpp:242
void add_certificate(const X509_Certificate &cert)
Definition certstor.cpp:85
std::vector< X509_DN > all_subjects() const override
Definition certstor.cpp:96
virtual std::optional< X509_CRL > find_crl_for(const X509_Certificate &subject) const
Definition certstor.cpp:50
bool certificate_known(const X509_Certificate &cert) const
Definition certstor.cpp:24
virtual bool contains(const X509_Certificate &cert) const
Definition certstor.cpp:28
virtual std::vector< X509_Certificate > find_all_certs(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const =0
virtual std::optional< X509_Certificate > find_cert(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const
Definition certstor.cpp:38
const X509_Time & this_update() const
Definition x509_crl.cpp:252
const X509_DN & issuer_dn() const
Definition x509_crl.cpp:231
const X509_DN & subject_dn() const
Definition x509cert.cpp:418
const std::vector< uint8_t > & authority_key_id() const
Definition x509cert.cpp:398
const std::vector< uint8_t > & subject_key_id() const
Definition x509cert.cpp:402
const X509_DN & issuer_dn() const
Definition x509cert.cpp:414
std::vector< std::string > get_files_recursive(std::string_view dir)