Botan  2.15.0
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::vector<std::shared_ptr<const X509_Certificate>> Flatfile_Certificate_Store::find_all_certs(
85  const X509_DN& subject_dn,
86  const std::vector<uint8_t>& key_id) const
87  {
88  std::vector<std::shared_ptr<const X509_Certificate>> found_certs;
89  try
90  {
91  const auto certs = m_dn_to_cert.at(subject_dn);
92 
93  for(auto cert : certs)
94  {
95  if(key_id.empty() || key_id == cert->subject_key_id())
96  {
97  found_certs.push_back(cert);
98  }
99  }
100  }
101  catch(const std::out_of_range&)
102  {
103  return {};
104  }
105 
106  return found_certs;
107  }
108 
109 std::shared_ptr<const X509_Certificate>
110 Flatfile_Certificate_Store::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
111  {
112  if(key_hash.size() != 20)
113  {
114  throw Invalid_Argument("Flatfile_Certificate_Store::find_cert_by_pubkey_sha1 invalid hash");
115  }
116 
117  auto found_cert = m_pubkey_sha1_to_cert.find(key_hash);
118 
119  if(found_cert != m_pubkey_sha1_to_cert.end())
120  {
121  return found_cert->second;
122  }
123 
124  return nullptr;
125  }
126 
127 std::shared_ptr<const X509_Certificate>
128 Flatfile_Certificate_Store::find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const
129  {
130  if(subject_hash.size() != 32)
131  { throw Invalid_Argument("Flatfile_Certificate_Store::find_cert_by_raw_subject_dn_sha256 invalid hash"); }
132 
133  auto found_cert = m_subject_dn_sha256_to_cert.find(subject_hash);
134 
135  if(found_cert != m_subject_dn_sha256_to_cert.end())
136  {
137  return found_cert->second;
138  }
139 
140  return nullptr;
141  }
142 
143 std::shared_ptr<const X509_CRL> Flatfile_Certificate_Store::find_crl_for(const X509_Certificate& subject) const
144  {
145  BOTAN_UNUSED(subject);
146  return {};
147  }
148 }
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