summaryrefslogtreecommitdiff
path: root/src/libstrongswan/crypto
diff options
context:
space:
mode:
authorRene Mayrhofer <rene@mayrhofer.eu.org>2007-06-03 17:36:35 +0000
committerRene Mayrhofer <rene@mayrhofer.eu.org>2007-06-03 17:36:35 +0000
commit08ee5250bd9c43fda5f24d10b791ca2c4c17fcee (patch)
treed4e2fc7144e288d624555a38955593e1ee066531 /src/libstrongswan/crypto
parentb0d8ed94fe9e74afb49fdf5f11e4add29879c65c (diff)
downloadvyos-strongswan-08ee5250bd9c43fda5f24d10b791ca2c4c17fcee.tar.gz
vyos-strongswan-08ee5250bd9c43fda5f24d10b791ca2c4c17fcee.zip
[svn-upgrade] Integrating new upstream version, strongswan (4.1.3)
Diffstat (limited to 'src/libstrongswan/crypto')
-rw-r--r--src/libstrongswan/crypto/ac.c665
-rw-r--r--src/libstrongswan/crypto/ac.h81
-rw-r--r--src/libstrongswan/crypto/ca.c179
-rw-r--r--src/libstrongswan/crypto/ca.h38
-rw-r--r--src/libstrongswan/crypto/certinfo.c48
-rwxr-xr-xsrc/libstrongswan/crypto/crl.c80
-rwxr-xr-xsrc/libstrongswan/crypto/crl.h9
-rw-r--r--src/libstrongswan/crypto/ocsp.c2
-rwxr-xr-xsrc/libstrongswan/crypto/x509.c261
-rwxr-xr-xsrc/libstrongswan/crypto/x509.h76
10 files changed, 1116 insertions, 323 deletions
diff --git a/src/libstrongswan/crypto/ac.c b/src/libstrongswan/crypto/ac.c
new file mode 100644
index 000000000..47605e9e1
--- /dev/null
+++ b/src/libstrongswan/crypto/ac.c
@@ -0,0 +1,665 @@
+/**
+ * @file ac.c
+ *
+ * @brief Implementation of x509ac_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
+ * Copyright (C) 2003 Martin Berner, Lukas Suter
+ * Copyright (C) 2007 Andreas Steffen, Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ */
+
+#include <library.h>
+#include <debug.h>
+
+#include <asn1/asn1.h>
+#include <utils/identification.h>
+#include <utils/linked_list.h>
+
+#include "ac.h"
+
+typedef struct private_x509ac_t private_x509ac_t;
+
+/**
+ * Private data of a x509ac_t object.
+ */
+struct private_x509ac_t {
+ /**
+ * Public interface for this attribute certificate.
+ */
+ x509ac_t public;
+
+ /**
+ * Time when attribute certificate was installed
+ */
+ time_t installed;
+
+ /**
+ * X.509 attribute certificate in DER format
+ */
+ chunk_t certificate;
+
+ /**
+ * X.509 attribute certificate body over which signature is computed
+ */
+ chunk_t certificateInfo;
+
+ /**
+ * Version of the X.509 attribute certificate
+ */
+ u_int version;
+
+ /**
+ * Serial number of the X.509 attribute certificate
+ */
+ chunk_t serialNumber;
+
+ /**
+ * ID representing the issuer of the holder certificate
+ */
+ identification_t *holderIssuer;
+
+ /**
+ * Serial number of the holder certificate
+ */
+ chunk_t holderSerial;
+
+ /**
+ * ID representing the holder
+ */
+ identification_t *entityName;
+
+ /**
+ * ID representing the attribute certificate issuer
+ */
+ identification_t *issuerName;
+
+ /**
+ * Signature algorithm
+ */
+ int sigAlg;
+
+ /**
+ * Start time of certificate validity
+ */
+ time_t notBefore;
+
+ /**
+ * End time of certificate validity
+ */
+ time_t notAfter;
+
+ /**
+ * List of charging attributes
+ */
+ linked_list_t *charging;
+
+ /**
+ * List of groub attributes
+ */
+ linked_list_t *groups;
+
+ /**
+ * Authority Key Identifier
+ */
+ chunk_t authKeyID;
+
+ /**
+ * Authority Key Serial Number
+ */
+ chunk_t authKeySerialNumber;
+
+ /**
+ * No revocation information available
+ */
+ bool noRevAvail;
+
+ /**
+ * Signature algorithm (must be identical to sigAlg)
+ */
+ int algorithm;
+
+ /**
+ * Signature
+ */
+ chunk_t signature;
+};
+
+/**
+ * definition of ietfAttribute kinds
+ */
+typedef enum {
+ IETF_ATTRIBUTE_OCTETS = 0,
+ IETF_ATTRIBUTE_OID = 1,
+ IETF_ATTRIBUTE_STRING = 2
+} ietfAttribute_t;
+
+/**
+ * access structure for an ietfAttribute
+ */
+typedef struct ietfAttr_t ietfAttr_t;
+
+struct ietfAttr_t {
+ /**
+ * IETF attribute kind
+ */
+ ietfAttribute_t kind;
+
+ /**
+ * IETF attribute valuse
+ */
+ chunk_t value;
+
+ /**
+ * Destroys the ietfAttr_t object.
+ *
+ * @param this ietfAttr_t to destroy
+ */
+ void (*destroy) (ietfAttr_t *this);
+};
+
+/**
+ * Destroys an ietfAttr_t object
+ */
+static void ietfAttr_destroy(ietfAttr_t *this)
+{
+ free(this->value.ptr);
+ free(this);
+}
+
+/**
+ * Creates an ietfAttr_t object.
+ */
+ietfAttr_t *ietfAttr_create(ietfAttribute_t kind, chunk_t value)
+{
+ ietfAttr_t *this = malloc_thing(ietfAttr_t);
+
+ /* initialize */
+ this->kind = kind;
+ this->value = chunk_clone(value);
+
+ /* function */
+ this->destroy = ietfAttr_destroy;
+
+ return this;
+}
+
+/**
+ * ASN.1 definition of ietfAttrSyntax
+ */
+static const asn1Object_t ietfAttrSyntaxObjects[] =
+{
+ { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_BODY }, /* 1 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
+ { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */
+ { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT |
+ ASN1_BODY }, /* 4 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
+ { 2, "oid", ASN1_OID, ASN1_OPT |
+ ASN1_BODY }, /* 6 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
+ { 2, "string", ASN1_UTF8STRING, ASN1_OPT |
+ ASN1_BODY }, /* 8 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
+ { 1, "end loop", ASN1_EOC, ASN1_END } /* 10 */
+};
+
+#define IETF_ATTR_OCTETS 4
+#define IETF_ATTR_OID 6
+#define IETF_ATTR_STRING 8
+#define IETF_ATTR_ROOF 11
+
+/**
+ * ASN.1 definition of roleSyntax
+ */
+static const asn1Object_t roleSyntaxObjects[] =
+{
+ { 0, "roleSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "roleAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_OBJ }, /* 1 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
+ { 1, "roleName", ASN1_CONTEXT_C_1, ASN1_OBJ } /* 3 */
+};
+
+#define ROLE_ROOF 4
+
+/**
+ * ASN.1 definition of an X509 attribute certificate
+ */
+static const asn1Object_t acObjects[] =
+{
+ { 0, "AttributeCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
+ { 1, "AttributeCertificateInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
+ { 2, "version", ASN1_INTEGER, ASN1_DEF |
+ ASN1_BODY }, /* 2 */
+ { 2, "holder", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
+ { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */
+ { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
+ { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 6 */
+ { 4, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
+ ASN1_BODY }, /* 7 */
+ { 4, "end opt", ASN1_EOC, ASN1_END }, /* 8 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 9 */
+ { 3, "entityName", ASN1_CONTEXT_C_1, ASN1_OPT |
+ ASN1_OBJ }, /* 10 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 11 */
+ { 3, "objectDigestInfo", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 12 */
+ { 4, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 13*/
+ { 4, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
+ ASN1_BODY }, /* 14 */
+ { 4, "end opt", ASN1_EOC, ASN1_END }, /* 15*/
+ { 4, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 16 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 17 */
+ { 2, "v2Form", ASN1_CONTEXT_C_0, ASN1_NONE }, /* 18 */
+ { 3, "issuerName", ASN1_SEQUENCE, ASN1_OPT |
+ ASN1_OBJ }, /* 19 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
+ { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 21 */
+ { 4, "issuerSerial", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
+ { 5, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 23 */
+ { 5, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */
+ { 5, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
+ ASN1_BODY }, /* 25 */
+ { 5, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 27 */
+ { 3, "objectDigestInfo", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 28 */
+ { 4, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 29 */
+ { 5, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 30 */
+ { 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
+ ASN1_BODY }, /* 31 */
+ { 5, "end opt", ASN1_EOC, ASN1_END }, /* 32 */
+ { 5, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 33 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 34 */
+ { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 35 */
+ { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 36 */
+ { 2, "attrCertValidityPeriod", ASN1_SEQUENCE, ASN1_NONE }, /* 37 */
+ { 3, "notBeforeTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 38 */
+ { 3, "notAfterTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 39 */
+ { 2, "attributes", ASN1_SEQUENCE, ASN1_LOOP }, /* 40 */
+ { 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 41 */
+ { 4, "type", ASN1_OID, ASN1_BODY }, /* 42 */
+ { 4, "values", ASN1_SET, ASN1_LOOP }, /* 43 */
+ { 5, "value", ASN1_EOC, ASN1_RAW }, /* 44 */
+ { 4, "end loop", ASN1_EOC, ASN1_END }, /* 45 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 46 */
+ { 2, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 47 */
+ { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 48 */
+ { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 49 */
+ { 4, "critical", ASN1_BOOLEAN, ASN1_DEF |
+ ASN1_BODY }, /* 50 */
+ { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 51 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 52 */
+ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 53 */
+ { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 54 */
+};
+
+#define AC_OBJ_CERTIFICATE 0
+#define AC_OBJ_CERTIFICATE_INFO 1
+#define AC_OBJ_VERSION 2
+#define AC_OBJ_HOLDER_ISSUER 5
+#define AC_OBJ_HOLDER_SERIAL 6
+#define AC_OBJ_ENTITY_NAME 10
+#define AC_OBJ_ISSUER_NAME 19
+#define AC_OBJ_ISSUER 23
+#define AC_OBJ_SIG_ALG 35
+#define AC_OBJ_SERIAL_NUMBER 36
+#define AC_OBJ_NOT_BEFORE 38
+#define AC_OBJ_NOT_AFTER 39
+#define AC_OBJ_ATTRIBUTE_TYPE 42
+#define AC_OBJ_ATTRIBUTE_VALUE 44
+#define AC_OBJ_EXTN_ID 49
+#define AC_OBJ_CRITICAL 50
+#define AC_OBJ_EXTN_VALUE 51
+#define AC_OBJ_ALGORITHM 53
+#define AC_OBJ_SIGNATURE 54
+#define AC_OBJ_ROOF 55
+
+/**
+ * Implements x509ac_t.is_valid
+ */
+static err_t is_valid(const private_x509ac_t *this, time_t *until)
+{
+ time_t current_time = time(NULL);
+
+ DBG2(" not before : %T", &this->notBefore);
+ DBG2(" current time: %T", &current_time);
+ DBG2(" not after : %T", &this->notAfter);
+
+ if (until != NULL &&
+ (*until == UNDEFINED_TIME || this->notAfter < *until))
+ {
+ *until = this->notAfter;
+ }
+ if (current_time < this->notBefore)
+ {
+ return "is not valid yet";
+ }
+ if (current_time > this->notAfter)
+ {
+ return "has expired";
+ }
+ DBG2(" attribute certificate is valid");
+ return NULL;
+}
+
+/**
+ * parses a directoryName
+ */
+static bool parse_directoryName(chunk_t blob, int level, bool implicit, identification_t **name)
+{
+ bool has_directoryName;
+ linked_list_t *list = linked_list_create();
+
+ parse_generalNames(blob, level, implicit, list);
+ has_directoryName = list->get_count(list) > 0;
+
+ if (has_directoryName)
+ {
+ iterator_t *iterator = list->create_iterator(list, TRUE);
+ identification_t *directoryName;
+ bool first = TRUE;
+
+ while (iterator->iterate(iterator, (void**)&directoryName))
+ {
+ if (first)
+ {
+ *name = directoryName;
+ first = FALSE;
+ }
+ else
+ {
+ DBG1("more than one directory name - first selected");
+ directoryName->destroy(directoryName);
+ }
+ }
+ iterator->destroy(iterator);
+ }
+ else
+ {
+ DBG1("no directoryName found");
+ }
+
+ list->destroy(list);
+ return has_directoryName;
+}
+
+/**
+ * parses ietfAttrSyntax
+ */
+static void parse_ietfAttrSyntax(chunk_t blob, int level0, linked_list_t *list)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, FALSE);
+
+ while (objectID < IETF_ATTR_ROOF)
+ {
+ if (!extract_object(ietfAttrSyntaxObjects, &objectID, &object, &level, &ctx))
+ {
+ return;
+ }
+
+ switch (objectID)
+ {
+ case IETF_ATTR_OCTETS:
+ case IETF_ATTR_OID:
+ case IETF_ATTR_STRING:
+ {
+ ietfAttribute_t kind = (objectID - IETF_ATTR_OCTETS) / 2;
+ ietfAttr_t *attr = ietfAttr_create(kind, object);
+ list->insert_last(list, (void *)attr);
+ }
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+}
+
+/**
+ * parses roleSyntax
+ */
+static void parse_roleSyntax(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, FALSE);
+ while (objectID < ROLE_ROOF)
+ {
+ if (!extract_object(roleSyntaxObjects, &objectID, &object, &level, &ctx))
+ {
+ return;
+ }
+
+ switch (objectID)
+ {
+ default:
+ break;
+ }
+ objectID++;
+ }
+}
+
+/**
+ * Parses an X.509 attribute certificate
+ */
+static bool parse_certificate(chunk_t blob, private_x509ac_t *this)
+{
+ asn1_ctx_t ctx;
+ bool critical;
+ chunk_t object;
+ u_int level;
+ u_int type = OID_UNKNOWN;
+ u_int extn_oid = OID_UNKNOWN;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, 0, FALSE, FALSE);
+ while (objectID < AC_OBJ_ROOF)
+ {
+ if (!extract_object(acObjects, &objectID, &object, &level, &ctx))
+ {
+ return FALSE;
+ }
+
+ /* those objects which will parsed further need the next higher level */
+ level++;
+
+ switch (objectID)
+ {
+ case AC_OBJ_CERTIFICATE:
+ this->certificate = object;
+ break;
+ case AC_OBJ_CERTIFICATE_INFO:
+ this->certificateInfo = object;
+ break;
+ case AC_OBJ_VERSION:
+ this->version = (object.len) ? (1 + (u_int)*object.ptr) : 1;
+ DBG2(" v%d", this->version);
+ if (this->version != 2)
+ {
+ DBG1("v%d attribute certificates are not supported", this->version);
+ return FALSE;
+ }
+ break;
+ case AC_OBJ_HOLDER_ISSUER:
+ if (!parse_directoryName(object, level, FALSE, &this->holderIssuer))
+ {
+ return FALSE;
+ }
+ break;
+ case AC_OBJ_HOLDER_SERIAL:
+ this->holderSerial = object;
+ break;
+ case AC_OBJ_ENTITY_NAME:
+ if (!parse_directoryName(object, level, TRUE, &this->entityName))
+ {
+ return FALSE;
+ }
+ break;
+ case AC_OBJ_ISSUER_NAME:
+ if (!parse_directoryName(object, level, FALSE, &this->issuerName))
+ {
+ return FALSE;
+ }
+ break;
+ case AC_OBJ_SIG_ALG:
+ this->sigAlg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case AC_OBJ_SERIAL_NUMBER:
+ this->serialNumber = object;
+ break;
+ case AC_OBJ_NOT_BEFORE:
+ this->notBefore = asn1totime(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case AC_OBJ_NOT_AFTER:
+ this->notAfter = asn1totime(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case AC_OBJ_ATTRIBUTE_TYPE:
+ type = known_oid(object);
+ break;
+ case AC_OBJ_ATTRIBUTE_VALUE:
+ {
+ switch (type)
+ {
+ case OID_AUTHENTICATION_INFO:
+ DBG2(" need to parse authenticationInfo");
+ break;
+ case OID_ACCESS_IDENTITY:
+ DBG2(" need to parse accessIdentity");
+ break;
+ case OID_CHARGING_IDENTITY:
+ parse_ietfAttrSyntax(object, level, this->charging);
+ break;
+ case OID_GROUP:
+ parse_ietfAttrSyntax(object, level, this->groups);
+ break;
+ case OID_ROLE:
+ parse_roleSyntax(object, level);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case AC_OBJ_EXTN_ID:
+ extn_oid = known_oid(object);
+ break;
+ case AC_OBJ_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG2(" %s",(critical)?"TRUE":"FALSE");
+ break;
+ case AC_OBJ_EXTN_VALUE:
+ {
+ switch (extn_oid)
+ {
+ case OID_CRL_DISTRIBUTION_POINTS:
+ DBG2(" need to parse crlDistributionPoints");
+ break;
+ case OID_AUTHORITY_KEY_ID:
+ parse_authorityKeyIdentifier(object, level,
+ &this->authKeyID, &this->authKeySerialNumber);
+ break;
+ case OID_TARGET_INFORMATION:
+ DBG2(" need to parse targetInformation");
+ break;
+ case OID_NO_REV_AVAIL:
+ this->noRevAvail = TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case AC_OBJ_ALGORITHM:
+ this->algorithm = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case AC_OBJ_SIGNATURE:
+ this->signature = object;
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+ this->installed = time(NULL);
+ return FALSE;
+}
+
+/**
+ * Implements x509ac_t.destroy
+ */
+static void destroy(private_x509ac_t *this)
+{
+ DESTROY_IF(this->holderIssuer);
+ DESTROY_IF(this->entityName);
+ DESTROY_IF(this->issuerName);
+ this->charging->destroy_offset(this->charging,
+ offsetof(ietfAttr_t, destroy));
+ this->groups->destroy_offset(this->groups,
+ offsetof(ietfAttr_t, destroy));
+ free(this->certificate.ptr);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+x509ac_t *x509ac_create_from_chunk(chunk_t chunk)
+{
+ private_x509ac_t *this = malloc_thing(private_x509ac_t);
+
+ /* initialize */
+ this->holderIssuer = NULL;
+ this->entityName = NULL;
+ this->issuerName = NULL;
+ this->charging = linked_list_create();
+ this->groups = linked_list_create();
+
+ /* public functions */
+ this->public.is_valid = (err_t (*) (const x509ac_t*,time_t*))is_valid;
+ this->public.destroy = (void (*) (x509ac_t*))destroy;
+
+ if (!parse_certificate(chunk, this))
+ {
+ destroy(this);
+ return NULL;
+ }
+ return &this->public;
+}
+
+/**
+ * Described in header.
+ */
+x509ac_t *x509ac_create_from_file(const char *filename)
+{
+ bool pgp = FALSE;
+ chunk_t chunk = chunk_empty;
+
+ if (!pem_asn1_load_file(filename, NULL, "attribute certificate", &chunk, &pgp))
+ {
+ return NULL;
+ }
+ return x509ac_create_from_chunk(chunk);
+}
+
diff --git a/src/libstrongswan/crypto/ac.h b/src/libstrongswan/crypto/ac.h
new file mode 100644
index 000000000..b7fd26c94
--- /dev/null
+++ b/src/libstrongswan/crypto/ac.h
@@ -0,0 +1,81 @@
+/**
+ * @file ac.h
+ *
+ * @brief Interface of x509ac_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
+ * Copyright (C) 2003 Martin Berner, Lukas Suter
+ * Copyright (C) 2007 Andreas Steffen
+ *
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ */
+
+#ifndef AC_H_
+#define AC_H_
+
+typedef struct x509ac_t x509ac_t;
+
+/**
+ * @brief X.509 attribute certificate.
+ *
+ * @b Constructors:
+ * - x509ac_create_from_chunk()
+ * - x509ac_create_from_file()
+ *
+ * @ingroup crypto
+ */
+struct x509ac_t {
+
+ /**
+ * @brief Checks the validity interval of the attribute certificate
+ *
+ * @param this certificate being examined
+ * @param until until = min(until, notAfter)
+ * @return NULL if the certificate is valid
+ */
+ err_t (*is_valid) (const x509ac_t *this, time_t *until);
+
+ /**
+ * @brief Destroys the attribute certificate.
+ *
+ * @param this certificate to destroy
+ */
+ void (*destroy) (x509ac_t *this);
+};
+
+/**
+ * @brief Read a x509 attribute certificate from a DER encoded blob.
+ *
+ * @param chunk chunk containing DER encoded data
+ * @return created x509ac_t certificate, or NULL if invalid.
+ *
+ * @ingroup crypto
+ */
+x509ac_t *x509ac_create_from_chunk(chunk_t chunk);
+
+/**
+ * @brief Read a x509 attribute certificate from a DER encoded file.
+ *
+ * @param filename file containing DER encoded data
+ * @return created x509ac_t certificate, or NULL if invalid.
+ *
+ * @ingroup crypto
+ */
+x509ac_t *x509ac_create_from_file(const char *filename);
+
+
+#endif /* AC_H_ */
+
diff --git a/src/libstrongswan/crypto/ca.c b/src/libstrongswan/crypto/ca.c
index 1f566a098..07413e805 100644
--- a/src/libstrongswan/crypto/ca.c
+++ b/src/libstrongswan/crypto/ca.c
@@ -29,6 +29,7 @@
#include "x509.h"
#include "crl.h"
#include "ca.h"
+#include "ac.h"
#include "certinfo.h"
#include "ocsp.h"
@@ -65,6 +66,11 @@ struct private_ca_info_t {
x509_t *cacert;
/**
+ * List of attribute certificates
+ */
+ linked_list_t *attrcerts;
+
+ /**
* List of crl URIs
*/
linked_list_t *crluris;
@@ -94,6 +100,7 @@ struct private_ca_info_t {
/**
* static options set by ca_info_set_options()
*/
+static strict_t strict_crl_policy = STRICT_NO;
static bool cache_crls = FALSE;
static u_int crl_check_interval = 0;
@@ -151,6 +158,31 @@ static bool is_crl_issuer(private_ca_info_t *this, const crl_t *crl)
}
/**
+ * Implements ca_info_t.is_ca
+ */
+static bool is_ca(private_ca_info_t *this)
+{
+ return this->cacert->is_ca(this->cacert);
+}
+
+/**
+ * Implements ca_info_t.is_strict
+ */
+static bool is_strict(private_ca_info_t *this)
+{
+ bool strict = strict_crl_policy != STRICT_NO;
+
+ if (strict_crl_policy == STRICT_IFURI)
+ {
+ pthread_mutex_lock(&(this->mutex));
+ strict = this->crluris->get_count(this->crluris) > 0 ||
+ this->ocspuris->get_count(this->ocspuris) > 0;
+ pthread_mutex_unlock(&(this->mutex));
+ }
+ return strict;
+}
+
+/**
* Implements ca_info_t.has_crl
*/
static bool has_crl(private_ca_info_t *this)
@@ -213,11 +245,9 @@ static void add_crl(private_ca_info_t *this, crl_t *crl)
*/
static void list_crl(private_ca_info_t *this, FILE *out, bool utc)
{
- pthread_mutex_lock(&(this->mutex));
-
- fprintf(out, "%#U\n", this->crl, utc);
-
- pthread_mutex_unlock(&(this->mutex));
+ pthread_mutex_lock(&this->mutex);
+ this->crl->list(this->crl, out, utc);
+ pthread_mutex_unlock(&this->mutex);
}
/**
@@ -225,26 +255,42 @@ static void list_crl(private_ca_info_t *this, FILE *out, bool utc)
*/
static void list_certinfos(private_ca_info_t *this, FILE *out, bool utc)
{
- pthread_mutex_lock(&(this->mutex));
+ iterator_t *iterator;
+ certinfo_t *certinfo;
+ chunk_t authkey;
+ pthread_mutex_lock(&this->mutex);
+
+ authkey = this->cacert->get_subjectKeyID(this->cacert);
fprintf(out," authname: '%D'\n", this->cacert->get_subject(this->cacert));
- {
- chunk_t authkey = this->cacert->get_subjectKeyID(this->cacert);
+ fprintf(out," authkey: %#B\n", &authkey);
- fprintf(out," authkey: %#B\n", &authkey);
- }
+ iterator = this->certinfos->create_iterator(this->certinfos, TRUE);
+ while (iterator->iterate(iterator, (void**)&certinfo))
{
- iterator_t *iterator = this->certinfos->create_iterator(this->certinfos, TRUE);
- certinfo_t *certinfo;
-
- while (iterator->iterate(iterator, (void**)&certinfo))
+ time_t nextUpdate, thisUpdate, now;
+ chunk_t serial;
+
+ now = time(NULL);
+ nextUpdate = certinfo->get_nextUpdate(certinfo);
+ thisUpdate = certinfo->get_thisUpdate(certinfo);
+ serial = certinfo->get_serialNumber(certinfo);
+
+ fprintf(out, "%#T, until %#T, ", &thisUpdate, utc, &nextUpdate, utc);
+ if (now > nextUpdate)
{
- fprintf(out, "%#Y\n", certinfo, utc);
+ fprintf(out, "expired (%V ago)\n", &now, &nextUpdate);
}
- iterator->destroy(iterator);
+ else
+ {
+ fprintf(out, "ok (expires in %V)\n", &now, &nextUpdate);
+ }
+ fprintf(out, " serial: %#B, %N\n", &serial,
+ cert_status_names, certinfo->get_status(certinfo));
}
+ iterator->destroy(iterator);
- pthread_mutex_unlock(&(this->mutex));
+ pthread_mutex_unlock(&this->mutex);
}
/**
@@ -644,6 +690,8 @@ static void purge_ocsp(private_ca_info_t *this)
*/
static void destroy(private_ca_info_t *this)
{
+ this->attrcerts->destroy_offset(this->attrcerts,
+ offsetof(x509ac_t, destroy));
this->crluris->destroy_offset(this->crluris,
offsetof(identification_t, destroy));
this->ocspuris->destroy_offset(this->ocspuris,
@@ -656,92 +704,59 @@ static void destroy(private_ca_info_t *this)
}
/**
- * output handler in printf()
+ * list the info of this CA
*/
-static int print(FILE *stream, const struct printf_info *info,
- const void *const *args)
+static void list(private_ca_info_t* this, FILE* out, bool utc)
{
- private_ca_info_t *this = *((private_ca_info_t**)(args[0]));
- bool utc = TRUE;
- int written = 0;
- const x509_t *cacert;
+ chunk_t chunk;
+ identification_t *uri;
+ iterator_t *iterator;
+ bool first;
- if (info->alt)
- {
- utc = *((bool*)args[1]);
- }
- if (this == NULL)
- {
- return fprintf(stream, "(null)");
- }
-
pthread_mutex_lock(&(this->mutex));
- written += fprintf(stream, "%#T", &this->installed, utc);
+ fprintf(out, "%#T", &this->installed, utc);
if (this->name)
{
- written += fprintf(stream, ", \"%s\"\n", this->name);
+ fprintf(out, ", \"%s\"\n", this->name);
}
else
{
- written += fprintf(stream, "\n");
+ fprintf(out, "\n");
}
- cacert = this->cacert;
- written += fprintf(stream, " authname: '%D'\n", cacert->get_subject(cacert));
- {
- chunk_t authkey = cacert->get_subjectKeyID(cacert);
-
- written += fprintf(stream, " authkey: %#B\n", &authkey);
- }
+ fprintf(out, " authname: '%D'\n", this->cacert->get_subject(this->cacert));
+ chunk = this->cacert->get_subjectKeyID(this->cacert);
+ fprintf(out, " authkey: %#B\n", &chunk);
+ chunk = this->cacert->get_keyid(this->cacert);
+ fprintf(out, " keyid: %#B\n", &chunk);
+
+ first = TRUE;
+ iterator = this->crluris->create_iterator(this->crluris, TRUE);
+ while (iterator->iterate(iterator, (void**)&uri))
{
- chunk_t keyid = cacert->get_keyid(cacert);
-
- written += fprintf(stream, " keyid: %#B\n", &keyid);
- }
- {
- identification_t *crluri;
- iterator_t *iterator = this->crluris->create_iterator(this->crluris, TRUE);
- bool first = TRUE;
-
- while (iterator->iterate(iterator, (void**)&crluri))
- {
- written += fprintf(stream, " %s '%D'\n",
- first? "crluris:":" ", crluri);
- first = FALSE;
- }
- iterator->destroy(iterator);
+ fprintf(out, " %s '%D'\n", first ? "crluris:":" ", uri);
+ first = FALSE;
}
+ iterator->destroy(iterator);
+
+ first = TRUE;
+ iterator = this->ocspuris->create_iterator(this->ocspuris, TRUE);
+ while (iterator->iterate(iterator, (void**)&uri))
{
- identification_t *ocspuri;
- iterator_t *iterator = this->ocspuris->create_iterator(this->ocspuris, TRUE);
- bool first = TRUE;
-
- while (iterator->iterate(iterator, (void**)&ocspuri))
- {
- written += fprintf(stream, " %s '%D'\n",
- first? "ocspuris:":" ", ocspuri);
- first = FALSE;
- }
- iterator->destroy(iterator);
+ fprintf(out, " %s '%D'\n", first ? "ocspuris:":" ", uri);
+ first = FALSE;
}
+ iterator->destroy(iterator);
pthread_mutex_unlock(&(this->mutex));
- return written;
-}
-
-/**
- * register printf() handlers
- */
-static void __attribute__ ((constructor))print_register()
-{
- register_printf_function(PRINTF_CAINFO, print, arginfo_ptr_alt_ptr_int);
}
/*
* Described in header.
*/
-void ca_info_set_options(bool cache, u_int interval)
+void ca_info_set_options(strict_t strict, bool cache, u_int interval)
{
+ strict_crl_policy = strict;
cache_crls = cache;
crl_check_interval = interval;
}
@@ -757,6 +772,7 @@ ca_info_t *ca_info_create(const char *name, x509_t *cacert)
this->installed = time(NULL);
this->name = (name == NULL)? NULL:strdup(name);
this->cacert = cacert;
+ this->attrcerts = linked_list_create();
this->crluris = linked_list_create();
this->ocspuris = linked_list_create();
this->certinfos = linked_list_create();
@@ -770,10 +786,13 @@ ca_info_t *ca_info_create(const char *name, x509_t *cacert)
this->public.equals_name_release_info = (bool (*) (ca_info_t*,const char*))equals_name_release_info;
this->public.is_cert_issuer = (bool (*) (ca_info_t*,const x509_t*))is_cert_issuer;
this->public.is_crl_issuer = (bool (*) (ca_info_t*,const crl_t*))is_crl_issuer;
+ this->public.is_ca = (bool (*) (ca_info_t*))is_ca;
+ this->public.is_strict = (bool (*) (ca_info_t*))is_strict;
this->public.add_info = (void (*) (ca_info_t*,const ca_info_t*))add_info;
this->public.add_crl = (void (*) (ca_info_t*,crl_t*))add_crl;
this->public.has_crl = (bool (*) (ca_info_t*))has_crl;
this->public.has_certinfos = (bool (*) (ca_info_t*))has_certinfos;
+ this->public.list = (void (*) (ca_info_t*,FILE*,bool))list;
this->public.list_crl = (void (*) (ca_info_t*,FILE*,bool))list_crl;
this->public.list_certinfos = (void (*) (ca_info_t*,FILE*,bool))list_certinfos;
this->public.add_crluri = (void (*) (ca_info_t*,chunk_t))add_crluri;
diff --git a/src/libstrongswan/crypto/ca.h b/src/libstrongswan/crypto/ca.h
index c494a4468..ff6271b15 100644
--- a/src/libstrongswan/crypto/ca.h
+++ b/src/libstrongswan/crypto/ca.h
@@ -26,13 +26,15 @@
typedef struct ca_info_t ca_info_t;
#include <library.h>
-#include <chunk.h>
-
-#include <credential_store.h>
#include "x509.h"
#include "crl.h"
+#define MAX_CA_PATH_LEN 7
+
+/*forward declaration */
+struct credential_store_t;
+
/**
* @brief X.509 certification authority information record
*
@@ -81,6 +83,22 @@ struct ca_info_t {
bool (*is_crl_issuer) (ca_info_t *this, const crl_t *crl);
/**
+ * @brief Checks if the ca certificate has the isCA flag set
+ *
+ * @param this ca info object
+ * @return TRUE if the isCA flag is set
+ */
+ bool (*is_ca) (ca_info_t *this);
+
+ /**
+ * @brief Checks if the ca enforces a strict crl policy
+ *
+ * @param this ca info object
+ * @return TRUE if the crl policy is strict
+ */
+ bool (*is_strict) (ca_info_t *this);
+
+ /**
* @brief Merges info from a secondary ca info object
*
* @param this primary ca info object
@@ -113,6 +131,16 @@ struct ca_info_t {
bool (*has_certinfos) (ca_info_t *this);
/**
+ * @brief Print the CA info onto the console
+ *
+ * @param this ca info object
+ * @param out output stream
+ * @param utc TRUE - utc
+ FALSE - local time
+ */
+ void (*list) (ca_info_t *this, FILE *out, bool utc);
+
+ /**
* @brief List the CRL onto the console
*
* @param this ca info object
@@ -174,7 +202,7 @@ struct ca_info_t {
* @param credentials credential store needed for trust path verification
* @return certificate status
*/
- cert_status_t (*verify_by_ocsp) (ca_info_t* this, certinfo_t* certinfo, credential_store_t* credentials);
+ cert_status_t (*verify_by_ocsp) (ca_info_t* this, certinfo_t* certinfo, struct credential_store_t* credentials);
/**
* @brief Purge the OCSP certinfos of a ca info record
@@ -199,7 +227,7 @@ struct ca_info_t {
*
* @ingroup crypto
*/
-void ca_info_set_options(bool cache, u_int interval);
+void ca_info_set_options(strict_t strict, bool cache, u_int interval);
/**
* @brief Create a ca info record
diff --git a/src/libstrongswan/crypto/certinfo.c b/src/libstrongswan/crypto/certinfo.c
index 654e4c2bd..8a125e247 100644
--- a/src/libstrongswan/crypto/certinfo.c
+++ b/src/libstrongswan/crypto/certinfo.c
@@ -221,54 +221,6 @@ static void destroy(private_certinfo_t *this)
free(this);
}
-/**
- * output handler in printf()
- */
-static int print(FILE *stream, const struct printf_info *info,
- const void *const *args)
-{
- private_certinfo_t *this = *((private_certinfo_t**)(args[0]));
- bool utc = TRUE;
- int written = 0;
- time_t now;
-
- if (info->alt)
- {
- utc = *((bool*)args[1]);
- }
-
- if (this == NULL)
- {
- return fprintf(stream, "(null)");
- }
-
- now = time(NULL);
-
- written += fprintf(stream, "%#T, until %#T, ",
- &this->thisUpdate, utc,
- &this->nextUpdate, utc);
- if (now > this->nextUpdate)
- {
- written += fprintf(stream, "expired (%V ago)\n", &now, &this->nextUpdate);
- }
- else
- {
- written += fprintf(stream, "ok (expires in %V)\n", &now, &this->nextUpdate);
- }
- written += fprintf(stream, " serial: %#B, %N",
- &this->serialNumber,
- cert_status_names, this->status);
- return written;
-}
-
-/**
- * register printf() handlers
- */
-static void __attribute__ ((constructor))print_register()
-{
- register_printf_function(PRINTF_CERTINFO, print, arginfo_ptr_alt_ptr_int);
-}
-
/*
* Described in header.
*/
diff --git a/src/libstrongswan/crypto/crl.c b/src/libstrongswan/crypto/crl.c
index 00d6a3ac3..b4ae37b2e 100755
--- a/src/libstrongswan/crypto/crl.c
+++ b/src/libstrongswan/crypto/crl.c
@@ -39,10 +39,6 @@
#define CRL_WARNING_INTERVAL 7 /* days */
-extern char* check_expiry(time_t expiration_date, int warning_interval, bool strict);
-extern time_t parse_time(chunk_t blob, int level0);
-extern void parse_authorityKeyIdentifier(chunk_t blob, int level0 , chunk_t *authKeyID, chunk_t *authKeySerialNumber);
-
/* access structure for a revoked certificate */
typedef struct revokedCert_t revokedCert_t;
@@ -100,6 +96,11 @@ struct private_crl_t {
identification_t *issuer;
/**
+ * CRL number
+ */
+ chunk_t crlNumber;
+
+ /**
* Time when the crl was generated
*/
time_t thisUpdate;
@@ -291,6 +292,14 @@ bool parse_x509crl(chunk_t blob, u_int level0, private_crl_t *crl)
{
parse_authorityKeyIdentifier(object, level, &crl->authKeyID, &crl->authKeySerialNumber);
}
+ else if (extn_oid == OID_CRL_NUMBER)
+ {
+ if (!parse_asn1_simple_object(&object, ASN1_INTEGER, level, "crlNumber"))
+ {
+ return FALSE;
+ }
+ crl->crlNumber = object;
+ }
}
break;
case CRL_OBJ_ALGORITHM:
@@ -416,66 +425,47 @@ static void destroy(private_crl_t *this)
}
/**
- * output handler in printf()
+ * Implementation of crl_t.list.
*/
-static int print(FILE *stream, const struct printf_info *info,
- const void *const *args)
+static void list(private_crl_t *this, FILE* out, bool utc)
{
- private_crl_t *this = *((private_crl_t**)(args[0]));
- bool utc = TRUE;
- int written = 0;
time_t now;
- if (info->alt)
- {
- utc = *((bool*)args[1]);
- }
-
- if (this == NULL)
- {
- return fprintf(stream, "(null)");
- }
-
now = time(NULL);
- written += fprintf(stream, "%#T, revoked certs: %d\n", &this->installed, utc,
+ fprintf(out, "%#T, revoked certs: %d\n", &this->installed, utc,
this->revokedCertificates->get_count(this->revokedCertificates));
- written += fprintf(stream, " issuer: '%D'\n", this->issuer);
- written += fprintf(stream, " updates: this %#T\n", &this->thisUpdate, utc);
- written += fprintf(stream, " next %#T ", &this->nextUpdate, utc);
+ fprintf(out, " issuer: '%D'\n", this->issuer);
+ if (this->crlNumber.ptr)
+ {
+ fprintf(out, " crlnumber: %#B\n", &this->crlNumber);
+ }
+ fprintf(out, " updates: this %#T\n", &this->thisUpdate, utc);
+ fprintf(out, " next %#T ", &this->nextUpdate, utc);
if (this->nextUpdate == UNDEFINED_TIME)
{
- written += fprintf(stream, "ok (expires never)");
+ fprintf(out, "ok (expires never)\n");
}
else if (now > this->nextUpdate)
{
- written += fprintf(stream, "expired (%V ago)", &now, &this->nextUpdate);
+ fprintf(out, "expired (%V ago)\n", &now, &this->nextUpdate);
}
else if (now > this->nextUpdate - CRL_WARNING_INTERVAL * 60 * 60 * 24)
{
- written += fprintf(stream, "ok (expires in %V)", &now, &this->nextUpdate);
+ fprintf(out, "ok (expires in %V)\n", &now, &this->nextUpdate);
}
else
{
- written += fprintf(stream, "ok");
+ fprintf(out, "ok\n");
}
if (this->authKeyID.ptr)
{
- written += fprintf(stream, "\n authkey: %#B", &this->authKeyID);
+ fprintf(out, " authkey: %#B\n", &this->authKeyID);
}
if (this->authKeySerialNumber.ptr)
{
- written += fprintf(stream, "\n aserial: %#B", &this->authKeySerialNumber);
+ fprintf(out, " aserial: %#B\n", &this->authKeySerialNumber);
}
- return written;
-}
-
-/**
- * register printf() handlers
- */
-static void __attribute__ ((constructor))print_register()
-{
- register_printf_function(PRINTF_CRL, print, arginfo_ptr_alt_ptr_int);
}
/*
@@ -489,6 +479,7 @@ crl_t *crl_create_from_chunk(chunk_t chunk)
this->crlDistributionPoints = linked_list_create();
this->tbsCertList = chunk_empty;
this->issuer = NULL;
+ this->crlNumber = chunk_empty;
this->revokedCertificates = linked_list_create();
this->authKeyID = chunk_empty;
this->authKeySerialNumber = chunk_empty;
@@ -502,6 +493,7 @@ crl_t *crl_create_from_chunk(chunk_t chunk)
this->public.verify = (bool (*) (const crl_t*,const rsa_public_key_t*))verify;
this->public.get_status = (void (*) (const crl_t*,certinfo_t*))get_status;
this->public.write_to_file = (bool (*) (const crl_t*,const char*,mode_t,bool))write_to_file;
+ this->public.list = (void(*)(crl_t*, FILE* out, bool utc))list;
this->public.destroy = (void (*) (crl_t*))destroy;
if (!parse_x509crl(chunk, 0, this))
@@ -520,14 +512,10 @@ crl_t *crl_create_from_file(const char *filename)
{
bool pgp = FALSE;
chunk_t chunk = chunk_empty;
- crl_t *crl = NULL;
if (!pem_asn1_load_file(filename, NULL, "crl", &chunk, &pgp))
+ {
return NULL;
-
- crl = crl_create_from_chunk(chunk);
-
- if (crl == NULL)
- free(chunk.ptr);
- return crl;
+ }
+ return crl_create_from_chunk(chunk);
}
diff --git a/src/libstrongswan/crypto/crl.h b/src/libstrongswan/crypto/crl.h
index 8a11fc390..a367c3aff 100755
--- a/src/libstrongswan/crypto/crl.h
+++ b/src/libstrongswan/crypto/crl.h
@@ -104,6 +104,15 @@ struct crl_t {
* @param certinfo certinfo is updated
*/
void (*get_status) (const crl_t *this, certinfo_t *certinfo);
+
+ /**
+ * @brief Log the info of this CRL to out.
+ *
+ * @param this calling object
+ * @param out stream to write to
+ * @param utc TRUE for UTC, FALSE for local time
+ */
+ void (*list)(crl_t *this, FILE* out, bool utc);
/**
* @brief Write a der-encoded crl to a file
diff --git a/src/libstrongswan/crypto/ocsp.c b/src/libstrongswan/crypto/ocsp.c
index 471996c8e..0d8093e4a 100644
--- a/src/libstrongswan/crypto/ocsp.c
+++ b/src/libstrongswan/crypto/ocsp.c
@@ -770,7 +770,7 @@ static void ocsp_process_response(private_ocsp_t *this, response_t *res, credent
if (res->responder_cert->is_ocsp_signer(res->responder_cert))
{
DBG2("received certificate is ocsp signer");
- if (credentials->is_trusted(credentials, res->responder_cert))
+ if (credentials->is_trusted(credentials, "OCSP signing", res->responder_cert))
{
DBG1("received ocsp signer certificate is trusted");
ocsp_cert = credentials->add_auth_certificate(credentials,
diff --git a/src/libstrongswan/crypto/x509.c b/src/libstrongswan/crypto/x509.c
index 58fcff16d..5bf3f26d7 100755
--- a/src/libstrongswan/crypto/x509.c
+++ b/src/libstrongswan/crypto/x509.c
@@ -6,7 +6,12 @@
*/
/*
- * Copyright (C) 2006 Martin Willi
+ * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
+ * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
+ * Copyright (C) 2002 Mario Strasser
+ * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ * Copyright (C) 2006 Martin Willi, Andreas Steffen
+ *
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -117,6 +122,11 @@ struct private_x509_t {
identification_t *issuer;
/**
+ * link to the info recored of the certificate issuer
+ */
+ ca_info_t *ca_info;
+
+ /**
* Start time of certificate validity
*/
time_t notBefore;
@@ -172,6 +182,11 @@ struct private_x509_t {
chunk_t authKeySerialNumber;
/**
+ * Indicates if the certificate is self-signed
+ */
+ bool isSelfSigned;
+
+ /**
* CA basic constraints flag
*/
bool isCA;
@@ -249,19 +264,6 @@ static const asn1Object_t basicConstraintsObjects[] = {
#define BASIC_CONSTRAINTS_CA 1
#define BASIC_CONSTRAINTS_ROOF 4
-/**
- * ASN.1 definition of time
- */
-static const asn1Object_t timeObjects[] = {
- { 0, "utcTime", ASN1_UTCTIME, ASN1_OPT|ASN1_BODY }, /* 0 */
- { 0, "end opt", ASN1_EOC, ASN1_END }, /* 1 */
- { 0, "generalizeTime",ASN1_GENERALIZEDTIME, ASN1_OPT|ASN1_BODY }, /* 2 */
- { 0, "end opt", ASN1_EOC, ASN1_END } /* 3 */
-};
-#define TIME_UTC 0
-#define TIME_GENERALIZED 2
-#define TIME_ROOF 4
-
/**
* ASN.1 definition of a keyIdentifier
*/
@@ -545,7 +547,7 @@ static identification_t *parse_generalName(chunk_t blob, int level0)
/**
* extracts one or several GNs and puts them into a chained list
*/
-static void parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list)
+void parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list)
{
asn1_ctx_t ctx;
chunk_t object;
@@ -572,33 +574,6 @@ static void parse_generalNames(chunk_t blob, int level0, bool implicit, linked_l
}
/**
- * extracts and converts a UTCTIME or GENERALIZEDTIME object
- */
-time_t parse_time(chunk_t blob, int level0)
-{
- asn1_ctx_t ctx;
- chunk_t object;
- u_int level;
- int objectID = 0;
-
- asn1_init(&ctx, blob, level0, FALSE, FALSE);
-
- while (objectID < TIME_ROOF)
- {
- if (!extract_object(timeObjects, &objectID, &object, &level, &ctx))
- return 0;
-
- if (objectID == TIME_UTC || objectID == TIME_GENERALIZED)
- {
- return asn1totime(&object, (objectID == TIME_UTC)
- ? ASN1_UTCTIME : ASN1_GENERALIZEDTIME);
- }
- objectID++;
- }
- return 0;
-}
-
-/**
* extracts a keyIdentifier
*/
static chunk_t parse_keyIdentifier(chunk_t blob, int level0, bool implicit)
@@ -624,7 +599,11 @@ void parse_authorityKeyIdentifier(chunk_t blob, int level0 , chunk_t *authKeyID,
u_int level;
int objectID = 0;
+ *authKeyID = chunk_empty;
+ *authKeySerialNumber = chunk_empty;
+
asn1_init(&ctx, blob, level0, FALSE, FALSE);
+
while (objectID < AUTH_KEY_ID_ROOF)
{
if (!extract_object(authorityKeyIdentifierObjects, &objectID, &object, &level, &ctx))
@@ -763,7 +742,7 @@ static void parse_crlDistributionPoints(chunk_t blob, int level0, linked_list_t
/**
* Parses an X.509v3 certificate
*/
-static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *cert)
+static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *this)
{
asn1_ctx_t ctx;
bool critical;
@@ -779,38 +758,41 @@ static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *cert)
{
return FALSE;
}
+
/* those objects which will parsed further need the next higher level */
level++;
- switch (objectID) {
+
+ switch (objectID)
+ {
case X509_OBJ_CERTIFICATE:
- cert->certificate = object;
+ this->certificate = object;
break;
case X509_OBJ_TBS_CERTIFICATE:
- cert->tbsCertificate = object;
+ this->tbsCertificate = object;
break;
case X509_OBJ_VERSION:
- cert->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
- DBG2(" v%d", cert->version);
+ this->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
+ DBG2(" v%d", this->version);
break;
case X509_OBJ_SERIAL_NUMBER:
- cert->serialNumber = object;
+ this->serialNumber = object;
break;
case X509_OBJ_SIG_ALG:
- cert->sigAlg = parse_algorithmIdentifier(object, level, NULL);
+ this->sigAlg = parse_algorithmIdentifier(object, level, NULL);
break;
case X509_OBJ_ISSUER:
- cert->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
- DBG2(" '%D'", cert->issuer);
+ this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
+ DBG2(" '%D'", this->issuer);
break;
case X509_OBJ_NOT_BEFORE:
- cert->notBefore = parse_time(object, level);
+ this->notBefore = parse_time(object, level);
break;
case X509_OBJ_NOT_AFTER:
- cert->notAfter = parse_time(object, level);
+ this->notAfter = parse_time(object, level);
break;
case X509_OBJ_SUBJECT:
- cert->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object);
- DBG2(" '%D'", cert->subject);
+ this->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object);
+ DBG2(" '%D'", this->subject);
break;
case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM:
if (parse_algorithmIdentifier(object, level, NULL) != OID_RSA_ENCRYPTION)
@@ -832,7 +814,7 @@ static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *cert)
}
break;
case X509_OBJ_RSA_PUBLIC_KEY:
- cert->subjectPublicKey = object;
+ this->subjectPublicKey = object;
break;
case X509_OBJ_EXTN_ID:
extn_oid = known_oid(object);
@@ -843,27 +825,28 @@ static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *cert)
break;
case X509_OBJ_EXTN_VALUE:
{
- switch (extn_oid) {
+ switch (extn_oid)
+ {
case OID_SUBJECT_KEY_ID:
- cert->subjectKeyID = chunk_clone(parse_keyIdentifier(object, level, FALSE));
+ this->subjectKeyID = chunk_clone(parse_keyIdentifier(object, level, FALSE));
break;
case OID_SUBJECT_ALT_NAME:
- parse_generalNames(object, level, FALSE, cert->subjectAltNames);
+ parse_generalNames(object, level, FALSE, this->subjectAltNames);
break;
case OID_BASIC_CONSTRAINTS:
- cert->isCA = parse_basicConstraints(object, level);
+ this->isCA = parse_basicConstraints(object, level);
break;
case OID_CRL_DISTRIBUTION_POINTS:
- parse_crlDistributionPoints(object, level, cert->crlDistributionPoints);
+ parse_crlDistributionPoints(object, level, this->crlDistributionPoints);
break;
case OID_AUTHORITY_KEY_ID:
- parse_authorityKeyIdentifier(object, level , &cert->authKeyID, &cert->authKeySerialNumber);
+ parse_authorityKeyIdentifier(object, level , &this->authKeyID, &this->authKeySerialNumber);
break;
case OID_AUTHORITY_INFO_ACCESS:
- parse_authorityInfoAccess(object, level, cert->ocspAccessLocations);
+ parse_authorityInfoAccess(object, level, this->ocspAccessLocations);
break;
case OID_EXTENDED_KEY_USAGE:
- cert->isOcspSigner = parse_extendedKeyUsage(object, level);
+ this->isOcspSigner = parse_extendedKeyUsage(object, level);
break;
case OID_NS_REVOCATION_URL:
case OID_NS_CA_REVOCATION_URL:
@@ -878,10 +861,10 @@ static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *cert)
break;
}
case X509_OBJ_ALGORITHM:
- cert->algorithm = parse_algorithmIdentifier(object, level, NULL);
+ this->algorithm = parse_algorithmIdentifier(object, level, NULL);
break;
case X509_OBJ_SIGNATURE:
- cert->signature = object;
+ this->signature = object;
break;
default:
break;
@@ -889,15 +872,16 @@ static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *cert)
objectID++;
}
- if (cert->subjectKeyID.ptr == NULL)
+ /* generate the subjectKeyID if it is missing in the certificate */
+ if (this->subjectKeyID.ptr == NULL)
{
hasher_t *hasher = hasher_create(HASH_SHA1);
- hasher->allocate_hash(hasher, cert->subjectPublicKey, &cert->subjectKeyID);
+ hasher->allocate_hash(hasher, this->subjectPublicKey, &this->subjectKeyID);
hasher->destroy(hasher);
}
- time(&cert->installed);
+ this->installed = time(NULL);
return TRUE;
}
@@ -950,7 +934,7 @@ static bool is_ocsp_signer(const private_x509_t *this)
*/
static bool is_self_signed(const private_x509_t *this)
{
- return this->subject->equals(this->subject, this->issuer);
+ return this->isSelfSigned;
}
/**
@@ -1043,6 +1027,22 @@ static identification_t *get_subject(const private_x509_t *this)
}
/**
+ * Implements x509_t.set_ca_info
+ */
+static void set_ca_info(private_x509_t *this, ca_info_t *ca_info)
+{
+ this->ca_info = ca_info;
+}
+
+/**
+ * Implements x509_t.get_ca_info
+ */
+static ca_info_t *get_ca_info(const private_x509_t *this)
+{
+ return this->ca_info;
+}
+
+/**
* Implements x509_t.set_until
*/
static void set_until(private_x509_t *this, time_t until)
@@ -1121,39 +1121,23 @@ static bool verify(const private_x509_t *this, const rsa_public_key_t *signer)
{
return signer->verify_emsa_pkcs1_signature(signer, this->tbsCertificate, this->signature) == SUCCESS;
}
-
+
/**
- * output handler in printf()
+ * Implementation of x509_t.list.
*/
-static int print(FILE *stream, const struct printf_info *info,
- const void *const *args)
+static void list(private_x509_t *this, FILE *out, bool utc)
{
- private_x509_t *this = *((private_x509_t**)(args[0]));
iterator_t *iterator;
- bool utc = TRUE;
- int written = 0;
-
- if (info->alt)
- {
- utc = *((bool*)(args[1]));
- }
-
- if (this == NULL)
- {
- return fprintf(stream, "(null)");
- }
-
- /* determine the current time */
time_t now = time(NULL);
- written += fprintf(stream, "%#T\n", &this->installed, utc);
+ fprintf(out, "%#T\n", &this->installed, utc);
if (this->subjectAltNames->get_count(this->subjectAltNames))
{
identification_t *subjectAltName;
bool first = TRUE;
- written += fprintf(stream, " altNames: ");
+ fprintf(out, " altNames: ");
iterator = this->subjectAltNames->create_iterator(this->subjectAltNames, TRUE);
while (iterator->iterate(iterator, (void**)&subjectAltName))
{
@@ -1163,71 +1147,71 @@ static int print(FILE *stream, const struct printf_info *info,
}
else
{
- written += fprintf(stream, ", ");
+ fprintf(out, ", ");
}
- written += fprintf(stream, "'%D'", subjectAltName);
+ fprintf(out, "'%D'", subjectAltName);
}
iterator->destroy(iterator);
- written += fprintf(stream, "\n");
+ fprintf(out, "\n");
}
- written += fprintf(stream, " subject: '%D'\n", this->subject);
- written += fprintf(stream, " issuer: '%D'\n", this->issuer);
- written += fprintf(stream, " serial: %#B\n", &this->serialNumber);
- written += fprintf(stream, " validity: not before %#T, ", &this->notBefore, utc);
+ fprintf(out, " subject: '%D'\n", this->subject);
+ fprintf(out, " issuer: '%D'\n", this->issuer);
+ fprintf(out, " serial: %#B\n", &this->serialNumber);
+ fprintf(out, " validity: not before %#T, ", &this->notBefore, utc);
if (now < this->notBefore)
{
- written += fprintf(stream, "not valid yet (valid in %V)\n", &now, &this->notBefore);
+ fprintf(out, "not valid yet (valid in %V)\n", &now, &this->notBefore);
}
else
{
- written += fprintf(stream, "ok\n");
+ fprintf(out, "ok\n");
}
- written += fprintf(stream, " not after %#T, ", &this->notAfter, utc);
+ fprintf(out, " not after %#T, ", &this->notAfter, utc);
if (now > this->notAfter)
{
- written += fprintf(stream, "expired (%V ago)\n", &now, &this->notAfter);
+ fprintf(out, "expired (%V ago)\n", &now, &this->notAfter);
}
else
{
- written += fprintf(stream, "ok");
+ fprintf(out, "ok");
if (now > this->notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24)
{
- written += fprintf(stream, " (expires in %V)", &now, &this->notAfter);
+ fprintf(out, " (expires in %V)", &now, &this->notAfter);
}
- written += fprintf(stream, " \n");
+ fprintf(out, " \n");
}
{
chunk_t keyid = this->public_key->get_keyid(this->public_key);
- written += fprintf(stream, " keyid: %#B\n", &keyid);
+ fprintf(out, " keyid: %#B\n", &keyid);
}
if (this->subjectKeyID.ptr)
{
- written += fprintf(stream, " subjkey: %#B\n", &this->subjectKeyID);
+ fprintf(out, " subjkey: %#B\n", &this->subjectKeyID);
}
if (this->authKeyID.ptr)
{
- written += fprintf(stream, " authkey: %#B\n", &this->authKeyID);
+ fprintf(out, " authkey: %#B\n", &this->authKeyID);
}
if (this->authKeySerialNumber.ptr)
{
- written += fprintf(stream, " aserial: %#B\n", &this->authKeySerialNumber);
+ fprintf(out, " aserial: %#B\n", &this->authKeySerialNumber);
}
- written += fprintf(stream, " pubkey: RSA %d bits", BITS_PER_BYTE *
- this->public_key->get_keysize(this->public_key));
- written += fprintf(stream, ", status %N",
- cert_status_names, this->status);
+ fprintf(out, " pubkey: RSA %d bits", BITS_PER_BYTE *
+ this->public_key->get_keysize(this->public_key));
+ fprintf(out, ", status %N",
+ cert_status_names, this->status);
switch (this->status)
{
case CERT_GOOD:
- written += fprintf(stream, " until %#T", &this->until, utc);
+ fprintf(out, " until %#T", &this->until, utc);
break;
case CERT_REVOKED:
- written += fprintf(stream, " on %#T", &this->until, utc);
+ fprintf(out, " on %#T", &this->until, utc);
break;
case CERT_UNKNOWN:
case CERT_UNDEFINED:
@@ -1235,15 +1219,6 @@ static int print(FILE *stream, const struct printf_info *info,
default:
break;
}
- return written;
-}
-
-/**
- * register printf() handlers
- */
-static void __attribute__ ((constructor))print_register()
-{
- register_printf_function(PRINTF_X509, print, arginfo_ptr_alt_ptr_int);
}
/**
@@ -1277,6 +1252,7 @@ x509_t *x509_create_from_chunk(chunk_t chunk, u_int level)
this->public_key = NULL;
this->subject = NULL;
this->issuer = NULL;
+ this->ca_info = NULL;
this->subjectAltNames = linked_list_create();
this->crlDistributionPoints = linked_list_create();
this->ocspAccessLocations = linked_list_create();
@@ -1284,6 +1260,8 @@ x509_t *x509_create_from_chunk(chunk_t chunk, u_int level)
this->authKeyID = chunk_empty;
this->authKeySerialNumber = chunk_empty;
this->authority_flags = AUTH_NONE;
+ this->isCA = FALSE;
+ this->isOcspSigner = FALSE;
/* public functions */
this->public.equals = (bool (*) (const x509_t*,const x509_t*))equals;
@@ -1300,6 +1278,8 @@ x509_t *x509_create_from_chunk(chunk_t chunk, u_int level)
this->public.get_keyid = (chunk_t (*) (const x509_t*))get_keyid;
this->public.get_issuer = (identification_t* (*) (const x509_t*))get_issuer;
this->public.get_subject = (identification_t* (*) (const x509_t*))get_subject;
+ this->public.set_ca_info = (void (*) (x509_t*,ca_info_t*))set_ca_info;
+ this->public.get_ca_info = (ca_info_t* (*) (const x509_t*))get_ca_info;
this->public.set_until = (void (*) (x509_t*,time_t))set_until;
this->public.get_until = (time_t (*) (const x509_t*))get_until;
this->public.set_status = (void (*) (x509_t*,cert_status_t))set_status;
@@ -1310,6 +1290,7 @@ x509_t *x509_create_from_chunk(chunk_t chunk, u_int level)
this->public.create_crluri_iterator = (iterator_t* (*) (const x509_t*))create_crluri_iterator;
this->public.create_ocspuri_iterator = (iterator_t* (*) (const x509_t*))create_ocspuri_iterator;
this->public.verify = (bool (*) (const x509_t*,const rsa_public_key_t*))verify;
+ this->public.list = (void(*)(x509_t*, FILE *out, bool utc))list;
this->public.destroy = (void (*) (x509_t*))destroy;
if (!parse_certificate(chunk, level, this))
@@ -1325,9 +1306,27 @@ x509_t *x509_create_from_chunk(chunk_t chunk, u_int level)
destroy(this);
return NULL;
}
+
/* set trusted lifetime of public key to notAfter */
- this->status = is_self_signed(this)? CERT_GOOD:CERT_UNDEFINED;
this->until = this->notAfter;
+
+ /* check if the certificate is self-signed */
+ this->isSelfSigned = FALSE;
+ if (this->subject->equals(this->subject, this->issuer))
+ {
+ this->isSelfSigned = this->public_key->verify_emsa_pkcs1_signature(this->public_key,
+ this->tbsCertificate, this->signature) == SUCCESS;
+ }
+ if (this->isSelfSigned)
+ {
+ DBG2(" certificate is self-signed");
+ this->status = CERT_GOOD;
+ }
+ else
+ {
+ this->status = CERT_UNDEFINED;
+ }
+
return &this->public;
}
@@ -1338,17 +1337,13 @@ x509_t *x509_create_from_file(const char *filename, const char *label)
{
bool pgp = FALSE;
chunk_t chunk = chunk_empty;
- x509_t *cert = NULL;
char cert_label[BUF_LEN];
snprintf(cert_label, BUF_LEN, "%s certificate", label);
if (!pem_asn1_load_file(filename, NULL, cert_label, &chunk, &pgp))
+ {
return NULL;
-
- cert = x509_create_from_chunk(chunk, 0);
-
- if (cert == NULL)
- free(chunk.ptr);
- return cert;
+ }
+ return x509_create_from_chunk(chunk, 0);
}
diff --git a/src/libstrongswan/crypto/x509.h b/src/libstrongswan/crypto/x509.h
index a949d99d2..c6fe148d4 100755
--- a/src/libstrongswan/crypto/x509.h
+++ b/src/libstrongswan/crypto/x509.h
@@ -6,7 +6,12 @@
*/
/*
+ * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
+ * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
+ * Copyright (C) 2002 Mario Strasser
+ * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
* Copyright (C) 2006 Martin Willi, Andreas Steffen
+ *
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -28,8 +33,10 @@ typedef struct x509_t x509_t;
#include <library.h>
#include <crypto/rsa/rsa_public_key.h>
#include <crypto/certinfo.h>
+#include <crypto/ca.h>
#include <utils/identification.h>
#include <utils/iterator.h>
+#include <utils/linked_list.h>
/* authority flags */
@@ -44,12 +51,8 @@ typedef struct x509_t x509_t;
* @b Constructors:
* - x509_create_from_chunk()
* - x509_create_from_file()
- *
- * @todo more code cleanup needed!
- * @todo fix unimplemented functions...
- * @todo handle memory management
*
- * @ingroup transforms
+ * @ingroup crypto
*/
struct x509_t {
@@ -151,7 +154,7 @@ struct x509_t {
chunk_t (*get_keyid) (const x509_t *this);
/**
- * @brief Get the certificate issuer's ID.
+ * @brief Get the issuerDistinguishedName
*
* The resulting ID is always a identification_t
* of type ID_DER_ASN1_DN.
@@ -162,7 +165,7 @@ struct x509_t {
identification_t *(*get_issuer) (const x509_t *this);
/**
- * @brief Get the subjectDistinguisheName.
+ * @brief Get the subjectDistinguishedName.
*
* The resulting ID is always a identification_t
* of type ID_DER_ASN1_DN.
@@ -173,6 +176,26 @@ struct x509_t {
identification_t *(*get_subject) (const x509_t *this);
/**
+ * @brief Set a link ca info
+ *
+ * @param this calling object
+ * @param ca_info link to the info record of the issuing ca
+ */
+ void (*set_ca_info) (x509_t *this, ca_info_t *ca_info);
+
+ /**
+ * @brief Get the .
+ *
+ * The resulting ID is always a identification_t
+ * of type ID_DER_ASN1_DN.
+ *
+ * @param this calling object
+ * @return link to the info record of the issuing ca
+ * or NULL if it does not [yet] exist
+ */
+ ca_info_t *(*get_ca_info) (const x509_t *this);
+
+ /**
* @brief Create an iterator for the crlDistributionPoints.
*
* @param this calling object
@@ -257,7 +280,16 @@ struct x509_t {
* @return TRUE if self-signed
*/
bool (*is_self_signed) (const x509_t *this);
-
+
+ /**
+ * @brief Log the certificate info to out.
+ *
+ * @param this calling object
+ * @param out stream to write to
+ * @param utc TRUE for UTC times, FALSE for local time
+ */
+ void (*list)(x509_t *this, FILE *out, bool utc);
+
/**
* @brief Destroys the certificate.
*
@@ -272,7 +304,7 @@ struct x509_t {
* @param chunk chunk containing DER encoded data
* @return created x509_t certificate, or NULL if invlid.
*
- * @ingroup transforms
+ * @ingroup crypto
*/
x509_t *x509_create_from_chunk(chunk_t chunk, u_int level);
@@ -283,8 +315,32 @@ x509_t *x509_create_from_chunk(chunk_t chunk, u_int level);
* @param label label describing kind of certificate
* @return created x509_t certificate, or NULL if invalid.
*
- * @ingroup transforms
+ * @ingroup crypto
*/
x509_t *x509_create_from_file(const char *filename, const char *label);
+/**
+ * @brief Parses a DER encoded authorityKeyIdentifier
+ *
+ * @param blob blob containing DER encoded data
+ * @param level0 indicates the current parsing level
+ * @param authKeyID assigns the authorityKeyIdentifier
+ * @param authKeySerialNumber assigns the authKeySerialNumber
+ *
+ * @ingroup crypto
+ */
+void parse_authorityKeyIdentifier(chunk_t blob, int level0, chunk_t *authKeyID, chunk_t *authKeySerialNumber);
+
+/**
+ * @brief Parses DER encoded generalNames
+ *
+ * @param blob blob containing DER encoded data
+ * @param level0 indicates the current parsing level
+ * @param implicit implicit coding is used
+ * @param list linked list of decoded generalNames
+ *
+ * @ingroup crypto
+ */
+void parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list);
+
#endif /* X509_H_ */