Coverage Report

Created: 2020-11-21 08:34

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