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

randombit / botan / 11844561993

14 Nov 2024 07:58PM UTC coverage: 91.178% (+0.1%) from 91.072%
11844561993

Pull #4435

github

web-flow
Merge 81dcb29da into e430f157a
Pull Request #4435: Test duration values ​​are now presented in seconds with six digits of precision. Tests without time measurements have been edited.

91856 of 100744 relevant lines covered (91.18%)

9311006.71 hits per line

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

80.43
/src/tests/test_certstor.cpp
1
/*
2
* (C) 2016 Kai Michaelis, Rohde & Schwarz Cybersecurity
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include "tests.h"
8

9
#if defined(BOTAN_HAS_X509_CERTIFICATES)
10
   #include <botan/certstor.h>
11
   #include <botan/pk_keys.h>
12
   #include <botan/pkcs8.h>
13
   #include <botan/pkix_types.h>
14
   #include <botan/x509cert.h>
15

16
   #if defined(BOTAN_HAS_CERTSTOR_SQLITE3)
17
      #include <botan/certstor_sqlite.h>
18
      #include <botan/sqlite3.h>
19
   #endif
20
#endif
21

22
namespace Botan_Tests {
23

24
namespace {
25

26
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_HAS_RSA) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
27

28
class CertificateAndKey {
13✔
29
   public:
30
      CertificateAndKey(const Botan::X509_Certificate& cert, std::shared_ptr<Botan::Private_Key> key) :
6✔
31
            m_certificate(cert), m_private_key(std::move(key)) {}
6✔
32

33
      bool operator!=(const CertificateAndKey& rhs) const {
9✔
34
         if(m_certificate != rhs.m_certificate) {
9✔
35
            return false;
36
         }
37
         // XXX: this is comparing the pointers, is that really correct?
38
         if(m_private_key != rhs.m_private_key) {
2✔
39
            return false;
40
         }
41
         return true;
42
      }
43

44
      const Botan::X509_DN& subject_dn() const { return certificate().subject_dn(); }
32✔
45

46
      const Botan::X509_Certificate& certificate() const { return m_certificate; }
13✔
47

48
      const Botan::Private_Key& private_key() const { return *m_private_key; }
12✔
49

50
   private:
51
      const Botan::X509_Certificate m_certificate;
52
      const std::shared_ptr<Botan::Private_Key> m_private_key;
53
};
54

55
   #if defined(BOTAN_HAS_CERTSTOR_SQLITE3)
56
Test::Result test_certstor_sqlite3_insert_find_remove_test(const std::vector<CertificateAndKey>& certsandkeys) {
1✔
57
   Test::Result result("Certificate Store SQLITE3 - Insert, Find, Remove");
1✔
58

59
   try {
1✔
60
      auto rng = Test::new_rng(__func__);
1✔
61
      const std::string passwd(reinterpret_cast<const char*>(rng->random_vec(8).data()), 8);
2✔
62
      // Just create a database in memory for testing (https://sqlite.org/inmemorydb.html)
63
      Botan::Certificate_Store_In_SQLite store(":memory:", passwd, *rng);
1✔
64

65
      for(const auto& a : certsandkeys) {
7✔
66
         store.insert_key(a.certificate(), a.private_key());
6✔
67
      }
68

69
      for(const auto& certandkey : certsandkeys) {
7✔
70
         const auto& cert = certandkey.certificate();
6✔
71
         const auto& key = certandkey.private_key();
6✔
72
         const auto wo_keyid = store.find_cert(cert.subject_dn(), {});
6✔
73
         const auto w_keyid = store.find_cert(cert.subject_dn(), cert.subject_key_id());
6✔
74

75
         if(!wo_keyid || !w_keyid) {
6✔
76
            result.test_failure("Can't retrieve certificate");
×
77
            return result;
×
78
         }
79

80
         const auto priv = store.find_key(cert);
6✔
81
         if(!priv && (certsandkeys[1] != certandkey && certsandkeys[0] != certandkey)) {
7✔
82
            result.test_failure("Can't retrieve private key for " + cert.fingerprint("SHA-1"));
×
83
            return result;
×
84
         }
85

86
         result.test_eq("Got wrong certificate", cert.fingerprint(), w_keyid->fingerprint());
12✔
87

88
         if(priv) {
6✔
89
            result.test_eq("Got wrong private key", key.private_key_bits(), priv->private_key_bits());
15✔
90

91
            const auto rev_certs = store.find_certs_for_key(*priv);
5✔
92

93
            if(rev_certs.empty()) {
5✔
94
               result.test_failure("No certificate");
×
95
            } else {
96
               const bool found =
5✔
97
                  std::any_of(rev_certs.begin(), rev_certs.end(), [&](const Botan::X509_Certificate& c) {
5✔
98
                     return c.fingerprint() == cert.fingerprint();
5✔
99
                  });
100

101
               result.test_eq("Got wrong/no certificate", found, true);
10✔
102
            }
103
         }
5✔
104

105
         if(certsandkeys[4] != certandkey && certsandkeys[5] != certandkey) {
7✔
106
            result.test_eq("Got wrong certificate", cert.fingerprint(), wo_keyid->fingerprint());
×
107
         }
108

109
         result.test_eq("Can't remove certificate", store.remove_cert(cert), true);
6✔
110
         result.test_eq("Can't remove certificate", !store.find_cert(cert.subject_dn(), cert.subject_key_id()), true);
12✔
111

112
         if(priv) {
6✔
113
            store.remove_key(key);
5✔
114
         }
115

116
         result.test_eq("Can't remove key", !store.find_key(cert), true);
12✔
117
      }
18✔
118

119
      return result;
120
   } catch(std::exception& e) {
2✔
121
      result.test_failure(e.what());
×
122
      return result;
×
123
   }
×
124
}
×
125

126
Test::Result test_certstor_sqlite3_crl_test(const std::vector<CertificateAndKey>& certsandkeys) {
1✔
127
   Test::Result result("Certificate Store SQLITE3 - CRL");
1✔
128
   try {
1✔
129
      auto rng = Test::new_rng(__func__);
1✔
130
      const std::string passwd(reinterpret_cast<const char*>(rng->random_vec(8).data()), 8);
2✔
131
      // Just create a database in memory for testing (https://sqlite.org/inmemorydb.html)
132
      Botan::Certificate_Store_In_SQLite store(":memory:", passwd, *rng);
1✔
133

134
      for(const auto& a : certsandkeys) {
7✔
135
         store.insert_cert(a.certificate());
6✔
136
      }
137

138
      store.revoke_cert(certsandkeys[0].certificate(), Botan::CRL_Code::CaCompromise);
1✔
139
      store.revoke_cert(certsandkeys[3].certificate(), Botan::CRL_Code::CaCompromise);
1✔
140
      store.revoke_cert(certsandkeys[3].certificate(), Botan::CRL_Code::CaCompromise);
1✔
141

142
      {
1✔
143
         const auto crls = store.generate_crls();
1✔
144

145
         result.test_eq("Can't revoke certificate", crls.size(), 2);
1✔
146
         result.test_eq(
2✔
147
            "Can't revoke certificate",
148
            crls[0].is_revoked(certsandkeys[0].certificate()) ^ crls[1].is_revoked(certsandkeys[0].certificate()),
1✔
149
            true);
150
         result.test_eq(
2✔
151
            "Can't revoke certificate",
152
            crls[0].is_revoked(certsandkeys[3].certificate()) ^ crls[1].is_revoked(certsandkeys[3].certificate()),
1✔
153
            true);
154
      }
1✔
155

156
      store.affirm_cert(certsandkeys[3].certificate());
1✔
157

158
      {
1✔
159
         const auto crls = store.generate_crls();
1✔
160

161
         result.test_eq("Can't revoke certificate, wrong crl size", crls.size(), 1);
1✔
162
         result.test_eq(
1✔
163
            "Can't revoke certificate, cert 0 not revoked", crls[0].is_revoked(certsandkeys[0].certificate()), true);
1✔
164
      }
1✔
165

166
      const auto cert0_crl = store.find_crl_for(certsandkeys[0].certificate());
1✔
167

168
      result.test_eq("Can't revoke certificate, crl for cert 0", !cert0_crl, false);
1✔
169
      result.test_eq("Can't revoke certificate, crl for cert 0 size check", cert0_crl->get_revoked().size(), 1);
1✔
170
      result.test_eq(
1✔
171
         "Can't revoke certificate, no crl for cert 0", cert0_crl->is_revoked(certsandkeys[0].certificate()), true);
1✔
172

173
      const auto cert3_crl = store.find_crl_for(certsandkeys[3].certificate());
1✔
174

175
      result.test_eq("Can't revoke certificate, crl for cert 3", !cert3_crl, true);
1✔
176

177
      return result;
1✔
178
   } catch(std::exception& e) {
3✔
179
      result.test_failure(e.what());
×
180
      return result;
×
181
   }
×
182
}
×
183

184
Test::Result test_certstor_sqlite3_all_subjects_test(const std::vector<CertificateAndKey>& certsandkeys) {
1✔
185
   Test::Result result("Certificate Store SQLITE3 - All subjects");
1✔
186
   try {
1✔
187
      auto rng = Test::new_rng(__func__);
1✔
188
      const std::string passwd(reinterpret_cast<const char*>(rng->random_vec(8).data()), 8);
2✔
189
      // Just create a database in memory for testing (https://sqlite.org/inmemorydb.html)
190
      Botan::Certificate_Store_In_SQLite store(":memory:", passwd, *rng);
1✔
191

192
      for(const auto& a : certsandkeys) {
7✔
193
         store.insert_cert(a.certificate());
6✔
194
      }
195

196
      const auto subjects = store.all_subjects();
1✔
197

198
      result.test_eq("Check subject list length", subjects.size(), 6);
1✔
199

200
      for(const auto& sub : subjects) {
7✔
201
         const std::string ss = sub.to_string();
6✔
202

203
         result.test_eq("Check subject " + ss,
18✔
204
                        certsandkeys[0].subject_dn() == sub || certsandkeys[1].subject_dn() == sub ||
15✔
205
                           certsandkeys[2].subject_dn() == sub || certsandkeys[3].subject_dn() == sub ||
9✔
206
                           certsandkeys[4].subject_dn() == sub || certsandkeys[5].subject_dn() == sub,
8✔
207
                        true);
208
      }
6✔
209
      return result;
1✔
210
   } catch(std::exception& e) {
2✔
211
      result.test_failure(e.what());
×
212
      return result;
×
213
   }
×
214
}
×
215

216
Test::Result test_certstor_sqlite3_find_all_certs_test(const std::vector<CertificateAndKey>& certsandkeys) {
1✔
217
   Test::Result result("Certificate Store SQLITE3 - Find all certs");
1✔
218
   try {
1✔
219
      auto rng = Test::new_rng(__func__);
1✔
220
      const std::string passwd(reinterpret_cast<const char*>(rng->random_vec(8).data()), 8);
2✔
221
      // Just create a database in memory for testing (https://sqlite.org/inmemorydb.html)
222
      Botan::Certificate_Store_In_SQLite store(":memory:", passwd, *rng);
1✔
223

224
      for(const auto& a : certsandkeys) {
7✔
225
         store.insert_cert(a.certificate());
6✔
226
      }
227

228
      for(const auto& a : certsandkeys) {
7✔
229
         auto res_vec = store.find_all_certs(a.subject_dn(), a.certificate().subject_key_id());
6✔
230
         if(res_vec.size() != 1) {
6✔
231
            result.test_failure("SQLITE all lookup error");
×
232
            return result;
×
233
         } else {
234
            const std::string a_str = a.subject_dn().to_string();
6✔
235
            const std::string res_str = res_vec.at(0).subject_dn().to_string();
6✔
236
            result.test_eq("Check subject " + a_str, a_str, res_str);
12✔
237
         }
6✔
238
      }
6✔
239

240
      Botan::X509_Certificate same_dn_1 =
1✔
241
         Botan::X509_Certificate(Test::data_file("x509/bsi/common_14/common_14_sub_ca.ca.pem.crt"));
2✔
242
      Botan::X509_Certificate same_dn_2 =
1✔
243
         Botan::X509_Certificate(Test::data_file("x509/bsi/common_14/common_14_wrong_sub_ca.ca.pem.crt"));
2✔
244

245
      store.insert_cert(same_dn_1);
1✔
246
      store.insert_cert(same_dn_2);
1✔
247
      auto res_vec = store.find_all_certs(same_dn_1.subject_dn(), {});
1✔
248

249
      if(res_vec.size() != 2) {
1✔
250
         result.test_failure("SQLITE all lookup error (duplicate) " + std::to_string(res_vec.size()));
×
251
         return result;
×
252
      } else {
253
         const std::string cert_dn = same_dn_1.subject_dn().to_string();
1✔
254
         const std::string res0_dn = res_vec.at(0).subject_dn().to_string();
1✔
255

256
         result.test_eq("Check subject " + cert_dn, cert_dn, res0_dn);
1✔
257

258
         const std::string res1_dn = res_vec.at(1).subject_dn().to_string();
1✔
259
         result.test_eq("Check subject " + cert_dn, cert_dn, res1_dn);
2✔
260
      }
1✔
261
   } catch(const std::exception& e) {
1✔
262
      result.test_failure(e.what());
×
263
      return result;
×
264
   }
×
265
   return result;
1✔
266
}
×
267

268
   #endif
269

270
Test::Result test_certstor_find_hash_subject(const std::vector<CertificateAndKey>& certsandkeys) {
1✔
271
   Test::Result result("Certificate Store - Find by subject hash");
1✔
272
   result.start_timer();
1✔
273

274
   try {
1✔
275
      Botan::Certificate_Store_In_Memory store;
1✔
276

277
      for(const auto& a : certsandkeys) {
7✔
278
         store.add_certificate(a.certificate());
6✔
279
      }
280

281
      for(const auto& certandkey : certsandkeys) {
7✔
282
         const auto& cert = certandkey.certificate();
6✔
283
         const auto hash = cert.raw_subject_dn_sha256();
6✔
284

285
         const auto found = store.find_cert_by_raw_subject_dn_sha256(hash);
6✔
286
         if(!found) {
6✔
287
            result.test_failure("Can't retrieve certificate " + cert.fingerprint("SHA-1"));
×
288
            result.end_timer();
×
289
            return result;
×
290
         }
291

292
         result.test_eq("Got wrong certificate", hash, found->raw_subject_dn_sha256());
18✔
293
      }
12✔
294

295
      const auto found = store.find_cert_by_raw_subject_dn_sha256(std::vector<uint8_t>(32, 0));
1✔
296
      if(found) {
1✔
297
         result.test_failure("Certificate found for dummy hash");
×
298
         result.end_timer();
×
299
         return result;
300
      }
301
      result.end_timer();
1✔
302
      return result;
303
   } catch(std::exception& e) {
1✔
304
      result.test_failure(e.what());
×
305
      result.end_timer();
×
306
      return result;
×
307
   }
×
308
}
×
309

310
Test::Result test_certstor_load_allcert() {
1✔
311
   Test::Result result("Certificate Store - Load every cert of every files");
1✔
312
   result.start_timer();
1✔
313

314
   // test_dir_bundled dir should contain only one file with 2 certificates
315
   // concatenated (ValidCert and root)
316
   const std::string test_dir_bundled = Test::data_dir("x509/misc/bundledcertdir");
1✔
317

318
   try {
1✔
319
      result.test_note("load certs from dir: " + test_dir_bundled);
1✔
320
      // Certificate_Store_In_Memory constructor loads every cert of every files of the dir.
321
      Botan::Certificate_Store_In_Memory store(test_dir_bundled);
1✔
322

323
      // X509_Certificate constructor loads only the first certificate found in the file.
324
      Botan::X509_Certificate root_cert(Test::data_file("x509/x509test/root.pem"));
2✔
325
      Botan::X509_Certificate valid_cert(Test::data_file("x509/x509test/ValidCert.pem"));
2✔
326
      std::vector<uint8_t> key_id;
1✔
327
      result.confirm("Root cert found", store.find_cert(root_cert.subject_dn(), key_id) != std::nullopt);
2✔
328
      result.confirm("ValidCert found", store.find_cert(valid_cert.subject_dn(), key_id) != std::nullopt);
2✔
329
      result.end_timer();
1✔
330
      return result;
1✔
331
   } catch(std::exception& e) {
1✔
332
      result.test_failure(e.what());
×
333
      result.end_timer();
×
334
      return result;
×
335
   }
×
336
}
1✔
337

338
class Certstor_Tests final : public Test {
×
339
   public:
340
      std::vector<Test::Result> run() override {
1✔
341
         struct CertificateAndKeyFilenames {
6✔
342
               const std::string certificate;
343
               const std::string private_key;
344
         } const certsandkeys_filenames[]{
345
            {"cert1.crt", "key01.pem"},
346
            {"cert2.crt", "key01.pem"},
347
            {"cert3.crt", "key03.pem"},
348
            {"cert4.crt", "key04.pem"},
349
            {"cert5a.crt", "key05.pem"},
350
            {"cert5b.crt", "key06.pem"},
351
         };
13✔
352

353
         std::vector<CertificateAndKey> certsandkeys;
1✔
354

355
         for(const auto& [certpath, keypath] : certsandkeys_filenames) {
7✔
356
            const auto test_cert = Test::data_file("x509/certstor/" + certpath);
6✔
357
            const Botan::X509_Certificate certificate(test_cert);
6✔
358

359
            const auto test_key = Test::data_file("x509/certstor/" + keypath);
6✔
360
            Botan::DataSource_Stream key_stream(test_key);
6✔
361
            std::shared_ptr<Botan::Private_Key> private_key = Botan::PKCS8::load_key(key_stream);
12✔
362

363
            if(!private_key) {
6✔
364
               Test::Result result("Certificate Store");
×
365
               result.test_failure("Failed to load key from disk at path: " + test_key);
×
366
               return {result};
×
367
            }
×
368

369
            certsandkeys.push_back(CertificateAndKey(certificate, private_key));
6✔
370
         }
6✔
371

372
         std::vector<Test::Result> results;
1✔
373

374
         results.push_back(test_certstor_find_hash_subject(certsandkeys));
2✔
375
         results.push_back(test_certstor_load_allcert());
2✔
376
   #if defined(BOTAN_HAS_CERTSTOR_SQLITE3)
377
         results.push_back(test_certstor_sqlite3_insert_find_remove_test(certsandkeys));
2✔
378
         results.push_back(test_certstor_sqlite3_crl_test(certsandkeys));
2✔
379
         results.push_back(test_certstor_sqlite3_all_subjects_test(certsandkeys));
2✔
380
         results.push_back(test_certstor_sqlite3_find_all_certs_test(certsandkeys));
2✔
381
   #endif
382
         return results;
1✔
383
      }
7✔
384
};
385

386
BOTAN_REGISTER_TEST("x509", "certstor", Certstor_Tests);
387
#endif
388
}  // namespace
389
}  // namespace Botan_Tests
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

© 2025 Coveralls, Inc