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