/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.95k | { |
33 | 2.95k | return "X509 CRL"; |
34 | 2.95k | } |
35 | | |
36 | | std::vector<std::string> X509_CRL::alternate_PEM_labels() const |
37 | 68 | { |
38 | 68 | return { "CRL" }; |
39 | 68 | } |
40 | | |
41 | | X509_CRL::X509_CRL(DataSource& src) |
42 | 3.78k | { |
43 | 3.78k | load_data(src); |
44 | 3.78k | } |
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 | | /* |
79 | | If the cert wasn't issued by the CRL issuer, it's possible the cert |
80 | | is revoked, but not by this CRL. Maybe throw an exception instead? |
81 | | */ |
82 | 0 | if(cert.issuer_dn() != issuer_dn()) |
83 | 0 | return false; |
84 | | |
85 | 0 | std::vector<uint8_t> crl_akid = authority_key_id(); |
86 | 0 | std::vector<uint8_t> cert_akid = cert.authority_key_id(); |
87 | |
|
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 | | |
94 | 0 | std::vector<uint8_t> cert_serial = cert.serial_number(); |
95 | |
|
96 | 0 | bool is_revoked = false; |
97 | | |
98 | | // 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 | |
|
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.47k | { |
121 | 2.47k | std::unique_ptr<CRL_Data> data(new CRL_Data); |
122 | | |
123 | 2.47k | BER_Decoder tbs_crl(body); |
124 | | |
125 | 2.47k | size_t version; |
126 | 2.47k | tbs_crl.decode_optional(version, INTEGER, UNIVERSAL); |
127 | | |
128 | 2.47k | if(version != 0 && version != 1) |
129 | 42 | throw Decoding_Error("Unknown X.509 CRL version " + std::to_string(version+1)); |
130 | | |
131 | 2.43k | AlgorithmIdentifier sig_algo_inner; |
132 | 2.43k | tbs_crl.decode(sig_algo_inner); |
133 | | |
134 | 2.43k | if(sig_algo != sig_algo_inner) |
135 | 127 | throw Decoding_Error("Algorithm identifier mismatch in CRL"); |
136 | | |
137 | 2.30k | tbs_crl.decode(data->m_issuer) |
138 | 2.30k | .decode(data->m_this_update) |
139 | 2.30k | .decode(data->m_next_update); |
140 | | |
141 | 2.30k | BER_Object next = tbs_crl.get_next_object(); |
142 | | |
143 | 2.30k | if(next.is_a(SEQUENCE, CONSTRUCTED)) |
144 | 406 | { |
145 | 406 | BER_Decoder cert_list(std::move(next)); |
146 | | |
147 | 14.5k | while(cert_list.more_items()) |
148 | 14.1k | { |
149 | 14.1k | CRL_Entry entry; |
150 | 14.1k | cert_list.decode(entry); |
151 | 14.1k | data->m_entries.push_back(entry); |
152 | 14.1k | } |
153 | 406 | next = tbs_crl.get_next_object(); |
154 | 406 | } |
155 | | |
156 | 2.30k | if(next.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) |
157 | 1.35k | { |
158 | 1.35k | BER_Decoder crl_options(std::move(next)); |
159 | 1.35k | crl_options.decode(data->m_extensions).verify_end(); |
160 | 1.35k | next = tbs_crl.get_next_object(); |
161 | 1.35k | } |
162 | | |
163 | 2.30k | if(next.is_set()) |
164 | 19 | throw Decoding_Error("Unknown tag following extensions in CRL"); |
165 | | |
166 | 2.28k | tbs_crl.verify_end(); |
167 | | |
168 | | // Now cache some fields from the extensions |
169 | 2.28k | if(auto ext = data->m_extensions.get_extension_object_as<Cert_Extension::CRL_Number>()) |
170 | 2 | { |
171 | 2 | data->m_crl_number = ext->get_crl_number(); |
172 | 2 | } |
173 | 2.28k | if(auto ext = data->m_extensions.get_extension_object_as<Cert_Extension::Authority_Key_ID>()) |
174 | 3 | { |
175 | 3 | data->m_auth_key_id = ext->get_key_id(); |
176 | 3 | } |
177 | 2.28k | if(auto ext = data->m_extensions.get_extension_object_as<Cert_Extension::CRL_Issuing_Distribution_Point>()) |
178 | 7 | { |
179 | 7 | std::stringstream ss; |
180 | | |
181 | 7 | for(const auto& pair : ext->get_point().contents()) |
182 | 10 | { |
183 | 10 | ss << pair.first << ": " << pair.second << " "; |
184 | 10 | } |
185 | 7 | data->m_issuing_distribution_point = ss.str(); |
186 | 7 | } |
187 | | |
188 | 2.28k | return data; |
189 | 2.28k | } |
190 | | |
191 | | } |
192 | | |
193 | | void X509_CRL::force_decode() |
194 | 2.47k | { |
195 | 2.47k | m_data.reset(decode_crl_body(signed_body(), signature_algorithm()).release()); |
196 | 2.47k | } |
197 | | |
198 | | const CRL_Data& X509_CRL::data() const |
199 | 0 | { |
200 | 0 | if(!m_data) |
201 | 0 | { |
202 | 0 | throw Invalid_State("X509_CRL uninitialized"); |
203 | 0 | } |
204 | 0 | return *m_data.get(); |
205 | 0 | } |
206 | | |
207 | | const Extensions& X509_CRL::extensions() const |
208 | 0 | { |
209 | 0 | return data().m_extensions; |
210 | 0 | } |
211 | | |
212 | | /* |
213 | | * Return the list of revoked certificates |
214 | | */ |
215 | | const std::vector<CRL_Entry>& X509_CRL::get_revoked() const |
216 | 0 | { |
217 | 0 | return data().m_entries; |
218 | 0 | } |
219 | | |
220 | | /* |
221 | | * Return the distinguished name of the issuer |
222 | | */ |
223 | | const X509_DN& X509_CRL::issuer_dn() const |
224 | 0 | { |
225 | 0 | return data().m_issuer; |
226 | 0 | } |
227 | | |
228 | | /* |
229 | | * Return the key identifier of the issuer |
230 | | */ |
231 | | const std::vector<uint8_t>& X509_CRL::authority_key_id() const |
232 | 0 | { |
233 | 0 | return data().m_auth_key_id; |
234 | 0 | } |
235 | | |
236 | | /* |
237 | | * Return the CRL number of this CRL |
238 | | */ |
239 | | uint32_t X509_CRL::crl_number() const |
240 | 0 | { |
241 | 0 | return static_cast<uint32_t>(data().m_crl_number); |
242 | 0 | } |
243 | | |
244 | | /* |
245 | | * Return the issue data of the CRL |
246 | | */ |
247 | | const X509_Time& X509_CRL::this_update() const |
248 | 0 | { |
249 | 0 | return data().m_this_update; |
250 | 0 | } |
251 | | |
252 | | /* |
253 | | * Return the date when a new CRL will be issued |
254 | | */ |
255 | | const X509_Time& X509_CRL::next_update() const |
256 | 0 | { |
257 | 0 | return data().m_next_update; |
258 | 0 | } |
259 | | |
260 | | /* |
261 | | * Return the CRL's distribution point |
262 | | */ |
263 | | std::string X509_CRL::crl_issuing_distribution_point() const |
264 | 0 | { |
265 | 0 | return data().m_issuing_distribution_point; |
266 | 0 | } |
267 | | } |