summaryrefslogtreecommitdiff
path: root/src/libstrongswan/plugins/openssl/openssl_x509.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/plugins/openssl/openssl_x509.c')
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_x509.c871
1 files changed, 871 insertions, 0 deletions
diff --git a/src/libstrongswan/plugins/openssl/openssl_x509.c b/src/libstrongswan/plugins/openssl/openssl_x509.c
new file mode 100644
index 000000000..1c9bb699e
--- /dev/null
+++ b/src/libstrongswan/plugins/openssl/openssl_x509.c
@@ -0,0 +1,871 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/*
+ * Copyright (C) 2010 secunet Security Networks AG
+ * Copyright (C) 2010 Thomas Egerer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "openssl_x509.h"
+#include "openssl_util.h"
+
+#include <debug.h>
+#include <asn1/oid.h>
+#include <utils/linked_list.h>
+
+
+typedef struct private_openssl_x509_t private_openssl_x509_t;
+
+/**
+ * Private data of an openssl_x509_t object.
+ */
+struct private_openssl_x509_t {
+
+ /**
+ * Public openssl_x509_t interface.
+ */
+ openssl_x509_t public;
+
+ /**
+ * OpenSSL certificate representation
+ */
+ X509 *x509;
+
+ /**
+ * DER encoded certificate
+ */
+ chunk_t encoding;
+
+ /**
+ * SHA1 hash of the certificate
+ */
+ chunk_t hash;
+
+ /**
+ * X509 flags
+ */
+ x509_flag_t flags;
+
+ /**
+ * Pathlen constraint
+ */
+ int pathlen;
+
+ /**
+ * certificate subject
+ */
+ identification_t *subject;
+
+ /**
+ * certificate issuer
+ */
+ identification_t *issuer;
+
+ /**
+ * Certificates public key
+ */
+ public_key_t *pubkey;
+
+ /**
+ * subjectKeyIdentifier as read from cert
+ */
+ chunk_t subjectKeyIdentifier;
+
+ /**
+ * authorityKeyIdentifier as read from cert
+ */
+ chunk_t authKeyIdentifier;
+
+ /**
+ * Start time of certificate validity
+ */
+ time_t notBefore;
+
+ /**
+ * End time of certificate validity
+ */
+ time_t notAfter;
+
+ /**
+ * Signature scheme of the certificate
+ */
+ signature_scheme_t scheme;
+
+ /**
+ * subjectAltNames
+ */
+ linked_list_t *subjectAltNames;
+
+ /**
+ * issuerAltNames
+ */
+ linked_list_t *issuerAltNames;
+
+ /**
+ * List of CRL URIs
+ */
+ linked_list_t *crl_uris;
+
+ /**
+ * List of OCSP URIs
+ */
+ linked_list_t *ocsp_uris;
+
+ /**
+ * References to this cert
+ */
+ refcount_t ref;
+};
+
+/**
+ * Convert a GeneralName to an identification_t.
+ */
+static identification_t *general_name2id(GENERAL_NAME *name)
+{
+ if (!name)
+ {
+ return NULL;
+ }
+ switch (name->type)
+ {
+ case GEN_EMAIL:
+ return identification_create_from_encoding(ID_RFC822_ADDR,
+ openssl_asn1_str2chunk(name->d.rfc822Name));
+ case GEN_DNS:
+ return identification_create_from_encoding(ID_FQDN,
+ openssl_asn1_str2chunk(name->d.dNSName));
+ case GEN_URI:
+ return identification_create_from_encoding(ID_DER_ASN1_GN_URI,
+ openssl_asn1_str2chunk(name->d.uniformResourceIdentifier));
+ case GEN_IPADD:
+ {
+ chunk_t chunk = openssl_asn1_str2chunk(name->d.iPAddress);
+ if (chunk.len == 4)
+ {
+ return identification_create_from_encoding(ID_IPV4_ADDR, chunk);
+ }
+ if (chunk.len == 16)
+ {
+ return identification_create_from_encoding(ID_IPV6_ADDR, chunk);
+ }
+ return NULL;
+ }
+ case GEN_DIRNAME :
+ return openssl_x509_name2id(name->d.directoryName);
+ default:
+ return NULL;
+ }
+}
+
+METHOD(x509_t, get_flags, x509_flag_t,
+ private_openssl_x509_t *this)
+{
+ return this->flags;
+}
+
+METHOD(x509_t, get_serial, chunk_t,
+ private_openssl_x509_t *this)
+{
+ return openssl_asn1_str2chunk(X509_get_serialNumber(this->x509));
+}
+
+METHOD(x509_t, get_subjectKeyIdentifier, chunk_t,
+ private_openssl_x509_t *this)
+{
+ chunk_t fingerprint;
+
+ if (this->subjectKeyIdentifier.len)
+ {
+ return this->subjectKeyIdentifier;
+ }
+ if (this->pubkey->get_fingerprint(this->pubkey, KEYID_PUBKEY_SHA1,
+ &fingerprint))
+ {
+ return fingerprint;
+ }
+ return chunk_empty;
+}
+
+METHOD(x509_t, get_authKeyIdentifier, chunk_t,
+ private_openssl_x509_t *this)
+{
+ if (this->authKeyIdentifier.len)
+ {
+ return this->authKeyIdentifier;
+ }
+ return chunk_empty;
+}
+
+METHOD(x509_t, get_pathLenConstraint, int,
+ private_openssl_x509_t *this)
+{
+ return this->pathlen;
+}
+
+METHOD(x509_t, create_subjectAltName_enumerator, enumerator_t*,
+ private_openssl_x509_t *this)
+{
+ return this->subjectAltNames->create_enumerator(this->subjectAltNames);
+}
+
+METHOD(x509_t, create_crl_uri_enumerator, enumerator_t*,
+ private_openssl_x509_t *this)
+{
+ return this->crl_uris->create_enumerator(this->crl_uris);
+}
+
+METHOD(x509_t, create_ocsp_uri_enumerator, enumerator_t*,
+ private_openssl_x509_t *this)
+{
+ return this->ocsp_uris->create_enumerator(this->ocsp_uris);
+}
+
+METHOD(x509_t, create_ipAddrBlock_enumerator, enumerator_t*,
+ private_openssl_x509_t *this)
+{
+ /* TODO */
+ return enumerator_create_empty();
+}
+
+METHOD(certificate_t, get_type, certificate_type_t,
+ private_openssl_x509_t *this)
+{
+ return CERT_X509;
+}
+
+METHOD(certificate_t, get_subject, identification_t*,
+ private_openssl_x509_t *this)
+{
+ return this->subject;
+}
+
+METHOD(certificate_t, get_issuer, identification_t*,
+ private_openssl_x509_t *this)
+{
+ return this->issuer;
+}
+
+METHOD(certificate_t, has_subject, id_match_t,
+ private_openssl_x509_t *this, identification_t *subject)
+{
+ identification_t *current;
+ enumerator_t *enumerator;
+ id_match_t match, best;
+
+ if (subject->get_type(subject) == ID_KEY_ID)
+ {
+ if (chunk_equals(this->hash, subject->get_encoding(subject)))
+ {
+ return ID_MATCH_PERFECT;
+ }
+ }
+ best = this->subject->matches(this->subject, subject);
+ enumerator = create_subjectAltName_enumerator(this);
+ while (enumerator->enumerate(enumerator, &current))
+ {
+ match = current->matches(current, subject);
+ if (match > best)
+ {
+ best = match;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return best;
+}
+
+METHOD(certificate_t, has_issuer, id_match_t,
+ private_openssl_x509_t *this, identification_t *issuer)
+{
+ /* issuerAltNames currently not supported */
+ return this->issuer->matches(this->issuer, issuer);
+}
+
+METHOD(certificate_t, issued_by, bool,
+ private_openssl_x509_t *this, certificate_t *issuer)
+{
+ public_key_t *key;
+ bool valid;
+ x509_t *x509 = (x509_t*)issuer;
+ chunk_t tbs;
+
+ if (&this->public.x509.interface == issuer)
+ {
+ if (this->flags & X509_SELF_SIGNED)
+ {
+ return TRUE;
+ }
+ }
+ else
+ {
+ if (issuer->get_type(issuer) != CERT_X509)
+ {
+ return FALSE;
+ }
+ if (!(x509->get_flags(x509) & X509_CA))
+ {
+ return FALSE;
+ }
+ if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer)))
+ {
+ return FALSE;
+ }
+ }
+ if (this->scheme == SIGN_UNKNOWN)
+ {
+ return FALSE;
+ }
+ key = issuer->get_public_key(issuer);
+ if (!key)
+ {
+ return FALSE;
+ }
+ tbs = openssl_i2chunk(X509_CINF, this->x509->cert_info);
+ valid = key->verify(key, this->scheme, tbs,
+ openssl_asn1_str2chunk(this->x509->signature));
+ free(tbs.ptr);
+ key->destroy(key);
+ return valid;
+}
+
+METHOD(certificate_t, get_public_key, public_key_t*,
+ private_openssl_x509_t *this)
+{
+ return this->pubkey->get_ref(this->pubkey);
+}
+
+METHOD(certificate_t, get_validity, bool,
+ private_openssl_x509_t *this,
+ time_t *when, time_t *not_before, time_t *not_after)
+{
+ time_t t;
+
+ if (when)
+ {
+ t = *when;
+ }
+ else
+ {
+ t = time(NULL);
+ }
+ if (not_before)
+ {
+ *not_before = this->notBefore;
+ }
+ if (not_after)
+ {
+ *not_after = this->notAfter;
+ }
+ return (t >= this->notBefore && t <= this->notAfter);
+}
+
+METHOD(certificate_t, get_encoding, bool,
+ private_openssl_x509_t *this, cred_encoding_type_t type, chunk_t *encoding)
+{
+ if (type == CERT_ASN1_DER)
+ {
+ *encoding = chunk_clone(this->encoding);
+ return TRUE;
+ }
+ return lib->encoding->encode(lib->encoding, type, NULL, encoding,
+ CRED_PART_X509_ASN1_DER, this->encoding, CRED_PART_END);
+}
+
+
+METHOD(certificate_t, equals, bool,
+ private_openssl_x509_t *this, certificate_t *other)
+{
+ chunk_t encoding;
+ bool equal;
+
+ if (this == (private_openssl_x509_t*)other)
+ {
+ return TRUE;
+ }
+ if (other->get_type(other) != CERT_X509)
+ {
+ return FALSE;
+ }
+ if (other->equals == (void*)equals)
+ { /* skip allocation if we have the same implementation */
+ encoding = ((private_openssl_x509_t*)other)->encoding;
+ return chunk_equals(this->encoding, encoding);
+ }
+ if (!other->get_encoding(other, CERT_ASN1_DER, &encoding))
+ {
+ return FALSE;
+ }
+ equal = chunk_equals(this->encoding, encoding);
+ free(encoding.ptr);
+ return equal;
+}
+
+METHOD(certificate_t, get_ref, certificate_t*,
+ private_openssl_x509_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.x509.interface;
+}
+
+METHOD(certificate_t, destroy, void,
+ private_openssl_x509_t *this)
+{
+ if (ref_put(&this->ref))
+ {
+ if (this->x509)
+ {
+ X509_free(this->x509);
+ }
+ DESTROY_IF(this->subject);
+ DESTROY_IF(this->issuer);
+ DESTROY_IF(this->pubkey);
+ free(this->subjectKeyIdentifier.ptr);
+ free(this->authKeyIdentifier.ptr);
+ free(this->encoding.ptr);
+ free(this->hash.ptr);
+ this->subjectAltNames->destroy_offset(this->subjectAltNames,
+ offsetof(identification_t, destroy));
+ this->issuerAltNames->destroy_offset(this->issuerAltNames,
+ offsetof(identification_t, destroy));
+ this->crl_uris->destroy_function(this->crl_uris, free);
+ this->ocsp_uris->destroy_function(this->ocsp_uris, free);
+ free(this);
+ }
+}
+
+/**
+ * Create an empty certificate
+ */
+static private_openssl_x509_t *create_empty()
+{
+ private_openssl_x509_t *this;
+
+ INIT(this,
+ .public = {
+ .x509 = {
+ .interface = {
+ .get_type = _get_type,
+ .get_subject = _get_subject,
+ .get_issuer = _get_issuer,
+ .has_subject = _has_subject,
+ .has_issuer = _has_issuer,
+ .issued_by = _issued_by,
+ .get_public_key = _get_public_key,
+ .get_validity = _get_validity,
+ .get_encoding = _get_encoding,
+ .equals = _equals,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .get_flags = _get_flags,
+ .get_serial = _get_serial,
+ .get_subjectKeyIdentifier = _get_subjectKeyIdentifier,
+ .get_authKeyIdentifier = _get_authKeyIdentifier,
+ .get_pathLenConstraint = _get_pathLenConstraint,
+ .create_subjectAltName_enumerator = _create_subjectAltName_enumerator,
+ .create_crl_uri_enumerator = _create_crl_uri_enumerator,
+ .create_ocsp_uri_enumerator = _create_ocsp_uri_enumerator,
+ .create_ipAddrBlock_enumerator = _create_ipAddrBlock_enumerator,
+ },
+ },
+ .subjectAltNames = linked_list_create(),
+ .issuerAltNames = linked_list_create(),
+ .crl_uris = linked_list_create(),
+ .ocsp_uris = linked_list_create(),
+ .pathlen = X509_NO_PATH_LEN_CONSTRAINT,
+ .ref = 1,
+ );
+
+ return this;
+}
+
+/**
+ * parse an extionsion containing GENERAL_NAMES into a list
+ */
+static bool parse_generalNames_ext(linked_list_t *list,
+ X509_EXTENSION *ext)
+{
+ GENERAL_NAMES *names;
+ GENERAL_NAME *name;
+ identification_t *id;
+ int i, num;
+
+ names = X509V3_EXT_d2i(ext);
+ if (!names)
+ {
+ return FALSE;
+ }
+
+ num = sk_GENERAL_NAME_num(names);
+ for (i = 0; i < num; i++)
+ {
+ name = sk_GENERAL_NAME_value(names, i);
+ id = general_name2id(name);
+ if (id)
+ {
+ list->insert_last(list, id);
+ }
+ GENERAL_NAME_free(name);
+ }
+ sk_GENERAL_NAME_free(names);
+ return TRUE;
+}
+
+/**
+ * parse basic constraints
+ */
+static bool parse_basicConstraints_ext(private_openssl_x509_t *this,
+ X509_EXTENSION *ext)
+{
+ BASIC_CONSTRAINTS *constraints;
+
+ constraints = (BASIC_CONSTRAINTS*)X509V3_EXT_d2i(ext);
+ if (constraints)
+ {
+ if (constraints->ca)
+ {
+ this->flags |= X509_CA;
+ }
+ if (constraints->pathlen)
+ {
+ this->pathlen = ASN1_INTEGER_get(constraints->pathlen);
+ }
+ BASIC_CONSTRAINTS_free(constraints);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Parse CRL distribution points
+ */
+static bool parse_crlDistributionPoints_ext(private_openssl_x509_t *this,
+ X509_EXTENSION *ext)
+{
+ CRL_DIST_POINTS *cdps;
+ DIST_POINT *cdp;
+ identification_t *id;
+ char *uri;
+ int i, j, point_num, name_num;
+
+ cdps = X509V3_EXT_d2i(ext);
+ if (!cdps)
+ {
+ return FALSE;
+ }
+ point_num = sk_DIST_POINT_num(cdps);
+ for (i = 0; i < point_num; i++)
+ {
+ cdp = sk_DIST_POINT_value(cdps, i);
+ if (cdp)
+ {
+ if (cdp->distpoint && cdp->distpoint->type == 0 &&
+ cdp->distpoint->name.fullname)
+ {
+ name_num = sk_GENERAL_NAME_num(cdp->distpoint->name.fullname);
+ for (j = 0; j < name_num; j++)
+ {
+ id = general_name2id(sk_GENERAL_NAME_value(
+ cdp->distpoint->name.fullname, j));
+ if (id)
+ {
+ if (asprintf(&uri, "%Y", id) > 0)
+ {
+ this->crl_uris->insert_first(this->crl_uris, uri);
+ }
+ id->destroy(id);
+ }
+ }
+ }
+ DIST_POINT_free(cdp);
+ }
+ }
+ sk_DIST_POINT_free(cdps);
+ return TRUE;
+}
+
+/**
+ * Parse authorityInfoAccess with OCSP URIs
+ */
+static bool parse_authorityInfoAccess_ext(private_openssl_x509_t *this,
+ X509_EXTENSION *ext)
+{
+ AUTHORITY_INFO_ACCESS *infos;
+ ACCESS_DESCRIPTION *desc;
+ identification_t *id;
+ int i, num;
+ char *uri;
+
+ infos = X509V3_EXT_d2i(ext);
+ if (!infos)
+ {
+ return FALSE;
+ }
+ num = sk_ACCESS_DESCRIPTION_num(infos);
+ for (i = 0; i < num; i++)
+ {
+ desc = sk_ACCESS_DESCRIPTION_value(infos, i);
+ if (desc)
+ {
+ if (openssl_asn1_known_oid(desc->method) == OID_OCSP)
+ {
+ id = general_name2id(desc->location);
+ if (id)
+ {
+ if (asprintf(&uri, "%Y", id) > 0)
+ {
+ this->ocsp_uris->insert_first(this->ocsp_uris, uri);
+ }
+ id->destroy(id);
+ }
+ }
+ ACCESS_DESCRIPTION_free(desc);
+ }
+ }
+ sk_ACCESS_DESCRIPTION_free(infos);
+ return TRUE;
+}
+
+/**
+ * Parse authorityKeyIdentifier extension
+ */
+static bool parse_authKeyIdentifier_ext(private_openssl_x509_t *this,
+ X509_EXTENSION *ext)
+{
+ AUTHORITY_KEYID *keyid;
+
+ keyid = (AUTHORITY_KEYID*)X509V3_EXT_d2i(ext);
+ if (keyid)
+ {
+ free(this->authKeyIdentifier.ptr);
+ this->authKeyIdentifier = chunk_clone(
+ openssl_asn1_str2chunk(keyid->keyid));
+ AUTHORITY_KEYID_free(keyid);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Parse subjectKeyIdentifier extension
+ */
+static bool parse_subjectKeyIdentifier_ext(private_openssl_x509_t *this,
+ X509_EXTENSION *ext)
+{
+ chunk_t ostr;
+
+ ostr = openssl_asn1_str2chunk(X509_EXTENSION_get_data(ext));
+ /* quick and dirty unwrap of octet string */
+ if (ostr.len > 2 &&
+ ostr.ptr[0] == V_ASN1_OCTET_STRING && ostr.ptr[1] == ostr.len - 2)
+ {
+ free(this->subjectKeyIdentifier.ptr);
+ this->subjectKeyIdentifier = chunk_clone(chunk_skip(ostr, 2));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Parse X509 extensions we are interested in
+ */
+static bool parse_extensions(private_openssl_x509_t *this)
+{
+ STACK_OF(X509_EXTENSION) *extensions;
+ int i, num;
+
+ extensions = this->x509->cert_info->extensions;
+ if (extensions)
+ {
+ num = sk_X509_EXTENSION_num(extensions);
+
+ for (i = 0; i < num; i++)
+ {
+ X509_EXTENSION *ext;
+ bool ok;
+
+ ext = sk_X509_EXTENSION_value(extensions, i);
+ switch (OBJ_obj2nid(X509_EXTENSION_get_object(ext)))
+ {
+ case NID_info_access:
+ ok = parse_authorityInfoAccess_ext(this, ext);
+ break;
+ case NID_authority_key_identifier:
+ ok = parse_authKeyIdentifier_ext(this, ext);
+ break;
+ case NID_subject_key_identifier:
+ ok = parse_subjectKeyIdentifier_ext(this, ext);
+ break;
+ case NID_subject_alt_name:
+ ok = parse_generalNames_ext(this->subjectAltNames, ext);
+ break;
+ case NID_issuer_alt_name:
+ ok = parse_generalNames_ext(this->issuerAltNames, ext);
+ break;
+ case NID_basic_constraints:
+ ok = parse_basicConstraints_ext(this, ext);
+ break;
+ case NID_crl_distribution_points:
+ ok = parse_crlDistributionPoints_ext(this, ext);
+ break;
+ default:
+ ok = TRUE;
+ break;
+ }
+ if (!ok)
+ {
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * Parse a DER encoded x509 certificate
+ */
+static bool parse_certificate(private_openssl_x509_t *this)
+{
+ const unsigned char *ptr = this->encoding.ptr;
+ hasher_t *hasher;
+ chunk_t chunk;
+
+ this->x509 = d2i_X509(NULL, &ptr, this->encoding.len);
+ if (!this->x509)
+ {
+ return FALSE;
+ }
+ this->subject = openssl_x509_name2id(X509_get_subject_name(this->x509));
+ this->issuer = openssl_x509_name2id(X509_get_issuer_name(this->x509));
+
+ switch (openssl_asn1_known_oid(this->x509->cert_info->key->algor->algorithm))
+ {
+ case OID_RSA_ENCRYPTION:
+ this->pubkey = lib->creds->create(lib->creds,
+ CRED_PUBLIC_KEY, KEY_RSA, BUILD_BLOB_ASN1_DER,
+ openssl_asn1_str2chunk(X509_get0_pubkey_bitstr(this->x509)),
+ BUILD_END);
+ break;
+ case OID_EC_PUBLICKEY:
+ /* for ECDSA, we need the full subjectPublicKeyInfo, as it contains
+ * the curve parameters. */
+ chunk = openssl_i2chunk(X509_PUBKEY, X509_get_X509_PUBKEY(this->x509));
+ this->pubkey = lib->creds->create(lib->creds,
+ CRED_PUBLIC_KEY, KEY_ECDSA, BUILD_BLOB_ASN1_DER,
+ chunk, BUILD_END);
+ free(chunk.ptr);
+ break;
+ default:
+ DBG1(DBG_LIB, "unsupported public key algorithm");
+ break;
+ }
+ if (!this->subject || !this->issuer || !this->pubkey)
+ {
+ return FALSE;
+ }
+
+ this->notBefore = openssl_asn1_to_time(X509_get_notBefore(this->x509));
+ this->notAfter = openssl_asn1_to_time(X509_get_notAfter(this->x509));
+
+ if (!chunk_equals(
+ openssl_asn1_obj2chunk(this->x509->cert_info->signature->algorithm),
+ openssl_asn1_obj2chunk(this->x509->sig_alg->algorithm)))
+ {
+ return FALSE;
+ }
+ this->scheme = signature_scheme_from_oid(openssl_asn1_known_oid(
+ this->x509->sig_alg->algorithm));
+
+ if (!parse_extensions(this))
+ {
+ return TRUE;
+ }
+
+ hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+ if (!hasher)
+ {
+ return FALSE;
+ }
+ hasher->allocate_hash(hasher, this->encoding, &this->hash);
+ hasher->destroy(hasher);
+
+ if (issued_by(this, &this->public.x509.interface))
+ {
+ this->flags |= X509_SELF_SIGNED;
+ }
+ return TRUE;
+}
+
+openssl_x509_t *openssl_x509_load(certificate_type_t type, va_list args)
+{
+ chunk_t blob = chunk_empty;
+ x509_flag_t flags = 0;
+
+ while (TRUE)
+ {
+ switch (va_arg(args, builder_part_t))
+ {
+ case BUILD_BLOB_ASN1_DER:
+ blob = va_arg(args, chunk_t);
+ continue;
+ case BUILD_X509_FLAG:
+ flags |= va_arg(args, x509_flag_t);
+ continue;
+ case BUILD_END:
+ break;
+ default:
+ return NULL;
+ }
+ break;
+ }
+
+ if (blob.ptr)
+ {
+ private_openssl_x509_t *this;
+
+ this = create_empty();
+ this->encoding = chunk_clone(blob);
+ this->flags |= flags;
+ if (parse_certificate(this))
+ {
+ return &this->public;
+ }
+ DBG1(DBG_LIB, "OpenSSL X.509 parsing failed");
+ destroy(this);
+ }
+ return NULL;
+}