]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/plugins/openssl/openssl_x509.c
Slightly renamed X509_NO_PATH_LEN_CONSTRAINT to use it for PolicyConstraints, too
[thirdparty/strongswan.git] / src / libstrongswan / plugins / openssl / openssl_x509.c
CommitLineData
5728c6aa
MW
1/*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16/*
17 * Copyright (C) 2010 secunet Security Networks AG
18 * Copyright (C) 2010 Thomas Egerer
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining a copy
21 * of this software and associated documentation files (the "Software"), to deal
22 * in the Software without restriction, including without limitation the rights
23 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24 * copies of the Software, and to permit persons to whom the Software is
25 * furnished to do so, subject to the following conditions:
26 *
27 * The above copyright notice and this permission notice shall be included in
28 * all copies or substantial portions of the Software.
29 *
30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
36 * THE SOFTWARE.
37 */
38
39#define _GNU_SOURCE
40#include <stdio.h>
41#include <openssl/x509.h>
42#include <openssl/x509v3.h>
43
44#include "openssl_x509.h"
45#include "openssl_util.h"
46
47#include <debug.h>
48#include <asn1/oid.h>
49#include <utils/linked_list.h>
50
51
52typedef struct private_openssl_x509_t private_openssl_x509_t;
53
54/**
55 * Private data of an openssl_x509_t object.
56 */
57struct private_openssl_x509_t {
58
59 /**
60 * Public openssl_x509_t interface.
61 */
62 openssl_x509_t public;
63
64 /**
65 * OpenSSL certificate representation
66 */
67 X509 *x509;
68
69 /**
70 * DER encoded certificate
71 */
72 chunk_t encoding;
73
74 /**
75 * SHA1 hash of the certificate
76 */
77 chunk_t hash;
78
79 /**
80 * X509 flags
81 */
82 x509_flag_t flags;
83
84 /**
85 * Pathlen constraint
86 */
87 int pathlen;
88
89 /**
90 * certificate subject
91 */
92 identification_t *subject;
93
94 /**
95 * certificate issuer
96 */
97 identification_t *issuer;
98
99 /**
100 * Certificates public key
101 */
102 public_key_t *pubkey;
103
104 /**
105 * subjectKeyIdentifier as read from cert
106 */
107 chunk_t subjectKeyIdentifier;
108
109 /**
110 * authorityKeyIdentifier as read from cert
111 */
112 chunk_t authKeyIdentifier;
113
114 /**
115 * Start time of certificate validity
116 */
117 time_t notBefore;
118
119 /**
120 * End time of certificate validity
121 */
122 time_t notAfter;
123
124 /**
125 * Signature scheme of the certificate
126 */
127 signature_scheme_t scheme;
128
129 /**
130 * subjectAltNames
131 */
132 linked_list_t *subjectAltNames;
133
134 /**
135 * issuerAltNames
136 */
137 linked_list_t *issuerAltNames;
138
139 /**
4e508517 140 * List of CRL URIs, as crl_uri_t
5728c6aa
MW
141 */
142 linked_list_t *crl_uris;
143
144 /**
145 * List of OCSP URIs
146 */
147 linked_list_t *ocsp_uris;
148
149 /**
150 * References to this cert
151 */
152 refcount_t ref;
153};
154
4e508517
MW
155/**
156 * CRL URIs with associated issuer
157 */
158typedef struct {
159 identification_t *issuer;
160 linked_list_t *uris;
161} crl_uri_t;
162
163/**
164 * Create a new issuer entry
165 */
166static crl_uri_t *crl_uri_create()
167{
168 crl_uri_t *this;
169
170 INIT(this,
171 .uris = linked_list_create(),
172 );
173 return this;
174}
175
176/**
177 * Destroy a CRL URI struct
178 */
179static void crl_uri_destroy(crl_uri_t *this)
180{
181 this->uris->destroy_function(this->uris, free);
182 DESTROY_IF(this->issuer);
183 free(this);
184}
185
5728c6aa
MW
186/**
187 * Convert a GeneralName to an identification_t.
188 */
189static identification_t *general_name2id(GENERAL_NAME *name)
190{
191 if (!name)
192 {
193 return NULL;
194 }
195 switch (name->type)
196 {
197 case GEN_EMAIL:
198 return identification_create_from_encoding(ID_RFC822_ADDR,
199 openssl_asn1_str2chunk(name->d.rfc822Name));
200 case GEN_DNS:
201 return identification_create_from_encoding(ID_FQDN,
202 openssl_asn1_str2chunk(name->d.dNSName));
203 case GEN_URI:
204 return identification_create_from_encoding(ID_DER_ASN1_GN_URI,
205 openssl_asn1_str2chunk(name->d.uniformResourceIdentifier));
206 case GEN_IPADD:
07c5aacc
MW
207 {
208 chunk_t chunk = openssl_asn1_str2chunk(name->d.iPAddress);
209 if (chunk.len == 4)
210 {
211 return identification_create_from_encoding(ID_IPV4_ADDR, chunk);
212 }
213 if (chunk.len == 16)
214 {
215 return identification_create_from_encoding(ID_IPV6_ADDR, chunk);
216 }
217 return NULL;
218 }
5728c6aa
MW
219 case GEN_DIRNAME :
220 return openssl_x509_name2id(name->d.directoryName);
a0a8aaaf
MW
221 case GEN_OTHERNAME:
222 if (OBJ_obj2nid(name->d.otherName->type_id) == NID_ms_upn &&
223 name->d.otherName->value->type == V_ASN1_UTF8STRING)
224 {
225 return identification_create_from_encoding(ID_RFC822_ADDR,
226 openssl_asn1_str2chunk(
227 name->d.otherName->value->value.utf8string));
228 }
229 return NULL;
5728c6aa
MW
230 default:
231 return NULL;
232 }
233}
234
235METHOD(x509_t, get_flags, x509_flag_t,
236 private_openssl_x509_t *this)
237{
238 return this->flags;
239}
240
241METHOD(x509_t, get_serial, chunk_t,
242 private_openssl_x509_t *this)
243{
244 return openssl_asn1_str2chunk(X509_get_serialNumber(this->x509));
245}
246
247METHOD(x509_t, get_subjectKeyIdentifier, chunk_t,
248 private_openssl_x509_t *this)
249{
250 chunk_t fingerprint;
251
252 if (this->subjectKeyIdentifier.len)
253 {
254 return this->subjectKeyIdentifier;
255 }
da9724e6 256 if (this->pubkey->get_fingerprint(this->pubkey, KEYID_PUBKEY_SHA1,
5728c6aa
MW
257 &fingerprint))
258 {
259 return fingerprint;
260 }
261 return chunk_empty;
262}
263
264METHOD(x509_t, get_authKeyIdentifier, chunk_t,
265 private_openssl_x509_t *this)
266{
267 if (this->authKeyIdentifier.len)
268 {
269 return this->authKeyIdentifier;
270 }
271 return chunk_empty;
272}
273
274METHOD(x509_t, get_pathLenConstraint, int,
275 private_openssl_x509_t *this)
276{
277 return this->pathlen;
278}
279
280METHOD(x509_t, create_subjectAltName_enumerator, enumerator_t*,
281 private_openssl_x509_t *this)
282{
283 return this->subjectAltNames->create_enumerator(this->subjectAltNames);
284}
285
4e508517
MW
286/**
287 * Convert enumerator value from entry to (uri, issuer)
288 */
289static bool crl_enum_filter(identification_t *issuer_in,
290 char **uri_in, char **uri_out,
291 void *none_in, identification_t **issuer_out)
292{
293 *uri_out = *uri_in;
294 if (issuer_out)
295 {
296 *issuer_out = issuer_in;
297 }
298 return TRUE;
299}
300
301/**
302 * Create inner enumerator over URIs
303 */
304static enumerator_t *crl_enum_create(crl_uri_t *entry)
305{
306 return enumerator_create_filter(entry->uris->create_enumerator(entry->uris),
307 (void*)crl_enum_filter, entry->issuer, NULL);
308}
309
5728c6aa
MW
310METHOD(x509_t, create_crl_uri_enumerator, enumerator_t*,
311 private_openssl_x509_t *this)
312{
4e508517
MW
313 return enumerator_create_nested(
314 this->crl_uris->create_enumerator(this->crl_uris),
315 (void*)crl_enum_create, NULL, NULL);
5728c6aa
MW
316}
317
318METHOD(x509_t, create_ocsp_uri_enumerator, enumerator_t*,
319 private_openssl_x509_t *this)
320{
321 return this->ocsp_uris->create_enumerator(this->ocsp_uris);
322}
323
5728c6aa
MW
324METHOD(certificate_t, get_type, certificate_type_t,
325 private_openssl_x509_t *this)
326{
327 return CERT_X509;
328}
329
330METHOD(certificate_t, get_subject, identification_t*,
331 private_openssl_x509_t *this)
332{
333 return this->subject;
334}
335
336METHOD(certificate_t, get_issuer, identification_t*,
337 private_openssl_x509_t *this)
338{
339 return this->issuer;
340}
341
342METHOD(certificate_t, has_subject, id_match_t,
343 private_openssl_x509_t *this, identification_t *subject)
344{
345 identification_t *current;
346 enumerator_t *enumerator;
347 id_match_t match, best;
663e7355 348 chunk_t encoding;
5728c6aa
MW
349
350 if (subject->get_type(subject) == ID_KEY_ID)
351 {
663e7355
MW
352 encoding = subject->get_encoding(subject);
353
354 if (chunk_equals(this->hash, encoding))
355 {
356 return ID_MATCH_PERFECT;
357 }
358 if (this->subjectKeyIdentifier.len &&
359 chunk_equals(this->subjectKeyIdentifier, encoding))
360 {
361 return ID_MATCH_PERFECT;
362 }
363 if (this->pubkey &&
364 this->pubkey->has_fingerprint(this->pubkey, encoding))
5728c6aa
MW
365 {
366 return ID_MATCH_PERFECT;
367 }
368 }
369 best = this->subject->matches(this->subject, subject);
370 enumerator = create_subjectAltName_enumerator(this);
371 while (enumerator->enumerate(enumerator, &current))
372 {
373 match = current->matches(current, subject);
374 if (match > best)
375 {
376 best = match;
377 }
378 }
379 enumerator->destroy(enumerator);
380 return best;
381}
382
383METHOD(certificate_t, has_issuer, id_match_t,
384 private_openssl_x509_t *this, identification_t *issuer)
385{
386 /* issuerAltNames currently not supported */
387 return this->issuer->matches(this->issuer, issuer);
388}
389
390METHOD(certificate_t, issued_by, bool,
391 private_openssl_x509_t *this, certificate_t *issuer)
392{
393 public_key_t *key;
394 bool valid;
395 x509_t *x509 = (x509_t*)issuer;
396 chunk_t tbs;
397
398 if (&this->public.x509.interface == issuer)
399 {
400 if (this->flags & X509_SELF_SIGNED)
401 {
402 return TRUE;
403 }
404 }
405 else
406 {
407 if (issuer->get_type(issuer) != CERT_X509)
408 {
409 return FALSE;
410 }
411 if (!(x509->get_flags(x509) & X509_CA))
412 {
413 return FALSE;
414 }
415 if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer)))
416 {
417 return FALSE;
418 }
419 }
420 if (this->scheme == SIGN_UNKNOWN)
421 {
422 return FALSE;
423 }
424 key = issuer->get_public_key(issuer);
425 if (!key)
426 {
427 return FALSE;
428 }
429 tbs = openssl_i2chunk(X509_CINF, this->x509->cert_info);
430 valid = key->verify(key, this->scheme, tbs,
431 openssl_asn1_str2chunk(this->x509->signature));
432 free(tbs.ptr);
433 key->destroy(key);
434 return valid;
435}
436
437METHOD(certificate_t, get_public_key, public_key_t*,
438 private_openssl_x509_t *this)
439{
440 return this->pubkey->get_ref(this->pubkey);
441}
442
443METHOD(certificate_t, get_validity, bool,
444 private_openssl_x509_t *this,
445 time_t *when, time_t *not_before, time_t *not_after)
446{
447 time_t t;
448
449 if (when)
450 {
451 t = *when;
452 }
453 else
454 {
455 t = time(NULL);
456 }
457 if (not_before)
458 {
459 *not_before = this->notBefore;
460 }
461 if (not_after)
462 {
463 *not_after = this->notAfter;
464 }
465 return (t >= this->notBefore && t <= this->notAfter);
466}
467
0406eeaa
MW
468METHOD(certificate_t, get_encoding, bool,
469 private_openssl_x509_t *this, cred_encoding_type_t type, chunk_t *encoding)
5728c6aa 470{
0406eeaa
MW
471 if (type == CERT_ASN1_DER)
472 {
473 *encoding = chunk_clone(this->encoding);
474 return TRUE;
475 }
476 return lib->encoding->encode(lib->encoding, type, NULL, encoding,
477 CRED_PART_X509_ASN1_DER, this->encoding, CRED_PART_END);
5728c6aa
MW
478}
479
0406eeaa 480
5728c6aa
MW
481METHOD(certificate_t, equals, bool,
482 private_openssl_x509_t *this, certificate_t *other)
483{
484 chunk_t encoding;
485 bool equal;
486
487 if (this == (private_openssl_x509_t*)other)
488 {
489 return TRUE;
490 }
491 if (other->get_type(other) != CERT_X509)
492 {
493 return FALSE;
494 }
495 if (other->equals == (void*)equals)
496 { /* skip allocation if we have the same implementation */
497 encoding = ((private_openssl_x509_t*)other)->encoding;
498 return chunk_equals(this->encoding, encoding);
499 }
0406eeaa
MW
500 if (!other->get_encoding(other, CERT_ASN1_DER, &encoding))
501 {
502 return FALSE;
503 }
5728c6aa
MW
504 equal = chunk_equals(this->encoding, encoding);
505 free(encoding.ptr);
506 return equal;
507}
508
509METHOD(certificate_t, get_ref, certificate_t*,
510 private_openssl_x509_t *this)
511{
512 ref_get(&this->ref);
513 return &this->public.x509.interface;
514}
515
516METHOD(certificate_t, destroy, void,
517 private_openssl_x509_t *this)
518{
519 if (ref_put(&this->ref))
520 {
521 if (this->x509)
522 {
523 X509_free(this->x509);
524 }
525 DESTROY_IF(this->subject);
526 DESTROY_IF(this->issuer);
527 DESTROY_IF(this->pubkey);
528 free(this->subjectKeyIdentifier.ptr);
529 free(this->authKeyIdentifier.ptr);
530 free(this->encoding.ptr);
531 free(this->hash.ptr);
532 this->subjectAltNames->destroy_offset(this->subjectAltNames,
533 offsetof(identification_t, destroy));
534 this->issuerAltNames->destroy_offset(this->issuerAltNames,
535 offsetof(identification_t, destroy));
4e508517 536 this->crl_uris->destroy_function(this->crl_uris, (void*)crl_uri_destroy);
5728c6aa
MW
537 this->ocsp_uris->destroy_function(this->ocsp_uris, free);
538 free(this);
539 }
540}
541
542/**
543 * Create an empty certificate
544 */
545static private_openssl_x509_t *create_empty()
546{
547 private_openssl_x509_t *this;
548
549 INIT(this,
550 .public = {
551 .x509 = {
552 .interface = {
553 .get_type = _get_type,
554 .get_subject = _get_subject,
555 .get_issuer = _get_issuer,
556 .has_subject = _has_subject,
557 .has_issuer = _has_issuer,
558 .issued_by = _issued_by,
559 .get_public_key = _get_public_key,
560 .get_validity = _get_validity,
5728c6aa
MW
561 .get_encoding = _get_encoding,
562 .equals = _equals,
563 .get_ref = _get_ref,
564 .destroy = _destroy,
565 },
566 .get_flags = _get_flags,
567 .get_serial = _get_serial,
568 .get_subjectKeyIdentifier = _get_subjectKeyIdentifier,
569 .get_authKeyIdentifier = _get_authKeyIdentifier,
570 .get_pathLenConstraint = _get_pathLenConstraint,
571 .create_subjectAltName_enumerator = _create_subjectAltName_enumerator,
572 .create_crl_uri_enumerator = _create_crl_uri_enumerator,
573 .create_ocsp_uri_enumerator = _create_ocsp_uri_enumerator,
20bd7810 574 .create_ipAddrBlock_enumerator = (void*)enumerator_create_empty,
dbfbbec3 575 .create_name_constraint_enumerator = (void*)enumerator_create_empty,
20bd7810 576 .create_cert_policy_enumerator = (void*)enumerator_create_empty,
5a0caa4b 577 .create_policy_mapping_enumerator = (void*)enumerator_create_empty,
5728c6aa
MW
578 },
579 },
580 .subjectAltNames = linked_list_create(),
581 .issuerAltNames = linked_list_create(),
582 .crl_uris = linked_list_create(),
583 .ocsp_uris = linked_list_create(),
5dba5852 584 .pathlen = X509_NO_CONSTRAINT,
5728c6aa
MW
585 .ref = 1,
586 );
587
588 return this;
589}
590
591/**
592 * parse an extionsion containing GENERAL_NAMES into a list
593 */
594static bool parse_generalNames_ext(linked_list_t *list,
595 X509_EXTENSION *ext)
596{
597 GENERAL_NAMES *names;
598 GENERAL_NAME *name;
599 identification_t *id;
600 int i, num;
601
602 names = X509V3_EXT_d2i(ext);
603 if (!names)
604 {
605 return FALSE;
606 }
607
608 num = sk_GENERAL_NAME_num(names);
609 for (i = 0; i < num; i++)
610 {
611 name = sk_GENERAL_NAME_value(names, i);
612 id = general_name2id(name);
613 if (id)
614 {
615 list->insert_last(list, id);
616 }
617 GENERAL_NAME_free(name);
618 }
619 sk_GENERAL_NAME_free(names);
620 return TRUE;
621}
622
623/**
624 * parse basic constraints
625 */
626static bool parse_basicConstraints_ext(private_openssl_x509_t *this,
627 X509_EXTENSION *ext)
628{
629 BASIC_CONSTRAINTS *constraints;
630
631 constraints = (BASIC_CONSTRAINTS*)X509V3_EXT_d2i(ext);
632 if (constraints)
633 {
634 if (constraints->ca)
635 {
636 this->flags |= X509_CA;
637 }
638 if (constraints->pathlen)
639 {
640 this->pathlen = ASN1_INTEGER_get(constraints->pathlen);
641 }
642 BASIC_CONSTRAINTS_free(constraints);
643 return TRUE;
644 }
645 return FALSE;
646}
647
648/**
649 * Parse CRL distribution points
650 */
651static bool parse_crlDistributionPoints_ext(private_openssl_x509_t *this,
652 X509_EXTENSION *ext)
653{
654 CRL_DIST_POINTS *cdps;
655 DIST_POINT *cdp;
656 identification_t *id;
657 char *uri;
658 int i, j, point_num, name_num;
659
660 cdps = X509V3_EXT_d2i(ext);
661 if (!cdps)
662 {
663 return FALSE;
664 }
665 point_num = sk_DIST_POINT_num(cdps);
666 for (i = 0; i < point_num; i++)
667 {
668 cdp = sk_DIST_POINT_value(cdps, i);
669 if (cdp)
670 {
4e508517
MW
671 crl_uri_t *entry;
672
673 entry = crl_uri_create();
674 this->crl_uris->insert_last(this->crl_uris, entry);
675
5728c6aa
MW
676 if (cdp->distpoint && cdp->distpoint->type == 0 &&
677 cdp->distpoint->name.fullname)
678 {
679 name_num = sk_GENERAL_NAME_num(cdp->distpoint->name.fullname);
680 for (j = 0; j < name_num; j++)
681 {
682 id = general_name2id(sk_GENERAL_NAME_value(
683 cdp->distpoint->name.fullname, j));
684 if (id)
685 {
686 if (asprintf(&uri, "%Y", id) > 0)
687 {
4e508517 688 entry->uris->insert_last(entry->uris, uri);
5728c6aa
MW
689 }
690 id->destroy(id);
691 }
692 }
693 }
4e508517
MW
694 if (cdp->CRLissuer)
695 {
696 name_num = sk_GENERAL_NAME_num(cdp->CRLissuer);
697 for (j = 0; j < name_num; j++)
698 {
699 id = general_name2id(sk_GENERAL_NAME_value(cdp->CRLissuer, j));
700 if (id)
701 { /* get only one */
702 entry->issuer = id;
703 break;
704 }
705 }
706 }
5728c6aa
MW
707 DIST_POINT_free(cdp);
708 }
709 }
710 sk_DIST_POINT_free(cdps);
711 return TRUE;
712}
713
714/**
715 * Parse authorityInfoAccess with OCSP URIs
716 */
717static bool parse_authorityInfoAccess_ext(private_openssl_x509_t *this,
718 X509_EXTENSION *ext)
719{
720 AUTHORITY_INFO_ACCESS *infos;
721 ACCESS_DESCRIPTION *desc;
722 identification_t *id;
723 int i, num;
724 char *uri;
725
726 infos = X509V3_EXT_d2i(ext);
727 if (!infos)
728 {
729 return FALSE;
730 }
731 num = sk_ACCESS_DESCRIPTION_num(infos);
732 for (i = 0; i < num; i++)
733 {
734 desc = sk_ACCESS_DESCRIPTION_value(infos, i);
735 if (desc)
736 {
737 if (openssl_asn1_known_oid(desc->method) == OID_OCSP)
738 {
739 id = general_name2id(desc->location);
740 if (id)
741 {
742 if (asprintf(&uri, "%Y", id) > 0)
743 {
744 this->ocsp_uris->insert_first(this->ocsp_uris, uri);
745 }
746 id->destroy(id);
747 }
748 }
749 ACCESS_DESCRIPTION_free(desc);
750 }
751 }
752 sk_ACCESS_DESCRIPTION_free(infos);
753 return TRUE;
754}
755
756/**
757 * Parse authorityKeyIdentifier extension
758 */
759static bool parse_authKeyIdentifier_ext(private_openssl_x509_t *this,
760 X509_EXTENSION *ext)
761{
762 AUTHORITY_KEYID *keyid;
763
764 keyid = (AUTHORITY_KEYID*)X509V3_EXT_d2i(ext);
765 if (keyid)
766 {
767 free(this->authKeyIdentifier.ptr);
768 this->authKeyIdentifier = chunk_clone(
769 openssl_asn1_str2chunk(keyid->keyid));
770 AUTHORITY_KEYID_free(keyid);
771 return TRUE;
772 }
773 return FALSE;
774}
775
776/**
777 * Parse subjectKeyIdentifier extension
778 */
779static bool parse_subjectKeyIdentifier_ext(private_openssl_x509_t *this,
780 X509_EXTENSION *ext)
781{
f00a1015
MW
782 chunk_t ostr;
783
784 ostr = openssl_asn1_str2chunk(X509_EXTENSION_get_data(ext));
785 /* quick and dirty unwrap of octet string */
786 if (ostr.len > 2 &&
787 ostr.ptr[0] == V_ASN1_OCTET_STRING && ostr.ptr[1] == ostr.len - 2)
788 {
789 free(this->subjectKeyIdentifier.ptr);
790 this->subjectKeyIdentifier = chunk_clone(chunk_skip(ostr, 2));
791 return TRUE;
792 }
793 return FALSE;
5728c6aa
MW
794}
795
796/**
797 * Parse X509 extensions we are interested in
798 */
799static bool parse_extensions(private_openssl_x509_t *this)
800{
801 STACK_OF(X509_EXTENSION) *extensions;
802 int i, num;
803
804 extensions = this->x509->cert_info->extensions;
805 if (extensions)
806 {
807 num = sk_X509_EXTENSION_num(extensions);
808
809 for (i = 0; i < num; i++)
810 {
811 X509_EXTENSION *ext;
812 bool ok;
813
814 ext = sk_X509_EXTENSION_value(extensions, i);
815 switch (OBJ_obj2nid(X509_EXTENSION_get_object(ext)))
816 {
817 case NID_info_access:
818 ok = parse_authorityInfoAccess_ext(this, ext);
819 break;
820 case NID_authority_key_identifier:
821 ok = parse_authKeyIdentifier_ext(this, ext);
822 break;
823 case NID_subject_key_identifier:
824 ok = parse_subjectKeyIdentifier_ext(this, ext);
825 break;
826 case NID_subject_alt_name:
827 ok = parse_generalNames_ext(this->subjectAltNames, ext);
828 break;
829 case NID_issuer_alt_name:
830 ok = parse_generalNames_ext(this->issuerAltNames, ext);
831 break;
832 case NID_basic_constraints:
833 ok = parse_basicConstraints_ext(this, ext);
834 break;
835 case NID_crl_distribution_points:
836 ok = parse_crlDistributionPoints_ext(this, ext);
837 break;
838 default:
b0892d09
MW
839 ok = X509_EXTENSION_get_critical(ext) != 0;
840 if (!ok)
841 {
842 DBG1(DBG_LIB, "found unsupported critical X.509 extension");
843 }
5728c6aa
MW
844 break;
845 }
846 if (!ok)
847 {
848 return FALSE;
849 }
850 }
851 }
852 return TRUE;
853}
854
07d2b391
MW
855/**
856 * Parse ExtendedKeyUsage
857 */
858static void parse_extKeyUsage(private_openssl_x509_t *this)
859{
860 EXTENDED_KEY_USAGE *usage;
861 int i;
862
863 usage = X509_get_ext_d2i(this->x509, NID_ext_key_usage, NULL, NULL);
864 if (usage)
865 {
866 for (i = 0; i < sk_ASN1_OBJECT_num(usage); i++)
867 {
868 switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(usage, i)))
869 {
870 case NID_server_auth:
871 this->flags |= X509_SERVER_AUTH;
872 break;
873 case NID_client_auth:
874 this->flags |= X509_CLIENT_AUTH;
875 break;
876 case NID_OCSP_sign:
877 this->flags |= X509_OCSP_SIGNER;
878 break;
879 default:
880 break;
881 }
882 }
883 sk_ASN1_OBJECT_pop_free(usage, ASN1_OBJECT_free);
884 }
885}
886
5728c6aa
MW
887/**
888 * Parse a DER encoded x509 certificate
889 */
890static bool parse_certificate(private_openssl_x509_t *this)
891{
892 const unsigned char *ptr = this->encoding.ptr;
893 hasher_t *hasher;
894 chunk_t chunk;
895
896 this->x509 = d2i_X509(NULL, &ptr, this->encoding.len);
897 if (!this->x509)
898 {
899 return FALSE;
900 }
a6850b84
MW
901 if (X509_get_version(this->x509) < 0 || X509_get_version(this->x509) > 2)
902 {
903 DBG1(DBG_LIB, "unsupported x509 version: %d",
904 X509_get_version(this->x509) + 1);
905 return FALSE;
906 }
907
5728c6aa
MW
908 this->subject = openssl_x509_name2id(X509_get_subject_name(this->x509));
909 this->issuer = openssl_x509_name2id(X509_get_issuer_name(this->x509));
910
911 switch (openssl_asn1_known_oid(this->x509->cert_info->key->algor->algorithm))
912 {
913 case OID_RSA_ENCRYPTION:
914 this->pubkey = lib->creds->create(lib->creds,
915 CRED_PUBLIC_KEY, KEY_RSA, BUILD_BLOB_ASN1_DER,
916 openssl_asn1_str2chunk(X509_get0_pubkey_bitstr(this->x509)),
917 BUILD_END);
918 break;
919 case OID_EC_PUBLICKEY:
920 /* for ECDSA, we need the full subjectPublicKeyInfo, as it contains
921 * the curve parameters. */
922 chunk = openssl_i2chunk(X509_PUBKEY, X509_get_X509_PUBKEY(this->x509));
923 this->pubkey = lib->creds->create(lib->creds,
924 CRED_PUBLIC_KEY, KEY_ECDSA, BUILD_BLOB_ASN1_DER,
925 chunk, BUILD_END);
926 free(chunk.ptr);
927 break;
928 default:
929 DBG1(DBG_LIB, "unsupported public key algorithm");
930 break;
931 }
932 if (!this->subject || !this->issuer || !this->pubkey)
933 {
934 return FALSE;
935 }
936
937 this->notBefore = openssl_asn1_to_time(X509_get_notBefore(this->x509));
938 this->notAfter = openssl_asn1_to_time(X509_get_notAfter(this->x509));
939
940 if (!chunk_equals(
941 openssl_asn1_obj2chunk(this->x509->cert_info->signature->algorithm),
942 openssl_asn1_obj2chunk(this->x509->sig_alg->algorithm)))
943 {
944 return FALSE;
945 }
946 this->scheme = signature_scheme_from_oid(openssl_asn1_known_oid(
947 this->x509->sig_alg->algorithm));
948
949 if (!parse_extensions(this))
950 {
951 return TRUE;
952 }
07d2b391 953 parse_extKeyUsage(this);
5728c6aa
MW
954
955 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
956 if (!hasher)
957 {
958 return FALSE;
959 }
960 hasher->allocate_hash(hasher, this->encoding, &this->hash);
961 hasher->destroy(hasher);
962
963 if (issued_by(this, &this->public.x509.interface))
964 {
965 this->flags |= X509_SELF_SIGNED;
966 }
967 return TRUE;
968}
969
970openssl_x509_t *openssl_x509_load(certificate_type_t type, va_list args)
971{
972 chunk_t blob = chunk_empty;
973 x509_flag_t flags = 0;
974
975 while (TRUE)
976 {
977 switch (va_arg(args, builder_part_t))
978 {
979 case BUILD_BLOB_ASN1_DER:
980 blob = va_arg(args, chunk_t);
981 continue;
982 case BUILD_X509_FLAG:
983 flags |= va_arg(args, x509_flag_t);
984 continue;
985 case BUILD_END:
986 break;
987 default:
988 return NULL;
989 }
990 break;
991 }
992
993 if (blob.ptr)
994 {
995 private_openssl_x509_t *this;
996
997 this = create_empty();
998 this->encoding = chunk_clone(blob);
999 this->flags |= flags;
1000 if (parse_certificate(this))
1001 {
1002 return &this->public;
1003 }
1004 DBG1(DBG_LIB, "OpenSSL X.509 parsing failed");
1005 destroy(this);
1006 }
1007 return NULL;
1008}