• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 17153399735

22 Aug 2025 10:55AM UTC coverage: 90.648% (-0.02%) from 90.666%
17153399735

push

github

web-flow
fix clang-format error

100199 of 110536 relevant lines covered (90.65%)

12179047.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.4
/src/lib/x509/certstor_sql/certstor_sql.cpp
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

17
namespace Botan {
18

19
Certificate_Store_In_SQL::Certificate_Store_In_SQL(std::shared_ptr<SQL_Database> db,
4✔
20
                                                   std::string_view passwd,
21
                                                   RandomNumberGenerator& rng,
22
                                                   std::string_view table_prefix) :
4✔
23
      m_rng(rng), m_database(std::move(db)), m_prefix(table_prefix), m_password(passwd) {
12✔
24
   m_database->create_table("CREATE TABLE IF NOT EXISTS " + m_prefix +
12✔
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 +
12✔
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 +
12✔
38
                            "revoked (\
39
                                 fingerprint BLOB PRIMARY KEY,                   \
40
                                 reason      BLOB NOT NULL,                      \
41
                                 time        BLOB NOT NULL                       \
42
                            )");
43
}
4✔
44

45
// Certificate handling
46
std::optional<X509_Certificate> Certificate_Store_In_SQL::find_cert(const X509_DN& subject_dn,
24✔
47
                                                                    const std::vector<uint8_t>& key_id) const {
48
   std::shared_ptr<SQL_Database::Statement> stmt;
24✔
49

50
   const std::vector<uint8_t> dn_encoding = subject_dn.BER_encode();
24✔
51

52
   if(key_id.empty()) {
24✔
53
      stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix +
12✔
54
                                       "certificates WHERE subject_dn == ?1 LIMIT 1");
6✔
55
      stmt->bind(1, dn_encoding);
6✔
56
   } else {
57
      stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix +
36✔
58
                                       "certificates WHERE\
59
                                        subject_dn == ?1 AND (key_id == NULL OR key_id == ?2) LIMIT 1");
18✔
60
      stmt->bind(1, dn_encoding);
18✔
61
      stmt->bind(2, key_id);
18✔
62
   }
63

64
   while(stmt->step()) {
24✔
65
      auto blob = stmt->get_blob(0);
18✔
66
      return X509_Certificate(blob.first, blob.second);
36✔
67
   }
68

69
   return std::optional<X509_Certificate>();
6✔
70
}
48✔
71

72
std::vector<X509_Certificate> Certificate_Store_In_SQL::find_all_certs(const X509_DN& subject_dn,
7✔
73
                                                                       const std::vector<uint8_t>& key_id) const {
74
   std::vector<X509_Certificate> certs;
7✔
75

76
   std::shared_ptr<SQL_Database::Statement> stmt;
7✔
77

78
   const std::vector<uint8_t> dn_encoding = subject_dn.BER_encode();
7✔
79

80
   if(key_id.empty()) {
7✔
81
      stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE subject_dn == ?1");
2✔
82
      stmt->bind(1, dn_encoding);
1✔
83
   } else {
84
      stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix +
12✔
85
                                       "certificates WHERE\
86
                                        subject_dn == ?1 AND (key_id == NULL OR key_id == ?2)");
6✔
87
      stmt->bind(1, dn_encoding);
6✔
88
      stmt->bind(2, key_id);
6✔
89
   }
90

91
   std::optional<X509_Certificate> cert;
7✔
92
   while(stmt->step()) {
15✔
93
      auto blob = stmt->get_blob(0);
8✔
94
      certs.push_back(X509_Certificate(blob.first, blob.second));
16✔
95
   }
96

97
   return certs;
7✔
98
}
14✔
99

100
std::optional<X509_Certificate> Certificate_Store_In_SQL::find_cert_by_pubkey_sha1(
×
101
   const std::vector<uint8_t>& /*key_hash*/) const {
102
   throw Not_Implemented("Certificate_Store_In_SQL::find_cert_by_pubkey_sha1");
×
103
}
104

