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

randombit / botan / 19098137421

05 Nov 2025 06:45AM UTC coverage: 90.681% (-0.005%) from 90.686%
19098137421

push

github

web-flow
Merge pull request #5143 from Rohde-Schwarz/feature/extend_certstore_in_memory

Add another `Certificate_Store_In_Memory` convenience constructor

100608 of 110947 relevant lines covered (90.68%)

12565851.55 hits per line

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

79.82
/src/lib/x509/certstor.cpp
1
/*
2
* Certificate Store
3
* (C) 1999-2010,2013 Jack Lloyd
4
* (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#include <botan/certstor.h>
10

11
#include <botan/assert.h>
12
#include <botan/data_src.h>
13
#include <botan/hash.h>
14
#include <botan/pkix_types.h>
15
#include <botan/internal/filesystem.h>
16

17
namespace Botan {
18

19
Certificate_Store::~Certificate_Store() = default;
5,713✔
20

21
std::optional<X509_Certificate> Certificate_Store::find_cert(const X509_DN& subject_dn,
13✔
22
                                                             const std::vector<uint8_t>& key_id) const {
23
   const auto certs = find_all_certs(subject_dn, key_id);
13✔
24

25
   if(certs.empty()) {
13✔
26
      return std::nullopt;
2✔
27
   }
28

29
   // `count` might be greater than 1, but we'll just select the first match
30
   return certs.front();
11✔
31
}
13✔
32

33
std::optional<X509_CRL> Certificate_Store::find_crl_for(const X509_Certificate& /*unused*/) const {
×
34
   return std::nullopt;
×
35
}
36

37
void Certificate_Store_In_Memory::add_certificate(const X509_Certificate& cert) {
3,770✔
38
   for(const auto& c : m_certs) {
4,659✔
39
      if(c == cert) {
907✔
40
         return;
3,770✔
41
      }
42
   }
43

44
   m_certs.push_back(cert);
3,752✔
45
}
46

47
std::vector<X509_DN> Certificate_Store_In_Memory::all_subjects() const {
928✔
48
   std::vector<X509_DN> subjects;
928✔
49
   subjects.reserve(m_certs.size());
928✔
50
   for(const auto& cert : m_certs) {
1,439✔
51
      subjects.push_back(cert.subject_dn());
511✔
52
   }
53
   return subjects;
928✔
54
}
×
55

56
std::optional<X509_Certificate> Certificate_Store_In_Memory::find_cert(const X509_DN& subject_dn,
1,127✔
57
                                                                       const std::vector<uint8_t>& key_id) const {
58
   for(const auto& cert : m_certs) {
1,128✔
59
      // Only compare key ids if set in both call and in the cert
60
      if(!key_id.empty()) {
1,085✔
61
         const std::vector<uint8_t>& skid = cert.subject_key_id();
1,077✔
62

63
         if(!skid.empty() && skid != key_id) {  // no match
1,077✔
64
            continue;
×
65
         }
66
      }
67

68
      if(cert.subject_dn() == subject_dn) {
1,085✔
69
         return cert;
1,084✔
70
      }
71
   }
72

73
   return std::nullopt;
43✔
74
}
75

76
std::vector<X509_Certificate> Certificate_Store_In_Memory::find_all_certs(const X509_DN& subject_dn,
6,137✔
77
                                                                          const std::vector<uint8_t>& key_id) const {
78
   std::vector<X509_Certificate> matches;
6,137✔
79

80
   for(const auto& cert : m_certs) {
14,298✔
81
      if(!key_id.empty()) {
8,161✔
82
         const std::vector<uint8_t>& skid = cert.subject_key_id();
7,505✔
83

84
         if(!skid.empty() && skid != key_id) {  // no match
7,505✔
85
            continue;
4,638✔
86
         }
87
      }
88

89
      if(cert.subject_dn() == subject_dn) {
3,523✔
90
         matches.push_back(cert);
3,091✔
91
      }
92
   }
93

94
   return matches;
6,137✔
95
}
×
96

97
std::optional<X509_Certificate> Certificate_Store_In_Memory::find_cert_by_pubkey_sha1(
×
98
   const std::vector<uint8_t>& key_hash) const {
99
   if(key_hash.size() != 20) {
×
100
      throw Invalid_Argument("Certificate_Store_In_Memory::find_cert_by_pubkey_sha1 invalid hash");
×
101
   }
102

103
   auto hash = HashFunction::create_or_throw("SHA-1");
×
104

105
   for(const auto& cert : m_certs) {
×
106
      hash->update(cert.subject_public_key_bitstring());
×
107
      if(key_hash == hash->final_stdvec()) {  //final_stdvec also clears the hash to initial state
×
108
         return cert;
×
109
      }
110
   }
111

112
   return std::nullopt;
×
113
}
×
114

