Coverage Report

Created: 2020-06-30 13:58

/src/botan/src/lib/x509/x509_crl.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* X.509 CRL
3
* (C) 1999-2007 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/x509_crl.h>
9
#include <botan/x509_ext.h>
10
#include <botan/x509cert.h>
11
#include <botan/ber_dec.h>
12
13
#include <sstream>
14
15
namespace Botan {
16
17
struct CRL_Data
18
   {
19
   X509_DN m_issuer;
20
   X509_Time m_this_update;
21
   X509_Time m_next_update;
22
   std::vector<CRL_Entry> m_entries;
23
   Extensions m_extensions;
24
25
   // cached values from extensions
26
   size_t m_crl_number = 0;
27
   std::vector<uint8_t> m_auth_key_id;
28
   std::string m_issuing_distribution_point;
29
   };
30
31
std::string X509_CRL::PEM_label() const
32
2.86k
   {
33
2.86k
   return "X509 CRL";
34
2.86k
   }
35
36
std::vector<std::string> X509_CRL::alternate_PEM_labels() const
37
66
   {
38
66
   return { "CRL" };
39
66
   }
40
41
X509_CRL::X509_CRL(DataSource& src)
42
3.61k
   {
43
3.61k
   load_data(src);
44
3.61k
   }
45
46
X509_CRL::X509_CRL(const std::vector<uint8_t>& vec)
47
0
   {
48
0
   DataSource_Memory src(vec.data(), vec.size());
49
0
   load_data(src);
50
0
   }
51
52
#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
53
X509_CRL::X509_CRL(const std::string& fsname)
54
0
   {
55
0
   DataSource_Stream src(fsname, true);
56
0
   load_data(src);
57
0
   }
58
#endif
59
60
X509_CRL::X509_CRL(const X509_DN& issuer,
61
                   const X509_Time& this_update,
62
                   const X509_Time& next_update,
63
                   const std::vector<CRL_Entry>& revoked) :
64
   X509_Object()
65
0
   {
66
0
   m_data.reset(new CRL_Data);
67
0
   m_data->m_issuer = issuer;
68
0
   m_data->m_this_update = this_update;
69
0
   m_data->m_next_update = next_update;
70
0
   m_data->m_entries = revoked;
71
0
   }
72
73
/**
74
* Check if this particular certificate is listed in the CRL
75
*/
76
bool X509_CRL::is_revoked(const X509_Certificate& cert) const
77
0
   {
78
0
   /*
79
0
   If the cert wasn't issued by the CRL issuer, it's possible the cert
80
0
   is revoked, but not by this CRL. Maybe throw an exception instead?
81
0
   */
82
0
   if(cert.issuer_dn() != issuer_dn())
83
0
      return false;
84
0
85
0
   std::vector<uint8_t> crl_akid = authority_key_id();
86
0
   std::vector<uint8_t> cert_akid = cert.authority_key_id();
87
0
88
0
   if(!crl_akid.empty() && !cert_akid.empty())
89
0
      {
90
0
      if(crl_akid != cert_akid)
91
0
         return false;
92
0
      }
93
0
94
0
   std::vector<uint8_t> cert_serial = cert.serial_number();
95
0
96
0
   bool is_revoked = false;
97
0
98
0
   // FIXME would be nice to avoid a linear scan here - maybe sort the entries?
99
0
   for(const CRL_Entry& entry : get_revoked())
100
0
      {
101
0
      if(cert_serial == entry.serial_number())
102
0
         {
103
0
         if(entry.reason_code() == REMOVE_FROM_CRL)
104
0
            is_revoked = false;
105
0
         else
106
0
            is_revoked = true;
107
0
         }
108
0
      }
109
0
110
0
   return is_revoked;
111
0
   }
112
113
/*
114
* Decode the TBSCertList data
115
*/
116
namespace {
117
118
std::unique_ptr<CRL_Data> decode_crl_body(const std::vector<uint8_t>& body,
119
                                          const AlgorithmIdentifier& sig_algo)
120
2.35k
   {
121
2.35k
   std::unique_ptr<CRL_Data> data(new CRL_Data);
122
2.35k
123
2.35k
   BER_Decoder tbs_crl(body);
124
2.35k
125
2.35k
   size_t version;
126
2.35k
   tbs_crl.decode_optional(version, INTEGER, UNIVERSAL);
127
2.35k
128
2.35k
   if(version != 0 && version != 1)
129
40
      throw X509_CRL::X509_CRL_Error("Unknown X.509 CRL version " +
130
40
                           std::to_string(version+1));
131
2.31k
132
2.31k
   AlgorithmIdentifier sig_algo_inner;
133
2.31k
   tbs_crl.decode(sig_algo_inner);
134
2.31k
135
2.31k
   if(sig_algo != sig_algo_inner)
136
126
      throw X509_CRL::X509_CRL_Error("Algorithm identifier mismatch");
137
2.18k
138
2.18k
   tbs_crl.decode(data->m_issuer)
139
2.18k
      .decode(data->m_this_update)
140
2.18k
      .decode(data->m_next_update);
141
2.18k
142
2.18k
   BER_Object next = tbs_crl.get_next_object();
143
2.18k
144
2.18k
   if(next.is_a(SEQUENCE, CONSTRUCTED))
145
357
      {
146
357
      BER_Decoder cert_list(std::move(next));
147
357
148
13.1k
      while(cert_list.more_items())
149
12.8k
         {
150
12.8k
         CRL_Entry entry;
151
12.8k
         cert_list.decode(entry);
152
12.8k
         data->m_entries.push_back(entry);
153
12.8k
         }
154
357
      next = tbs_crl.get_next_object();
155
357
      }
156
2.18k
157
2.18k
   if(next.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)))
158
1.30k
      {
159
1.30k
      BER_Decoder crl_options(std::move(next));
160
1.30k
      crl_options.decode(data->m_extensions).verify_end();
161
1.30k
      next = tbs_crl.get_next_object();
162
1.30k
      }
163
2.18k
164
2.18k
   if(next.is_set())
165
37
      throw X509_CRL::X509_CRL_Error("Unknown tag in CRL");
166
2.15k
167
2.15k
   tbs_crl.verify_end();
168
2.15k
169
2.15k
   // Now cache some fields from the extensions
170
2.15k
   if(auto ext = data->m_extensions.get_extension_object_as<Cert_Extension::CRL_Number>())
171
2
      {
172
2
      data->m_crl_number = ext->get_crl_number();
173
2
      }
174
2.15k
   if(auto ext = data->m_extensions.get_extension_object_as<Cert_Extension::Authority_Key_ID>())
175
4
      {
176
4
      data->m_auth_key_id = ext->get_key_id();
177
4
      }
178
2.15k
   if(auto ext = data->m_extensions.get_extension_object_as<Cert_Extension::CRL_Issuing_Distribution_Point>())
179
7
      {
180
7
      std::stringstream ss;
181
7
182
7
      for(const auto& pair : ext->get_point().contents())
183
14
         {
184
14
         ss << pair.first << ": " << pair.second << " ";
185
14
         }
186
7
      data->m_issuing_distribution_point = ss.str();
187
7
      }
188
2.15k
189
2.15k
   return data;
190
2.15k
   }
