Botan 3.10.0
Crypto and TLS for C&
x509_crl.cpp
Go to the documentation of this file.
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
10#include <botan/ber_dec.h>
11#include <botan/x509_ext.h>
12#include <botan/x509cert.h>
13
14namespace Botan {
15
16struct CRL_Data {
17 X509_DN m_issuer;
18 size_t m_version{};
19 X509_Time m_this_update;
20 X509_Time m_next_update;
21 std::vector<CRL_Entry> m_entries;
22 Extensions m_extensions;
23
24 // cached values from extensions
25 size_t m_crl_number = 0;
26 std::vector<uint8_t> m_auth_key_id;
27 std::vector<std::string> m_idp_urls;
28};
29
30std::string X509_CRL::PEM_label() const {
31 return "X509 CRL";
32}
33
34std::vector<std::string> X509_CRL::alternate_PEM_labels() const {
35 return {"CRL"};
36}
37
41
42X509_CRL::X509_CRL(const std::vector<uint8_t>& vec) {
43 DataSource_Memory src(vec.data(), vec.size());
44 load_data(src);
45}
46
47#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
48X509_CRL::X509_CRL(std::string_view fsname) {
49 DataSource_Stream src(fsname, true);
50 load_data(src);
51}
52#endif
53
57 const std::vector<CRL_Entry>& revoked) {
58 m_data = std::make_shared<CRL_Data>();
59 m_data->m_issuer = issuer;
60 m_data->m_this_update = this_update;
61 m_data->m_next_update = next_update;
62 m_data->m_entries = revoked;
63}
64
65/**
66* Check if this particular certificate is listed in the CRL
67*/
68bool X509_CRL::is_revoked(const X509_Certificate& cert) const {
69 /*
70 If the cert wasn't issued by the CRL issuer, it's possible the cert
71 is revoked, but not by this CRL. Maybe throw an exception instead?
72 */
73 if(cert.issuer_dn() != issuer_dn()) {
74 return false;
75 }
76
77 std::vector<uint8_t> crl_akid = authority_key_id();
78 const std::vector<uint8_t>& cert_akid = cert.authority_key_id();
79
80 if(!crl_akid.empty() && !cert_akid.empty()) {
81 if(crl_akid != cert_akid) {
82 return false;
83 }
84 }
85
86 const std::vector<uint8_t>& cert_serial = cert.serial_number();
87
88 bool is_revoked = false;
89
90 // FIXME would be nice to avoid a linear scan here - maybe sort the entries?
91 for(const CRL_Entry& entry : get_revoked()) {
92 if(cert_serial == entry.serial_number()) {
93 if(entry.reason_code() == CRL_Code::RemoveFromCrl) {
94 is_revoked = false;
95 } else {
96 is_revoked = true;
97 }
98 }
99 }
100
101 return is_revoked;
102}
103
104/*
105* Decode the TBSCertList data
106*/
107namespace {
108
109std::unique_ptr<CRL_Data> decode_crl_body(const std::vector<uint8_t>& body, const AlgorithmIdentifier& sig_algo) {
110 auto data = std::make_unique<CRL_Data>();
111
112 BER_Decoder tbs_crl(body);
113
114 tbs_crl.decode_optional(data->m_version, ASN1_Type::Integer, ASN1_Class::Universal);
115 data->m_version += 1; // wire-format is 0-based
116
117 if(data->m_version != 1 && data->m_version != 2) {
118 throw Decoding_Error("Unknown X.509 CRL version " + std::to_string(data->m_version));
119 }
120
121 AlgorithmIdentifier sig_algo_inner;
122 tbs_crl.decode(sig_algo_inner);
123
124 if(sig_algo != sig_algo_inner) {
125 throw Decoding_Error("Algorithm identifier mismatch in CRL");
126 }
127
128 tbs_crl.decode(data->m_issuer).decode(data->m_this_update);
129
130 // According to RFC 5280 Section 5.1, nextUpdate is OPTIONAL and may be
131 // encoded as either a UTCTime or a GeneralizedTime. Section 5.1.2.5
132 // further states that "[c]onforming CRL issuers MUST include the nextUpdate
133 // field in all CRLs". Obviously, not everyone complies...
134 //
135 // See https://github.com/randombit/botan/issues/4722 for more details.
136 tbs_crl.decode_optional(data->m_next_update, ASN1_Type::UtcTime, ASN1_Class::Universal);
137 if(!data->m_next_update.time_is_set()) {
138 tbs_crl.decode_optional(data->m_next_update, ASN1_Type::GeneralizedTime, ASN1_Class::Universal);
139 }
140
141 BER_Object next = tbs_crl.get_next_object();
142
144 BER_Decoder cert_list(std::move(next));
145
146 while(cert_list.more_items()) {
147 CRL_Entry entry;
148 cert_list.decode(entry);
149 data->m_entries.push_back(entry);
150 }
151 next = tbs_crl.get_next_object();
152 }
153
155 BER_Decoder crl_options(std::move(next));
156 crl_options.decode(data->m_extensions).verify_end();
157 next = tbs_crl.get_next_object();
158 }
159
160 if(next.is_set()) {
161 throw Decoding_Error("Unknown tag following extensions in CRL");
162 }
163
164 tbs_crl.verify_end();
165
166 // Now cache some fields from the extensions
167 if(const auto* ext = data->m_extensions.get_extension_object_as<Cert_Extension::CRL_Number>()) {
168 data->m_crl_number = ext->get_crl_number();
169 }
170 if(const auto* ext = data->m_extensions.get_extension_object_as<Cert_Extension::Authority_Key_ID>()) {
171 data->m_auth_key_id = ext->get_key_id();
172 }
173 if(const auto* ext = data->m_extensions.get_extension_object_as<Cert_Extension::CRL_Issuing_Distribution_Point>()) {
174 data->m_idp_urls = ext->get_point().get_attribute("URL");
175 }
176
177 return data;
178}
179
180} // namespace
181
182void X509_CRL::force_decode() {
183 m_data.reset(decode_crl_body(signed_body(), signature_algorithm()).release());
184}
185
186const CRL_Data& X509_CRL::data() const {
187 if(!m_data) {
188 throw Invalid_State("X509_CRL uninitialized");
189 }
190 return *m_data;
191}
192
194 return data().m_extensions;
195}
196
197/*
198* Return the list of revoked certificates
199*/
200const std::vector<CRL_Entry>& X509_CRL::get_revoked() const {
201 return data().m_entries;
202}
203
204uint32_t X509_CRL::x509_version() const {
205 return static_cast<uint32_t>(data().m_version);
206}
207
208/*
209* Return the distinguished name of the issuer
210*/
212 return data().m_issuer;
213}
214
215/*
216* Return the key identifier of the issuer
217*/
218const std::vector<uint8_t>& X509_CRL::authority_key_id() const {
219 return data().m_auth_key_id;
220}
221
222/*
223* Return the CRL number of this CRL
224*/
225uint32_t X509_CRL::crl_number() const {
226 return static_cast<uint32_t>(data().m_crl_number);
227}
228
229/*
230* Return the issue data of the CRL
231*/
233 return data().m_this_update;
234}
235
236/*
237* Return the date when a new CRL will be issued
238*/
240 return data().m_next_update;
241}
242
243/*
244* Return the CRL's distribution point
245*/
247 if(!data().m_idp_urls.empty()) {
248 return data().m_idp_urls[0];
249 }
250 return "";
251}
252
253/*
254* Return the CRL's issuing distribution point
255*/
256std::vector<std::string> X509_CRL::issuing_distribution_points() const {
257 return data().m_idp_urls;
258}
259
260} // namespace Botan
Definition x509_crl.h:29
const std::vector< CRL_Entry > & get_revoked() const
Definition x509_crl.cpp:200
const std::vector< uint8_t > & authority_key_id() const
Definition x509_crl.cpp:218
const X509_Time & this_update() const
Definition x509_crl.cpp:232
std::vector< std::string > issuing_distribution_points() const
Definition x509_crl.cpp:256
X509_CRL()=default
const Extensions & extensions() const
Definition x509_crl.cpp:193
uint32_t crl_number() const
Definition x509_crl.cpp:225
const X509_Time & next_update() const
Definition x509_crl.cpp:239
const X509_DN & issuer_dn() const
Definition x509_crl.cpp:211
bool is_revoked(const X509_Certificate &cert) const
Definition x509_crl.cpp:68
std::string crl_issuing_distribution_point() const
Definition x509_crl.cpp:246
uint32_t x509_version() const
Definition x509_crl.cpp:204
const std::vector< uint8_t > & serial_number() const
Definition x509cert.cpp:399
const std::vector< uint8_t > & authority_key_id() const
Definition x509cert.cpp:391
const X509_DN & issuer_dn() const
Definition x509cert.cpp:407
const std::vector< uint8_t > & signed_body() const
Definition x509_obj.h:45
const AlgorithmIdentifier & signature_algorithm() const
Definition x509_obj.h:50
virtual std::vector< std::string > alternate_PEM_labels() const
Definition x509_obj.h:101
void load_data(DataSource &src)
Definition x509_obj.cpp:23
virtual std::string PEM_label() const =0
ASN1_Time X509_Time
Definition asn1_obj.h:424