/src/botan/src/lib/x509/x509_ext.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * X.509 Certificate Extensions |
3 | | * (C) 1999-2010,2012 Jack Lloyd |
4 | | * (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity |
5 | | * (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity |
6 | | * |
7 | | * Botan is released under the Simplified BSD License (see license.txt) |
8 | | */ |
9 | | |
10 | | #include <botan/x509_ext.h> |
11 | | #include <botan/x509cert.h> |
12 | | #include <botan/der_enc.h> |
13 | | #include <botan/ber_dec.h> |
14 | | #include <botan/hash.h> |
15 | | #include <botan/internal/loadstor.h> |
16 | | #include <botan/internal/bit_ops.h> |
17 | | #include <algorithm> |
18 | | #include <set> |
19 | | #include <sstream> |
20 | | |
21 | | namespace Botan { |
22 | | |
23 | | /* |
24 | | * Create a Certificate_Extension object of some kind to handle |
25 | | */ |
26 | | std::unique_ptr<Certificate_Extension> |
27 | | Extensions::create_extn_obj(const OID& oid, |
28 | | bool critical, |
29 | | const std::vector<uint8_t>& body) |
30 | 45.9k | { |
31 | 45.9k | const std::string oid_str = oid.to_string(); |
32 | | |
33 | 45.9k | std::unique_ptr<Certificate_Extension> extn; |
34 | | |
35 | 45.9k | if(oid == Cert_Extension::Subject_Key_ID::static_oid()) |
36 | 1.73k | { |
37 | 1.73k | extn.reset(new Cert_Extension::Subject_Key_ID); |
38 | 1.73k | } |
39 | 44.2k | else if(oid == Cert_Extension::Key_Usage::static_oid()) |
40 | 2.00k | { |
41 | 2.00k | extn.reset(new Cert_Extension::Key_Usage); |
42 | 2.00k | } |
43 | 42.2k | else if(oid == Cert_Extension::Subject_Alternative_Name::static_oid()) |
44 | 1.92k | { |
45 | 1.92k | extn.reset(new Cert_Extension::Subject_Alternative_Name); |
46 | 1.92k | } |
47 | 40.2k | else if(oid == Cert_Extension::Issuer_Alternative_Name::static_oid()) |
48 | 1.82k | { |
49 | 1.82k | extn.reset(new Cert_Extension::Issuer_Alternative_Name); |
50 | 1.82k | } |
51 | 38.4k | else if(oid == Cert_Extension::Basic_Constraints::static_oid()) |
52 | 2.13k | { |
53 | 2.13k | extn.reset(new Cert_Extension::Basic_Constraints); |
54 | 2.13k | } |
55 | 36.3k | else if(oid == Cert_Extension::CRL_Number::static_oid()) |
56 | 743 | { |
57 | 743 | extn.reset(new Cert_Extension::CRL_Number); |
58 | 743 | } |
59 | 35.5k | else if(oid == Cert_Extension::CRL_ReasonCode::static_oid()) |
60 | 1.98k | { |
61 | 1.98k | extn.reset(new Cert_Extension::CRL_ReasonCode); |
62 | 1.98k | } |
63 | 33.6k | else if(oid == Cert_Extension::Authority_Key_ID::static_oid()) |
64 | 1.54k | { |
65 | 1.54k | extn.reset(new Cert_Extension::Authority_Key_ID); |
66 | 1.54k | } |
67 | 32.0k | else if(oid == Cert_Extension::Name_Constraints::static_oid()) |
68 | 4.69k | { |
69 | 4.69k | extn.reset(new Cert_Extension::Name_Constraints); |
70 | 4.69k | } |
71 | 27.3k | else if(oid == Cert_Extension::CRL_Distribution_Points::static_oid()) |
72 | 2.03k | { |
73 | 2.03k | extn.reset(new Cert_Extension::CRL_Distribution_Points); |
74 | 2.03k | } |
75 | 25.3k | else if(oid == Cert_Extension::CRL_Issuing_Distribution_Point::static_oid()) |
76 | 531 | { |
77 | 531 | extn.reset(new Cert_Extension::CRL_Issuing_Distribution_Point); |
78 | 531 | } |
79 | 24.8k | else if(oid == Cert_Extension::Certificate_Policies::static_oid()) |
80 | 997 | { |
81 | 997 | extn.reset(new Cert_Extension::Certificate_Policies); |
82 | 997 | } |
83 | 23.8k | else if(oid == Cert_Extension::Extended_Key_Usage::static_oid()) |
84 | 2.39k | { |
85 | 2.39k | extn.reset(new Cert_Extension::Extended_Key_Usage); |
86 | 2.39k | } |
87 | 21.4k | else if(oid == Cert_Extension::Authority_Information_Access::static_oid()) |
88 | 541 | { |
89 | 541 | extn.reset(new Cert_Extension::Authority_Information_Access); |
90 | 541 | } |
91 | 20.8k | else |
92 | 20.8k | { |
93 | | // some other unknown extension type |
94 | 20.8k | extn.reset(new Cert_Extension::Unknown_Extension(oid, critical)); |
95 | 20.8k | } |
96 | | |
97 | 45.9k | try |
98 | 45.9k | { |
99 | 45.9k | extn->decode_inner(body); |
100 | 45.9k | } |
101 | 45.9k | catch(Decoding_Error&) |
102 | 18.6k | { |
103 | 18.6k | extn.reset(new Cert_Extension::Unknown_Extension(oid, critical)); |
104 | 18.6k | extn->decode_inner(body); |
105 | 18.6k | } |
106 | 45.9k | return extn; |
107 | 45.9k | } |
108 | | |
109 | | /* |
110 | | * Validate the extension (the default implementation is a NOP) |
111 | | */ |
112 | | void Certificate_Extension::validate(const X509_Certificate&, const X509_Certificate&, |
113 | | const std::vector<X509_Certificate>&, |
114 | | std::vector<std::set<Certificate_Status_Code>>&, |
115 | | size_t) |
116 | 0 | { |
117 | 0 | } |
118 | | |
119 | | /* |
120 | | * Add a new cert |
121 | | */ |
122 | | void Extensions::add(Certificate_Extension* extn, bool critical) |
123 | 0 | { |
124 | | // sanity check: we don't want to have the same extension more than once |
125 | 0 | if(m_extension_info.count(extn->oid_of()) > 0) |
126 | 0 | { |
127 | 0 | const std::string name = extn->oid_name(); |
128 | 0 | delete extn; |
129 | 0 | throw Invalid_Argument("Extension " + name + " already present in Extensions::add"); |
130 | 0 | } |
131 | | |
132 | 0 | const OID oid = extn->oid_of(); |
133 | 0 | Extensions_Info info(critical, extn); |
134 | 0 | m_extension_oids.push_back(oid); |
135 | 0 | m_extension_info.emplace(oid, info); |
136 | 0 | } |
137 | | |
138 | | bool Extensions::add_new(Certificate_Extension* extn, bool critical) |
139 | 0 | { |
140 | 0 | if(m_extension_info.count(extn->oid_of()) > 0) |
141 | 0 | { |
142 | 0 | delete extn; |
143 | 0 | return false; // already exists |
144 | 0 | } |
145 | | |
146 | 0 | const OID oid = extn->oid_of(); |
147 | 0 | Extensions_Info info(critical, extn); |
148 | 0 | m_extension_oids.push_back(oid); |
149 | 0 | m_extension_info.emplace(oid, info); |
150 | 0 | return true; |
151 | 0 | } |
152 | | |
153 | | bool Extensions::remove(const OID& oid) |
154 | 0 | { |
155 | 0 | const bool erased = m_extension_info.erase(oid) > 0; |
156 | |
|
157 | 0 | if(erased) |
158 | 0 | { |
159 | 0 | m_extension_oids.erase(std::find(m_extension_oids.begin(), m_extension_oids.end(), oid)); |
160 | 0 | } |
161 | |
|
162 | 0 | return erased; |
163 | 0 | } |
164 | | |
165 | | void Extensions::replace(Certificate_Extension* extn, bool critical) |
166 | 0 | { |
167 | | // Remove it if it existed |
168 | 0 | remove(extn->oid_of()); |
169 | |
|
170 | 0 | const OID oid = extn->oid_of(); |
171 | 0 | Extensions_Info info(critical, extn); |
172 | 0 | m_extension_oids.push_back(oid); |
173 | 0 | m_extension_info.emplace(oid, info); |
174 | 0 | } |
175 | | |
176 | | bool Extensions::extension_set(const OID& oid) const |
177 | 0 | { |
178 | 0 | return (m_extension_info.find(oid) != m_extension_info.end()); |
179 | 0 | } |
180 | | |
181 | | bool Extensions::critical_extension_set(const OID& oid) const |
182 | 0 | { |
183 | 0 | auto i = m_extension_info.find(oid); |
184 | 0 | if(i != m_extension_info.end()) |
185 | 0 | return i->second.is_critical(); |
186 | 0 | return false; |
187 | 0 | } |
188 | | |
189 | | std::vector<uint8_t> Extensions::get_extension_bits(const OID& oid) const |
190 | 0 | { |
191 | 0 | auto i = m_extension_info.find(oid); |
192 | 0 | if(i == m_extension_info.end()) |
193 | 0 | throw Invalid_Argument("Extensions::get_extension_bits no such extension set"); |
194 | | |
195 | 0 | return i->second.bits(); |
196 | 0 | } |
197 | | |
198 | | const Certificate_Extension* Extensions::get_extension_object(const OID& oid) const |
199 | 132k | { |
200 | 132k | auto extn = m_extension_info.find(oid); |
201 | 132k | if(extn == m_extension_info.end()) |
202 | 127k | return nullptr; |
203 | | |
204 | 5.74k | return &extn->second.obj(); |
205 | 5.74k | } |
206 | | |
207 | | std::unique_ptr<Certificate_Extension> Extensions::get(const OID& oid) const |
208 | 0 | { |
209 | 0 | if(const Certificate_Extension* ext = this->get_extension_object(oid)) |
210 | 0 | { |
211 | 0 | return std::unique_ptr<Certificate_Extension>(ext->copy()); |
212 | 0 | } |
213 | 0 | return nullptr; |
214 | 0 | } |
215 | | |
216 | | std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> Extensions::extensions() const |
217 | 0 | { |
218 | 0 | std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> exts; |
219 | 0 | for(auto&& ext : m_extension_info) |
220 | 0 | { |
221 | 0 | exts.push_back( |
222 | 0 | std::make_pair( |
223 | 0 | std::unique_ptr<Certificate_Extension>(ext.second.obj().copy()), |
224 | 0 | ext.second.is_critical()) |
225 | 0 | ); |
226 | 0 | } |
227 | 0 | return exts; |
228 | 0 | } |
229 | | |
230 | | std::map<OID, std::pair<std::vector<uint8_t>, bool>> Extensions::extensions_raw() const |
231 | 0 | { |
232 | 0 | std::map<OID, std::pair<std::vector<uint8_t>, bool>> out; |
233 | 0 | for(auto&& ext : m_extension_info) |
234 | 0 | { |
235 | 0 | out.emplace(ext.first, |
236 | 0 | std::make_pair(ext.second.bits(), |
237 | 0 | ext.second.is_critical())); |
238 | 0 | } |
239 | 0 | return out; |
240 | 0 | } |
241 | | |
242 | | /* |
243 | | * Encode an Extensions list |
244 | | */ |
245 | | void Extensions::encode_into(DER_Encoder& to_object) const |
246 | 0 | { |
247 | 0 | for(auto ext_info : m_extension_info) |
248 | 0 | { |
249 | 0 | const OID& oid = ext_info.first; |
250 | 0 | const bool should_encode = ext_info.second.obj().should_encode(); |
251 | |
|
252 | 0 | if(should_encode) |
253 | 0 | { |
254 | 0 | const bool is_critical = ext_info.second.is_critical(); |
255 | 0 | const std::vector<uint8_t>& ext_value = ext_info.second.bits(); |
256 | |
|
257 | 0 | to_object.start_sequence() |
258 | 0 | .encode(oid) |
259 | 0 | .encode_optional(is_critical, false) |
260 | 0 | .encode(ext_value, ASN1_Type::OctetString) |
261 | 0 | .end_cons(); |
262 | 0 | } |
263 | 0 | } |
264 | 0 | } |
265 | | |
266 | | /* |
267 | | * Decode a list of Extensions |
268 | | */ |
269 | | void Extensions::decode_from(BER_Decoder& from_source) |
270 | 10.6k | { |
271 | 10.6k | m_extension_oids.clear(); |
272 | 10.6k | m_extension_info.clear(); |
273 | | |
274 | 10.6k | BER_Decoder sequence = from_source.start_sequence(); |
275 | | |
276 | 59.2k | while(sequence.more_items()) |
277 | 48.6k | { |
278 | 48.6k | OID oid; |
279 | 48.6k | bool critical; |
280 | 48.6k | std::vector<uint8_t> bits; |
281 | | |
282 | 48.6k | sequence.start_sequence() |
283 | 48.6k | .decode(oid) |
284 | 48.6k | .decode_optional(critical, ASN1_Type::Boolean, ASN1_Class::Universal, false) |
285 | 48.6k | .decode(bits, ASN1_Type::OctetString) |
286 | 48.6k | .end_cons(); |
287 | | |
288 | 48.6k | std::unique_ptr<Certificate_Extension> obj = create_extn_obj(oid, critical, bits); |
289 | 48.6k | Extensions_Info info(critical, bits, obj.release()); |
290 | | |
291 | 48.6k | m_extension_oids.push_back(oid); |
292 | 48.6k | m_extension_info.emplace(oid, info); |
293 | 48.6k | } |
294 | 10.6k | sequence.verify_end(); |
295 | 10.6k | } |
296 | | |
297 | | namespace Cert_Extension { |
298 | | |
299 | | /* |
300 | | * Checked accessor for the path_limit member |
301 | | */ |
302 | | size_t Basic_Constraints::get_path_limit() const |
303 | 43 | { |
304 | 43 | if(!m_is_ca) |
305 | 0 | throw Invalid_State("Basic_Constraints::get_path_limit: Not a CA"); |
306 | 43 | return m_path_limit; |
307 | 43 | } |
308 | | |
309 | | /* |
310 | | * Encode the extension |
311 | | */ |
312 | | std::vector<uint8_t> Basic_Constraints::encode_inner() const |
313 | 0 | { |
314 | 0 | std::vector<uint8_t> output; |
315 | 0 | DER_Encoder(output) |
316 | 0 | .start_sequence() |
317 | 0 | .encode_if(m_is_ca, |
318 | 0 | DER_Encoder() |
319 | 0 | .encode(m_is_ca) |
320 | 0 | .encode_optional(m_path_limit, NO_CERT_PATH_LIMIT) |
321 | 0 | ) |
322 | 0 | .end_cons(); |
323 | 0 | return output; |
324 | 0 | } |
325 | | |
326 | | /* |
327 | | * Decode the extension |
328 | | */ |
329 | | void Basic_Constraints::decode_inner(const std::vector<uint8_t>& in) |
330 | 2.13k | { |
331 | 2.13k | BER_Decoder(in) |
332 | 2.13k | .start_sequence() |
333 | 2.13k | .decode_optional(m_is_ca, ASN1_Type::Boolean, ASN1_Class::Universal, false) |
334 | 2.13k | .decode_optional(m_path_limit, ASN1_Type::Integer, ASN1_Class::Universal, NO_CERT_PATH_LIMIT) |
335 | 2.13k | .end_cons(); |
336 | | |
337 | 2.13k | if(m_is_ca == false) |
338 | 374 | m_path_limit = 0; |
339 | 2.13k | } |
340 | | |
341 | | /* |
342 | | * Encode the extension |
343 | | */ |
344 | | std::vector<uint8_t> Key_Usage::encode_inner() const |
345 | 0 | { |
346 | 0 | if(m_constraints == NO_CONSTRAINTS) |
347 | 0 | throw Encoding_Error("Cannot encode zero usage constraints"); |
348 | | |
349 | 0 | const size_t unused_bits = ctz(static_cast<uint32_t>(m_constraints)); |
350 | |
|
351 | 0 | std::vector<uint8_t> der; |
352 | 0 | der.push_back(static_cast<uint8_t>(ASN1_Type::BitString)); |
353 | 0 | der.push_back(2 + ((unused_bits < 8) ? 1 : 0)); |
354 | 0 | der.push_back(unused_bits % 8); |
355 | 0 | der.push_back((m_constraints >> 8) & 0xFF); |
356 | 0 | if(m_constraints & 0xFF) |
357 | 0 | der.push_back(m_constraints & 0xFF); |
358 | |
|
359 | 0 | return der; |
360 | 0 | } |
361 | | |
362 | | /* |
363 | | * Decode the extension |
364 | | */ |
365 | | void Key_Usage::decode_inner(const std::vector<uint8_t>& in) |
366 | 2.00k | { |
367 | 2.00k | BER_Decoder ber(in); |
368 | | |
369 | 2.00k | BER_Object obj = ber.get_next_object(); |
370 | | |
371 | 2.00k | obj.assert_is_a(ASN1_Type::BitString, ASN1_Class::Universal, "usage constraint"); |
372 | | |
373 | 2.00k | if(obj.length() != 2 && obj.length() != 3) |
374 | 233 | throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint"); |
375 | | |
376 | 1.77k | uint16_t usage = 0; |
377 | | |
378 | 1.77k | const uint8_t* bits = obj.bits(); |
379 | | |
380 | 1.77k | if(bits[0] >= 8) |
381 | 209 | throw BER_Decoding_Error("Invalid unused bits in usage constraint"); |
382 | | |
383 | 1.56k | const uint8_t mask = static_cast<uint8_t>(0xFF << bits[0]); |
384 | | |
385 | 1.56k | if(obj.length() == 2) |
386 | 258 | { |
387 | 258 | usage = make_uint16(bits[1] & mask, 0); |
388 | 258 | } |
389 | 1.30k | else if(obj.length() == 3) |
390 | 108 | { |
391 | 108 | usage = make_uint16(bits[1], bits[2] & mask); |
392 | 108 | } |
393 | | |
394 | 1.56k | m_constraints = Key_Constraints(usage); |
395 | 1.56k | } |
396 | | |
397 | | /* |
398 | | * Encode the extension |
399 | | */ |
400 | | std::vector<uint8_t> Subject_Key_ID::encode_inner() const |
401 | 0 | { |
402 | 0 | std::vector<uint8_t> output; |
403 | 0 | DER_Encoder(output).encode(m_key_id, ASN1_Type::OctetString); |
404 | 0 | return output; |
405 | 0 | } |
406 | | |
407 | | /* |
408 | | * Decode the extension |
409 | | */ |
410 | | void Subject_Key_ID::decode_inner(const std::vector<uint8_t>& in) |
411 | 1.73k | { |
412 | 1.73k | BER_Decoder(in).decode(m_key_id, ASN1_Type::OctetString).verify_end(); |
413 | 1.73k | } |
414 | | |
415 | | /* |
416 | | * Subject_Key_ID Constructor |
417 | | */ |
418 | | Subject_Key_ID::Subject_Key_ID(const std::vector<uint8_t>& pub_key, const std::string& hash_name) |
419 | 0 | { |
420 | 0 | std::unique_ptr<HashFunction> hash(HashFunction::create_or_throw(hash_name)); |
421 | |
|
422 | 0 | m_key_id.resize(hash->output_length()); |
423 | |
|
424 | 0 | hash->update(pub_key); |
425 | 0 | hash->final(m_key_id.data()); |
426 | | |
427 | | // Truncate longer hashes, 192 bits here seems plenty |
428 | 0 | const size_t max_skid_len = (192 / 8); |
429 | 0 | if(m_key_id.size() > max_skid_len) |
430 | 0 | m_key_id.resize(max_skid_len); |
431 | 0 | } |
432 | | |
433 | | /* |
434 | | * Encode the extension |
435 | | */ |
436 | | std::vector<uint8_t> Authority_Key_ID::encode_inner() const |
437 | 0 | { |
438 | 0 | std::vector<uint8_t> output; |
439 | 0 | DER_Encoder(output) |
440 | 0 | .start_sequence() |
441 | 0 | .encode(m_key_id, ASN1_Type::OctetString, ASN1_Type(0), ASN1_Class::ContextSpecific) |
442 | 0 | .end_cons(); |
443 | 0 | return output; |
444 | 0 | } |
445 | | |
446 | | /* |
447 | | * Decode the extension |
448 | | */ |
449 | | void Authority_Key_ID::decode_inner(const std::vector<uint8_t>& in) |
450 | 1.54k | { |
451 | 1.54k | BER_Decoder(in) |
452 | 1.54k | .start_sequence() |
453 | 1.54k | .decode_optional_string(m_key_id, ASN1_Type::OctetString, 0); |
454 | 1.54k | } |
455 | | |
456 | | /* |
457 | | * Encode the extension |
458 | | */ |
459 | | std::vector<uint8_t> Subject_Alternative_Name::encode_inner() const |
460 | 0 | { |
461 | 0 | std::vector<uint8_t> output; |
462 | 0 | DER_Encoder(output).encode(m_alt_name); |
463 | 0 | return output; |
464 | 0 | } |
465 | | |
466 | | /* |
467 | | * Encode the extension |
468 | | */ |
469 | | std::vector<uint8_t> Issuer_Alternative_Name::encode_inner() const |
470 | 0 | { |
471 | 0 | std::vector<uint8_t> output; |
472 | 0 | DER_Encoder(output).encode(m_alt_name); |
473 | 0 | return output; |
474 | 0 | } |
475 | | |
476 | | /* |
477 | | * Decode the extension |
478 | | */ |
479 | | void Subject_Alternative_Name::decode_inner(const std::vector<uint8_t>& in) |
480 | 1.92k | { |
481 | 1.92k | BER_Decoder(in).decode(m_alt_name); |
482 | 1.92k | } |
483 | | |
484 | | /* |
485 | | * Decode the extension |
486 | | */ |
487 | | void Issuer_Alternative_Name::decode_inner(const std::vector<uint8_t>& in) |
488 | 1.82k | { |
489 | 1.82k | BER_Decoder(in).decode(m_alt_name); |
490 | 1.82k | } |
491 | | |
492 | | /* |
493 | | * Encode the extension |
494 | | */ |
495 | | std::vector<uint8_t> Extended_Key_Usage::encode_inner() const |
496 | 0 | { |
497 | 0 | std::vector<uint8_t> output; |
498 | 0 | DER_Encoder(output) |
499 | 0 | .start_sequence() |
500 | 0 | .encode_list(m_oids) |
501 | 0 | .end_cons(); |
502 | 0 | return output; |
503 | 0 | } |
504 | | |
505 | | /* |
506 | | * Decode the extension |
507 | | */ |
508 | | void Extended_Key_Usage::decode_inner(const std::vector<uint8_t>& in) |
509 | 2.39k | { |
510 | 2.39k | BER_Decoder(in).decode_list(m_oids); |
511 | 2.39k | } |
512 | | |
513 | | /* |
514 | | * Encode the extension |
515 | | */ |
516 | | std::vector<uint8_t> Name_Constraints::encode_inner() const |
517 | 0 | { |
518 | 0 | throw Not_Implemented("Name_Constraints encoding"); |
519 | 0 | } |
520 | | |
521 | | |
522 | | /* |
523 | | * Decode the extension |
524 | | */ |
525 | | void Name_Constraints::decode_inner(const std::vector<uint8_t>& in) |
526 | 4.69k | { |
527 | 4.69k | std::vector<GeneralSubtree> permit, exclude; |
528 | 4.69k | BER_Decoder ber(in); |
529 | 4.69k | BER_Decoder ext = ber.start_sequence(); |
530 | 4.69k | BER_Object per = ext.get_next_object(); |
531 | | |
532 | 4.69k | ext.push_back(per); |
533 | 4.69k | if(per.is_a(0, ASN1_Class::Constructed | ASN1_Class::ContextSpecific)) |
534 | 826 | { |
535 | 826 | ext.decode_list(permit, ASN1_Type(0), ASN1_Class::Constructed | ASN1_Class::ContextSpecific); |
536 | 826 | if(permit.empty()) |
537 | 7 | throw Encoding_Error("Empty Name Contraint list"); |
538 | 4.68k | } |
539 | | |
540 | 4.68k | BER_Object exc = ext.get_next_object(); |
541 | 4.68k | ext.push_back(exc); |
542 | 4.68k | if(per.is_a(1, ASN1_Class::Constructed | ASN1_Class::ContextSpecific)) |
543 | 2.43k | { |
544 | 2.43k | ext.decode_list(exclude, ASN1_Type(1), ASN1_Class::Constructed | ASN1_Class::ContextSpecific); |
545 | 2.43k | if(exclude.empty()) |
546 | 9 | throw Encoding_Error("Empty Name Contraint list"); |
547 | 4.67k | } |
548 | | |
549 | 4.67k | ext.end_cons(); |
550 | | |
551 | 4.67k | if(permit.empty() && exclude.empty()) |
552 | 28 | throw Encoding_Error("Empty Name Contraint extension"); |
553 | | |
554 | 4.65k | m_name_constraints = NameConstraints(std::move(permit),std::move(exclude)); |
555 | 4.65k | } |
556 | | |
557 | | void Name_Constraints::validate(const X509_Certificate& subject, const X509_Certificate& issuer, |
558 | | const std::vector<X509_Certificate>& cert_path, |
559 | | std::vector<std::set<Certificate_Status_Code>>& cert_status, |
560 | | size_t pos) |
561 | 0 | { |
562 | 0 | if(!m_name_constraints.permitted().empty() || !m_name_constraints.excluded().empty()) |
563 | 0 | { |
564 | 0 | if(!subject.is_CA_cert() || !subject.is_critical("X509v3.NameConstraints")) |
565 | 0 | cert_status.at(pos).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR); |
566 | |
|
567 | 0 | const bool issuer_name_constraint_critical = |
568 | 0 | issuer.is_critical("X509v3.NameConstraints"); |
569 | |
|
570 | 0 | const bool at_self_signed_root = (pos == cert_path.size() - 1); |
571 | | |
572 | | // Check that all subordinate certs pass the name constraint |
573 | 0 | for(size_t j = 0; j <= pos; ++j) |
574 | 0 | { |
575 | 0 | if(pos == j && at_self_signed_root) |
576 | 0 | continue; |
577 | | |
578 | 0 | bool permitted = m_name_constraints.permitted().empty(); |
579 | 0 | bool failed = false; |
580 | |
|
581 | 0 | for(auto c: m_name_constraints.permitted()) |
582 | 0 | { |
583 | 0 | switch(c.base().matches(cert_path.at(j))) |
584 | 0 | { |
585 | 0 | case GeneralName::MatchResult::NotFound: |
586 | 0 | case GeneralName::MatchResult::All: |
587 | 0 | permitted = true; |
588 | 0 | break; |
589 | 0 | case GeneralName::MatchResult::UnknownType: |
590 | 0 | failed = issuer_name_constraint_critical; |
591 | 0 | permitted = true; |
592 | 0 | break; |
593 | 0 | default: |
594 | 0 | break; |
595 | 0 | } |
596 | 0 | } |
597 | |
|
598 | 0 | for(auto c: m_name_constraints.excluded()) |
599 | 0 | { |
600 | 0 | switch(c.base().matches(cert_path.at(j))) |
601 | 0 | { |
602 | 0 | case GeneralName::MatchResult::All: |
603 | 0 | case GeneralName::MatchResult::Some: |
604 | 0 | failed = true; |
605 | 0 | break; |
606 | 0 | case GeneralName::MatchResult::UnknownType: |
607 | 0 | failed = issuer_name_constraint_critical; |
608 | 0 | break; |
609 | 0 | default: |
610 | 0 | break; |
611 | 0 | } |
612 | 0 | } |
613 | |
|
614 | 0 | if(failed || !permitted) |
615 | 0 | { |
616 | 0 | cert_status.at(j).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR); |
617 | 0 | } |
618 | 0 | } |
619 | 0 | } |
620 | 0 | } |
621 | | |
622 | | namespace { |
623 | | |
624 | | /* |
625 | | * A policy specifier |
626 | | */ |
627 | | class Policy_Information final : public ASN1_Object |
628 | | { |
629 | | public: |
630 | 1.42k | Policy_Information() = default; |
631 | 0 | explicit Policy_Information(const OID& oid) : m_oid(oid) {} |
632 | | |
633 | 693 | const OID& oid() const { return m_oid; } |
634 | | |
635 | | void encode_into(DER_Encoder& codec) const override |
636 | 0 | { |
637 | 0 | codec.start_sequence() |
638 | 0 | .encode(m_oid) |
639 | 0 | .end_cons(); |
640 | 0 | } |
641 | | |
642 | | void decode_from(BER_Decoder& codec) override |
643 | 1.42k | { |
644 | 1.42k | codec.start_sequence() |
645 | 1.42k | .decode(m_oid) |
646 | 1.42k | .discard_remaining() |
647 | 1.42k | .end_cons(); |
648 | 1.42k | } |
649 | | |
650 | | private: |
651 | | OID m_oid; |
652 | | }; |
653 | | |
654 | | } |
655 | | |
656 | | /* |
657 | | * Encode the extension |
658 | | */ |
659 | | std::vector<uint8_t> Certificate_Policies::encode_inner() const |
660 | 0 | { |
661 | 0 | std::vector<Policy_Information> policies; |
662 | |
|
663 | 0 | for(size_t i = 0; i != m_oids.size(); ++i) |
664 | 0 | policies.push_back(Policy_Information(m_oids[i])); |
665 | |
|
666 | 0 | std::vector<uint8_t> output; |
667 | 0 | DER_Encoder(output) |
668 | 0 | .start_sequence() |
669 | 0 | .encode_list(policies) |
670 | 0 | .end_cons(); |
671 | 0 | return output; |
672 | 0 | } |
673 | | |
674 | | /* |
675 | | * Decode the extension |
676 | | */ |
677 | | void Certificate_Policies::decode_inner(const std::vector<uint8_t>& in) |
678 | 997 | { |
679 | 997 | std::vector<Policy_Information> policies; |
680 | | |
681 | 997 | BER_Decoder(in).decode_list(policies); |
682 | 997 | m_oids.clear(); |
683 | 1.69k | for(size_t i = 0; i != policies.size(); ++i) |
684 | 693 | m_oids.push_back(policies[i].oid()); |
685 | 997 | } |
686 | | |
687 | | void Certificate_Policies::validate( |
688 | | const X509_Certificate& /*subject*/, |
689 | | const X509_Certificate& /*issuer*/, |
690 | | const std::vector<X509_Certificate>& /*cert_path*/, |
691 | | std::vector<std::set<Certificate_Status_Code>>& cert_status, |
692 | | size_t pos) |
693 | 0 | { |
694 | 0 | std::set<OID> oid_set(m_oids.begin(), m_oids.end()); |
695 | 0 | if(oid_set.size() != m_oids.size()) |
696 | 0 | { |
697 | 0 | cert_status.at(pos).insert(Certificate_Status_Code::DUPLICATE_CERT_POLICY); |
698 | 0 | } |
699 | 0 | } |
700 | | |
701 | | std::vector<uint8_t> Authority_Information_Access::encode_inner() const |
702 | 0 | { |
703 | 0 | ASN1_String url(m_ocsp_responder, ASN1_Type::Ia5String); |
704 | |
|
705 | 0 | std::vector<uint8_t> output; |
706 | 0 | DER_Encoder(output) |
707 | 0 | .start_sequence() |
708 | 0 | .start_sequence() |
709 | 0 | .encode(OID::from_string("PKIX.OCSP")) |
710 | 0 | .add_object(ASN1_Type(6), ASN1_Class::ContextSpecific, url.value()) |
711 | 0 | .end_cons() |
712 | 0 | .end_cons(); |
713 | 0 | return output; |
714 | 0 | } |
715 | | |
716 | | void Authority_Information_Access::decode_inner(const std::vector<uint8_t>& in) |
717 | 541 | { |
718 | 541 | BER_Decoder ber = BER_Decoder(in).start_sequence(); |
719 | | |
720 | 1.27k | while(ber.more_items()) |
721 | 734 | { |
722 | 734 | OID oid; |
723 | | |
724 | 734 | BER_Decoder info = ber.start_sequence(); |
725 | | |
726 | 734 | info.decode(oid); |
727 | | |
728 | 734 | if(oid == OID::from_string("PKIX.OCSP")) |
729 | 118 | { |
730 | 118 | BER_Object name = info.get_next_object(); |
731 | | |
732 | 118 | if(name.is_a(6, ASN1_Class::ContextSpecific)) |
733 | 33 | { |
734 | 33 | m_ocsp_responder = ASN1::to_string(name); |
735 | 33 | } |
736 | | |
737 | 118 | } |
738 | 734 | if(oid == OID::from_string("PKIX.CertificateAuthorityIssuers")) |
739 | 152 | { |
740 | 152 | BER_Object name = info.get_next_object(); |
741 | | |
742 | 152 | if(name.is_a(6, ASN1_Class::ContextSpecific)) |
743 | 73 | { |
744 | 73 | m_ca_issuers.push_back(ASN1::to_string(name)); |
745 | 73 | } |
746 | 152 | } |
747 | 734 | } |
748 | 541 | } |
749 | | |
750 | | /* |
751 | | * Checked accessor for the crl_number member |
752 | | */ |
753 | | size_t CRL_Number::get_crl_number() const |
754 | 5 | { |
755 | 5 | if(!m_has_value) |
756 | 0 | throw Invalid_State("CRL_Number::get_crl_number: Not set"); |
757 | 5 | return m_crl_number; |
758 | 5 | } |
759 | | |
760 | | /* |
761 | | * Copy a CRL_Number extension |
762 | | */ |
763 | | CRL_Number* CRL_Number::copy() const |
764 | 0 | { |
765 | 0 | if(!m_has_value) |
766 | 0 | throw Invalid_State("CRL_Number::copy: Not set"); |
767 | 0 | return new CRL_Number(m_crl_number); |
768 | 0 | } |
769 | | |
770 | | /* |
771 | | * Encode the extension |
772 | | */ |
773 | | std::vector<uint8_t> CRL_Number::encode_inner() const |
774 | 0 | { |
775 | 0 | std::vector<uint8_t> output; |
776 | 0 | DER_Encoder(output).encode(m_crl_number); |
777 | 0 | return output; |
778 | 0 | } |
779 | | |
780 | | /* |
781 | | * Decode the extension |
782 | | */ |
783 | | void CRL_Number::decode_inner(const std::vector<uint8_t>& in) |
784 | 743 | { |
785 | 743 | BER_Decoder(in).decode(m_crl_number); |
786 | 743 | m_has_value = true; |
787 | 743 | } |
788 | | |
789 | | /* |
790 | | * Encode the extension |
791 | | */ |
792 | | std::vector<uint8_t> CRL_ReasonCode::encode_inner() const |
793 | 0 | { |
794 | 0 | std::vector<uint8_t> output; |
795 | 0 | DER_Encoder(output).encode(static_cast<size_t>(m_reason), ASN1_Type::Enumerated, ASN1_Class::Universal); |
796 | 0 | return output; |
797 | 0 | } |
798 | | |
799 | | /* |
800 | | * Decode the extension |
801 | | */ |
802 | | void CRL_ReasonCode::decode_inner(const std::vector<uint8_t>& in) |
803 | 1.98k | { |
804 | 1.98k | size_t reason_code = 0; |
805 | 1.98k | BER_Decoder(in).decode(reason_code, ASN1_Type::Enumerated, ASN1_Class::Universal); |
806 | 1.98k | m_reason = static_cast<CRL_Code>(reason_code); |
807 | 1.98k | } |
808 | | |
809 | | std::vector<uint8_t> CRL_Distribution_Points::encode_inner() const |
810 | 0 | { |
811 | 0 | throw Not_Implemented("CRL_Distribution_Points encoding"); |
812 | 0 | } |
813 | | |
814 | | void CRL_Distribution_Points::decode_inner(const std::vector<uint8_t>& buf) |
815 | 2.03k | { |
816 | 2.03k | BER_Decoder(buf) |
817 | 2.03k | .decode_list(m_distribution_points) |
818 | 2.03k | .verify_end(); |
819 | | |
820 | 2.03k | std::stringstream ss; |
821 | | |
822 | 2.61k | for(size_t i = 0; i != m_distribution_points.size(); ++i) |
823 | 586 | { |
824 | 586 | auto contents = m_distribution_points[i].point().contents(); |
825 | | |
826 | 586 | for(const auto& pair : contents) |
827 | 2.95k | { |
828 | 2.95k | ss << pair.first << ": " << pair.second << " "; |
829 | 2.95k | } |
830 | 586 | } |
831 | | |
832 | 2.03k | m_crl_distribution_urls.push_back(ss.str()); |
833 | 2.03k | } |
834 | | |
835 | | void CRL_Distribution_Points::Distribution_Point::encode_into(class DER_Encoder&) const |
836 | 0 | { |
837 | 0 | throw Not_Implemented("CRL_Distribution_Points encoding"); |
838 | 0 | } |
839 | | |
840 | | void CRL_Distribution_Points::Distribution_Point::decode_from(class BER_Decoder& ber) |
841 | 4.02k | { |
842 | 4.02k | ber.start_sequence() |
843 | 4.02k | .start_context_specific(0) |
844 | 4.02k | .decode_optional_implicit(m_point, ASN1_Type(0), |
845 | 4.02k | ASN1_Class::ContextSpecific | ASN1_Class::Constructed, |
846 | 4.02k | ASN1_Type::Sequence, ASN1_Class::Constructed) |
847 | 4.02k | .end_cons().end_cons(); |
848 | 4.02k | } |
849 | | |
850 | | std::vector<uint8_t> CRL_Issuing_Distribution_Point::encode_inner() const |
851 | 0 | { |
852 | 0 | throw Not_Implemented("CRL_Issuing_Distribution_Point encoding"); |
853 | 0 | } |
854 | | |
855 | | void CRL_Issuing_Distribution_Point::decode_inner(const std::vector<uint8_t>& buf) |
856 | 531 | { |
857 | 531 | BER_Decoder(buf).decode(m_distribution_point).verify_end(); |
858 | 531 | } |
859 | | |
860 | | std::vector<uint8_t> Unknown_Extension::encode_inner() const |
861 | 0 | { |
862 | 0 | return m_bytes; |
863 | 0 | } |
864 | | |
865 | | void Unknown_Extension::decode_inner(const std::vector<uint8_t>& bytes) |
866 | 39.5k | { |
867 | | // Just treat as an opaque blob at this level |
868 | 39.5k | m_bytes = bytes; |
869 | 39.5k | } |
870 | | |
871 | | } |
872 | | |
873 | | } |