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

randombit / botan / 20283898778

16 Dec 2025 09:52PM UTC coverage: 90.52% (+0.2%) from 90.36%
20283898778

Pull #5167

github

web-flow
Merge 795a38954 into 3d96b675e
Pull Request #5167: Changes to reduce unnecessary inclusions

101154 of 111748 relevant lines covered (90.52%)

12682929.61 hits per line

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

80.73
/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/x509_time.h>
16
#include <botan/internal/filesystem.h>
17

18
namespace Botan {
19

20
Certificate_Store::~Certificate_Store() = default;
6,990✔
21

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

26
   if(certs.empty()) {
20✔
27
      return std::nullopt;
9✔
28
   }
29

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

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

38
void Certificate_Store_In_Memory::add_certificate(const X509_Certificate& cert) {
4,896✔
39
   for(const auto& c : m_certs) {
5,873✔
40
      if(c == cert) {
992✔
41
         return;
4,896✔
42
      }
43
   }
44

45
   m_certs.push_back(cert);
4,881✔
46
}
47

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

57
std::optional<X509_Certificate> Certificate_Store_In_Memory::find_cert(const X509_DN& subject_dn,
6,526✔
58
                                                                       const std::vector<uint8_t>& key_id) const {
59
   for(const auto& cert : m_certs) {
11,766✔
60
      // Only compare key ids if set in both call and in the cert
61
      if(!key_id.empty()) {
6,592✔
62
         const std::vector<uint8_t>& skid = cert.subject_key_id();
5,885✔
63

64
         if(!skid.empty() && skid != key_id) {  // no match
5,885✔
65
            continue;
4,626✔
66
         }
67
      }
68

69
      if(cert.subject_dn() == subject_dn) {
1,966✔
70
         return cert;
1,352✔
71
      }
72
   }
73

74
   return std::nullopt;
5,174✔
75
}
76

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

81
   for(const auto& cert : m_certs) {
32,046✔
82
      if(!key_id.empty()) {
17,114✔
83
         const std::vector<uint8_t>& skid = cert.subject_key_id();
15,375✔
84

85
         if(!skid.empty() && skid != key_id) {  // no match
15,375✔
86
            continue;
8,738✔
87
         }
88
      }
89

90
      if(cert.subject_dn() == subject_dn) {
8,376✔
91
         matches.push_back(cert);
7,290✔
92
      }
93
   }
94

95
   return matches;
14,932✔
96
}
×
97

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

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

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

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

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

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

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

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

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

142
   return std::nullopt;
×
143
}
144

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

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

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

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

165
   for(const auto& c : m_crls) {
8,421✔
166
      // Only compare key ids if set in both call and in the CRL
167
      if(!key_id.empty()) {
3,588✔
168
         const std::vector<uint8_t>& akid = c.authority_key_id();
3,586✔
169

170
         if(!akid.empty() && akid != key_id) {  // no match
3,586✔
171
            continue;
1,427✔
172
         }
173
      }
174

175
      if(c.issuer_dn() == subject.issuer_dn()) {
2,161✔
176
         return c;
2,093✔
177
      }
178
   }
179

180
   return {};
4,833✔
181
}
182

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

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

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

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

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

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

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