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