191
192
}
193
194
void X509_CRL::force_decode()
195
2.35k
   {
196
2.35k
   m_data.reset(decode_crl_body(signed_body(), signature_algorithm()).release());
197
2.35k
   }
198
199
const CRL_Data& X509_CRL::data() const
200
0
   {
201
0
   if(!m_data)
202
0
      {
203
0
      throw Invalid_State("X509_CRL uninitialized");
204
0
      }
205
0
   return *m_data.get();
206
0
   }
207
208
const Extensions& X509_CRL::extensions() const
209
0
   {
210
0
   return data().m_extensions;
211
0
   }
212
213
/*
214
* Return the list of revoked certificates
215
*/
216
const std::vector<CRL_Entry>& X509_CRL::get_revoked() const
217
0
   {
218
0
   return data().m_entries;
219
0
   }
220
221
/*
222
* Return the distinguished name of the issuer
223
*/
224
const X509_DN& X509_CRL::issuer_dn() const
225
0
   {
226
0
   return data().m_issuer;
227
0
   }
228
229
/*
230
* Return the key identifier of the issuer
231
*/
232
const std::vector<uint8_t>& X509_CRL::authority_key_id() const
233
0
   {
234
0
   return data().m_auth_key_id;
235
0
   }
236
237
/*
238
* Return the CRL number of this CRL
239
*/
240
uint32_t X509_CRL::crl_number() const
241
0
   {
242
0
   return static_cast<uint32_t>(data().m_crl_number);
243
0
   }
244
245
/*
246
* Return the issue data of the CRL
247
*/
248
const X509_Time& X509_CRL::this_update() const
249
0
   {
250
0
   return data().m_this_update;
251
0
   }
252
253
/*
254
* Return the date when a new CRL will be issued
255
*/
256
const X509_Time& X509_CRL::next_update() const
257
0
   {
258
0
   return data().m_next_update;
259
0
   }
260
261
/*
262
* Return the CRL's distribution point
263
*/
264
std::string X509_CRL::crl_issuing_distribution_point() const
265
0
   {
266
0
   return data().m_issuing_distribution_point;
267
0
   }
268
}