/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/datastor.h> |
13 | | #include <botan/der_enc.h> |
14 | | #include <botan/ber_dec.h> |
15 | | #include <botan/hash.h> |
16 | | #include <botan/loadstor.h> |
17 | | #include <botan/internal/bit_ops.h> |
18 | | #include <algorithm> |
19 | | #include <set> |
20 | | #include <sstream> |
21 | | |
22 | | namespace Botan { |
23 | | |
24 | | /* |
25 | | * Create a Certificate_Extension object of some kind to handle |
26 | | */ |
27 | | std::unique_ptr<Certificate_Extension> |
28 | | Extensions::create_extn_obj(const OID& oid, |
29 | | bool critical, |
30 | | const std::vector<uint8_t>& body) |
31 | 39.7k | { |
32 | 39.7k | const std::string oid_str = oid.to_string(); |
33 | 39.7k | |
34 | 39.7k | std::unique_ptr<Certificate_Extension> extn; |
35 | 39.7k | |
36 | 39.7k | if(oid == Cert_Extension::Subject_Key_ID::static_oid()) |
37 | 1.65k | { |
38 | 1.65k | extn.reset(new Cert_Extension::Subject_Key_ID); |
39 | 1.65k | } |
40 | 38.0k | else if(oid == Cert_Extension::Key_Usage::static_oid()) |
41 | 1.41k | { |
42 | 1.41k | extn.reset(new Cert_Extension::Key_Usage); |
43 | 1.41k | } |
44 | 36.6k | else if(oid == Cert_Extension::Subject_Alternative_Name::static_oid()) |
45 | 2.54k | { |
46 | 2.54k | extn.reset(new Cert_Extension::Subject_Alternative_Name); |
47 | 2.54k | } |
48 | 34.1k | else if(oid == Cert_Extension::Issuer_Alternative_Name::static_oid()) |
49 | 1.33k | { |
50 | 1.33k | extn.reset(new Cert_Extension::Issuer_Alternative_Name); |
51 | 1.33k | } |
52 | 32.8k | else if(oid == Cert_Extension::Basic_Constraints::static_oid()) |
53 | 1.76k | { |
54 | 1.76k | extn.reset(new Cert_Extension::Basic_Constraints); |
55 | 1.76k | } |
56 | 31.0k | else if(oid == Cert_Extension::CRL_Number::static_oid()) |
57 | 678 | { |
58 | 678 | extn.reset(new Cert_Extension::CRL_Number); |
59 | 678 | } |
60 | 30.3k | else if(oid == Cert_Extension::CRL_ReasonCode::static_oid()) |
61 | 3.30k | { |
62 | 3.30k | extn.reset(new Cert_Extension::CRL_ReasonCode); |
63 | 3.30k | } |
64 | 27.0k | else if(oid == Cert_Extension::Authority_Key_ID::static_oid()) |
65 | 1.71k | { |
66 | 1.71k | extn.reset(new Cert_Extension::Authority_Key_ID); |
67 | 1.71k | } |
68 | 25.3k | else if(oid == Cert_Extension::Name_Constraints::static_oid()) |
69 | 3.40k | { |
70 | 3.40k | extn.reset(new Cert_Extension::Name_Constraints); |
71 | 3.40k | } |
72 | 21.9k | else if(oid == Cert_Extension::CRL_Distribution_Points::static_oid()) |
73 | 1.68k | { |
74 | 1.68k | extn.reset(new Cert_Extension::CRL_Distribution_Points); |
75 | 1.68k | } |
76 | 20.2k | else if(oid == Cert_Extension::CRL_Issuing_Distribution_Point::static_oid()) |
77 | 451 | { |
78 | 451 | extn.reset(new Cert_Extension::CRL_Issuing_Distribution_Point); |
79 | 451 | } |
80 | 19.7k | else if(oid == Cert_Extension::Certificate_Policies::static_oid()) |
81 | 991 | { |
82 | 991 | extn.reset(new Cert_Extension::Certificate_Policies); |
83 | 991 | } |
84 | 18.8k | else if(oid == Cert_Extension::Extended_Key_Usage::static_oid()) |
85 | 1.08k | { |
86 | 1.08k | extn.reset(new Cert_Extension::Extended_Key_Usage); |
87 | 1.08k | } |
88 | 17.7k | else if(oid == Cert_Extension::Authority_Information_Access::static_oid()) |
89 | 618 | { |
90 | 618 | extn.reset(new Cert_Extension::Authority_Information_Access); |
91 | 618 | } |
92 | 17.0k | else |
93 | 17.0k | { |
94 | 17.0k | // some other unknown extension type |
95 | 17.0k | extn.reset(new Cert_Extension::Unknown_Extension(oid, critical)); |
96 | 17.0k | } |
97 | 39.7k | |
98 | 39.7k | try |
99 | 39.7k | { |
100 | 39.7k | extn->decode_inner(body); |
101 | 39.7k | } |
102 | 39.7k | catch(Decoding_Error&) |
103 | 39.7k | { |
104 | 14.1k | extn.reset(new Cert_Extension::Unknown_Extension(oid, critical)); |
105 | 14.1k | extn->decode_inner(body); |
106 | 14.1k | } |
107 | 39.7k | return extn; |
108 | 39.7k | } |
109 | | |
110 | | /* |
111 | | * Validate the extension (the default implementation is a NOP) |
112 | | */ |
113 | | void Certificate_Extension::validate(const X509_Certificate&, const X509_Certificate&, |
114 | | const std::vector<std::shared_ptr<const X509_Certificate>>&, |
115 | | std::vector<std::set<Certificate_Status_Code>>&, |
116 | | size_t) |
117 | 0 | { |
118 | 0 | } |
119 | | |
120 | | /* |
121 | | * Add a new cert |
122 | | */ |
123 | | void Extensions::add(Certificate_Extension* extn, bool critical) |
124 | 0 | { |
125 | 0 | // sanity check: we don't want to have the same extension more than once |
126 | 0 | if(m_extension_info.count(extn->oid_of()) > 0) |
127 | 0 | { |
128 | 0 | const std::string name = extn->oid_name(); |
129 | 0 | delete extn; |
130 | 0 | throw Invalid_Argument("Extension " + name + " already present in Extensions::add"); |
131 | 0 | } |
132 | 0 | |
133 | 0 | const OID oid = extn->oid_of(); |
134 | 0 | Extensions_Info info(critical, extn); |
135 | 0 | m_extension_oids.push_back(oid); |
136 | 0 | m_extension_info.emplace(oid, info); |
137 | 0 | } |
138 | | |
139 | | bool Extensions::add_new(Certificate_Extension* extn, bool critical) |
140 | 0 | { |
141 | 0 | if(m_extension_info.count(extn->oid_of()) > 0) |
142 | 0 | { |
143 | 0 | delete extn; |
144 | 0 | return false; // already exists |
145 | 0 | } |
146 | 0 | |
147 | 0 | const OID oid = extn->oid_of(); |
148 | 0 | Extensions_Info info(critical, extn); |
149 | 0 | m_extension_oids.push_back(oid); |
150 | 0 | m_extension_info.emplace(oid, info); |
151 | 0 | return true; |
152 | 0 | } |
153 | | |
154 | | bool Extensions::remove(const OID& oid) |
155 | 0 | { |
156 | 0 | const bool erased = m_extension_info.erase(oid) > 0; |
157 | 0 |
|
158 | 0 | if(erased) |
159 | 0 | { |
160 | 0 | m_extension_oids.erase(std::find(m_extension_oids.begin(), m_extension_oids.end(), oid)); |
161 | 0 | } |
162 | 0 |
|
163 | 0 | return erased; |
164 | 0 | } |
165 | | |
166 | | void Extensions::replace(Certificate_Extension* extn, bool critical) |
167 | 0 | { |
168 | 0 | // Remove it if it existed |
169 | 0 | remove(extn->oid_of()); |
170 | 0 |
|
171 | 0 | const OID oid = extn->oid_of(); |
172 | 0 | Extensions_Info info(critical, extn); |
173 | 0 | m_extension_oids.push_back(oid); |
174 | 0 | m_extension_info.emplace(oid, info); |
175 | 0 | } |
176 | | |
177 | | bool Extensions::extension_set(const OID& oid) const |
178 | 0 | { |
179 | 0 | return (m_extension_info.find(oid) != m_extension_info.end()); |
180 | 0 | } |
181 | | |
182 | | bool Extensions::critical_extension_set(const OID& oid) const |
183 | 0 | { |
184 | 0 | auto i = m_extension_info.find(oid); |
185 | 0 | if(i != m_extension_info.end()) |
186 | 0 | return i->second.is_critical(); |
187 | 0 | return false; |
188 | 0 | } |
189 | | |
190 | | std::vector<uint8_t> Extensions::get_extension_bits(const OID& oid) const |
191 | 0 | { |
192 | 0 | auto i = m_extension_info.find(oid); |
193 | 0 | if(i == m_extension_info.end()) |
194 | 0 | throw Invalid_Argument("Extensions::get_extension_bits no such extension set"); |
195 | 0 | |
196 | 0 | return i->second.bits(); |
197 | 0 | } |
198 | | |
199 | | const Certificate_Extension* Extensions::get_extension_object(const OID& oid) const |
200 | 135k | { |
201 | 135k | auto extn = m_extension_info.find(oid); |
202 | 135k | if(extn == m_extension_info.end()) |
203 | 128k | return nullptr; |
204 | 6.97k | |
205 | 6.97k | return &extn->second.obj(); |
206 | 6.97k | } |
207 | | |
208 | | std::unique_ptr<Certificate_Extension> Extensions::get(const OID& oid) const |
209 | 0 | { |
210 | 0 | if(const Certificate_Extension* ext = this->get_extension_object(oid)) |
211 | 0 | { |
212 | 0 | return std::unique_ptr<Certificate_Extension>(ext->copy()); |
213 | 0 | } |
214 | 0 | return nullptr; |
215 | 0 | } |
216 | | |
217 | | std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> Extensions::extensions() const |
218 | 0 | { |
219 | 0 | std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> exts; |
220 | 0 | for(auto&& ext : m_extension_info) |
221 | 0 | { |
222 | 0 | exts.push_back( |
223 | 0 | std::make_pair( |
224 | 0 | std::unique_ptr<Certificate_Extension>(ext.second.obj().copy()), |
225 | 0 | ext.second.is_critical()) |
226 | 0 | ); |
227 | 0 | } |
228 | 0 | return exts; |
229 | 0 | } |
230 | | |
231 | | std::map<OID, std::pair<std::vector<uint8_t>, bool>> Extensions::extensions_raw() const |
232 | 0 | { |
233 | 0 | std::map<OID, std::pair<std::vector<uint8_t>, bool>> out; |
234 | 0 | for(auto&& ext : m_extension_info) |
235 | 0 | { |
236 | 0 | out.emplace(ext.first, |
237 | 0 | std::make_pair(ext.second.bits(), |
238 | 0 | ext.second.is_critical())); |
239 | 0 | } |
240 | 0 | return out; |
241 | 0 | } |
242 | | |
243 | | /* |
244 | | * Encode an Extensions list |
245 | | */ |
246 | | void Extensions::encode_into(DER_Encoder& to_object) const |
247 | 0 | { |
248 | 0 | for(auto ext_info : m_extension_info) |
249 | 0 | { |
250 | 0 | const OID& oid = ext_info.first; |
251 | 0 | const bool should_encode = ext_info.second.obj().should_encode(); |
252 | 0 |
|
253 | 0 | if(should_encode) |
254 | 0 | { |
255 | 0 | const bool is_critical = ext_info.second.is_critical(); |
256 | 0 | const std::vector<uint8_t>& ext_value = ext_info.second.bits(); |
257 | 0 |
|
258 | 0 | to_object.start_cons(SEQUENCE) |
259 | 0 | .encode(oid) |
260 | 0 | .encode_optional(is_critical, false) |
261 | 0 | .encode(ext_value, OCTET_STRING) |
262 | 0 | .end_cons(); |
263 | 0 | } |
264 | 0 | } |
265 | 0 | } |
266 | | |
267 | | /* |
268 | | * Decode a list of Extensions |
269 | | */ |
270 | | void Extensions::decode_from(BER_Decoder& from_source) |
271 | 11.0k | { |
272 | 11.0k | m_extension_oids.clear(); |
273 | 11.0k | m_extension_info.clear(); |
274 | 11.0k | |
275 | 11.0k | BER_Decoder sequence = from_source.start_cons(SEQUENCE); |
276 | 11.0k | |
277 | 53.2k | while(sequence.more_items()) |
278 | 42.2k | { |
279 | 42.2k | OID oid; |
280 | 42.2k | bool critical; |
281 | 42.2k | std::vector<uint8_t> bits; |
282 | 42.2k | |
283 | 42.2k | sequence.start_cons(SEQUENCE) |
284 | 42.2k | .decode(oid) |
285 | 42.2k | .decode_optional(critical, BOOLEAN, UNIVERSAL, false) |
286 | 42.2k | .decode(bits, OCTET_STRING) |
287 | 42.2k | .end_cons(); |
288 | 42.2k | |
289 | 42.2k | std::unique_ptr<Certificate_Extension> obj = create_extn_obj(oid, critical, bits); |
290 | 42.2k | Extensions_Info info(critical, bits, obj.release()); |
291 | 42.2k | |
292 | 42.2k | m_extension_oids.push_back(oid); |
293 | 42.2k | m_extension_info.emplace(oid, info); |
294 | 42.2k | } |
295 | 11.0k | sequence.verify_end(); |
296 | 11.0k | } |
297 | | |
298 | | /* |
299 | | * Write the extensions to an info store |
300 | | */ |
301 | | void Extensions::contents_to(Data_Store& subject_info, |
302 | | Data_Store& issuer_info) const |
303 | 11.8k | { |
304 | 11.8k | for(auto&& m_extn_info : m_extension_info) |
305 | 12.7k | { |
306 | 12.7k | m_extn_info.second.obj().contents_to(subject_info, issuer_info); |
307 | 12.7k | subject_info.add(m_extn_info.second.obj().oid_name() + ".is_critical", |
308 | 12.7k | m_extn_info.second.is_critical()); |
309 | 12.7k | } |
310 | 11.8k | } |
311 | | |
312 | | namespace Cert_Extension { |
313 | | |
314 | | /* |
315 | | * Checked accessor for the path_limit member |
316 | | */ |
317 | | size_t Basic_Constraints::get_path_limit() const |
318 | 71 | { |
319 | 71 | if(!m_is_ca) |
320 | 0 | throw Invalid_State("Basic_Constraints::get_path_limit: Not a CA"); |
321 | 71 | return m_path_limit; |
322 | 71 | } |
323 | | |
324 | | /* |
325 | | * Encode the extension |
326 | | */ |
327 | | std::vector<uint8_t> Basic_Constraints::encode_inner() const |
328 | 0 | { |
329 | 0 | std::vector<uint8_t> output; |
330 | 0 | DER_Encoder(output) |
331 | 0 | .start_cons(SEQUENCE) |
332 | 0 | .encode_if(m_is_ca, |
333 | 0 | DER_Encoder() |
334 | 0 | .encode(m_is_ca) |
335 | 0 | .encode_optional(m_path_limit, NO_CERT_PATH_LIMIT) |
336 | 0 | ) |
337 | 0 | .end_cons(); |
338 | 0 | return output; |
339 | 0 | } |
340 | | |
341 | | /* |
342 | | * Decode the extension |
343 | | */ |
344 | | void Basic_Constraints::decode_inner(const std::vector<uint8_t>& in) |
345 | 1.76k | { |
346 | 1.76k | BER_Decoder(in) |
347 | 1.76k | .start_cons(SEQUENCE) |
348 | 1.76k | .decode_optional(m_is_ca, BOOLEAN, UNIVERSAL, false) |
349 | 1.76k | .decode_optional(m_path_limit, INTEGER, UNIVERSAL, NO_CERT_PATH_LIMIT) |
350 | 1.76k | .end_cons(); |
351 | 1.76k | |
352 | 1.76k | if(m_is_ca == false) |
353 | 472 | m_path_limit = 0; |
354 | 1.76k | } |
355 | | |
356 | | /* |
357 | | * Return a textual representation |
358 | | */ |
359 | | void Basic_Constraints::contents_to(Data_Store& subject, Data_Store&) const |
360 | 247 | { |
361 | 247 | subject.add("X509v3.BasicConstraints.is_ca", (m_is_ca ? 1 : 0)); |
362 | 247 | subject.add("X509v3.BasicConstraints.path_constraint", static_cast<uint32_t>(m_path_limit)); |
363 | 247 | } |
364 | | |
365 | | /* |
366 | | * Encode the extension |
367 | | */ |
368 | | std::vector<uint8_t> Key_Usage::encode_inner() const |
369 | 0 | { |
370 | 0 | if(m_constraints == NO_CONSTRAINTS) |
371 | 0 | throw Encoding_Error("Cannot encode zero usage constraints"); |
372 | 0 | |
373 | 0 | const size_t unused_bits = ctz(static_cast<uint32_t>(m_constraints)); |
374 | 0 |
|
375 | 0 | std::vector<uint8_t> der; |
376 | 0 | der.push_back(BIT_STRING); |
377 | 0 | der.push_back(2 + ((unused_bits < 8) ? 1 : 0)); |
378 | 0 | der.push_back(unused_bits % 8); |
379 | 0 | der.push_back((m_constraints >> 8) & 0xFF); |
380 | 0 | if(m_constraints & 0xFF) |
381 | 0 | der.push_back(m_constraints & 0xFF); |
382 | 0 |
|
383 | 0 | return der; |
384 | 0 | } |
385 | | |
386 | | /* |
387 | | * Decode the extension |
388 | | */ |
389 | | void Key_Usage::decode_inner(const std::vector<uint8_t>& in) |
390 | 1.41k | { |
391 | 1.41k | BER_Decoder ber(in); |
392 | 1.41k | |
393 | 1.41k | BER_Object obj = ber.get_next_object(); |
394 | 1.41k | |
395 | 1.41k | obj.assert_is_a(BIT_STRING, UNIVERSAL, "usage constraint"); |
396 | 1.41k | |
397 | 1.41k | if(obj.length() != 2 && obj.length() != 3) |
398 | 99 | throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint"); |
399 | 1.32k | |
400 | 1.32k | uint16_t usage = 0; |
401 | 1.32k | |
402 | 1.32k | const uint8_t* bits = obj.bits(); |
403 | 1.32k | |
404 | 1.32k | if(bits[0] >= 8) |
405 | 221 | throw BER_Decoding_Error("Invalid unused bits in usage constraint"); |
406 | 1.09k | |
407 | 1.09k | const uint8_t mask = static_cast<uint8_t>(0xFF << bits[0]); |
408 | 1.09k | |
409 | 1.09k | if(obj.length() == 2) |
410 | 401 | { |
411 | 401 | usage = make_uint16(bits[1] & mask, 0); |
412 | 401 | } |
413 | 698 | else if(obj.length() == 3) |
414 | 60 | { |
415 | 60 | usage = make_uint16(bits[1], bits[2] & mask); |
416 | 60 | } |
417 | 1.09k | |
418 | 1.09k | m_constraints = Key_Constraints(usage); |
419 | 1.09k | } |
420 | | |
421 | | /* |
422 | | * Return a textual representation |
423 | | */ |
424 | | void Key_Usage::contents_to(Data_Store& subject, Data_Store&) const |
425 | 121 | { |
426 | 121 | subject.add("X509v3.KeyUsage", m_constraints); |
427 | 121 | } |
428 | | |
429 | | /* |
430 | | * Encode the extension |
431 | | */ |
432 | | std::vector<uint8_t> Subject_Key_ID::encode_inner() const |
433 | 0 | { |
434 | 0 | std::vector<uint8_t> output; |
435 | 0 | DER_Encoder(output).encode(m_key_id, OCTET_STRING); |
436 | 0 | return output; |
437 | 0 | } |
438 | | |
439 | | /* |
440 | | * Decode the extension |
441 | | */ |
442 | | void Subject_Key_ID::decode_inner(const std::vector<uint8_t>& in) |
443 | 1.65k | { |
444 | 1.65k | BER_Decoder(in).decode(m_key_id, OCTET_STRING).verify_end(); |
445 | 1.65k | } |
446 | | |
447 | | /* |
448 | | * Return a textual representation |
449 | | */ |
450 | | void Subject_Key_ID::contents_to(Data_Store& subject, Data_Store&) const |
451 | 469 | { |
452 | 469 | subject.add("X509v3.SubjectKeyIdentifier", m_key_id); |
453 | 469 | } |
454 | | |
455 | | /* |
456 | | * Subject_Key_ID Constructor |
457 | | */ |
458 | | Subject_Key_ID::Subject_Key_ID(const std::vector<uint8_t>& pub_key, const std::string& hash_name) |
459 | 0 | { |
460 | 0 | std::unique_ptr<HashFunction> hash(HashFunction::create_or_throw(hash_name)); |
461 | 0 |
|
462 | 0 | m_key_id.resize(hash->output_length()); |
463 | 0 |
|
464 | 0 | hash->update(pub_key); |
465 | 0 | hash->final(m_key_id.data()); |
466 | 0 |
|
467 | 0 | // Truncate longer hashes, 192 bits here seems plenty |
468 | 0 | const size_t max_skid_len = (192 / 8); |
469 | 0 | if(m_key_id.size() > max_skid_len) |
470 | 0 | m_key_id.resize(max_skid_len); |
471 | 0 | } |
472 | | |
473 | | /* |
474 | | * Encode the extension |
475 | | */ |
476 | | std::vector<uint8_t> Authority_Key_ID::encode_inner() const |
477 | 0 | { |
478 | 0 | std::vector<uint8_t> output; |
479 | 0 | DER_Encoder(output) |
480 | 0 | .start_cons(SEQUENCE) |
481 | 0 | .encode(m_key_id, OCTET_STRING, ASN1_Tag(0), CONTEXT_SPECIFIC) |
482 | 0 | .end_cons(); |
483 | 0 | return output; |
484 | 0 | } |
485 | | |
486 | | /* |
487 | | * Decode the extension |
488 | | */ |
489 | | void Authority_Key_ID::decode_inner(const std::vector<uint8_t>& in) |
490 | 1.71k | { |
491 | 1.71k | BER_Decoder(in) |
492 | 1.71k | .start_cons(SEQUENCE) |
493 | 1.71k | .decode_optional_string(m_key_id, OCTET_STRING, 0); |
494 | 1.71k | } |
495 | | |
496 | | /* |
497 | | * Return a textual representation |
498 | | */ |
499 | | void Authority_Key_ID::contents_to(Data_Store&, Data_Store& issuer) const |
500 | 601 | { |
501 | 601 | if(m_key_id.size()) |
502 | 497 | issuer.add("X509v3.AuthorityKeyIdentifier", m_key_id); |
503 | 601 | } |
504 | | |
505 | | /* |
506 | | * Encode the extension |
507 | | */ |
508 | | std::vector<uint8_t> Subject_Alternative_Name::encode_inner() const |
509 | 0 | { |
510 | 0 | std::vector<uint8_t> output; |
511 | 0 | DER_Encoder(output).encode(m_alt_name); |
512 | 0 | return output; |
513 | 0 | } |
514 | | |
515 | | /* |
516 | | * Encode the extension |
517 | | */ |
518 | | std::vector<uint8_t> Issuer_Alternative_Name::encode_inner() const |
519 | 0 | { |
520 | 0 | std::vector<uint8_t> output; |
521 | 0 | DER_Encoder(output).encode(m_alt_name); |
522 | 0 | return output; |
523 | 0 | } |
524 | | |
525 | | /* |
526 | | * Decode the extension |
527 | | */ |
528 | | void Subject_Alternative_Name::decode_inner(const std::vector<uint8_t>& in) |
529 | 2.54k | { |
530 | 2.54k | BER_Decoder(in).decode(m_alt_name); |
531 | 2.54k | } |
532 | | |
533 | | /* |
534 | | * Decode the extension |
535 | | */ |
536 | | void Issuer_Alternative_Name::decode_inner(const std::vector<uint8_t>& in) |
537 | 1.33k | { |
538 | 1.33k | BER_Decoder(in).decode(m_alt_name); |
539 | 1.33k | } |
540 | | |
541 | | /* |
542 | | * Return a textual representation |
543 | | */ |
544 | | void Subject_Alternative_Name::contents_to(Data_Store& subject_info, |
545 | | Data_Store&) const |
546 | 346 | { |
547 | 346 | subject_info.add(get_alt_name().contents()); |
548 | 346 | } |
549 | | |
550 | | /* |
551 | | * Return a textual representation |
552 | | */ |
553 | | void Issuer_Alternative_Name::contents_to(Data_Store&, Data_Store& issuer_info) const |
554 | 182 | { |
555 | 182 | issuer_info.add(get_alt_name().contents()); |
556 | 182 | } |
557 | | |
558 | | /* |
559 | | * Encode the extension |
560 | | */ |
561 | | std::vector<uint8_t> Extended_Key_Usage::encode_inner() const |
562 | 0 | { |
563 | 0 | std::vector<uint8_t> output; |
564 | 0 | DER_Encoder(output) |
565 | 0 | .start_cons(SEQUENCE) |
566 | 0 | .encode_list(m_oids) |
567 | 0 | .end_cons(); |
568 | 0 | return output; |
569 | 0 | } |
570 | | |
571 | | /* |
572 | | * Decode the extension |
573 | | */ |
574 | | void Extended_Key_Usage::decode_inner(const std::vector<uint8_t>& in) |
575 | 1.08k | { |
576 | 1.08k | BER_Decoder(in).decode_list(m_oids); |
577 | 1.08k | } |
578 | | |
579 | | /* |
580 | | * Return a textual representation |
581 | | */ |
582 | | void Extended_Key_Usage::contents_to(Data_Store& subject, Data_Store&) const |
583 | 141 | { |
584 | 505 | for(size_t i = 0; i != m_oids.size(); ++i) |
585 | 364 | subject.add("X509v3.ExtendedKeyUsage", m_oids[i].to_string()); |
586 | 141 | } |
587 | | |
588 | | /* |
589 | | * Encode the extension |
590 | | */ |
591 | | std::vector<uint8_t> Name_Constraints::encode_inner() const |
592 | 0 | { |
593 | 0 | throw Not_Implemented("Name_Constraints encoding"); |
594 | 0 | } |
595 | | |
596 | | |
597 | | /* |
598 | | * Decode the extension |
599 | | */ |
600 | | void Name_Constraints::decode_inner(const std::vector<uint8_t>& in) |
601 | 3.40k | { |
602 | 3.40k | std::vector<GeneralSubtree> permit, exclude; |
603 | 3.40k | BER_Decoder ber(in); |
604 | 3.40k | BER_Decoder ext = ber.start_cons(SEQUENCE); |
605 | 3.40k | BER_Object per = ext.get_next_object(); |
606 | 3.40k | |
607 | 3.40k | ext.push_back(per); |
608 | 3.40k | if(per.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) |
609 | 850 | { |
610 | 850 | ext.decode_list(permit,ASN1_Tag(0),ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); |
611 | 850 | if(permit.empty()) |
612 | 5 | throw Encoding_Error("Empty Name Contraint list"); |
613 | 3.40k | } |
614 | 3.40k | |
615 | 3.40k | BER_Object exc = ext.get_next_object(); |
616 | 3.40k | ext.push_back(exc); |
617 | 3.40k | if(per.is_a(1, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) |
618 | 1.72k | { |
619 | 1.72k | ext.decode_list(exclude,ASN1_Tag(1),ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); |
620 | 1.72k | if(exclude.empty()) |
621 | 5 | throw Encoding_Error("Empty Name Contraint list"); |
622 | 3.39k | } |
623 | 3.39k | |
624 | 3.39k | ext.end_cons(); |
625 | 3.39k | |
626 | 3.39k | if(permit.empty() && exclude.empty()) |
627 | 28 | throw Encoding_Error("Empty Name Contraint extension"); |
628 | 3.37k | |
629 | 3.37k | m_name_constraints = NameConstraints(std::move(permit),std::move(exclude)); |
630 | 3.37k | } |
631 | | |
632 | | /* |
633 | | * Return a textual representation |
634 | | */ |
635 | | void Name_Constraints::contents_to(Data_Store& subject, Data_Store&) const |
636 | 65 | { |
637 | 65 | std::stringstream ss; |
638 | 65 | |
639 | 65 | for(const GeneralSubtree& gs: m_name_constraints.permitted()) |
640 | 91 | { |
641 | 91 | ss << gs; |
642 | 91 | subject.add("X509v3.NameConstraints.permitted", ss.str()); |
643 | 91 | ss.str(std::string()); |
644 | 91 | } |
645 | 65 | for(const GeneralSubtree& gs: m_name_constraints.excluded()) |
646 | 135 | { |
647 | 135 | ss << gs; |
648 | 135 | subject.add("X509v3.NameConstraints.excluded", ss.str()); |
649 | 135 | ss.str(std::string()); |
650 | 135 | } |
651 | 65 | } |
652 | | |
653 | | void Name_Constraints::validate(const X509_Certificate& subject, const X509_Certificate& issuer, |
654 | | const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, |
655 | | std::vector<std::set<Certificate_Status_Code>>& cert_status, |
656 | | size_t pos) |
657 | 0 | { |
658 | 0 | if(!m_name_constraints.permitted().empty() || !m_name_constraints.excluded().empty()) |
659 | 0 | { |
660 | 0 | if(!subject.is_CA_cert() || !subject.is_critical("X509v3.NameConstraints")) |
661 | 0 | cert_status.at(pos).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR); |
662 | 0 |
|
663 | 0 | const bool issuer_name_constraint_critical = |
664 | 0 | issuer.is_critical("X509v3.NameConstraints"); |
665 | 0 |
|
666 | 0 | const bool at_self_signed_root = (pos == cert_path.size() - 1); |
667 | 0 |
|
668 | 0 | // Check that all subordinate certs pass the name constraint |
669 | 0 | for(size_t j = 0; j <= pos; ++j) |
670 | 0 | { |
671 | 0 | if(pos == j && at_self_signed_root) |
672 | 0 | continue; |
673 | 0 | |
674 | 0 | bool permitted = m_name_constraints.permitted().empty(); |
675 | 0 | bool failed = false; |
676 | 0 |
|
677 | 0 | for(auto c: m_name_constraints.permitted()) |
678 | 0 | { |
679 | 0 | switch(c.base().matches(*cert_path.at(j))) |
680 | 0 | { |
681 | 0 | case GeneralName::MatchResult::NotFound: |
682 | 0 | case GeneralName::MatchResult::All: |
683 | 0 | permitted = true; |
684 | 0 | break; |
685 | 0 | case GeneralName::MatchResult::UnknownType: |
686 | 0 | failed = issuer_name_constraint_critical; |
687 | 0 | permitted = true; |
688 | 0 | break; |
689 | 0 | default: |
690 | 0 | break; |
691 | 0 | } |
692 | 0 | } |
693 | 0 |
|
694 | 0 | for(auto c: m_name_constraints.excluded()) |
695 | 0 | { |
696 | 0 | switch(c.base().matches(*cert_path.at(j))) |
697 | 0 | { |
698 | 0 | case GeneralName::MatchResult::All: |
699 | 0 | case GeneralName::MatchResult::Some: |
700 | 0 | failed = true; |
701 | 0 | break; |
702 | 0 | case GeneralName::MatchResult::UnknownType: |
703 | 0 | failed = issuer_name_constraint_critical; |
704 | 0 | break; |
705 | 0 | default: |
706 | 0 | break; |
707 | 0 | } |
708 | 0 | } |
709 | 0 |
|
710 | 0 | if(failed || !permitted) |
711 | 0 | { |
712 | 0 | cert_status.at(j).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR); |
713 | 0 | } |
714 | 0 | } |
715 | 0 | } |
716 | 0 | } |
717 | | |
718 | | namespace { |
719 | | |
720 | | /* |
721 | | * A policy specifier |
722 | | */ |
723 | | class Policy_Information final : public ASN1_Object |
724 | | { |
725 | | public: |
726 | 1.21k | Policy_Information() = default; |
727 | 0 | explicit Policy_Information(const OID& oid) : m_oid(oid) {} |
728 | | |
729 | 731 | const OID& oid() const { return m_oid; } |
730 | | |
731 | | void encode_into(DER_Encoder& codec) const override |
732 | 0 | { |
733 | 0 | codec.start_cons(SEQUENCE) |
734 | 0 | .encode(m_oid) |
735 | 0 | .end_cons(); |
736 | 0 | } |
737 | | |
738 | | void decode_from(BER_Decoder& codec) override |
739 | 1.21k | { |
740 | 1.21k | codec.start_cons(SEQUENCE) |
741 | 1.21k | .decode(m_oid) |
742 | 1.21k | .discard_remaining() |
743 | 1.21k | .end_cons(); |
744 | 1.21k | } |
745 | | |
746 | | private: |
747 | | OID m_oid; |
748 | | }; |
749 | | |
750 | | } |
751 | | |
752 | | /* |
753 | | * Encode the extension |
754 | | */ |
755 | | std::vector<uint8_t> Certificate_Policies::encode_inner() const |
756 | 0 | { |
757 | 0 | std::vector<Policy_Information> policies; |
758 | 0 |
|
759 | 0 | for(size_t i = 0; i != m_oids.size(); ++i) |
760 | 0 | policies.push_back(Policy_Information(m_oids[i])); |
761 | 0 |
|
762 | 0 | std::vector<uint8_t> output; |
763 | 0 | DER_Encoder(output) |
764 | 0 | .start_cons(SEQUENCE) |
765 | 0 | .encode_list(policies) |
766 | 0 | .end_cons(); |
767 | 0 | return output; |
768 | 0 | } |
769 | | |
770 | | /* |
771 | | * Decode the extension |
772 | | */ |
773 | | void Certificate_Policies::decode_inner(const std::vector<uint8_t>& in) |
774 | 991 | { |
775 | 991 | std::vector<Policy_Information> policies; |
776 | 991 | |
777 | 991 | BER_Decoder(in).decode_list(policies); |
778 | 991 | m_oids.clear(); |
779 | 1.72k | for(size_t i = 0; i != policies.size(); ++i) |
780 | 731 | m_oids.push_back(policies[i].oid()); |
781 | 991 | } |
782 | | |
783 | | /* |
784 | | * Return a textual representation |
785 | | */ |
786 | | void Certificate_Policies::contents_to(Data_Store& info, Data_Store&) const |
787 | 82 | { |
788 | 220 | for(size_t i = 0; i != m_oids.size(); ++i) |
789 | 138 | info.add("X509v3.CertificatePolicies", m_oids[i].to_string()); |
790 | 82 | } |
791 | | |
792 | | void Certificate_Policies::validate( |
793 | | const X509_Certificate& /*subject*/, |
794 | | const X509_Certificate& /*issuer*/, |
795 | | const std::vector<std::shared_ptr<const X509_Certificate>>& /*cert_path*/, |
796 | | std::vector<std::set<Certificate_Status_Code>>& cert_status, |
797 | | size_t pos) |
798 | 0 | { |
799 | 0 | std::set<OID> oid_set(m_oids.begin(), m_oids.end()); |
800 | 0 | if(oid_set.size() != m_oids.size()) |
801 | 0 | { |
802 | 0 | cert_status.at(pos).insert(Certificate_Status_Code::DUPLICATE_CERT_POLICY); |
803 | 0 | } |
804 | 0 | } |
805 | | |
806 | | std::vector<uint8_t> Authority_Information_Access::encode_inner() const |
807 | 0 | { |
808 | 0 | ASN1_String url(m_ocsp_responder, IA5_STRING); |
809 | 0 |
|
810 | 0 | std::vector<uint8_t> output; |
811 | 0 | DER_Encoder(output) |
812 | 0 | .start_cons(SEQUENCE) |
813 | 0 | .start_cons(SEQUENCE) |
814 | 0 | .encode(OID::from_string("PKIX.OCSP")) |
815 | 0 | .add_object(ASN1_Tag(6), CONTEXT_SPECIFIC, url.value()) |
816 | 0 | .end_cons() |
817 | 0 | .end_cons(); |
818 | 0 | return output; |
819 | 0 | } |
820 | | |
821 | | void Authority_Information_Access::decode_inner(const std::vector<uint8_t>& in) |
822 | 618 | { |
823 | 618 | BER_Decoder ber = BER_Decoder(in).start_cons(SEQUENCE); |
824 | 618 | |
825 | 1.28k | while(ber.more_items()) |
826 | 669 | { |
827 | 669 | OID oid; |
828 | 669 | |
829 | 669 | BER_Decoder info = ber.start_cons(SEQUENCE); |
830 | 669 | |
831 | 669 | info.decode(oid); |
832 | 669 | |
833 | 669 | if(oid == OID::from_string("PKIX.OCSP")) |
834 | 120 | { |
835 | 120 | BER_Object name = info.get_next_object(); |
836 | 120 | |
837 | 120 | if(name.is_a(6, CONTEXT_SPECIFIC)) |
838 | 49 | { |
839 | 49 | m_ocsp_responder = ASN1::to_string(name); |
840 | 49 | } |
841 | 120 | |
842 | 120 | } |
843 | 669 | if(oid == OID::from_string("PKIX.CertificateAuthorityIssuers")) |
844 | 144 | { |
845 | 144 | BER_Object name = info.get_next_object(); |
846 | 144 | |
847 | 144 | if(name.is_a(6, CONTEXT_SPECIFIC)) |
848 | 77 | { |
849 | 77 | m_ca_issuers.push_back(ASN1::to_string(name)); |
850 | 77 | } |
851 | 144 | } |
852 | 669 | } |
853 | 618 | } |
854 | | |
855 | | void Authority_Information_Access::contents_to(Data_Store& subject, Data_Store&) const |
856 | 53 | { |
857 | 53 | if(!m_ocsp_responder.empty()) |
858 | 13 | subject.add("OCSP.responder", m_ocsp_responder); |
859 | 53 | for(const std::string& ca_issuer : m_ca_issuers) |
860 | 51 | subject.add("PKIX.CertificateAuthorityIssuers", ca_issuer); |
861 | 53 | } |
862 | | |
863 | | /* |
864 | | * Checked accessor for the crl_number member |
865 | | */ |
866 | | size_t CRL_Number::get_crl_number() const |
867 | 2 | { |
868 | 2 | if(!m_has_value) |
869 | 0 | throw Invalid_State("CRL_Number::get_crl_number: Not set"); |
870 | 2 | return m_crl_number; |
871 | 2 | } |
872 | | |
873 | | /* |
874 | | * Copy a CRL_Number extension |
875 | | */ |
876 | | CRL_Number* CRL_Number::copy() const |
877 | 0 | { |
878 | 0 | if(!m_has_value) |
879 | 0 | throw Invalid_State("CRL_Number::copy: Not set"); |
880 | 0 | return new CRL_Number(m_crl_number); |
881 | 0 | } |
882 | | |
883 | | /* |
884 | | * Encode the extension |
885 | | */ |
886 | | std::vector<uint8_t> CRL_Number::encode_inner() const |
887 | 0 | { |
888 | 0 | std::vector<uint8_t> output; |
889 | 0 | DER_Encoder(output).encode(m_crl_number); |
890 | 0 | return output; |
891 | 0 | } |
892 | | |
893 | | /* |
894 | | * Decode the extension |
895 | | */ |
896 | | void CRL_Number::decode_inner(const std::vector<uint8_t>& in) |
897 | 678 | { |
898 | 678 | BER_Decoder(in).decode(m_crl_number); |
899 | 678 | m_has_value = true; |
900 | 678 | } |
901 | | |
902 | | /* |
903 | | * Return a textual representation |
904 | | */ |
905 | | void CRL_Number::contents_to(Data_Store& info, Data_Store&) const |
906 | 23 | { |
907 | 23 | info.add("X509v3.CRLNumber", static_cast<uint32_t>(m_crl_number)); |
908 | 23 | } |
909 | | |
910 | | /* |
911 | | * Encode the extension |
912 | | */ |
913 | | std::vector<uint8_t> CRL_ReasonCode::encode_inner() const |
914 | 0 | { |
915 | 0 | std::vector<uint8_t> output; |
916 | 0 | DER_Encoder(output).encode(static_cast<size_t>(m_reason), ENUMERATED, UNIVERSAL); |
917 | 0 | return output; |
918 | 0 | } |
919 | | |
920 | | /* |
921 | | * Decode the extension |
922 | | */ |
923 | | void CRL_ReasonCode::decode_inner(const std::vector<uint8_t>& in) |
924 | 3.30k | { |
925 | 3.30k | size_t reason_code = 0; |
926 | 3.30k | BER_Decoder(in).decode(reason_code, ENUMERATED, UNIVERSAL); |
927 | 3.30k | m_reason = static_cast<CRL_Code>(reason_code); |
928 | 3.30k | } |
929 | | |
930 | | /* |
931 | | * Return a textual representation |
932 | | */ |
933 | | void CRL_ReasonCode::contents_to(Data_Store& info, Data_Store&) const |
934 | 28 | { |
935 | 28 | info.add("X509v3.CRLReasonCode", m_reason); |
936 | 28 | } |
937 | | |
938 | | std::vector<uint8_t> CRL_Distribution_Points::encode_inner() const |
939 | 0 | { |
940 | 0 | throw Not_Implemented("CRL_Distribution_Points encoding"); |
941 | 0 | } |
942 | | |
943 | | void CRL_Distribution_Points::decode_inner(const std::vector<uint8_t>& buf) |
944 | 1.68k | { |
945 | 1.68k | BER_Decoder(buf) |
946 | 1.68k | .decode_list(m_distribution_points) |
947 | 1.68k | .verify_end(); |
948 | 1.68k | |
949 | 1.68k | std::stringstream ss; |
950 | 1.68k | |
951 | 2.22k | for(size_t i = 0; i != m_distribution_points.size(); ++i) |
952 | 535 | { |
953 | 535 | auto contents = m_distribution_points[i].point().contents(); |
954 | 535 | |
955 | 535 | for(const auto& pair : contents) |
956 | 2.50k | { |
957 | 2.50k | ss << pair.first << ": " << pair.second << " "; |
958 | 2.50k | } |
959 | 535 | } |
960 | 1.68k | |
961 | 1.68k | m_crl_distribution_urls.push_back(ss.str()); |
962 | 1.68k | } |
963 | | |
964 | | void CRL_Distribution_Points::contents_to(Data_Store& subject, Data_Store&) const |
965 | 68 | { |
966 | 68 | for(const std::string& crl_url : m_crl_distribution_urls) |
967 | 68 | subject.add("CRL.DistributionPoint", crl_url); |
968 | 68 | } |
969 | | |
970 | | void CRL_Distribution_Points::Distribution_Point::encode_into(class DER_Encoder&) const |
971 | 0 | { |
972 | 0 | throw Not_Implemented("CRL_Distribution_Points encoding"); |
973 | 0 | } |
974 | | |
975 | | void CRL_Distribution_Points::Distribution_Point::decode_from(class BER_Decoder& ber) |
976 | 1.77k | { |
977 | 1.77k | ber.start_cons(SEQUENCE) |
978 | 1.77k | .start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC) |
979 | 1.77k | .decode_optional_implicit(m_point, ASN1_Tag(0), |
980 | 1.77k | ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED), |
981 | 1.77k | SEQUENCE, CONSTRUCTED) |
982 | 1.77k | .end_cons().end_cons(); |
983 | 1.77k | } |
984 | | |
985 | | std::vector<uint8_t> CRL_Issuing_Distribution_Point::encode_inner() const |
986 | 0 | { |
987 | 0 | throw Not_Implemented("CRL_Issuing_Distribution_Point encoding"); |
988 | 0 | } |
989 | | |
990 | | void CRL_Issuing_Distribution_Point::decode_inner(const std::vector<uint8_t>& buf) |
991 | 451 | { |
992 | 451 | BER_Decoder(buf).decode(m_distribution_point).verify_end(); |
993 | 451 | } |
994 | | |
995 | | void CRL_Issuing_Distribution_Point::contents_to(Data_Store& info, Data_Store&) const |
996 | 18 | { |
997 | 18 | auto contents = m_distribution_point.point().contents(); |
998 | 18 | std::stringstream ss; |
999 | 18 | |
1000 | 18 | for(const auto& pair : contents) |
1001 | 34 | { |
1002 | 34 | ss << pair.first << ": " << pair.second << " "; |
1003 | 34 | } |
1004 | 18 | |
1005 | 18 | info.add("X509v3.CRLIssuingDistributionPoint", ss.str()); |
1006 | 18 | } |
1007 | | |
1008 | | std::vector<uint8_t> Unknown_Extension::encode_inner() const |
1009 | 0 | { |
1010 | 0 | return m_bytes; |
1011 | 0 | } |
1012 | | |
1013 | | void Unknown_Extension::decode_inner(const std::vector<uint8_t>& bytes) |
1014 | 31.2k | { |
1015 | 31.2k | // Just treat as an opaque blob at this level |
1016 | 31.2k | m_bytes = bytes; |
1017 | 31.2k | } |
1018 | | |
1019 | | void Unknown_Extension::contents_to(Data_Store&, Data_Store&) const |
1020 | 10.3k | { |
1021 | 10.3k | // No information store |
1022 | 10.3k | } |
1023 | | |
1024 | | } |
1025 | | |
1026 | | } |