Botan  2.12.1
Crypto and TLS for C++11
certstor_flatfile.cpp
Go to the documentation of this file.
1 /*
2 * Certificate Store
3 * (C) 1999-2019 Jack Lloyd
4 * (C) 2019 Patrick Schmidt
5 *
6 * Botan is released under the Simplified BSD License (see license.txt)
7 */
8 
9 #include <botan/build.h>
10 
11 #include <botan/certstor_flatfile.h>
12 #include <botan/data_src.h>
13 #include <botan/pem.h>
14 
15 namespace Botan {
16 namespace {
17 std::vector<std::vector<uint8_t>> decode_all_certificates(DataSource& source)
18  {
19  std::vector<std::vector<uint8_t>> pems;
20 
21  while(!source.end_of_data())
22  {
23  std::string label;
24  std::vector<uint8_t> cert;
25  try
26  {
27  cert = unlock(PEM_Code::decode(source, label));
28 
29  if(label == "CERTIFICATE" || label == "X509 CERTIFICATE" || label == "TRUSTED CERTIFICATE")
30  {
31  pems.push_back(cert);
32  }
33  }
34  catch(const Decoding_Error&) {}
35  }
36 
37  return pems;
38  }
39 }
40 
41 Flatfile_Certificate_Store::Flatfile_Certificate_Store(const std::string& file, bool ignore_non_ca)
42  {
43  if(file.empty())
44  {
45  throw Invalid_Argument("Flatfile_Certificate_Store::Flatfile_Certificate_Store invalid file path");
46  }
47 
48  DataSource_Stream file_stream(file);
49 
50  for(const std::vector<uint8_t> der : decode_all_certificates(file_stream))
51  {
52  std::shared_ptr<const X509_Certificate> cert = std::make_shared<const X509_Certificate>(der.data(), der.size());
53 
54  /*
55  * Various weird or misconfigured system roots include intermediate certificates,
56  * or even stranger certificates which are not valid for cert issuance at all.
57  * Previously this code would error on such cases as an obvious misconfiguration,
58  * but we cannot fix the trust store. So instead just ignore any such certificate.
59  */
60  if(cert->is_self_signed() && cert->is_CA_cert())
61  {
62  m_all_subjects.push_back(cert->subject_dn());
63  m_dn_to_cert[cert->subject_dn()].push_back(cert);
64  m_pubkey_sha1_to_cert.emplace(cert->subject_public_key_bitstring_sha1(), cert);
65  m_subject_dn_sha256_to_cert.emplace(cert->raw_subject_dn_sha256(), cert);
66  }
67  else if(!ignore_non_ca)
68  {
69  throw Invalid_Argument("Flatfile_Certificate_Store received non CA cert " + cert->subject_dn().to_string());
70  }
71  }
72 
73  if(m_all_subjects.empty())
74  {
75  throw Invalid_Argument("Flatfile_Certificate_Store::Flatfile_Certificate_Store cert file is empty");
76  }
77  }
78 
79 std::vector<X509_DN> Flatfile_Certificate_Store::all_subjects() const
80  {
81  return m_all_subjects;
82  }
83 
84 std::shared_ptr<const X509_Certificate>
86  const std::vector<uint8_t>& key_id) const
87  {
88  std::vector<std::shared_ptr<const X509_Certificate>> found_certs = find_all_certs(subject_dn, key_id);
89 
90  return !found_certs.empty() ? found_certs.front() : nullptr;
91  }
92 
93 std::vector<std::shared_ptr<const X509_Certificate>> Flatfile_Certificate_Store::find_all_certs(
94  const X509_DN& subject_dn,
95  const std::vector<uint8_t>& key_id) const
96  {
97  std::vector<std::shared_ptr<const X509_Certificate>> found_certs;
98  try
99  {
100  const auto certs = m_dn_to_cert.at(subject_dn);
101 
102  for(auto cert : certs)
103  {
104  if(key_id.empty() || key_id == cert->subject_key_id())
105  {
106  found_certs.push_back(cert);
107  }
108  }
109  }
110  catch(const std::out_of_range&)
111  {
112  return {};
113  }
114 
115  return found_certs;
116  }
117 
118 std::shared_ptr<const X509_Certificate>
119 Flatfile_Certificate_Store::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
120  {
121  if(key_hash.size() != 20)
122  {
123  throw Invalid_Argument("Flatfile_Certificate_Store::find_cert_by_pubkey_sha1 invalid hash");
124  }
125 
126  auto found_cert = m_pubkey_sha1_to_cert.find(key_hash);
127 
128  if(found_cert != m_pubkey_sha1_to_cert.end())
129  {
130  return found_cert->second;
131  }
132 
133  return nullptr;
134  }
135 
136 std::shared_ptr<const X509_Certificate>
137 Flatfile_Certificate_Store::find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const
138  {
139  if(subject_hash.size() != 32)
140  { throw Invalid_Argument("Flatfile_Certificate_Store::find_cert_by_raw_subject_dn_sha256 invalid hash"); }
141 
142  auto found_cert = m_subject_dn_sha256_to_cert.find(subject_hash);
143 
144  if(found_cert != m_subject_dn_sha256_to_cert.end())
145  {
146  return found_cert->second;
147  }
148 
149  return nullptr;
150  }
151 
152 std::shared_ptr<const X509_CRL> Flatfile_Certificate_Store::find_crl_for(const X509_Certificate& subject) const
153  {
154  BOTAN_UNUSED(subject);
155  return {};
156  }
157 }
std::shared_ptr< const X509_Certificate > find_cert(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const override
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
Definition: pem.cpp:68
Definition: alg_id.cpp:13
std::shared_ptr< const X509_Certificate > find_cert_by_pubkey_sha1(const std::vector< uint8_t > &key_hash) const override
#define BOTAN_UNUSED(...)
Definition: assert.h:142
std::vector< T > unlock(const secure_vector< T > &in)
Definition: secmem.h:72
std::vector< std::shared_ptr< const X509_Certificate > > find_all_certs(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const override
std::shared_ptr< const X509_Certificate > find_cert_by_raw_subject_dn_sha256(const std::vector< uint8_t > &subject_hash) const override
Flatfile_Certificate_Store(const std::string &file, bool ignore_non_ca=false)
std::shared_ptr< const X509_CRL > find_crl_for(const X509_Certificate &subject) const override
std::vector< X509_DN > all_subjects() const override