aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/x509/certstor_flatfile/certstor_flatfile.cpp
blob: 74837cd1ea2362615559c71ba76eb0bf29064b5a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
* Certificate Store
* (C) 1999-2019 Jack Lloyd
* (C) 2019      Patrick Schmidt
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/certstor_flatfile.h>
#include <botan/pkix_types.h>
#include <botan/data_src.h>
#include <botan/pem.h>
#include <stdexcept>

namespace Botan {
namespace {
std::vector<std::vector<uint8_t>> decode_all_certificates(DataSource& source)
   {
   std::vector<std::vector<uint8_t>> pems;

   while(!source.end_of_data())
      {
      std::string label;
      std::vector<uint8_t> cert;
      try
         {
         cert = unlock(PEM_Code::decode(source, label));

         if(label == "CERTIFICATE" || label == "X509 CERTIFICATE" || label == "TRUSTED CERTIFICATE")
            {
            pems.push_back(cert);
            }
         }
      catch(const Decoding_Error&) {}
      }

   return pems;
   }
}

Flatfile_Certificate_Store::Flatfile_Certificate_Store(const std::string& file, bool ignore_non_ca)
   {
   if(file.empty())
      {
      throw Invalid_Argument("Flatfile_Certificate_Store::Flatfile_Certificate_Store invalid file path");
      }

   DataSource_Stream file_stream(file);

   for(const std::vector<uint8_t>& der : decode_all_certificates(file_stream))
      {
      X509_Certificate cert(der);

      /*
      * Various weird or misconfigured system roots include intermediate certificates,
      * or even stranger certificates which are not valid for cert issuance at all.
      * Previously this code would error on such cases as an obvious misconfiguration,
      * but we cannot fix the trust store. So instead just ignore any such certificate.
      */
      if(cert.is_self_signed() && cert.is_CA_cert())
         {
         m_all_subjects.push_back(cert.subject_dn());
         m_dn_to_cert[cert.subject_dn()].push_back(cert);
         m_pubkey_sha1_to_cert.emplace(cert.subject_public_key_bitstring_sha1(), cert);
         m_subject_dn_sha256_to_cert.emplace(cert.raw_subject_dn_sha256(), cert);
         }
      else if(!ignore_non_ca)
         {
         throw Invalid_Argument("Flatfile_Certificate_Store received non CA cert " + cert.subject_dn().to_string());
         }
      }

   if(m_all_subjects.empty())
      {
      throw Invalid_Argument("Flatfile_Certificate_Store::Flatfile_Certificate_Store cert file is empty");
      }
   }

std::vector<X509_DN> Flatfile_Certificate_Store::all_subjects() const
   {
   return m_all_subjects;
   }

std::vector<X509_Certificate> Flatfile_Certificate_Store::find_all_certs(
         const X509_DN& subject_dn,
         const std::vector<uint8_t>& key_id) const
   {
   std::vector<X509_Certificate> found_certs;
   try
      {
      const auto certs = m_dn_to_cert.at(subject_dn);

      for(auto cert : certs)
         {
         if(key_id.empty() || key_id == cert.subject_key_id())
            {
            found_certs.push_back(cert);
            }
         }
      }
   catch(const std::out_of_range&)
      {
      return {};
      }

   return found_certs;
   }

std::optional<X509_Certificate>
Flatfile_Certificate_Store::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
   {
   if(key_hash.size() != 20)
      {
      throw Invalid_Argument("Flatfile_Certificate_Store::find_cert_by_pubkey_sha1 invalid hash");
      }

   auto found_cert = m_pubkey_sha1_to_cert.find(key_hash);

   if(found_cert != m_pubkey_sha1_to_cert.end())
      {
      return found_cert->second;
      }

   return std::nullopt;
   }

std::optional<X509_Certificate>
Flatfile_Certificate_Store::find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const
   {
   if(subject_hash.size() != 32)
      { throw Invalid_Argument("Flatfile_Certificate_Store::find_cert_by_raw_subject_dn_sha256 invalid hash"); }

   auto found_cert = m_subject_dn_sha256_to_cert.find(subject_hash);

   if(found_cert != m_subject_dn_sha256_to_cert.end())
      {
      return found_cert->second;
      }

   return std::nullopt;
   }

std::optional<X509_CRL> Flatfile_Certificate_Store::find_crl_for(const X509_Certificate& subject) const
   {
   BOTAN_UNUSED(subject);
   return {};
   }
}