Botan 2.1.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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