diff options
Diffstat (limited to 'src/libstrongswan/crypto')
-rw-r--r-- | src/libstrongswan/crypto/ac.c | 665 | ||||
-rw-r--r-- | src/libstrongswan/crypto/ac.h | 81 | ||||
-rw-r--r-- | src/libstrongswan/crypto/ca.c | 179 | ||||
-rw-r--r-- | src/libstrongswan/crypto/ca.h | 38 | ||||
-rw-r--r-- | src/libstrongswan/crypto/certinfo.c | 48 | ||||
-rwxr-xr-x | src/libstrongswan/crypto/crl.c | 80 | ||||
-rwxr-xr-x | src/libstrongswan/crypto/crl.h | 9 | ||||
-rw-r--r-- | src/libstrongswan/crypto/ocsp.c | 2 | ||||
-rwxr-xr-x | src/libstrongswan/crypto/x509.c | 261 | ||||
-rwxr-xr-x | src/libstrongswan/crypto/x509.h | 76 |
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", ¤t_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_ */ |