105
std::optional<X509_Certificate> Certificate_Store_In_SQL::find_cert_by_raw_subject_dn_sha256(
×
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

110
std::optional<X509_Certificate> Certificate_Store_In_SQL::find_cert_by_issuer_dn_and_serial_number(
×
111
   const X509_DN& /*issuer_dn*/, const std::vector<uint8_t>& /*serial_number*/) const {
112
   throw Not_Implemented("Certificate_Store_In_SQL::find_cert_by_issuer_dn_and_serial_number");
×
113
}
114

115
std::optional<X509_CRL> Certificate_Store_In_SQL::find_crl_for(const X509_Certificate& subject) const {
2✔
116
   auto all_crls = generate_crls();
2✔
117

118
   for(auto crl : all_crls) {
3✔
119
      if(!crl.get_revoked().empty() && crl.issuer_dn() == subject.issuer_dn()) {
2✔
120
         return crl;
1✔
121
      }
122
   }
2✔
123

124
   return std::optional<X509_CRL>();
1✔
125
}
2✔
126

127
std::vector<X509_DN> Certificate_Store_In_SQL::all_subjects() const {
1✔
128
   std::vector<X509_DN> ret;
1✔
129
   auto stmt = m_database->new_statement("SELECT subject_dn FROM " + m_prefix + "certificates");
3✔
130

131
   while(stmt->step()) {
7✔
132
      auto blob = stmt->get_blob(0);
6✔
133
      BER_Decoder dec(blob.first, blob.second);
6✔
134
      X509_DN dn;
6✔
135

136
      dn.decode_from(dec);
6✔
137

138
      ret.push_back(dn);
6✔
139
   }
6✔
140

141
   return ret;
1✔
142
}
1✔
143

144
bool Certificate_Store_In_SQL::insert_cert(const X509_Certificate& cert) {
29✔
145
   const std::vector<uint8_t> dn_encoding = cert.subject_dn().BER_encode();
29✔
146
   const std::vector<uint8_t> cert_encoding = cert.BER_encode();
29✔
147

148
   auto stmt = m_database->new_statement("INSERT OR REPLACE INTO " + m_prefix +
87✔
149
                                         "certificates (\
150
                                         fingerprint,          \
151
                                         subject_dn,           \
152
                                         key_id,               \
153
                                         priv_fingerprint,     \
154
                                         certificate           \
155
                                     ) VALUES ( ?1, ?2, ?3, ?4, ?5 )");
29✔
156

157
   stmt->bind(1, cert.fingerprint("SHA-256"));
29✔
158
   stmt->bind(2, dn_encoding);
29✔
159
   stmt->bind(3, cert.subject_key_id());
29✔
160
   stmt->bind(4, std::vector<uint8_t>());
29✔
161
   stmt->bind(5, cert_encoding);
29✔
162
   stmt->spin();
29✔
163

164
   return true;
58✔
165
}
29✔
166

167
bool Certificate_Store_In_SQL::remove_cert(const X509_Certificate& cert) {
6✔
168
   if(!find_cert(cert.subject_dn(), cert.subject_key_id())) {
12✔
169
      return false;
170
   }
171

172
   auto stmt = m_database->new_statement("DELETE FROM " + m_prefix + "certificates WHERE fingerprint == ?1");
18✔
173

174
   stmt->bind(1, cert.fingerprint("SHA-256"));
6✔
175
   stmt->spin();
6✔
176

177
   return true;
6✔
178
}
6✔
179

180
// Private key handling
181
std::shared_ptr<const Private_Key> Certificate_Store_In_SQL::find_key(const X509_Certificate& cert) const {
18✔
182
   auto stmt = m_database->new_statement("SELECT key FROM " + m_prefix +
54✔
183
                                         "keys "
184
                                         "JOIN " +
18✔
185
                                         m_prefix + "certificates ON " + m_prefix + "keys.fingerprint == " + m_prefix +
108✔
186
                                         "certificates.priv_fingerprint "
187
                                         "WHERE " +
36✔
188
                                         m_prefix + "certificates.fingerprint == ?1");
54✔
189
   stmt->bind(1, cert.fingerprint("SHA-256"));
18✔
190

191
   std::shared_ptr<const Private_Key> key;
18✔
192
   while(stmt->step()) {
23✔
193
      auto blob = stmt->get_blob(0);
5✔
194
      DataSource_Memory src(blob.first, blob.second);
5✔
195
      key = PKCS8::load_key(src, m_password);
10✔
196
   }
5✔
197

198
   return key;
18✔
199
}
18✔
200

201
std::vector<X509_Certificate> Certificate_Store_In_SQL::find_certs_for_key(const Private_Key& key) const {
5✔
202
   auto fpr = key.fingerprint_private("SHA-256");
5✔
203
   auto stmt =
5✔
204
      m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE priv_fingerprint == ?1");
15✔
205

206
   stmt->bind(1, fpr);
5✔
207

208
   std::vector<X509_Certificate> certs;
5✔
209
   while(stmt->step()) {
11✔
210
      auto blob = stmt->get_blob(0);
6✔
211
      certs.push_back(X509_Certificate(blob.first, blob.second));
12✔
212
   }
213

214
   return certs;
5✔
215
}
5✔
216

217
bool Certificate_Store_In_SQL::insert_key(const X509_Certificate& cert, const Private_Key& key) {
6✔
218
   insert_cert(cert);
6✔
219

220
   if(find_key(cert)) {
6✔
221
      return false;
222
   }
223

224
   auto pkcs8 = PKCS8::BER_encode(key, m_rng, m_password);
6✔
225
   auto fpr = key.fingerprint_private("SHA-256");
6✔
226

227
   auto stmt1 =
6✔
228
      m_database->new_statement("INSERT OR REPLACE INTO " + m_prefix + "keys ( fingerprint, key ) VALUES ( ?1, ?2 )");
18✔
229

230
   stmt1->bind(1, fpr);
6✔
231
   stmt1->bind(2, pkcs8.data(), pkcs8.size());
6✔
232
   stmt1->spin();
6✔
233

234
   auto stmt2 = m_database->new_statement("UPDATE " + m_prefix +
18✔
235
                                          "certificates SET priv_fingerprint = ?1 WHERE fingerprint == ?2");
6✔
236

237
   stmt2->bind(1, fpr);
6✔
238
   stmt2->bind(2, cert.fingerprint("SHA-256"));
6✔
239
   stmt2->spin();
6✔
240

241
   return true;
6✔
242
}
12✔
243

244
void Certificate_Store_In_SQL::remove_key(const Private_Key& key) {
5✔
245
   auto fpr = key.fingerprint_private("SHA-256");
5✔
246
   auto stmt = m_database->new_statement("DELETE FROM " + m_prefix + "keys WHERE fingerprint == ?1");
15✔
247

248
   stmt->bind(1, fpr);
5✔
249
   stmt->spin();
5✔
250
}
5✔
251

252
// Revocation
253
void Certificate_Store_In_SQL::revoke_cert(const X509_Certificate& cert, CRL_Code code, const X509_Time& time) {
3✔
254
   insert_cert(cert);
3✔
255

256
   auto stmt1 = m_database->new_statement("INSERT OR REPLACE INTO " + m_prefix +
9✔
257
                                          "revoked ( fingerprint, reason, time ) VALUES ( ?1, ?2, ?3 )");
3✔
258

259
   stmt1->bind(1, cert.fingerprint("SHA-256"));
3✔
260
   stmt1->bind(2, static_cast<uint32_t>(code));
3✔
261

262
   if(time.time_is_set()) {
3✔
263
      stmt1->bind(3, time.BER_encode());
×
264
   } else {
265
      stmt1->bind(3, static_cast<size_t>(-1));
3✔
266
   }
267

268
   stmt1->spin();
3✔
269
}
3✔
270

271
void Certificate_Store_In_SQL::affirm_cert(const X509_Certificate& cert) {
1✔
272
   auto stmt = m_database->new_statement("DELETE FROM " + m_prefix + "revoked WHERE fingerprint == ?1");
3✔
273

274
   stmt->bind(1, cert.fingerprint("SHA-256"));
1✔
275
   stmt->spin();
1✔
276
}
1✔
277

278
std::vector<X509_CRL> Certificate_Store_In_SQL::generate_crls() const {
4✔
279
   auto stmt = m_database->new_statement("SELECT certificate,reason,time FROM " + m_prefix +
12✔
280
                                         "revoked "
281
                                         "JOIN " +
8✔
282
                                         m_prefix + "certificates ON " + m_prefix +
16✔
283
                                         "certificates.fingerprint == " + m_prefix + "revoked.fingerprint");
16✔
284

285
   std::map<X509_DN, std::vector<CRL_Entry>> crls;
4✔
286
   while(stmt->step()) {
9✔
287
      auto blob = stmt->get_blob(0);
5✔
288
      auto cert = X509_Certificate(std::vector<uint8_t>(blob.first, blob.first + blob.second));
5✔
289
      auto code = static_cast<CRL_Code>(stmt->get_size_t(1));
5✔
290
      auto ent = CRL_Entry(cert, code);
5✔
291

292
      auto i = crls.find(cert.issuer_dn());
5✔
293
      if(i == crls.end()) {
5✔
294
         crls.insert(std::make_pair(cert.issuer_dn(), std::vector<CRL_Entry>({ent})));
15✔
295
      } else {
296
         i->second.push_back(ent);
×
297
      }
298
   }
5✔
299

300
   X509_Time t(std::chrono::system_clock::now());
4✔
301

302
   std::vector<X509_CRL> ret;
4✔
303
   ret.reserve(crls.size());
4✔
304

305
   for(const auto& p : crls) {
9✔
306
      ret.push_back(X509_CRL(p.first, t, t, p.second));
10✔
307
   }
308

309
   return ret;
4✔
310
}
13✔
311

312
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc