Botan 3.10.0
Crypto and TLS for C&
certstor_sql.cpp
Go to the documentation of this file.
1/*
2* Certificate Store in SQL
3* (C) 2016 Kai Michaelis, Rohde & Schwarz Cybersecurity
4* (C) 2018 Jack Lloyd
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/certstor_sql.h>
10
11#include <botan/ber_dec.h>
12#include <botan/data_src.h>
13#include <botan/pk_keys.h>
14#include <botan/pkcs8.h>
15#include <botan/pkix_types.h>
16
17namespace Botan {
18
20 std::string_view passwd,
22 std::string_view table_prefix) :
23 m_rng(rng), m_database(std::move(db)), m_prefix(table_prefix), m_password(passwd) {
24 m_database->create_table("CREATE TABLE IF NOT EXISTS " + m_prefix +
25 "certificates ( \
26 fingerprint BLOB PRIMARY KEY, \
27 subject_dn BLOB, \
28 key_id BLOB, \
29 priv_fingerprint BLOB, \
30 certificate BLOB UNIQUE NOT NULL\
31 )");
32 m_database->create_table("CREATE TABLE IF NOT EXISTS " + m_prefix +
33 "keys (\
34 fingerprint BLOB PRIMARY KEY, \
35 key BLOB UNIQUE NOT NULL \
36 )");
37 m_database->create_table("CREATE TABLE IF NOT EXISTS " + m_prefix +
38 "revoked (\
39 fingerprint BLOB PRIMARY KEY, \
40 reason BLOB NOT NULL, \
41 time BLOB NOT NULL \
42 )");
43}
44
45// Certificate handling
46std::optional<X509_Certificate> Certificate_Store_In_SQL::find_cert(const X509_DN& subject_dn,
47 const std::vector<uint8_t>& key_id) const {
48 std::shared_ptr<SQL_Database::Statement> stmt;
49
50 const std::vector<uint8_t> dn_encoding = subject_dn.BER_encode();
51
52 if(key_id.empty()) {
53 stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix +
54 "certificates WHERE subject_dn == ?1 LIMIT 1");
55 stmt->bind(1, dn_encoding);
56 } else {
57 stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix +
58 "certificates WHERE\
59 subject_dn == ?1 AND (key_id == NULL OR key_id == ?2) LIMIT 1");
60 stmt->bind(1, dn_encoding);
61 stmt->bind(2, key_id);
62 }
63
64 while(stmt->step()) {
65 auto blob = stmt->get_blob(0);
66 return X509_Certificate(blob.first, blob.second);
67 }
68
69 return std::optional<X509_Certificate>();
70}
71
72std::vector<X509_Certificate> Certificate_Store_In_SQL::find_all_certs(const X509_DN& subject_dn,
73 const std::vector<uint8_t>& key_id) const {
74 std::vector<X509_Certificate> certs;
75
76 std::shared_ptr<SQL_Database::Statement> stmt;
77
78 const std::vector<uint8_t> dn_encoding = subject_dn.BER_encode();
79
80 if(key_id.empty()) {
81 stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE subject_dn == ?1");
82 stmt->bind(1, dn_encoding);
83 } else {
84 stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix +
85 "certificates WHERE\
86 subject_dn == ?1 AND (key_id == NULL OR key_id == ?2)");
87 stmt->bind(1, dn_encoding);
88 stmt->bind(2, key_id);
89 }
90
91 std::optional<X509_Certificate> cert;
92 while(stmt->step()) {
93 auto blob = stmt->get_blob(0);
94 certs.push_back(X509_Certificate(blob.first, blob.second));
95 }
96
97 return certs;
98}
99
101 const std::vector<uint8_t>& /*key_hash*/) const {
102 throw Not_Implemented("Certificate_Store_In_SQL::find_cert_by_pubkey_sha1");
103}
104
106 const std::vector<uint8_t>& /*subject_hash*/) const {
107 throw Not_Implemented("Certificate_Store_In_SQL::find_cert_by_raw_subject_dn_sha256");
108}
109
111 const X509_DN& /*issuer_dn*/, std::span<const uint8_t> /*serial_number*/) const {
112 throw Not_Implemented("Certificate_Store_In_SQL::find_cert_by_issuer_dn_and_serial_number");
113}
114
115std::optional<X509_CRL> Certificate_Store_In_SQL::find_crl_for(const X509_Certificate& subject) const {
116 auto all_crls = generate_crls();
117
118 for(auto crl : all_crls) {
119 if(!crl.get_revoked().empty() && crl.issuer_dn() == subject.issuer_dn()) {
120 return crl;
121 }
122 }
123
124 return std::optional<X509_CRL>();
125}
126
127std::vector<X509_DN> Certificate_Store_In_SQL::all_subjects() const {
128 std::vector<X509_DN> ret;
129 auto stmt = m_database->new_statement("SELECT subject_dn FROM " + m_prefix + "certificates");
130
131 while(stmt->step()) {
132 auto blob = stmt->get_blob(0);
133 BER_Decoder dec(blob.first, blob.second);
134 X509_DN dn;
135
136 dn.decode_from(dec);
137
138 ret.push_back(dn);
139 }
140
141 return ret;
142}
143
145 const std::vector<uint8_t> dn_encoding = cert.subject_dn().BER_encode();
146 const std::vector<uint8_t> cert_encoding = cert.BER_encode();
147
148 auto stmt = m_database->new_statement("INSERT OR REPLACE INTO " + m_prefix +
149 "certificates (\
150 fingerprint, \
151 subject_dn, \
152 key_id, \
153 priv_fingerprint, \
154 certificate \
155 ) VALUES ( ?1, ?2, ?3, ?4, ?5 )");
156
157 stmt->bind(1, cert.fingerprint("SHA-256"));
158 stmt->bind(2, dn_encoding);
159 stmt->bind(3, cert.subject_key_id());
160 stmt->bind(4, std::vector<uint8_t>());
161 stmt->bind(5, cert_encoding);
162 stmt->spin();
163
164 return true;
165}
166
168 if(!find_cert(cert.subject_dn(), cert.subject_key_id())) {
169 return false;
170 }
171
172 auto stmt = m_database->new_statement("DELETE FROM " + m_prefix + "certificates WHERE fingerprint == ?1");
173
174 stmt->bind(1, cert.fingerprint("SHA-256"));
175 stmt->spin();
176
177 return true;
178}
179
180// Private key handling
181std::shared_ptr<const Private_Key> Certificate_Store_In_SQL::find_key(const X509_Certificate& cert) const {
182 auto stmt = m_database->new_statement("SELECT key FROM " + m_prefix +
183 "keys "
184 "JOIN " +
185 m_prefix + "certificates ON " + m_prefix + "keys.fingerprint == " + m_prefix +
186 "certificates.priv_fingerprint "
187 "WHERE " +
188 m_prefix + "certificates.fingerprint == ?1");
189 stmt->bind(1, cert.fingerprint("SHA-256"));
190
191 std::shared_ptr<const Private_Key> key;
192 while(stmt->step()) {
193 auto blob = stmt->get_blob(0);
194 DataSource_Memory src(blob.first, blob.second);
195 key = PKCS8::load_key(src, m_password);
196 }
197
198 return key;
199}
200
201std::vector<X509_Certificate> Certificate_Store_In_SQL::find_certs_for_key(const Private_Key& key) const {
202 auto fprint = key.fingerprint_private("SHA-256");
203 auto stmt =
204 m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE priv_fingerprint == ?1");
205
206 stmt->bind(1, fprint);
207
208 std::vector<X509_Certificate> certs;
209 while(stmt->step()) {
210 auto blob = stmt->get_blob(0);
211 certs.push_back(X509_Certificate(blob.first, blob.second));
212 }
213
214 return certs;
215}
216
218 insert_cert(cert);
219
220 if(find_key(cert)) {
221 return false;
222 }
223
224 auto pkcs8 = PKCS8::BER_encode(key, m_rng, m_password);
225 auto fprint = key.fingerprint_private("SHA-256");
226
227 auto stmt1 =
228 m_database->new_statement("INSERT OR REPLACE INTO " + m_prefix + "keys ( fingerprint, key ) VALUES ( ?1, ?2 )");
229
230 stmt1->bind(1, fprint);
231 stmt1->bind(2, pkcs8.data(), pkcs8.size());
232 stmt1->spin();
233
234 auto stmt2 = m_database->new_statement("UPDATE " + m_prefix +
235 "certificates SET priv_fingerprint = ?1 WHERE fingerprint == ?2");
236
237 stmt2->bind(1, fprint);
238 stmt2->bind(2, cert.fingerprint("SHA-256"));
239 stmt2->spin();
240
241 return true;
242}
243
245 auto fprint = key.fingerprint_private("SHA-256");
246 auto stmt = m_database->new_statement("DELETE FROM " + m_prefix + "keys WHERE fingerprint == ?1");
247
248 stmt->bind(1, fprint);
249 stmt->spin();
250}
251
252// Revocation
254 insert_cert(cert);
255
256 auto stmt1 = m_database->new_statement("INSERT OR REPLACE INTO " + m_prefix +
257 "revoked ( fingerprint, reason, time ) VALUES ( ?1, ?2, ?3 )");
258
259 stmt1->bind(1, cert.fingerprint("SHA-256"));
260 stmt1->bind(2, static_cast<uint32_t>(code));
261
262 if(time.time_is_set()) {
263 stmt1->bind(3, time.BER_encode());
264 } else {
265 stmt1->bind(3, static_cast<size_t>(-1));
266 }
267
268 stmt1->spin();
269}
270
272 auto stmt = m_database->new_statement("DELETE FROM " + m_prefix + "revoked WHERE fingerprint == ?1");
273
274 stmt->bind(1, cert.fingerprint("SHA-256"));
275 stmt->spin();
276}
277
278std::vector<X509_CRL> Certificate_Store_In_SQL::generate_crls() const {
279 auto stmt = m_database->new_statement("SELECT certificate,reason,time FROM " + m_prefix +
280 "revoked "
281 "JOIN " +
282 m_prefix + "certificates ON " + m_prefix +
283 "certificates.fingerprint == " + m_prefix + "revoked.fingerprint");
284
285 std::map<X509_DN, std::vector<CRL_Entry>> crls;
286 while(stmt->step()) {
287 auto blob = stmt->get_blob(0);
288 auto cert = X509_Certificate(std::vector<uint8_t>(blob.first, blob.first + blob.second));
289 auto code = static_cast<CRL_Code>(stmt->get_size_t(1));
290 auto ent = CRL_Entry(cert, code);
291
292 auto i = crls.find(cert.issuer_dn());
293 if(i == crls.end()) {
294 crls.insert(std::make_pair(cert.issuer_dn(), std::vector<CRL_Entry>({ent})));
295 } else {
296 i->second.push_back(ent);
297 }
298 }
299
300 X509_Time t(std::chrono::system_clock::now());
301
302 std::vector<X509_CRL> ret;
303 ret.reserve(crls.size());
304
305 for(const auto& p : crls) {
306 ret.push_back(X509_CRL(p.first, t, t, p.second));
307 }
308
309 return ret;
310}
311
312} // namespace Botan
std::vector< uint8_t > BER_encode() const
Definition asn1_obj.cpp:19
bool time_is_set() const
Return if the time has been set somehow.
Definition x509_crl.h:29
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
std::vector< X509_DN > all_subjects() const override
bool insert_cert(const X509_Certificate &cert)
std::vector< X509_Certificate > find_all_certs(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 &issuer) const override
void revoke_cert(const X509_Certificate &cert, CRL_Code reason, const X509_Time &time=X509_Time())
Marks "cert" as revoked starting from "time".
Certificate_Store_In_SQL(std::shared_ptr< SQL_Database > db, std::string_view passwd, RandomNumberGenerator &rng, std::string_view table_prefix="")
std::vector< X509_Certificate > find_certs_for_key(const Private_Key &key) const
Returns all certificates for private key "key".
void affirm_cert(const X509_Certificate &cert)
Reverses the revocation for "cert".
bool remove_cert(const X509_Certificate &cert)
std::shared_ptr< const Private_Key > find_key(const X509_Certificate &cert) const
Returns the private key for "cert" or an empty shared_ptr if none was found.
std::optional< X509_Certificate > find_cert(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const override
void remove_key(const Private_Key &key)
Removes "key" from the store.
bool insert_key(const X509_Certificate &cert, const Private_Key &key)
std::optional< X509_Certificate > find_cert_by_pubkey_sha1(const std::vector< uint8_t > &key_hash) const override
std::vector< X509_CRL > generate_crls() const
std::string fingerprint_private(std::string_view alg) const
Definition pk_keys.cpp:94
std::string fingerprint(std::string_view hash_name="SHA-1") const
Definition x509cert.cpp:635
const X509_DN & subject_dn() const
Definition x509cert.cpp:411
const std::vector< uint8_t > & subject_key_id() const
Definition x509cert.cpp:395
const X509_DN & issuer_dn() const
Definition x509cert.cpp:407
void decode_from(BER_Decoder &from) override
Definition x509_dn.cpp:354
std::vector< uint8_t > BER_encode(const Private_Key &key, RandomNumberGenerator &rng, std::string_view pass, std::chrono::milliseconds msec, std::string_view pbe_algo)
Definition pkcs8.cpp:161
std::unique_ptr< Private_Key > load_key(DataSource &source, const std::function< std::string()> &get_pass)
Definition pkcs8.cpp:314
ASN1_Time X509_Time
Definition asn1_obj.h:424