Coverage Report

Created: 2024-10-01 06:14

/src/botan/src/lib/x509/certstor.cpp
Line
Count
Source (jump to first uncovered line)
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/data_src.h>
12
#include <botan/hash.h>
13
#include <botan/pkix_types.h>
14
#include <botan/internal/filesystem.h>
15
16
namespace Botan {
17
18
2.03k
Certificate_Store::~Certificate_Store() = default;
19
20
std::optional<X509_Certificate> Certificate_Store::find_cert(const X509_DN& subject_dn,
21
0
                                                             const std::vector<uint8_t>& key_id) const {
22
0
   const auto certs = find_all_certs(subject_dn, key_id);
23
24
0
   if(certs.empty()) {
25
0
      return std::nullopt;
26
0
   }
27
28
   // `count` might be greater than 1, but we'll just select the first match
29
0
   return certs.front();
30
0
}
31
32
0
std::optional<X509_CRL> Certificate_Store::find_crl_for(const X509_Certificate& /*unused*/) const {
33
0
   return std::nullopt;
34
0
}
35
36
736
void Certificate_Store_In_Memory::add_certificate(const X509_Certificate& cert) {
37
736
   for(const auto& c : m_certs) {
38
0
      if(c == cert) {
39
0
         return;
40
0
      }
41
0
   }
42
43
736
   m_certs.push_back(cert);
44
736
}
45
46
0
std::vector<X509_DN> Certificate_Store_In_Memory::all_subjects() const {
47
0
   std::vector<X509_DN> subjects;
48
0
   subjects.reserve(m_certs.size());
49
0
   for(const auto& cert : m_certs) {
50
0
      subjects.push_back(cert.subject_dn());
51
0
   }
52
0
   return subjects;
53
0
}
54
55
std::optional<X509_Certificate> Certificate_Store_In_Memory::find_cert(const X509_DN& subject_dn,
56
0
                                                                       const std::vector<uint8_t>& key_id) const {
57
0
   for(const auto& cert : m_certs) {
58
      // Only compare key ids if set in both call and in the cert
59
0
      if(!key_id.empty()) {
60
0
         const std::vector<uint8_t>& skid = cert.subject_key_id();
61
62
0
         if(!skid.empty() && skid != key_id) {  // no match
63
0
            continue;
64
0
         }
65
0
      }
66
67
0
      if(cert.subject_dn() == subject_dn) {
68
0
         return cert;
69
0
      }
70
0
   }
71
72
0
   return std::nullopt;
73
0
}
74
75
std::vector<X509_Certificate> Certificate_Store_In_Memory::find_all_certs(const X509_DN& subject_dn,
76
1.37k
                                                                          const std::vector<uint8_t>& key_id) const {
77
1.37k
   std::vector<X509_Certificate> matches;
78
79
1.37k
   for(const auto& cert : m_certs) {
80
685
      if(!key_id.empty()) {
81
33
         const std::vector<uint8_t>& skid = cert.subject_key_id();
82
83
33
         if(!skid.empty() && skid != key_id) {  // no match
84
22
            continue;
85
22
         }
86
33
      }
87
88
663
      if(cert.subject_dn() == subject_dn) {
89
524
         matches.push_back(cert);
90
524
      }
91
663
   }
92
93
1.37k
   return matches;
94
1.37k
}
95
96
std::optional<X509_Certificate> Certificate_Store_In_Memory::find_cert_by_pubkey_sha1(
97
0
   const std::vector<uint8_t>& key_hash) const {
98
0
   if(key_hash.size() != 20) {
99
0
      throw Invalid_Argument("Certificate_Store_In_Memory::find_cert_by_pubkey_sha1 invalid hash");
100
0
   }
101
102
0
   auto hash = HashFunction::create("SHA-1");
103
104
0
   for(const auto& cert : m_certs) {
105
0
      hash->update(cert.subject_public_key_bitstring());
106
0
      if(key_hash == hash->final_stdvec()) {  //final_stdvec also clears the hash to initial state
107
0
         return cert;
108
0
      }
109
0
   }
110
111
0
   return std::nullopt;
112
0
}
113
114
std::optional<X509_Certificate> Certificate_Store_In_Memory::find_cert_by_raw_subject_dn_sha256(
115
0
   const std::vector<uint8_t>& subject_hash) const {
116
0
   if(subject_hash.size() != 32) {
117
0
      throw Invalid_Argument("Certificate_Store_In_Memory::find_cert_by_raw_subject_dn_sha256 invalid hash");
118
0
   }
119
120
0
   auto hash = HashFunction::create("SHA-256");
121
122
0
   for(const auto& cert : m_certs) {
123
0
      hash->update(cert.raw_subject_dn());
124
0
      if(subject_hash == hash->final_stdvec()) {  //final_stdvec also clears the hash to initial state
125
0
         return cert;
126
0
      }
127
0
   }
128
129
0
   return std::nullopt;
130
0
}
131
132
0
void Certificate_Store_In_Memory::add_crl(const X509_CRL& crl) {
133
0
   const X509_DN& crl_issuer = crl.issuer_dn();
134
135
0
   for(auto& c : m_crls) {
136
      // Found an update of a previously existing one; replace it
137
0
      if(c.issuer_dn() == crl_issuer) {
138
0
         if(c.this_update() <= crl.this_update()) {
139
0
            c = crl;
140
0
         }
141
0
         return;
142
0
      }
143
0
   }
144
145
   // Totally new CRL, add to the list
146
0
   m_crls.push_back(crl);
147
0
}
148
149
584
std::optional<X509_CRL> Certificate_Store_In_Memory::find_crl_for(const X509_Certificate& subject) const {
150
584
   const std::vector<uint8_t>& key_id = subject.authority_key_id();
151
152
584
   for(const auto& c : m_crls) {
153
      // Only compare key ids if set in both call and in the CRL
154
0
      if(!key_id.empty()) {
155
0
         const std::vector<uint8_t>& akid = c.authority_key_id();
156
157
0
         if(!akid.empty() && akid != key_id) {  // no match
158
0
            continue;
159
0
         }
160
0
      }
161
162
0
      if(c.issuer_dn() == subject.issuer_dn()) {
163
0
         return c;
164
0
      }
165
0
   }
166
167
584
   return {};
168
584
}
169
170
736
Certificate_Store_In_Memory::Certificate_Store_In_Memory(const X509_Certificate& cert) {
171
736
   add_certificate(cert);
172
736
}
173
174
#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
175
0
Certificate_Store_In_Memory::Certificate_Store_In_Memory(std::string_view dir) {
176
0
   if(dir.empty()) {
177
0
      return;
178
0
   }
179
180
0
   std::vector<std::string> maybe_certs = get_files_recursive(dir);
181
182
0
   if(maybe_certs.empty()) {
183
0
      maybe_certs.push_back(std::string(dir));
184
0
   }
185
186
0
   for(auto&& cert_file : maybe_certs) {
187
0
      try {
188
0
         DataSource_Stream src(cert_file, true);
189
0
         while(!src.end_of_data()) {
190
0
            try {
191
0
               X509_Certificate cert(src);
192
0
               m_certs.push_back(cert);
193
0
            } catch(std::exception&) {
194
               // stop searching for other certificate at first exception
195
0
               break;
196
0
            }
197
0
         }
198
0
      } catch(std::exception&) {}
199
0
   }
200
0
}
201
#endif
202
203
}  // namespace Botan