115
std::optional<X509_Certificate> Certificate_Store_In_Memory::find_cert_by_raw_subject_dn_sha256(
7✔
116
   const std::vector<uint8_t>& subject_hash) const {
117
   if(subject_hash.size() != 32) {
7✔
118
      throw Invalid_Argument("Certificate_Store_In_Memory::find_cert_by_raw_subject_dn_sha256 invalid hash");
×
119
   }
120

121
   auto hash = HashFunction::create_or_throw("SHA-256");
7✔
122

123
   for(const auto& cert : m_certs) {
27✔
124
      hash->update(cert.raw_subject_dn());
26✔
125
      if(subject_hash == hash->final_stdvec()) {  //final_stdvec also clears the hash to initial state
52✔
126
         return cert;
6✔
127
      }
128
   }
129

130
   return std::nullopt;
1✔
131
}
7✔
132

133
std::optional<X509_Certificate> Certificate_Store_In_Memory::find_cert_by_issuer_dn_and_serial_number(
6✔
134
   const X509_DN& issuer_dn, std::span<const uint8_t> serial_number) const {
135
   for(const auto& cert : m_certs) {
20✔
136
      if(cert.issuer_dn() == issuer_dn && std::ranges::equal(cert.serial_number(), serial_number)) {
26✔
137
         return cert;
6✔
138
      }
139
   }
140

141
   return std::nullopt;
×
142
}
143

144
void Certificate_Store_In_Memory::add_crl(const X509_CRL& crl) {
272✔
145
   const X509_DN& crl_issuer = crl.issuer_dn();
272✔
146

147
   for(auto& c : m_crls) {
497✔
148
      // Found an update of a previously existing one; replace it
149
      if(c.issuer_dn() == crl_issuer) {
247✔
150
         if(c.this_update() <= crl.this_update()) {
22✔
151
            c = crl;
22✔
152
         }
153
         return;
22✔
154
      }
155
   }
156

157
   // Totally new CRL, add to the list
158
   m_crls.push_back(crl);
250✔
159
}
160

161
std::optional<X509_CRL> Certificate_Store_In_Memory::find_crl_for(const X509_Certificate& subject) const {
4,142✔
162
   const std::vector<uint8_t>& key_id = subject.authority_key_id();
4,142✔
163

164
   for(const auto& c : m_crls) {
4,968✔
165
      // Only compare key ids if set in both call and in the CRL
166
      if(!key_id.empty()) {
2,033✔
167
         const std::vector<uint8_t>& akid = c.authority_key_id();
2,031✔
168

169
         if(!akid.empty() && akid != key_id) {  // no match
2,031✔
170
            continue;
792✔
171
         }
172
      }
173

174
      if(c.issuer_dn() == subject.issuer_dn()) {
1,241✔
175
         return c;
1,207✔
176
      }
177
   }
178

179
   return {};
2,935✔
180
}
181

182
Certificate_Store_In_Memory::Certificate_Store_In_Memory(const X509_Certificate& cert) {
289✔
183
   add_certificate(cert);
289✔
184
}
289✔
185

186
Certificate_Store_In_Memory::Certificate_Store_In_Memory(const X509_Certificate& cert, const X509_CRL& crl) {
×
187
   add_certificate(cert);
×
188
   add_crl(crl);
×
189
}
×
190

191
#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
192
Certificate_Store_In_Memory::Certificate_Store_In_Memory(std::string_view dir) {
13✔
193
   if(dir.empty()) {
13✔
194
      return;
×
195
   }
196

197
   std::vector<std::string> maybe_certs = get_files_recursive(dir);
13✔
198

199
   if(maybe_certs.empty()) {
13✔
200
      maybe_certs.push_back(std::string(dir));
22✔
201
   }
202

203
   for(auto&& cert_file : maybe_certs) {
351✔
204
      try {
338✔
205
         DataSource_Stream src(cert_file, true);
338✔
206
         while(!src.end_of_data()) {
550✔
207
            try {
550✔
208
               X509_Certificate cert(src);
550✔
209
               m_certs.push_back(cert);
213✔
210
            } catch(std::exception&) {
550✔
211
               // stop searching for other certificate at first exception
212
               break;
337✔
213
            }
337✔
214
         }
215
      } catch(std::exception&) {}
338✔
216
   }
217
}
13✔
218
#endif
219

220
}  // 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