diff options
Diffstat (limited to 'src/pluto/ac.c')
-rw-r--r-- | src/pluto/ac.c | 994 |
1 files changed, 154 insertions, 840 deletions
diff --git a/src/pluto/ac.c b/src/pluto/ac.c index 3b5df9738..d8b16112f 100644 --- a/src/pluto/ac.c +++ b/src/pluto/ac.c @@ -1,6 +1,7 @@ /* Support of X.509 attribute certificates * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler * Copyright (C) 2003 Martin Berner, Lukas Suter + * Copyright (C) 2009 Andreas Steffen * * 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 @@ -13,971 +14,284 @@ * for more details. */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <dirent.h> +#include <sys/stat.h> #include <time.h> -#include <sys/types.h> -#include <freeswan.h> - -#include <utils.h> -#include <asn1/asn1.h> -#include <asn1/asn1_parser.h> -#include <asn1/oid.h> +#include <debug.h> +#include <utils/enumerator.h> +#include <utils/linked_list.h> +#include <credentials/certificates/ac.h> #include "ac.h" -#include "x509.h" -#include "crl.h" #include "ca.h" #include "certs.h" -#include "log.h" -#include "whack.h" #include "fetch.h" +#include "log.h" /** * Chained list of X.509 attribute certificates */ -static x509acert_t *x509acerts = NULL; - -/** - * Chained list of ietfAttributes - */ -static ietfAttrList_t *ietfAttributes = NULL; - -/** - * 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 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; - -#define IETF_ATTR_OCTETS 4 -#define IETF_ATTR_OID 6 -#define IETF_ATTR_STRING 8 - -/** - * 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 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; - -/** - * 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 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; - -#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 - -const x509acert_t empty_ac = { - NULL , /* *next */ - 0 , /* installed */ - { NULL, 0 }, /* certificate */ - { NULL, 0 }, /* certificateInfo */ - 1 , /* version */ - /* holder */ - /* baseCertificateID */ - { NULL, 0 }, /* holderIssuer */ - { NULL, 0 }, /* holderSerial */ - /* entityName */ - { NULL, 0 }, /* generalNames */ - /* v2Form */ - { NULL, 0 }, /* issuerName */ - /* signature */ - OID_UNKNOWN, /* sigAlg */ - { NULL, 0 }, /* serialNumber */ - /* attrCertValidityPeriod */ - 0 , /* notBefore */ - 0 , /* notAfter */ - /* attributes */ - NULL , /* charging */ - NULL , /* groups */ - /* extensions */ - { NULL, 0 }, /* authKeyID */ - { NULL, 0 }, /* authKeySerialNumber */ - FALSE , /* noRevAvail */ - /* signatureAlgorithm */ - OID_UNKNOWN, /* algorithm */ - { NULL, 0 }, /* signature */ -}; - +static linked_list_t *acerts = NULL; /** - * compare two ietfAttributes, returns zero if a equals b - * negative/positive if a is earlier/later in the alphabet than b + * Initialize the linked list of attribute certificates */ -static int cmp_ietfAttr(ietfAttr_t *a,ietfAttr_t *b) +void ac_initialize(void) { - int cmp_len, len, cmp_value; - - /* cannot compare OID with STRING or OCTETS attributes */ - if (a->kind == IETF_ATTRIBUTE_OID && b->kind != IETF_ATTRIBUTE_OID) - return 1; - - cmp_len = a->value.len - b->value.len; - len = (cmp_len < 0)? a->value.len : b->value.len; - cmp_value = memcmp(a->value.ptr, b->value.ptr, len); - - return (cmp_value == 0)? cmp_len : cmp_value; + acerts = linked_list_create(); } /** - * add an ietfAttribute to the chained list + * Free the linked list of attribute certificates */ -static ietfAttr_t* add_ietfAttr(ietfAttr_t *attr) +void ac_finalize(void) { - ietfAttrList_t **listp = &ietfAttributes; - ietfAttrList_t *list = *listp; - int cmp = -1; - - while (list != NULL) - { - cmp = cmp_ietfAttr(attr, list->attr); - if (cmp <= 0) - break; - listp = &list->next; - list = *listp; - } - - if (cmp == 0) - { - /* attribute already exists, increase count */ - free(attr); - list->attr->count++; - return list->attr; - } - else + if (acerts) { - ietfAttrList_t *el = malloc_thing(ietfAttrList_t); - - /* new attribute, unshare value */ - attr->value = chunk_clone(attr->value); - attr->count = 1; - time(&attr->installed); - - el->attr = attr; - el->next = list; - *listp = el; - - return attr; + acerts->destroy_offset(acerts, offsetof(certificate_t, destroy)); } } /** - * decodes a comma separated list of group attributes + * Get a X.509 attribute certificate for a given holder */ -void decode_groups(char *groups, ietfAttrList_t **listp) +certificate_t* ac_get_cert(identification_t *issuer, chunk_t serial) { - if (groups == NULL) - return; + enumerator_t *enumerator; + certificate_t *cert, *found = NULL; - while (strlen(groups) > 0) + enumerator = acerts->create_enumerator(acerts); + while (enumerator->enumerate(enumerator, &cert)) { - char *end; - char *next = strchr(groups, ','); - - if (next == NULL) - end = next = groups + strlen(groups); - else - end = next++; - - /* eat preceeding whitespace */ - while (groups < end && *groups == ' ') - groups++; + ac_t *ac = (ac_t*)cert; - /* eat trailing whitespace */ - while (end > groups && *(end-1) == ' ') - end--; - - if (groups < end) + if (issuer->equals(issuer, ac->get_holderIssuer(ac)) && + chunk_equals(serial, ac->get_holderSerial(ac))) { - ietfAttr_t *attr = malloc_thing(ietfAttr_t); - ietfAttrList_t *el = malloc_thing(ietfAttrList_t); - - attr->kind = IETF_ATTRIBUTE_STRING; - attr->value.ptr = groups; - attr->value.len = end - groups; - attr->count = 0; - - el->attr = add_ietfAttr(attr); - el->next = *listp; - *listp = el; + found = cert; + break; } - - groups = next; } + enumerator->destroy(enumerator); + return found; } -static bool same_attribute(const ietfAttr_t *a, const ietfAttr_t *b) +/** + * Verifies a X.509 attribute certificate + */ +bool ac_verify_cert(certificate_t *cert, bool strict) { - return (a->kind == b->kind && a->value.len == b->value.len - && memeq(a->value.ptr, b->value.ptr, b->value.len)); -} + ac_t *ac = (ac_t*)cert; + identification_t *subject = cert->get_subject(cert); + identification_t *issuer = cert->get_issuer(cert); + chunk_t authKeyID = ac->get_authKeyIdentifier(ac); + cert_t *aacert; + time_t notBefore, valid_until; -bool group_membership(const ietfAttrList_t *peer_list - , const char *conn - , const ietfAttrList_t *conn_list) -{ - if (conn_list == NULL) - return TRUE; + DBG1("holder: '%Y'", subject); + DBG1("issuer: '%Y'", issuer); - while (peer_list != NULL) + if (!cert->get_validity(cert, NULL, NULL, &valid_until)) { - const ietfAttr_t *peer_attr = peer_list->attr; - const ietfAttrList_t *list = conn_list; - - while (list != NULL) - { - ietfAttr_t *conn_attr = list->attr; - - if (same_attribute(conn_attr, peer_attr)) - { - DBG(DBG_CONTROL, - DBG_log("%s: peer matches group '%.*s'" - , conn - , (int)peer_attr->value.len, peer_attr->value.ptr) - ) - return TRUE; - } - list = list->next; - } - peer_list = peer_list->next; + DBG1("attribute certificate is invalid (valid from %T to %T)", + ¬Before, FALSE, &valid_until, FALSE); + return FALSE; } - DBG(DBG_CONTROL, - DBG_log("%s: peer doesn't match any group", conn) - ) - return FALSE; -} + DBG1("attribute certificate is valid until %T", &valid_until, FALSE); -void unshare_ietfAttrList(ietfAttrList_t **listp) -{ - ietfAttrList_t *list = *listp; + lock_authcert_list("verify_x509acert"); + aacert = get_authcert(issuer, authKeyID, X509_AA); + unlock_authcert_list("verify_x509acert"); - while (list != NULL) + if (aacert == NULL) { - ietfAttrList_t *el = malloc_thing(ietfAttrList_t); - - el->attr = list->attr; - el->attr->count++; - el->next = NULL; - *listp = el; - listp = &el->next; - list = list->next; + DBG1("issuer aacert not found"); + return FALSE; } -} - -/** - * Parses ietfAttrSyntax - */ -static ietfAttrList_t* parse_ietfAttrSyntax(chunk_t blob, int level0) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; + DBG2("issuer aacert found"); - ietfAttrList_t *list = NULL; - - parser = asn1_parser_create(ietfAttrSyntaxObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) + if (!cert->issued_by(cert, aacert->cert)) { - switch (objectID) - { - case IETF_ATTR_OCTETS: - case IETF_ATTR_OID: - case IETF_ATTR_STRING: - { - ietfAttr_t *attr = malloc_thing(ietfAttr_t); - ietfAttrList_t *el = malloc_thing(ietfAttrList_t); - - attr->kind = (objectID - IETF_ATTR_OCTETS) / 2; - attr->value = object; - attr->count = 0; - - el->attr = add_ietfAttr(attr); - el->next = list; - list = el; - } - break; - default: - break; - } + DBG1("attribute certificate signature is invalid"); + return FALSE; } - parser->destroy(parser); - return list; -} - -/** - * Parses roleSyntax - */ -static void parse_roleSyntax(chunk_t blob, int level0) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; + DBG1("attribute certificate signature is valid"); - parser = asn1_parser_create(roleSyntaxObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - default: - break; - } - } - parser->destroy(parser); + return verify_x509cert(aacert, strict, &valid_until); } /** - * Parses an X.509 attribute certificate + * Add a X.509 attribute certificate to the chained list */ -bool parse_ac(chunk_t blob, x509acert_t *ac) +static void ac_add_cert(certificate_t *cert) { - asn1_parser_t *parser; - chunk_t object; - int objectID; - int type = OID_UNKNOWN; - int extn_oid = OID_UNKNOWN; - bool success = FALSE; - bool critical; + ac_t *ac = (ac_t*)cert; + identification_t *hIssuer = ac->get_holderIssuer(ac); + chunk_t hSerial = ac->get_holderSerial(ac); - parser = asn1_parser_create(acObjects, blob); + enumerator_t *enumerator; + certificate_t *cert_old; - while (parser->iterate(parser, &objectID, &object)) + enumerator = acerts->create_enumerator(acerts); + while (enumerator->enumerate(enumerator, &cert_old)) { - u_int level = parser->get_level(parser)+1; + ac_t *ac_old = (ac_t*)cert_old; - switch (objectID) + if (hIssuer->equals(hIssuer, ac_old->get_holderIssuer(ac_old)) && + chunk_equals(hSerial, ac_old->get_holderSerial(ac_old))) { - case AC_OBJ_CERTIFICATE: - ac->certificate = object; - break; - case AC_OBJ_CERTIFICATE_INFO: - ac->certificateInfo = object; - break; - case AC_OBJ_VERSION: - ac->version = (object.len) ? (1 + (u_int)*object.ptr) : 1; - DBG(DBG_PARSING, - DBG_log(" v%d", ac->version); - ) - if (ac->version != 2) + if (cert->is_newer(cert, cert_old)) { - plog("v%d attribute certificates are not supported" - , ac->version); - goto end; + acerts->remove_at(acerts, enumerator); + cert_old->destroy(cert_old); } - break; - case AC_OBJ_HOLDER_ISSUER: - ac->holderIssuer = get_directoryName(object, level, FALSE); - break; - case AC_OBJ_HOLDER_SERIAL: - ac->holderSerial = object; - break; - case AC_OBJ_ENTITY_NAME: - ac->entityName = get_directoryName(object, level, TRUE); - break; - case AC_OBJ_ISSUER_NAME: - ac->issuerName = get_directoryName(object, level, FALSE); - break; - case AC_OBJ_SIG_ALG: - ac->sigAlg = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case AC_OBJ_SERIAL_NUMBER: - ac->serialNumber = object; - break; - case AC_OBJ_NOT_BEFORE: - ac->notBefore = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case AC_OBJ_NOT_AFTER: - ac->notAfter = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case AC_OBJ_ATTRIBUTE_TYPE: - type = asn1_known_oid(object); - break; - case AC_OBJ_ATTRIBUTE_VALUE: + else { - switch (type) { - case OID_AUTHENTICATION_INFO: - DBG(DBG_PARSING, - DBG_log(" need to parse authenticationInfo") - ) - break; - case OID_ACCESS_IDENTITY: - DBG(DBG_PARSING, - DBG_log(" need to parse accessIdentity") - ) - break; - case OID_CHARGING_IDENTITY: - ac->charging = parse_ietfAttrSyntax(object, level); - break; - case OID_GROUP: - ac->groups = parse_ietfAttrSyntax(object, level); - break; - case OID_ROLE: - parse_roleSyntax(object, level); - break; - default: - break; - } + cert->destroy(cert); + cert = NULL; } break; - case AC_OBJ_EXTN_ID: - extn_oid = asn1_known_oid(object); - break; - case AC_OBJ_CRITICAL: - critical = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(critical)?"TRUE":"FALSE"); - ) - break; - case AC_OBJ_EXTN_VALUE: - { - switch (extn_oid) { - case OID_CRL_DISTRIBUTION_POINTS: - DBG(DBG_PARSING, - DBG_log(" need to parse crlDistributionPoints") - ) - break; - case OID_AUTHORITY_KEY_ID: - parse_authorityKeyIdentifier(object, level - , &ac->authKeyID, &ac->authKeySerialNumber); - break; - case OID_TARGET_INFORMATION: - DBG(DBG_PARSING, - DBG_log(" need to parse targetInformation") - ) - break; - case OID_NO_REV_AVAIL: - ac->noRevAvail = TRUE; - break; - default: - break; - } - } - break; - case AC_OBJ_ALGORITHM: - ac->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case AC_OBJ_SIGNATURE: - ac->signature = object; - break; - - default: - break; } } - success = parser->success(parser); - time(&ac->installed); - -end: - parser->destroy(parser); - return success; -} + enumerator->destroy(enumerator); -/** - * Release an ietfAttribute, free it if count reaches zero - */ -static void release_ietfAttr(ietfAttr_t* attr) -{ - if (--attr->count == 0) + if (cert) { - ietfAttrList_t **plist = &ietfAttributes; - ietfAttrList_t *list = *plist; - - while (list->attr != attr) - { - plist = &list->next; - list = *plist; - } - *plist = list->next; - - free(attr->value.ptr); - free(attr); - free(list); + acerts->insert_last(acerts, cert); } } /** - * Free an ietfAttrList + * Check if at least one peer attribute matches a connection attribute */ -void free_ietfAttrList(ietfAttrList_t* list) +bool match_group_membership(ietf_attributes_t *peer_attributes, char *conn, + ietf_attributes_t *conn_attributes) { - while (list != NULL) - { - ietfAttrList_t *el = list; - - release_ietfAttr(el->attr); - list = list->next; - free(el); - } -} + bool match; -/** - * Free a X.509 attribute certificate - */ -void free_acert(x509acert_t *ac) -{ - if (ac != NULL) + if (conn_attributes == NULL) { - free_ietfAttrList(ac->charging); - free_ietfAttrList(ac->groups); - free(ac->certificate.ptr); - free(ac); - } -} - -/** - * Free first X.509 attribute certificate in the chained list - */ -static void free_first_acert(void) -{ - x509acert_t *first = x509acerts; - x509acerts = first->next; - free_acert(first); -} - -/** - * Free all attribute certificates in the chained list - */ -void free_acerts(void) -{ - while (x509acerts != NULL) - free_first_acert(); -} - -/** - * Get a X.509 attribute certificate for a given holder - */ -x509acert_t* get_x509acert(chunk_t issuer, chunk_t serial) -{ - x509acert_t *ac = x509acerts; - x509acert_t *prev_ac = NULL; - - while (ac != NULL) - { - if (same_dn(issuer, ac->holderIssuer) - && same_serial(serial, ac->holderSerial)) - { - if (ac!= x509acerts) - { - /* bring the certificate up front */ - prev_ac->next = ac->next; - ac->next = x509acerts; - x509acerts = ac; - } - return ac; - } - prev_ac = ac; - ac = ac->next; - } - return NULL; -} - -/** - * Add a X.509 attribute certificate to the chained list - */ -static void add_acert(x509acert_t *ac) -{ - x509acert_t *old_ac = get_x509acert(ac->holderIssuer, ac->holderSerial); - - if (old_ac != NULL) - { - if (ac->notBefore >old_ac->notBefore) - { - /* delete the old attribute cert */ - free_first_acert(); - DBG(DBG_CONTROL, - DBG_log("attribute cert is newer - existing cert deleted") - ) - } - else - { - DBG(DBG_CONTROL, - DBG_log("attribute cert is not newer - existing cert kept"); - ) - free_acert(ac); - return; - } + return TRUE; } - plog("attribute cert added"); - /* insert new attribute cert at the root of the chain */ - ac->next = x509acerts; - x509acerts = ac; -} + match = conn_attributes->matches(conn_attributes, peer_attributes); + DBG1("%s: peer with attributes '%s' is %sa member of the groups '%s'", + conn, peer_attributes->get_string(peer_attributes), + match ? "" : "not ", conn_attributes->get_string(conn_attributes)); -/** - * Verify the validity of an attribute certificate by - * checking the notBefore and notAfter dates - */ -static err_t check_ac_validity(const x509acert_t *ac) -{ - time_t current_time; - - time(¤t_time); - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" not before : %T", &ac->notBefore, TRUE); - DBG_log(" current time: %T", ¤t_time, TRUE); - DBG_log(" not after : %T", &ac->notAfter, TRUE); - ) - - if (current_time < ac->notBefore) - return "attribute certificate is not valid yet"; - if (current_time > ac->notAfter) - return "attribute certificate has expired"; - else - return NULL; + return match; } /** - * verifies a X.509 attribute certificate + * Loads X.509 attribute certificates */ -bool verify_x509acert(x509acert_t *ac, bool strict) +void ac_load_certs(void) { - u_char buf[BUF_LEN]; - x509cert_t *aacert; - err_t ugh = NULL; - time_t valid_until = ac->notAfter; - - DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, ac->entityName); - DBG_log("holder: '%s'",buf); - dntoa(buf, BUF_LEN, ac->issuerName); - DBG_log("issuer: '%s'",buf); - ) - - ugh = check_ac_validity(ac); - - if (ugh != NULL) - { - plog("%s", ugh); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("attribute certificate is valid") - ) + enumerator_t *enumerator; + struct stat st; + char *file; - lock_authcert_list("verify_x509acert"); - aacert = get_authcert(ac->issuerName, ac->authKeySerialNumber - , ac->authKeyID, AUTH_AA); - unlock_authcert_list("verify_x509acert"); - - if (aacert == NULL) - { - plog("issuer aacert not found"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("issuer aacert found") - ) + DBG1("loading attribute certificates from '%s'", A_CERT_PATH); - if (!x509_check_signature(ac->certificateInfo, ac->signature, ac->algorithm, - aacert)) + enumerator = enumerator_create_directory(A_CERT_PATH); + if (!enumerator) { - plog("attribute certificate signature is invalid"); - return FALSE; + return; } - DBG(DBG_CONTROL, - DBG_log("attribute certificate signature is valid"); - ) - - return verify_x509cert(aacert, strict, &valid_until); -} - -/** - * Loads X.509 attribute certificates - */ -void load_acerts(void) -{ - u_char buf[BUF_LEN]; - - /* change directory to specified path */ - u_char *save_dir = getcwd(buf, BUF_LEN); - if (!chdir(A_CERT_PATH)) + while (enumerator->enumerate(enumerator, NULL, &file, &st)) { - struct dirent **filelist; - int n; + certificate_t *cert; - plog("Changing to directory '%s'",A_CERT_PATH); - n = scandir(A_CERT_PATH, &filelist, file_select, alphasort); - - if (n > 0) + if (!S_ISREG(st.st_mode)) { - while (n--) - { - chunk_t blob = chunk_empty; - bool pgp = FALSE; - - if (load_coded_file(filelist[n]->d_name, NULL, "acert", &blob, &pgp)) - { - x509acert_t *ac = malloc_thing(x509acert_t); - - *ac = empty_ac; - - if (parse_ac(blob, ac) - && verify_x509acert(ac, FALSE)) - add_acert(ac); - else - free_acert(ac); - } - free(filelist[n]); - } - free(filelist); + /* skip special file */ + continue; } - } - /* restore directory path */ - ignore_result(chdir(save_dir)); -} - -/** - * lists group attributes separated by commas on a single line - */ -void format_groups(const ietfAttrList_t *list, char *buf, int len) -{ - bool first_group = TRUE; - - while (list != NULL && len > 0) - { - ietfAttr_t *attr = list->attr; - - if (attr->kind == IETF_ATTRIBUTE_OCTETS - || attr->kind == IETF_ATTRIBUTE_STRING) + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, + BUILD_FROM_FILE, file, BUILD_END); + if (cert) { - int written = snprintf(buf, len, "%s%.*s" - , (first_group)? "" : ", " - , (int)attr->value.len, attr->value.ptr); - - first_group = FALSE; - - /* return value of snprintf() up to glibc 2.0.6 */ - if (written < 0) - break; - - buf += written; - len -= written; + DBG1(" loaded attribute certificate from '%s'", file); + ac_add_cert(cert); } - list = list->next; } + enumerator->destroy(enumerator); } /** - * list all X.509 attribute certificates in the chained list + * List all X.509 attribute certificates in the chained list */ -void list_acerts(bool utc) +void ac_list_certs(bool utc) { - x509acert_t *ac = x509acerts; + enumerator_t *enumerator; + certificate_t *cert; time_t now; /* determine the current time */ time(&now); - if (ac != NULL) + if (acerts->get_count(acerts) > 0) { whack_log(RC_COMMENT, " "); whack_log(RC_COMMENT, "List of X.509 Attribute Certificates:"); - whack_log(RC_COMMENT, " "); } - while (ac != NULL) + enumerator = acerts->create_enumerator(acerts); + while (enumerator->enumerate(enumerator, &cert)) { - u_char buf[BUF_LEN]; + ac_t *ac = (ac_t*)cert; + identification_t *entityName, *holderIssuer, *issuer; + chunk_t holderSerial, serial, authKeyID; + time_t notBefore, notAfter; + ietf_attributes_t *groups; - whack_log(RC_COMMENT, "%T", &ac->installed, utc); - if (ac->entityName.ptr != NULL) - { - dntoa(buf, BUF_LEN, ac->entityName); - whack_log(RC_COMMENT, " holder: '%s'", buf); - } - if (ac->holderIssuer.ptr != NULL) - { - dntoa(buf, BUF_LEN, ac->holderIssuer); - whack_log(RC_COMMENT, " hissuer: '%s'", buf); - } - if (ac->holderSerial.ptr != NULL) + whack_log(RC_COMMENT, " "); + + entityName = cert->get_subject(cert); + if (entityName) { - datatot(ac->holderSerial.ptr, ac->holderSerial.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " hserial: %s", buf); + whack_log(RC_COMMENT, " holder: \"%Y\"", entityName); } - if (ac->groups != NULL) + + holderIssuer = ac->get_holderIssuer(ac); + if (holderIssuer) { - format_groups(ac->groups, buf, BUF_LEN); - whack_log(RC_COMMENT, " groups: %s", buf); + whack_log(RC_COMMENT, " hissuer: \"%Y\"", holderIssuer); } - dntoa(buf, BUF_LEN, ac->issuerName); - whack_log(RC_COMMENT, " issuer: '%s'", buf); - datatot(ac->serialNumber.ptr, ac->serialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " serial: %s", buf); - whack_log(RC_COMMENT, " validity: not before %T %s", - &ac->notBefore, utc, - (ac->notBefore < now)?"ok":"fatal (not valid yet)"); - whack_log(RC_COMMENT, " not after %T %s", - &ac->notAfter, utc, - check_expiry(ac->notAfter, ACERT_WARNING_INTERVAL, TRUE)); - if (ac->authKeyID.ptr != NULL) + + holderSerial = ac->get_holderSerial(ac); + if (holderSerial.ptr) { - datatot(ac->authKeyID.ptr, ac->authKeyID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authkey: %s", buf); + whack_log(RC_COMMENT, " hserial: %#B", &holderSerial); } - if (ac->authKeySerialNumber.ptr != NULL) + + groups = ac->get_groups(ac); + if (groups) { - datatot(ac->authKeySerialNumber.ptr, ac->authKeySerialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); + whack_log(RC_COMMENT, " groups: %s", groups->get_string(groups)); + groups->destroy(groups); } - ac = ac->next; - } -} + issuer = cert->get_issuer(cert); + whack_log(RC_COMMENT, " issuer: \"%Y\"", issuer); -/** - * list all group attributes in alphabetical order - */ -void list_groups(bool utc) -{ - ietfAttrList_t *list = ietfAttributes; - - if (list != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of Group Attributes:"); - whack_log(RC_COMMENT, " "); - } + serial = ac->get_serial(ac); + whack_log(RC_COMMENT, " serial: %#B", &serial); - while (list != NULL) - { - ietfAttr_t *attr = list->attr; + cert->get_validity(cert, &now, ¬Before, ¬After); + whack_log(RC_COMMENT, " validity: not before %T %s", + ¬Before, utc, + (notBefore < now)?"ok":"fatal (not valid yet)"); + whack_log(RC_COMMENT, " not after %T %s", ¬After, utc, + check_expiry(notAfter, ACERT_WARNING_INTERVAL, TRUE)); - whack_log(RC_COMMENT, "%T, count: %d", &attr->installed, utc, attr->count); - - switch (attr->kind) + authKeyID = ac->get_authKeyIdentifier(ac); + if (authKeyID.ptr) { - case IETF_ATTRIBUTE_OCTETS: - case IETF_ATTRIBUTE_STRING: - whack_log(RC_COMMENT, " %.*s", (int)attr->value.len, attr->value.ptr); - break; - case IETF_ATTRIBUTE_OID: - whack_log(RC_COMMENT, " OID"); - break; - default: - break; + whack_log(RC_COMMENT, " authkey: %#B", &authKeyID); } - - list = list->next; } + enumerator->destroy(enumerator); } + |