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