]>
Commit | Line | Data |
---|---|---|
5728c6aa | 1 | /* |
f781b9d3 | 2 | * Copyright (C) 2011-2023 Tobias Brunner |
5728c6aa | 3 | * Copyright (C) 2010 Martin Willi |
19ef2aec TB |
4 | * |
5 | * Copyright (C) secunet Security Networks AG | |
5728c6aa MW |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2 of the License, or (at your | |
10 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | * for more details. | |
16 | */ | |
17 | ||
18 | /* | |
5e4b1ad2 MR |
19 | * Copyright (C) 2013 Michael Rossberg |
20 | * Copyright (C) 2013 Technische Universität Ilmenau | |
21 | * | |
5728c6aa MW |
22 | * Copyright (C) 2010 Thomas Egerer |
23 | * | |
24 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
25 | * of this software and associated documentation files (the "Software"), to deal | |
26 | * in the Software without restriction, including without limitation the rights | |
27 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
28 | * copies of the Software, and to permit persons to whom the Software is | |
29 | * furnished to do so, subject to the following conditions: | |
30 | * | |
31 | * The above copyright notice and this permission notice shall be included in | |
32 | * all copies or substantial portions of the Software. | |
33 | * | |
34 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
35 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
36 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
37 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
38 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
39 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
40 | * THE SOFTWARE. | |
41 | */ | |
42 | ||
43 | #define _GNU_SOURCE | |
44 | #include <stdio.h> | |
45 | #include <openssl/x509.h> | |
46 | #include <openssl/x509v3.h> | |
47 | ||
48 | #include "openssl_x509.h" | |
49 | #include "openssl_util.h" | |
50 | ||
f05b4272 | 51 | #include <utils/debug.h> |
5728c6aa | 52 | #include <asn1/oid.h> |
12642a68 | 53 | #include <collections/linked_list.h> |
5e4b1ad2 | 54 | #include <selectors/traffic_selector.h> |
5728c6aa | 55 | |
5e4b1ad2 MR |
56 | /* IP Addr block extension support was introduced with 0.9.8e */ |
57 | #if OPENSSL_VERSION_NUMBER < 0x0090805fL | |
58 | #define OPENSSL_NO_RFC3779 | |
59 | #endif | |
5728c6aa | 60 | |
08d7e1f1 TB |
61 | /* added with 1.0.2 */ |
62 | #if OPENSSL_VERSION_NUMBER < 0x10002000L | |
63 | static inline void X509_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, const X509 *x) { | |
64 | if (psig) { *psig = x->signature; } | |
65 | if (palg) { *palg = x->sig_alg; } | |
66 | } | |
67 | #endif | |
68 | ||
69 | /* added with 1.1.0 when X509 etc. was made opaque */ | |
70 | #if OPENSSL_VERSION_NUMBER < 0x10100000L | |
71 | #define X509_get0_extensions(x509) ({ (x509)->cert_info->extensions; }) | |
72 | #define X509_get0_tbs_sigalg(x509) ({ (x509)->cert_info->signature; }) | |
73 | #define X509_ALGOR_get0(oid, ppt, ppv, alg) ({ *(oid) = (alg)->algorithm; }) | |
74 | #define X509_PUBKEY_get0_param(oid, pk, len, pa, pub) X509_ALGOR_get0(oid, NULL, NULL, (pub)->algor) | |
75 | #define X509v3_addr_get_afi v3_addr_get_afi | |
76 | #define X509v3_addr_get_range v3_addr_get_range | |
77 | #define X509v3_addr_is_canonical v3_addr_is_canonical | |
a4abb263 TB |
78 | #define X509_get0_notBefore X509_get_notBefore |
79 | #define X509_get0_notAfter X509_get_notAfter | |
08d7e1f1 TB |
80 | #endif |
81 | ||
5728c6aa MW |
82 | typedef struct private_openssl_x509_t private_openssl_x509_t; |
83 | ||
84 | /** | |
85 | * Private data of an openssl_x509_t object. | |
86 | */ | |
87 | struct private_openssl_x509_t { | |
88 | ||
89 | /** | |
90 | * Public openssl_x509_t interface. | |
91 | */ | |
92 | openssl_x509_t public; | |
93 | ||
94 | /** | |
95 | * OpenSSL certificate representation | |
96 | */ | |
97 | X509 *x509; | |
98 | ||
99 | /** | |
100 | * DER encoded certificate | |
101 | */ | |
102 | chunk_t encoding; | |
103 | ||
104 | /** | |
105 | * SHA1 hash of the certificate | |
106 | */ | |
107 | chunk_t hash; | |
108 | ||
109 | /** | |
110 | * X509 flags | |
111 | */ | |
112 | x509_flag_t flags; | |
113 | ||
114 | /** | |
115 | * Pathlen constraint | |
116 | */ | |
d390b3b9 | 117 | u_char pathlen; |
5728c6aa MW |
118 | |
119 | /** | |
120 | * certificate subject | |
121 | */ | |
122 | identification_t *subject; | |
123 | ||
124 | /** | |
125 | * certificate issuer | |
126 | */ | |
127 | identification_t *issuer; | |
128 | ||
129 | /** | |
130 | * Certificates public key | |
131 | */ | |
132 | public_key_t *pubkey; | |
133 | ||
134 | /** | |
135 | * subjectKeyIdentifier as read from cert | |
136 | */ | |
137 | chunk_t subjectKeyIdentifier; | |
138 | ||
139 | /** | |
140 | * authorityKeyIdentifier as read from cert | |
141 | */ | |
142 | chunk_t authKeyIdentifier; | |
143 | ||
144 | /** | |
145 | * Start time of certificate validity | |
146 | */ | |
147 | time_t notBefore; | |
148 | ||
149 | /** | |
150 | * End time of certificate validity | |
151 | */ | |
152 | time_t notAfter; | |
153 | ||
154 | /** | |
155 | * Signature scheme of the certificate | |
156 | */ | |
fb63012e | 157 | signature_params_t *scheme; |
5728c6aa MW |
158 | |
159 | /** | |
160 | * subjectAltNames | |
161 | */ | |
162 | linked_list_t *subjectAltNames; | |
163 | ||
164 | /** | |
165 | * issuerAltNames | |
166 | */ | |
167 | linked_list_t *issuerAltNames; | |
168 | ||
169 | /** | |
a6478a04 | 170 | * List of CRL URIs, as x509_cdp_t |
5728c6aa MW |
171 | */ |
172 | linked_list_t *crl_uris; | |
173 | ||
174 | /** | |
175 | * List of OCSP URIs | |
176 | */ | |
177 | linked_list_t *ocsp_uris; | |
178 | ||
5e4b1ad2 MR |
179 | /** |
180 | * List of ipAddrBlocks as traffic_selector_t | |
181 | */ | |
182 | linked_list_t *ipAddrBlocks; | |
183 | ||
f781b9d3 TB |
184 | /** |
185 | * List of permitted name constraints | |
186 | */ | |
187 | linked_list_t *permitted_names; | |
188 | ||
189 | /** | |
190 | * List of excluded name constraints | |
191 | */ | |
192 | linked_list_t *excluded_names; | |
5e4b1ad2 | 193 | |
5728c6aa MW |
194 | /** |
195 | * References to this cert | |
196 | */ | |
197 | refcount_t ref; | |
198 | }; | |
199 | ||
200 | /** | |
201 | * Convert a GeneralName to an identification_t. | |
202 | */ | |
203 | static identification_t *general_name2id(GENERAL_NAME *name) | |
204 | { | |
205 | if (!name) | |
206 | { | |
207 | return NULL; | |
208 | } | |
209 | switch (name->type) | |
210 | { | |
211 | case GEN_EMAIL: | |
212 | return identification_create_from_encoding(ID_RFC822_ADDR, | |
213 | openssl_asn1_str2chunk(name->d.rfc822Name)); | |
214 | case GEN_DNS: | |
215 | return identification_create_from_encoding(ID_FQDN, | |
216 | openssl_asn1_str2chunk(name->d.dNSName)); | |
217 | case GEN_URI: | |
218 | return identification_create_from_encoding(ID_DER_ASN1_GN_URI, | |
219 | openssl_asn1_str2chunk(name->d.uniformResourceIdentifier)); | |
220 | case GEN_IPADD: | |
07c5aacc MW |
221 | { |
222 | chunk_t chunk = openssl_asn1_str2chunk(name->d.iPAddress); | |
223 | if (chunk.len == 4) | |
224 | { | |
225 | return identification_create_from_encoding(ID_IPV4_ADDR, chunk); | |
226 | } | |
1c3096fe TB |
227 | if (chunk.len == 8) |
228 | { | |
229 | return identification_create_from_encoding(ID_IPV4_ADDR_SUBNET, | |
230 | chunk); | |
231 | } | |
07c5aacc MW |
232 | if (chunk.len == 16) |
233 | { | |
234 | return identification_create_from_encoding(ID_IPV6_ADDR, chunk); | |
235 | } | |
1c3096fe TB |
236 | if (chunk.len == 32) |
237 | { | |
238 | return identification_create_from_encoding(ID_IPV6_ADDR_SUBNET, | |
239 | chunk); | |
240 | } | |
07c5aacc MW |
241 | return NULL; |
242 | } | |
5728c6aa MW |
243 | case GEN_DIRNAME : |
244 | return openssl_x509_name2id(name->d.directoryName); | |
a0a8aaaf MW |
245 | case GEN_OTHERNAME: |
246 | if (OBJ_obj2nid(name->d.otherName->type_id) == NID_ms_upn && | |
247 | name->d.otherName->value->type == V_ASN1_UTF8STRING) | |
248 | { | |
249 | return identification_create_from_encoding(ID_RFC822_ADDR, | |
250 | openssl_asn1_str2chunk( | |
251 | name->d.otherName->value->value.utf8string)); | |
252 | } | |
253 | return NULL; | |
5728c6aa MW |
254 | default: |
255 | return NULL; | |
256 | } | |
257 | } | |
258 | ||
259 | METHOD(x509_t, get_flags, x509_flag_t, | |
260 | private_openssl_x509_t *this) | |
261 | { | |
262 | return this->flags; | |
263 | } | |
264 | ||
265 | METHOD(x509_t, get_serial, chunk_t, | |
266 | private_openssl_x509_t *this) | |
267 | { | |
44e241fc | 268 | return openssl_asn1_int2chunk(X509_get_serialNumber(this->x509)); |
5728c6aa MW |
269 | } |
270 | ||
271 | METHOD(x509_t, get_subjectKeyIdentifier, chunk_t, | |
272 | private_openssl_x509_t *this) | |
273 | { | |
274 | chunk_t fingerprint; | |
275 | ||
276 | if (this->subjectKeyIdentifier.len) | |
277 | { | |
278 | return this->subjectKeyIdentifier; | |
279 | } | |
da9724e6 | 280 | if (this->pubkey->get_fingerprint(this->pubkey, KEYID_PUBKEY_SHA1, |
5728c6aa MW |
281 | &fingerprint)) |
282 | { | |
283 | return fingerprint; | |
284 | } | |
285 | return chunk_empty; | |
286 | } | |
287 | ||
288 | METHOD(x509_t, get_authKeyIdentifier, chunk_t, | |
289 | private_openssl_x509_t *this) | |
290 | { | |
291 | if (this->authKeyIdentifier.len) | |
292 | { | |
293 | return this->authKeyIdentifier; | |
294 | } | |
295 | return chunk_empty; | |
296 | } | |
297 | ||
d390b3b9 | 298 | METHOD(x509_t, get_constraint, u_int, |
b3d359e5 | 299 | private_openssl_x509_t *this, x509_constraint_t type) |
a742d97f | 300 | { |
b3d359e5 MW |
301 | switch (type) |
302 | { | |
303 | case X509_PATH_LEN: | |
304 | return this->pathlen; | |
305 | default: | |
306 | return X509_NO_CONSTRAINT; | |
307 | } | |
a742d97f MW |
308 | } |
309 | ||
5728c6aa MW |
310 | METHOD(x509_t, create_subjectAltName_enumerator, enumerator_t*, |
311 | private_openssl_x509_t *this) | |
312 | { | |
313 | return this->subjectAltNames->create_enumerator(this->subjectAltNames); | |
314 | } | |
315 | ||
316 | METHOD(x509_t, create_crl_uri_enumerator, enumerator_t*, | |
317 | private_openssl_x509_t *this) | |
318 | { | |
a6478a04 | 319 | return this->crl_uris->create_enumerator(this->crl_uris); |
5728c6aa MW |
320 | } |
321 | ||
322 | METHOD(x509_t, create_ocsp_uri_enumerator, enumerator_t*, | |
323 | private_openssl_x509_t *this) | |
324 | { | |
325 | return this->ocsp_uris->create_enumerator(this->ocsp_uris); | |
326 | } | |
327 | ||
5e4b1ad2 MR |
328 | METHOD(x509_t, create_ipAddrBlock_enumerator, enumerator_t*, |
329 | private_openssl_x509_t *this) | |
330 | { | |
331 | return this->ipAddrBlocks->create_enumerator(this->ipAddrBlocks); | |
332 | } | |
333 | ||
f781b9d3 TB |
334 | METHOD(x509_t, create_name_constraint_enumerator, enumerator_t*, |
335 | private_openssl_x509_t *this, bool perm) | |
336 | { | |
337 | if (perm) | |
338 | { | |
339 | return this->permitted_names->create_enumerator(this->permitted_names); | |
340 | } | |
341 | return this->excluded_names->create_enumerator(this->excluded_names); | |
342 | } | |
343 | ||
5728c6aa MW |
344 | METHOD(certificate_t, get_type, certificate_type_t, |
345 | private_openssl_x509_t *this) | |
346 | { | |
347 | return CERT_X509; | |
348 | } | |
349 | ||
350 | METHOD(certificate_t, get_subject, identification_t*, | |
351 | private_openssl_x509_t *this) | |
352 | { | |
353 | return this->subject; | |
354 | } | |
355 | ||
356 | METHOD(certificate_t, get_issuer, identification_t*, | |
357 | private_openssl_x509_t *this) | |
358 | { | |
359 | return this->issuer; | |
360 | } | |
361 | ||
362 | METHOD(certificate_t, has_subject, id_match_t, | |
363 | private_openssl_x509_t *this, identification_t *subject) | |
364 | { | |
365 | identification_t *current; | |
366 | enumerator_t *enumerator; | |
367 | id_match_t match, best; | |
663e7355 | 368 | chunk_t encoding; |
5728c6aa MW |
369 | |
370 | if (subject->get_type(subject) == ID_KEY_ID) | |
371 | { | |
663e7355 MW |
372 | encoding = subject->get_encoding(subject); |
373 | ||
374 | if (chunk_equals(this->hash, encoding)) | |
375 | { | |
376 | return ID_MATCH_PERFECT; | |
377 | } | |
378 | if (this->subjectKeyIdentifier.len && | |
379 | chunk_equals(this->subjectKeyIdentifier, encoding)) | |
380 | { | |
381 | return ID_MATCH_PERFECT; | |
382 | } | |
383 | if (this->pubkey && | |
384 | this->pubkey->has_fingerprint(this->pubkey, encoding)) | |
5728c6aa MW |
385 | { |
386 | return ID_MATCH_PERFECT; | |
387 | } | |
ed1c4303 MW |
388 | if (chunk_equals(get_serial(this), encoding)) |
389 | { | |
390 | return ID_MATCH_PERFECT; | |
391 | } | |
5728c6aa MW |
392 | } |
393 | best = this->subject->matches(this->subject, subject); | |
394 | enumerator = create_subjectAltName_enumerator(this); | |
395 | while (enumerator->enumerate(enumerator, ¤t)) | |
396 | { | |
397 | match = current->matches(current, subject); | |
398 | if (match > best) | |
399 | { | |
400 | best = match; | |
401 | } | |
402 | } | |
403 | enumerator->destroy(enumerator); | |
404 | return best; | |
405 | } | |
406 | ||
407 | METHOD(certificate_t, has_issuer, id_match_t, | |
408 | private_openssl_x509_t *this, identification_t *issuer) | |
409 | { | |
410 | /* issuerAltNames currently not supported */ | |
411 | return this->issuer->matches(this->issuer, issuer); | |
412 | } | |
413 | ||
414 | METHOD(certificate_t, issued_by, bool, | |
a37f2d20 | 415 | private_openssl_x509_t *this, certificate_t *issuer, |
024b9795 | 416 | signature_params_t **scheme) |
5728c6aa MW |
417 | { |
418 | public_key_t *key; | |
419 | bool valid; | |
420 | x509_t *x509 = (x509_t*)issuer; | |
f0c25960 | 421 | chunk_t keyid = chunk_empty; |
8b4c2a1d TB |
422 | #if OPENSSL_VERSION_NUMBER >= 0x10100000L |
423 | const ASN1_BIT_STRING *sig; | |
424 | #else | |
08d7e1f1 | 425 | ASN1_BIT_STRING *sig; |
8b4c2a1d | 426 | #endif |
5728c6aa MW |
427 | chunk_t tbs; |
428 | ||
429 | if (&this->public.x509.interface == issuer) | |
430 | { | |
431 | if (this->flags & X509_SELF_SIGNED) | |
432 | { | |
024b9795 TB |
433 | valid = TRUE; |
434 | goto out; | |
5728c6aa MW |
435 | } |
436 | } | |
437 | else | |
438 | { | |
439 | if (issuer->get_type(issuer) != CERT_X509) | |
440 | { | |
441 | return FALSE; | |
442 | } | |
443 | if (!(x509->get_flags(x509) & X509_CA)) | |
444 | { | |
445 | return FALSE; | |
446 | } | |
61769fd1 | 447 | } |
f0c25960 AKR |
448 | |
449 | /* compare keyIdentifiers if available, otherwise use DNs */ | |
450 | if (this->authKeyIdentifier.ptr) | |
61769fd1 | 451 | { |
f0c25960 AKR |
452 | keyid = x509->get_subjectKeyIdentifier(x509); |
453 | if (keyid.len && !chunk_equals(keyid, this->authKeyIdentifier)) | |
454 | { | |
455 | return FALSE; | |
456 | } | |
5728c6aa | 457 | } |
f0c25960 AKR |
458 | if (!keyid.len) |
459 | { | |
460 | if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer))) | |
461 | { | |
462 | return FALSE; | |
463 | } | |
464 | } | |
465 | ||
5728c6aa MW |
466 | key = issuer->get_public_key(issuer); |
467 | if (!key) | |
468 | { | |
469 | return FALSE; | |
470 | } | |
08d7e1f1 TB |
471 | /* i2d_re_X509_tbs() was added with 1.1.0 when X509 was made opaque */ |
472 | #if OPENSSL_VERSION_NUMBER >= 0x10100000L | |
473 | tbs = openssl_i2chunk(re_X509_tbs, this->x509); | |
474 | #else | |
5728c6aa | 475 | tbs = openssl_i2chunk(X509_CINF, this->x509->cert_info); |
08d7e1f1 TB |
476 | #endif |
477 | X509_get0_signature(&sig, NULL, this->x509); | |
fb63012e | 478 | valid = key->verify(key, this->scheme->scheme, this->scheme->params, tbs, |
a413571f | 479 | openssl_asn1_str2chunk(sig)); |
5728c6aa MW |
480 | free(tbs.ptr); |
481 | key->destroy(key); | |
024b9795 TB |
482 | |
483 | out: | |
a37f2d20 MW |
484 | if (valid && scheme) |
485 | { | |
fb63012e | 486 | *scheme = signature_params_clone(this->scheme); |
a37f2d20 | 487 | } |
5728c6aa MW |
488 | return valid; |
489 | } | |
490 | ||
491 | METHOD(certificate_t, get_public_key, public_key_t*, | |
492 | private_openssl_x509_t *this) | |
493 | { | |
494 | return this->pubkey->get_ref(this->pubkey); | |
495 | } | |
496 | ||
497 | METHOD(certificate_t, get_validity, bool, | |
498 | private_openssl_x509_t *this, | |
499 | time_t *when, time_t *not_before, time_t *not_after) | |
500 | { | |
501 | time_t t; | |
502 | ||
503 | if (when) | |
504 | { | |
505 | t = *when; | |
506 | } | |
507 | else | |
508 | { | |
509 | t = time(NULL); | |
510 | } | |
511 | if (not_before) | |
512 | { | |
513 | *not_before = this->notBefore; | |
514 | } | |
515 | if (not_after) | |
516 | { | |
517 | *not_after = this->notAfter; | |
518 | } | |
519 | return (t >= this->notBefore && t <= this->notAfter); | |
520 | } | |
521 | ||
0406eeaa MW |
522 | METHOD(certificate_t, get_encoding, bool, |
523 | private_openssl_x509_t *this, cred_encoding_type_t type, chunk_t *encoding) | |
5728c6aa | 524 | { |
0406eeaa MW |
525 | if (type == CERT_ASN1_DER) |
526 | { | |
527 | *encoding = chunk_clone(this->encoding); | |
528 | return TRUE; | |
529 | } | |
530 | return lib->encoding->encode(lib->encoding, type, NULL, encoding, | |
531 | CRED_PART_X509_ASN1_DER, this->encoding, CRED_PART_END); | |
5728c6aa MW |
532 | } |
533 | ||
0406eeaa | 534 | |
5728c6aa MW |
535 | METHOD(certificate_t, equals, bool, |
536 | private_openssl_x509_t *this, certificate_t *other) | |
537 | { | |
538 | chunk_t encoding; | |
539 | bool equal; | |
540 | ||
541 | if (this == (private_openssl_x509_t*)other) | |
542 | { | |
543 | return TRUE; | |
544 | } | |
545 | if (other->get_type(other) != CERT_X509) | |
546 | { | |
547 | return FALSE; | |
548 | } | |
549 | if (other->equals == (void*)equals) | |
550 | { /* skip allocation if we have the same implementation */ | |
551 | encoding = ((private_openssl_x509_t*)other)->encoding; | |
552 | return chunk_equals(this->encoding, encoding); | |
553 | } | |
0406eeaa MW |
554 | if (!other->get_encoding(other, CERT_ASN1_DER, &encoding)) |
555 | { | |
556 | return FALSE; | |
557 | } | |
5728c6aa MW |
558 | equal = chunk_equals(this->encoding, encoding); |
559 | free(encoding.ptr); | |
560 | return equal; | |
561 | } | |
562 | ||
563 | METHOD(certificate_t, get_ref, certificate_t*, | |
564 | private_openssl_x509_t *this) | |
565 | { | |
566 | ref_get(&this->ref); | |
567 | return &this->public.x509.interface; | |
568 | } | |
569 | ||
570 | METHOD(certificate_t, destroy, void, | |
571 | private_openssl_x509_t *this) | |
572 | { | |
573 | if (ref_put(&this->ref)) | |
574 | { | |
575 | if (this->x509) | |
576 | { | |
577 | X509_free(this->x509); | |
578 | } | |
fb63012e | 579 | signature_params_destroy(this->scheme); |
5728c6aa MW |
580 | DESTROY_IF(this->subject); |
581 | DESTROY_IF(this->issuer); | |
582 | DESTROY_IF(this->pubkey); | |
583 | free(this->subjectKeyIdentifier.ptr); | |
584 | free(this->authKeyIdentifier.ptr); | |
585 | free(this->encoding.ptr); | |
586 | free(this->hash.ptr); | |
587 | this->subjectAltNames->destroy_offset(this->subjectAltNames, | |
588 | offsetof(identification_t, destroy)); | |
589 | this->issuerAltNames->destroy_offset(this->issuerAltNames, | |
590 | offsetof(identification_t, destroy)); | |
4e7b7db6 TB |
591 | this->crl_uris->destroy_function(this->crl_uris, |
592 | (void*)x509_cdp_destroy); | |
5728c6aa | 593 | this->ocsp_uris->destroy_function(this->ocsp_uris, free); |
5e4b1ad2 MR |
594 | this->ipAddrBlocks->destroy_offset(this->ipAddrBlocks, |
595 | offsetof(traffic_selector_t, destroy)); | |
f781b9d3 TB |
596 | this->permitted_names->destroy_offset(this->permitted_names, |
597 | offsetof(identification_t, destroy)); | |
598 | this->excluded_names->destroy_offset(this->excluded_names, | |
599 | offsetof(identification_t, destroy)); | |
5728c6aa MW |
600 | free(this); |
601 | } | |
602 | } | |
603 | ||
604 | /** | |
605 | * Create an empty certificate | |
606 | */ | |
607 | static private_openssl_x509_t *create_empty() | |
608 | { | |
609 | private_openssl_x509_t *this; | |
610 | ||
611 | INIT(this, | |
612 | .public = { | |
613 | .x509 = { | |
614 | .interface = { | |
615 | .get_type = _get_type, | |
616 | .get_subject = _get_subject, | |
617 | .get_issuer = _get_issuer, | |
618 | .has_subject = _has_subject, | |
619 | .has_issuer = _has_issuer, | |
620 | .issued_by = _issued_by, | |
621 | .get_public_key = _get_public_key, | |
622 | .get_validity = _get_validity, | |
5728c6aa MW |
623 | .get_encoding = _get_encoding, |
624 | .equals = _equals, | |
625 | .get_ref = _get_ref, | |
626 | .destroy = _destroy, | |
627 | }, | |
628 | .get_flags = _get_flags, | |
629 | .get_serial = _get_serial, | |
630 | .get_subjectKeyIdentifier = _get_subjectKeyIdentifier, | |
631 | .get_authKeyIdentifier = _get_authKeyIdentifier, | |
b3d359e5 | 632 | .get_constraint = _get_constraint, |
5728c6aa MW |
633 | .create_subjectAltName_enumerator = _create_subjectAltName_enumerator, |
634 | .create_crl_uri_enumerator = _create_crl_uri_enumerator, | |
635 | .create_ocsp_uri_enumerator = _create_ocsp_uri_enumerator, | |
5e4b1ad2 | 636 | .create_ipAddrBlock_enumerator = _create_ipAddrBlock_enumerator, |
f781b9d3 | 637 | .create_name_constraint_enumerator = _create_name_constraint_enumerator, |
20bd7810 | 638 | .create_cert_policy_enumerator = (void*)enumerator_create_empty, |
5a0caa4b | 639 | .create_policy_mapping_enumerator = (void*)enumerator_create_empty, |
5728c6aa MW |
640 | }, |
641 | }, | |
642 | .subjectAltNames = linked_list_create(), | |
643 | .issuerAltNames = linked_list_create(), | |
644 | .crl_uris = linked_list_create(), | |
645 | .ocsp_uris = linked_list_create(), | |
5e4b1ad2 | 646 | .ipAddrBlocks = linked_list_create(), |
f781b9d3 TB |
647 | .permitted_names = linked_list_create(), |
648 | .excluded_names = linked_list_create(), | |
5dba5852 | 649 | .pathlen = X509_NO_CONSTRAINT, |
5728c6aa MW |
650 | .ref = 1, |
651 | ); | |
652 | ||
653 | return this; | |
654 | } | |
655 | ||
656 | /** | |
b3ab7a48 | 657 | * parse an extension containing GENERAL_NAMES into a list |
5728c6aa MW |
658 | */ |
659 | static bool parse_generalNames_ext(linked_list_t *list, | |
660 | X509_EXTENSION *ext) | |
661 | { | |
662 | GENERAL_NAMES *names; | |
663 | GENERAL_NAME *name; | |
664 | identification_t *id; | |
665 | int i, num; | |
666 | ||
667 | names = X509V3_EXT_d2i(ext); | |
668 | if (!names) | |
669 | { | |
670 | return FALSE; | |
671 | } | |
672 | ||
673 | num = sk_GENERAL_NAME_num(names); | |
674 | for (i = 0; i < num; i++) | |
675 | { | |
676 | name = sk_GENERAL_NAME_value(names, i); | |
677 | id = general_name2id(name); | |
678 | if (id) | |
679 | { | |
680 | list->insert_last(list, id); | |
681 | } | |
682 | GENERAL_NAME_free(name); | |
683 | } | |
684 | sk_GENERAL_NAME_free(names); | |
685 | return TRUE; | |
686 | } | |
687 | ||
688 | /** | |
689 | * parse basic constraints | |
690 | */ | |
691 | static bool parse_basicConstraints_ext(private_openssl_x509_t *this, | |
692 | X509_EXTENSION *ext) | |
693 | { | |
694 | BASIC_CONSTRAINTS *constraints; | |
d390b3b9 | 695 | long pathlen; |
5728c6aa MW |
696 | |
697 | constraints = (BASIC_CONSTRAINTS*)X509V3_EXT_d2i(ext); | |
698 | if (constraints) | |
699 | { | |
700 | if (constraints->ca) | |
701 | { | |
702 | this->flags |= X509_CA; | |
703 | } | |
704 | if (constraints->pathlen) | |
705 | { | |
28bcbc29 | 706 | |
d390b3b9 AS |
707 | pathlen = ASN1_INTEGER_get(constraints->pathlen); |
708 | this->pathlen = (pathlen >= 0 && pathlen < 128) ? | |
709 | pathlen : X509_NO_CONSTRAINT; | |
5728c6aa MW |
710 | } |
711 | BASIC_CONSTRAINTS_free(constraints); | |
712 | return TRUE; | |
713 | } | |
714 | return FALSE; | |
715 | } | |
716 | ||
28bcbc29 TB |
717 | /** |
718 | * parse key usage | |
719 | */ | |
720 | static bool parse_keyUsage_ext(private_openssl_x509_t *this, | |
721 | X509_EXTENSION *ext) | |
722 | { | |
723 | ASN1_BIT_STRING *usage; | |
724 | ||
725 | usage = X509V3_EXT_d2i(ext); | |
726 | if (usage) | |
727 | { | |
728 | if (usage->length > 0) | |
729 | { | |
730 | int flags = usage->data[0]; | |
731 | if (usage->length > 1) | |
732 | { | |
733 | flags |= usage->data[1] << 8; | |
734 | } | |
e793d65a | 735 | if (flags & X509v3_KU_CRL_SIGN) |
28bcbc29 | 736 | { |
e793d65a TB |
737 | this->flags |= X509_CRL_SIGN; |
738 | } | |
504e1232 TB |
739 | if (flags & X509v3_KU_DIGITAL_SIGNATURE || |
740 | flags & X509v3_KU_NON_REPUDIATION) | |
741 | { | |
742 | this->flags |= X509_IKE_COMPLIANT; | |
743 | } | |
e793d65a TB |
744 | if (flags & X509v3_KU_KEY_CERT_SIGN) |
745 | { | |
b3ab7a48 | 746 | /* we use the caBasicConstraint, MUST be set */ |
28bcbc29 TB |
747 | } |
748 | } | |
749 | ASN1_BIT_STRING_free(usage); | |
750 | return TRUE; | |
751 | } | |
752 | return FALSE; | |
753 | } | |
754 | ||
c3e7b3de MW |
755 | /** |
756 | * Parse ExtendedKeyUsage | |
757 | */ | |
758 | static bool parse_extKeyUsage_ext(private_openssl_x509_t *this, | |
759 | X509_EXTENSION *ext) | |
760 | { | |
761 | EXTENDED_KEY_USAGE *usage; | |
762 | int i; | |
763 | ||
764 | usage = X509V3_EXT_d2i(ext); | |
765 | if (usage) | |
766 | { | |
767 | for (i = 0; i < sk_ASN1_OBJECT_num(usage); i++) | |
768 | { | |
769 | switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(usage, i))) | |
770 | { | |
771 | case NID_server_auth: | |
772 | this->flags |= X509_SERVER_AUTH; | |
773 | break; | |
774 | case NID_client_auth: | |
775 | this->flags |= X509_CLIENT_AUTH; | |
776 | break; | |
777 | case NID_OCSP_sign: | |
778 | this->flags |= X509_OCSP_SIGNER; | |
779 | break; | |
780 | default: | |
781 | break; | |
782 | } | |
783 | } | |
784 | sk_ASN1_OBJECT_pop_free(usage, ASN1_OBJECT_free); | |
785 | return TRUE; | |
786 | } | |
787 | return FALSE; | |
788 | } | |
789 | ||
5728c6aa MW |
790 | /** |
791 | * Parse CRL distribution points | |
792 | */ | |
86c10a95 TB |
793 | bool openssl_parse_crlDistributionPoints(X509_EXTENSION *ext, |
794 | linked_list_t *list) | |
5728c6aa MW |
795 | { |
796 | CRL_DIST_POINTS *cdps; | |
797 | DIST_POINT *cdp; | |
a6478a04 MW |
798 | identification_t *id, *issuer; |
799 | x509_cdp_t *entry; | |
5728c6aa | 800 | char *uri; |
86c10a95 | 801 | int i, j, k, point_num, name_num, issuer_num, len; |
5728c6aa MW |
802 | |
803 | cdps = X509V3_EXT_d2i(ext); | |
804 | if (!cdps) | |
805 | { | |
806 | return FALSE; | |
807 | } | |
808 | point_num = sk_DIST_POINT_num(cdps); | |
809 | for (i = 0; i < point_num; i++) | |
810 | { | |
811 | cdp = sk_DIST_POINT_value(cdps, i); | |
812 | if (cdp) | |
813 | { | |
814 | if (cdp->distpoint && cdp->distpoint->type == 0 && | |
815 | cdp->distpoint->name.fullname) | |
816 | { | |
817 | name_num = sk_GENERAL_NAME_num(cdp->distpoint->name.fullname); | |
818 | for (j = 0; j < name_num; j++) | |
819 | { | |
820 | id = general_name2id(sk_GENERAL_NAME_value( | |
821 | cdp->distpoint->name.fullname, j)); | |
822 | if (id) | |
823 | { | |
86c10a95 TB |
824 | len = asprintf(&uri, "%Y", id); |
825 | if (!len) | |
826 | { | |
827 | free(uri); | |
828 | } | |
829 | else if (len > 0) | |
5728c6aa | 830 | { |
a6478a04 MW |
831 | if (cdp->CRLissuer) |
832 | { | |
833 | issuer_num = sk_GENERAL_NAME_num(cdp->CRLissuer); | |
834 | for (k = 0; k < issuer_num; k++) | |
835 | { | |
836 | issuer = general_name2id( | |
837 | sk_GENERAL_NAME_value(cdp->CRLissuer, k)); | |
838 | if (issuer) | |
839 | { | |
840 | INIT(entry, | |
841 | .uri = strdup(uri), | |
842 | .issuer = issuer, | |
843 | ); | |
86c10a95 | 844 | list->insert_last(list, entry); |
a6478a04 MW |
845 | } |
846 | } | |
847 | free(uri); | |
848 | } | |
849 | else | |
850 | { | |
851 | INIT(entry, | |
852 | .uri = uri, | |
853 | ); | |
86c10a95 | 854 | list->insert_last(list, entry); |
a6478a04 | 855 | } |
5728c6aa MW |
856 | } |
857 | id->destroy(id); | |
858 | } | |
859 | } | |
860 | } | |
a6478a04 | 861 | |
5728c6aa MW |
862 | DIST_POINT_free(cdp); |
863 | } | |
864 | } | |
865 | sk_DIST_POINT_free(cdps); | |
866 | return TRUE; | |
867 | } | |
868 | ||
869 | /** | |
870 | * Parse authorityInfoAccess with OCSP URIs | |
871 | */ | |
872 | static bool parse_authorityInfoAccess_ext(private_openssl_x509_t *this, | |
873 | X509_EXTENSION *ext) | |
874 | { | |
875 | AUTHORITY_INFO_ACCESS *infos; | |
876 | ACCESS_DESCRIPTION *desc; | |
877 | identification_t *id; | |
86c10a95 | 878 | int i, num, len; |
5728c6aa MW |
879 | char *uri; |
880 | ||
881 | infos = X509V3_EXT_d2i(ext); | |
882 | if (!infos) | |
883 | { | |
884 | return FALSE; | |
885 | } | |
886 | num = sk_ACCESS_DESCRIPTION_num(infos); | |
887 | for (i = 0; i < num; i++) | |
888 | { | |
889 | desc = sk_ACCESS_DESCRIPTION_value(infos, i); | |
890 | if (desc) | |
891 | { | |
892 | if (openssl_asn1_known_oid(desc->method) == OID_OCSP) | |
893 | { | |
894 | id = general_name2id(desc->location); | |
895 | if (id) | |
896 | { | |
86c10a95 TB |
897 | len = asprintf(&uri, "%Y", id); |
898 | if (!len) | |
899 | { | |
900 | free(uri); | |
901 | } | |
902 | else if (len > 0) | |
5728c6aa | 903 | { |
93818392 | 904 | this->ocsp_uris->insert_last(this->ocsp_uris, uri); |
5728c6aa MW |
905 | } |
906 | id->destroy(id); | |
907 | } | |
908 | } | |
909 | ACCESS_DESCRIPTION_free(desc); | |
910 | } | |
911 | } | |
912 | sk_ACCESS_DESCRIPTION_free(infos); | |
913 | return TRUE; | |
914 | } | |
915 | ||
5e4b1ad2 MR |
916 | #ifndef OPENSSL_NO_RFC3779 |
917 | ||
918 | /** | |
919 | * Parse a single block of ipAddrBlock extension | |
920 | */ | |
921 | static void parse_ipAddrBlock_ext_fam(private_openssl_x509_t *this, | |
922 | IPAddressFamily *fam) | |
923 | { | |
924 | const IPAddressOrRanges *list; | |
925 | IPAddressOrRange *aor; | |
926 | traffic_selector_t *ts; | |
927 | ts_type_t type; | |
928 | chunk_t from, to; | |
929 | int i, afi; | |
930 | ||
931 | if (fam->ipAddressChoice->type != IPAddressChoice_addressesOrRanges) | |
932 | { | |
933 | return; | |
934 | } | |
935 | ||
08d7e1f1 | 936 | afi = X509v3_addr_get_afi(fam); |
5e4b1ad2 MR |
937 | switch (afi) |
938 | { | |
939 | case IANA_AFI_IPV4: | |
940 | from = chunk_alloca(4); | |
941 | to = chunk_alloca(4); | |
942 | type = TS_IPV4_ADDR_RANGE; | |
943 | break; | |
944 | case IANA_AFI_IPV6: | |
945 | from = chunk_alloca(16); | |
946 | to = chunk_alloca(16); | |
947 | type = TS_IPV6_ADDR_RANGE; | |
948 | break; | |
949 | default: | |
950 | return; | |
951 | } | |
952 | ||
953 | list = fam->ipAddressChoice->u.addressesOrRanges; | |
954 | for (i = 0; i < sk_IPAddressOrRange_num(list); i++) | |
955 | { | |
956 | aor = sk_IPAddressOrRange_value(list, i); | |
08d7e1f1 | 957 | if (X509v3_addr_get_range(aor, afi, from.ptr, to.ptr, from.len) > 0) |
5e4b1ad2 MR |
958 | { |
959 | ts = traffic_selector_create_from_bytes(0, type, from, 0, to, 65535); | |
960 | if (ts) | |
961 | { | |
962 | this->ipAddrBlocks->insert_last(this->ipAddrBlocks, ts); | |
963 | } | |
964 | } | |
965 | } | |
966 | } | |
967 | ||
968 | /** | |
969 | * Parse ipAddrBlock extension | |
970 | */ | |
971 | static bool parse_ipAddrBlock_ext(private_openssl_x509_t *this, | |
972 | X509_EXTENSION *ext) | |
973 | { | |
974 | STACK_OF(IPAddressFamily) *blocks; | |
975 | IPAddressFamily *fam; | |
976 | ||
977 | blocks = (STACK_OF(IPAddressFamily)*)X509V3_EXT_d2i(ext); | |
978 | if (!blocks) | |
979 | { | |
980 | return FALSE; | |
981 | } | |
982 | ||
08d7e1f1 | 983 | if (!X509v3_addr_is_canonical(blocks)) |
5e4b1ad2 MR |
984 | { |
985 | sk_IPAddressFamily_free(blocks); | |
986 | return FALSE; | |
987 | } | |
988 | ||
989 | while (sk_IPAddressFamily_num(blocks) > 0) | |
990 | { | |
991 | fam = sk_IPAddressFamily_pop(blocks); | |
992 | parse_ipAddrBlock_ext_fam(this, fam); | |
993 | IPAddressFamily_free(fam); | |
994 | } | |
995 | sk_IPAddressFamily_free(blocks); | |
996 | ||
997 | this->flags |= X509_IP_ADDR_BLOCKS; | |
998 | return TRUE; | |
999 | } | |
1000 | #endif /* !OPENSSL_NO_RFC3779 */ | |
1001 | ||
f781b9d3 TB |
1002 | /** |
1003 | * Parse a "generalSubtree" structure (sequence of generalNames) | |
1004 | */ | |
1005 | static bool parse_generalSubtrees(linked_list_t *list, | |
1006 | STACK_OF(GENERAL_SUBTREE) *subtrees) | |
1007 | { | |
1008 | GENERAL_SUBTREE *subtree; | |
1009 | identification_t *id; | |
1010 | int i; | |
1011 | ||
1012 | for (i = 0; i < sk_GENERAL_SUBTREE_num(subtrees); i++) | |
1013 | { | |
1014 | subtree = sk_GENERAL_SUBTREE_value(subtrees, i); | |
1015 | id = general_name2id(subtree->base); | |
1016 | if (id) | |
1017 | { | |
1018 | list->insert_last(list, id); | |
1019 | } | |
1020 | else | |
1021 | { | |
1022 | return FALSE; | |
1023 | } | |
1024 | } | |
1025 | return TRUE; | |
1026 | } | |
1027 | ||
1028 | /** | |
1029 | * Parse permitted/excluded nameConstraints | |
1030 | */ | |
1031 | static bool parse_nameConstraints_ext(private_openssl_x509_t *this, | |
1032 | X509_EXTENSION *ext) | |
1033 | { | |
1034 | NAME_CONSTRAINTS *nc; | |
1035 | bool ok = FALSE; | |
1036 | ||
1037 | nc = (NAME_CONSTRAINTS*)X509V3_EXT_d2i(ext); | |
1038 | if (nc) | |
1039 | { | |
1040 | ok = parse_generalSubtrees(this->permitted_names, nc->permittedSubtrees) && | |
1041 | parse_generalSubtrees(this->excluded_names, nc->excludedSubtrees); | |
1042 | NAME_CONSTRAINTS_free(nc); | |
1043 | } | |
1044 | return ok; | |
1045 | } | |
1046 | ||
5728c6aa MW |
1047 | /** |
1048 | * Parse authorityKeyIdentifier extension | |
1049 | */ | |
1050 | static bool parse_authKeyIdentifier_ext(private_openssl_x509_t *this, | |
1051 | X509_EXTENSION *ext) | |
1052 | { | |
1053 | AUTHORITY_KEYID *keyid; | |
1054 | ||
1055 | keyid = (AUTHORITY_KEYID*)X509V3_EXT_d2i(ext); | |
1056 | if (keyid) | |
1057 | { | |
1058 | free(this->authKeyIdentifier.ptr); | |
1059 | this->authKeyIdentifier = chunk_clone( | |
1060 | openssl_asn1_str2chunk(keyid->keyid)); | |
1061 | AUTHORITY_KEYID_free(keyid); | |
1062 | return TRUE; | |
1063 | } | |
1064 | return FALSE; | |
1065 | } | |
1066 | ||
1067 | /** | |
1068 | * Parse subjectKeyIdentifier extension | |
1069 | */ | |
1070 | static bool parse_subjectKeyIdentifier_ext(private_openssl_x509_t *this, | |
1071 | X509_EXTENSION *ext) | |
1072 | { | |
f00a1015 MW |
1073 | chunk_t ostr; |
1074 | ||
1075 | ostr = openssl_asn1_str2chunk(X509_EXTENSION_get_data(ext)); | |
1076 | /* quick and dirty unwrap of octet string */ | |
1077 | if (ostr.len > 2 && | |
1078 | ostr.ptr[0] == V_ASN1_OCTET_STRING && ostr.ptr[1] == ostr.len - 2) | |
1079 | { | |
1080 | free(this->subjectKeyIdentifier.ptr); | |
1081 | this->subjectKeyIdentifier = chunk_clone(chunk_skip(ostr, 2)); | |
1082 | return TRUE; | |
1083 | } | |
1084 | return FALSE; | |
5728c6aa MW |
1085 | } |
1086 | ||
1087 | /** | |
1088 | * Parse X509 extensions we are interested in | |
1089 | */ | |
1090 | static bool parse_extensions(private_openssl_x509_t *this) | |
1091 | { | |
8b4c2a1d | 1092 | const STACK_OF(X509_EXTENSION) *extensions; |
d12a4f5d | 1093 | bool key_usage_parsed = FALSE; |
5728c6aa MW |
1094 | int i, num; |
1095 | ||
08d7e1f1 | 1096 | extensions = X509_get0_extensions(this->x509); |
5728c6aa MW |
1097 | if (extensions) |
1098 | { | |
1099 | num = sk_X509_EXTENSION_num(extensions); | |
1100 | ||
1101 | for (i = 0; i < num; i++) | |
1102 | { | |
1103 | X509_EXTENSION *ext; | |
1104 | bool ok; | |
1105 | ||
1106 | ext = sk_X509_EXTENSION_value(extensions, i); | |
1107 | switch (OBJ_obj2nid(X509_EXTENSION_get_object(ext))) | |
1108 | { | |
1109 | case NID_info_access: | |
1110 | ok = parse_authorityInfoAccess_ext(this, ext); | |
1111 | break; | |
1112 | case NID_authority_key_identifier: | |
1113 | ok = parse_authKeyIdentifier_ext(this, ext); | |
1114 | break; | |
1115 | case NID_subject_key_identifier: | |
1116 | ok = parse_subjectKeyIdentifier_ext(this, ext); | |
1117 | break; | |
1118 | case NID_subject_alt_name: | |
1119 | ok = parse_generalNames_ext(this->subjectAltNames, ext); | |
1120 | break; | |
1121 | case NID_issuer_alt_name: | |
1122 | ok = parse_generalNames_ext(this->issuerAltNames, ext); | |
1123 | break; | |
1124 | case NID_basic_constraints: | |
1125 | ok = parse_basicConstraints_ext(this, ext); | |
1126 | break; | |
28bcbc29 TB |
1127 | case NID_key_usage: |
1128 | ok = parse_keyUsage_ext(this, ext); | |
d12a4f5d | 1129 | key_usage_parsed = TRUE; |
28bcbc29 | 1130 | break; |
c3e7b3de MW |
1131 | case NID_ext_key_usage: |
1132 | ok = parse_extKeyUsage_ext(this, ext); | |
1133 | break; | |
5728c6aa | 1134 | case NID_crl_distribution_points: |
86c10a95 | 1135 | ok = openssl_parse_crlDistributionPoints(ext, this->crl_uris); |
5728c6aa | 1136 | break; |
5e4b1ad2 MR |
1137 | #ifndef OPENSSL_NO_RFC3779 |
1138 | case NID_sbgp_ipAddrBlock: | |
1139 | ok = parse_ipAddrBlock_ext(this, ext); | |
1140 | break; | |
1141 | #endif /* !OPENSSL_NO_RFC3779 */ | |
f781b9d3 TB |
1142 | case NID_name_constraints: |
1143 | ok = parse_nameConstraints_ext(this, ext); | |
1144 | break; | |
5728c6aa | 1145 | default: |
c4fd3b2f AS |
1146 | ok = X509_EXTENSION_get_critical(ext) == 0 || |
1147 | !lib->settings->get_bool(lib->settings, | |
8dc6e716 | 1148 | "%s.x509.enforce_critical", TRUE, lib->ns); |
b0892d09 MW |
1149 | if (!ok) |
1150 | { | |
3f55f203 MW |
1151 | char buf[80] = ""; |
1152 | ||
1153 | OBJ_obj2txt(buf, sizeof(buf), | |
1154 | X509_EXTENSION_get_object(ext), 0); | |
1155 | DBG1(DBG_LIB, "found unsupported critical X.509 " | |
1156 | "extension: %s", buf); | |
b0892d09 | 1157 | } |
5728c6aa MW |
1158 | break; |
1159 | } | |
1160 | if (!ok) | |
1161 | { | |
1162 | return FALSE; | |
1163 | } | |
1164 | } | |
1165 | } | |
d12a4f5d TB |
1166 | if (!key_usage_parsed) |
1167 | { | |
1168 | /* we are compliant with RFC 4945 without keyUsage extension */ | |
1169 | this->flags |= X509_IKE_COMPLIANT; | |
1170 | /* allow CA certificates without keyUsage extension to sign CRLs */ | |
1171 | if (this->flags & X509_CA) | |
1172 | { | |
1173 | this->flags |= X509_CRL_SIGN; | |
1174 | } | |
1175 | } | |
5728c6aa MW |
1176 | return TRUE; |
1177 | } | |
1178 | ||
1179 | /** | |
1180 | * Parse a DER encoded x509 certificate | |
1181 | */ | |
1182 | static bool parse_certificate(private_openssl_x509_t *this) | |
1183 | { | |
1184 | const unsigned char *ptr = this->encoding.ptr; | |
1185 | hasher_t *hasher; | |
fb63012e TB |
1186 | chunk_t chunk, sig_scheme, sig_scheme_tbs; |
1187 | ASN1_OBJECT *oid; | |
8b4c2a1d TB |
1188 | #if OPENSSL_VERSION_NUMBER >= 0x10100000L |
1189 | const X509_ALGOR *alg; | |
1190 | #else | |
08d7e1f1 | 1191 | X509_ALGOR *alg; |
8b4c2a1d | 1192 | #endif |
85a35fc9 | 1193 | key_type_t ed_type = KEY_ED448; |
5728c6aa MW |
1194 | |
1195 | this->x509 = d2i_X509(NULL, &ptr, this->encoding.len); | |
1196 | if (!this->x509) | |
1197 | { | |
1198 | return FALSE; | |
1199 | } | |
a6850b84 MW |
1200 | if (X509_get_version(this->x509) < 0 || X509_get_version(this->x509) > 2) |
1201 | { | |
1202 | DBG1(DBG_LIB, "unsupported x509 version: %d", | |
1203 | X509_get_version(this->x509) + 1); | |
1204 | return FALSE; | |
1205 | } | |
1206 | ||
5728c6aa MW |
1207 | this->subject = openssl_x509_name2id(X509_get_subject_name(this->x509)); |
1208 | this->issuer = openssl_x509_name2id(X509_get_issuer_name(this->x509)); | |
1209 | ||
08d7e1f1 TB |
1210 | if (!X509_PUBKEY_get0_param(&oid, NULL, NULL, NULL, |
1211 | X509_get_X509_PUBKEY(this->x509))) | |
1212 | { | |
1213 | return FALSE; | |
1214 | } | |
1215 | switch (openssl_asn1_known_oid(oid)) | |
5728c6aa | 1216 | { |
364395d2 TB |
1217 | case OID_RSASSA_PSS: |
1218 | /* TODO: we should treat such keys special and use the params as | |
1219 | * restrictions regarding the use of this key (or rather the | |
1220 | * associated private key) */ | |
5728c6aa MW |
1221 | case OID_RSA_ENCRYPTION: |
1222 | this->pubkey = lib->creds->create(lib->creds, | |
1223 | CRED_PUBLIC_KEY, KEY_RSA, BUILD_BLOB_ASN1_DER, | |
1224 | openssl_asn1_str2chunk(X509_get0_pubkey_bitstr(this->x509)), | |
1225 | BUILD_END); | |
1226 | break; | |
1227 | case OID_EC_PUBLICKEY: | |
1228 | /* for ECDSA, we need the full subjectPublicKeyInfo, as it contains | |
1229 | * the curve parameters. */ | |
1230 | chunk = openssl_i2chunk(X509_PUBKEY, X509_get_X509_PUBKEY(this->x509)); | |
1231 | this->pubkey = lib->creds->create(lib->creds, | |
1232 | CRED_PUBLIC_KEY, KEY_ECDSA, BUILD_BLOB_ASN1_DER, | |
1233 | chunk, BUILD_END); | |
1234 | free(chunk.ptr); | |
1235 | break; | |
85a35fc9 TB |
1236 | case OID_ED25519: |
1237 | ed_type = KEY_ED25519; | |
1238 | /* fall-through */ | |
1239 | case OID_ED448: | |
1240 | /* for EdDSA, the parsers expect the full subjectPublicKeyInfo */ | |
1241 | chunk = openssl_i2chunk(X509_PUBKEY, X509_get_X509_PUBKEY(this->x509)); | |
1242 | this->pubkey = lib->creds->create(lib->creds, | |
1243 | CRED_PUBLIC_KEY, ed_type, BUILD_BLOB_ASN1_DER, | |
1244 | chunk, BUILD_END); | |
1245 | free(chunk.ptr); | |
1246 | break; | |
5728c6aa MW |
1247 | default: |
1248 | DBG1(DBG_LIB, "unsupported public key algorithm"); | |
1249 | break; | |
1250 | } | |
1251 | if (!this->subject || !this->issuer || !this->pubkey) | |
1252 | { | |
1253 | return FALSE; | |
1254 | } | |
1255 | ||
a4abb263 TB |
1256 | this->notBefore = openssl_asn1_to_time(X509_get0_notBefore(this->x509)); |
1257 | this->notAfter = openssl_asn1_to_time(X509_get0_notAfter(this->x509)); | |
5728c6aa | 1258 | |
08d7e1f1 TB |
1259 | /* while X509_ALGOR_cmp() is declared in the headers of older OpenSSL |
1260 | * versions, at least on Ubuntu 14.04 it is not actually defined */ | |
1261 | X509_get0_signature(NULL, &alg, this->x509); | |
8b4c2a1d | 1262 | sig_scheme = openssl_i2chunk(X509_ALGOR, (X509_ALGOR*)alg); |
08d7e1f1 | 1263 | alg = X509_get0_tbs_sigalg(this->x509); |
8b4c2a1d | 1264 | sig_scheme_tbs = openssl_i2chunk(X509_ALGOR, (X509_ALGOR*)alg); |
fb63012e TB |
1265 | if (!chunk_equals(sig_scheme, sig_scheme_tbs)) |
1266 | { | |
1267 | free(sig_scheme_tbs.ptr); | |
1268 | free(sig_scheme.ptr); | |
1269 | return FALSE; | |
1270 | } | |
1271 | free(sig_scheme_tbs.ptr); | |
1272 | ||
1273 | INIT(this->scheme); | |
1274 | if (!signature_params_parse(sig_scheme, 0, this->scheme)) | |
5728c6aa | 1275 | { |
fb63012e TB |
1276 | DBG1(DBG_ASN, "unable to parse signature algorithm"); |
1277 | free(sig_scheme.ptr); | |
5728c6aa MW |
1278 | return FALSE; |
1279 | } | |
fb63012e | 1280 | free(sig_scheme.ptr); |
5728c6aa MW |
1281 | |
1282 | if (!parse_extensions(this)) | |
1283 | { | |
c4fd3b2f | 1284 | return FALSE; |
5728c6aa MW |
1285 | } |
1286 | ||
1287 | hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); | |
87dd205b | 1288 | if (!hasher || !hasher->allocate_hash(hasher, this->encoding, &this->hash)) |
5728c6aa | 1289 | { |
87dd205b | 1290 | DESTROY_IF(hasher); |
5728c6aa MW |
1291 | return FALSE; |
1292 | } | |
5728c6aa MW |
1293 | hasher->destroy(hasher); |
1294 | ||
a37f2d20 | 1295 | if (issued_by(this, &this->public.x509.interface, NULL)) |
5728c6aa MW |
1296 | { |
1297 | this->flags |= X509_SELF_SIGNED; | |
1298 | } | |
1299 | return TRUE; | |
1300 | } | |
1301 | ||
1302 | openssl_x509_t *openssl_x509_load(certificate_type_t type, va_list args) | |
1303 | { | |
1304 | chunk_t blob = chunk_empty; | |
1305 | x509_flag_t flags = 0; | |
1306 | ||
1307 | while (TRUE) | |
1308 | { | |
1309 | switch (va_arg(args, builder_part_t)) | |
1310 | { | |
1311 | case BUILD_BLOB_ASN1_DER: | |
1312 | blob = va_arg(args, chunk_t); | |
1313 | continue; | |
1314 | case BUILD_X509_FLAG: | |
1315 | flags |= va_arg(args, x509_flag_t); | |
1316 | continue; | |
1317 | case BUILD_END: | |
1318 | break; | |
1319 | default: | |
1320 | return NULL; | |
1321 | } | |
1322 | break; | |
1323 | } | |
1324 | ||
1325 | if (blob.ptr) | |
1326 | { | |
1327 | private_openssl_x509_t *this; | |
1328 | ||
1329 | this = create_empty(); | |
1330 | this->encoding = chunk_clone(blob); | |
1331 | this->flags |= flags; | |
1332 | if (parse_certificate(this)) | |
1333 | { | |
1334 | return &this->public; | |
1335 | } | |
1336 | DBG1(DBG_LIB, "OpenSSL X.509 parsing failed"); | |
1337 | destroy(this); | |
1338 | } | |
1339 | return NULL; | |
1340 | } |