diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2008-03-20 15:23:52 +0000 |
---|---|---|
committer | Andreas Steffen <andreas.steffen@strongswan.org> | 2008-03-20 15:23:52 +0000 |
commit | bdec2e4f52918b007d3f0abe81a74e5ce2cc2532 (patch) | |
tree | f4318155078a5308be2d4f5c3b99461597951a83 | |
parent | 25c9637222291903cb61ce36f5b8c61f741afe0f (diff) | |
download | strongswan-bdec2e4f5291.tar.bz2 strongswan-bdec2e4f5291.tar.xz |
refactored openac and its attribute certificate factory
-rw-r--r-- | src/libstrongswan/Makefile.am | 1 | ||||
-rw-r--r-- | src/libstrongswan/credentials/builder.h | 4 | ||||
-rw-r--r-- | src/libstrongswan/credentials/certificates/ac.h | 58 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/Makefile.am | 7 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/ietf_attr_list.c | 405 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/ietf_attr_list.h | 89 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_ac.c | 807 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_ac.h | 59 | ||||
-rw-r--r-- | src/openac/Makefile.am | 2 | ||||
-rw-r--r-- | src/openac/build.c | 193 | ||||
-rw-r--r-- | src/openac/build.h | 45 | ||||
-rwxr-xr-x | src/openac/openac.c | 147 |
12 files changed, 1542 insertions, 275 deletions
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index b858e2585..5f2169cc4 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -34,6 +34,7 @@ credentials/keys/public_key.c credentials/keys/public_key.h \ credentials/keys/shared_key.c credentials/keys/shared_key.h \ credentials/certificates/certificate.c credentials/certificates/certificate.h \ credentials/certificates/x509.h credentials/certificates/x509.c \ +credentials/certificates/ac.h \ credentials/certificates/crl.h credentials/certificates/crl.c \ credentials/certificates/ocsp_request.h credentials/certificates/ocsp_request.c \ credentials/certificates/ocsp_response.h credentials/certificates/ocsp_response.c \ diff --git a/src/libstrongswan/credentials/builder.h b/src/libstrongswan/credentials/builder.h index fd1cc69cf..37259e606 100644 --- a/src/libstrongswan/credentials/builder.h +++ b/src/libstrongswan/credentials/builder.h @@ -56,6 +56,10 @@ enum builder_part_t { BUILD_ISSUER, /** additional issuer name, identification_t* */ BUILD_ISSUER_ALTNAME, + /** notBefore, time_t* */ + BUILD_NOT_BEFORE_TIME, + /** notAfter, time_t* */ + BUILD_NOT_AFTER_TIME, /** a CA certificate, certificate_t* */ BUILD_CA_CERT, /** a certificate, certificate_t* */ diff --git a/src/libstrongswan/credentials/certificates/ac.h b/src/libstrongswan/credentials/certificates/ac.h new file mode 100644 index 000000000..20c88b829 --- /dev/null +++ b/src/libstrongswan/credentials/certificates/ac.h @@ -0,0 +1,58 @@ +/* + * 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. + * + * RCSID $Id: ac.h 3300 2007-10-12 21:53:18Z andreas $ + */ + +/** + * @defgroup ac ac + * @{ @ingroup certificates + */ + +#ifndef AC_H_ +#define AC_H_ + +#include <library.h> +#include <credentials/certificates/certificate.h> + +typedef struct ac_t ac_t; + +/** + * X.509 attribute certificate interface. + * + * This interface adds additional methods to the certificate_t type to + * allow further operations on these certificates. + */ +struct ac_t { + + /** + * Implements the certificate_t interface + */ + certificate_t certificate; + + /** + * @brief Checks if two attribute certificates belong to the same holder + * + * @param this calling attribute certificate + * @param that other attribute certificate + * @return TRUE if same holder + */ + bool (*equals_holder) (const ac_t *this, const ac_t *other); +}; + +#endif /* AC_H_ @}*/ + diff --git a/src/libstrongswan/plugins/x509/Makefile.am b/src/libstrongswan/plugins/x509/Makefile.am index 12441b357..3f9f85c36 100644 --- a/src/libstrongswan/plugins/x509/Makefile.am +++ b/src/libstrongswan/plugins/x509/Makefile.am @@ -6,8 +6,11 @@ AM_CFLAGS = -rdynamic plugin_LTLIBRARIES = libstrongswan-x509.la libstrongswan_x509_la_SOURCES = x509_plugin.h x509_plugin.c \ - x509_cert.h x509_cert.c x509_crl.h x509_crl.c \ + x509_cert.h x509_cert.c \ + x509_crl.h x509_crl.c \ + x509_ac.h x509_ac.c \ x509_ocsp_request.h x509_ocsp_request.c \ - x509_ocsp_response.h x509_ocsp_response.c + x509_ocsp_response.h x509_ocsp_response.c \ + ietf_attr_list.h ietf_attr_list.c libstrongswan_x509_la_LDFLAGS = -module diff --git a/src/libstrongswan/plugins/x509/ietf_attr_list.c b/src/libstrongswan/plugins/x509/ietf_attr_list.c new file mode 100644 index 000000000..1ecadf679 --- /dev/null +++ b/src/libstrongswan/plugins/x509/ietf_attr_list.c @@ -0,0 +1,405 @@ +/** + * @file ietf_attr.c + * + * @brief Implementation of ietfAttr_t. + * + */ + +/* + * 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 <string.h> +#include <stdio.h> + +#include <debug.h> +#include <asn1/asn1.h> +#include <utils/lexparser.h> + +#include "ietf_attr_list.h" + +/** + * Private definition of ietfAttribute kinds + */ +typedef enum { + IETF_ATTRIBUTE_OCTETS = 0, + IETF_ATTRIBUTE_OID = 1, + IETF_ATTRIBUTE_STRING = 2 +} ietfAttribute_t; + +typedef struct ietfAttr_t ietfAttr_t; + +/** + * Private definition of an ietfAttribute + */ +struct ietfAttr_t { + /** + * IETF attribute kind + */ + ietfAttribute_t kind; + + /** + * IETF attribute valuse + */ + chunk_t value; + + /** + * Compares two ietfAttributes + * + * return -1 if this is earlier in the alphabet than other + * return 0 if this equals other + * return +1 if this is later in the alphabet than other + * + * @param this calling object + * @param other other object + */ + int (*compare) (const ietfAttr_t *this ,const ietfAttr_t *other); + + /** + * Destroys the ietfAttr_t object. + * + * @param this ietfAttr_t to destroy + */ + void (*destroy) (ietfAttr_t *this); +}; + +/** + * Implements ietfAttr_t.compare. + */ +static int ietfAttr_compare(const ietfAttr_t *this ,const ietfAttr_t *other) +{ + int cmp_len, len, cmp_value; + + /* OID attributes are appended after STRING and OCTETS attributes */ + if (this->kind != IETF_ATTRIBUTE_OID && other->kind == IETF_ATTRIBUTE_OID) + { + return -1; + } + if (this->kind == IETF_ATTRIBUTE_OID && other->kind != IETF_ATTRIBUTE_OID) + { + return 1; + } + + cmp_len = this->value.len - other->value.len; + len = (cmp_len < 0)? this->value.len : other->value.len; + cmp_value = memcmp(this->value.ptr, other->value.ptr, len); + + return (cmp_value == 0)? cmp_len : cmp_value; +} + +/** + * Implements ietfAttr_t.destroy. + */ +static void ietfAttr_destroy(ietfAttr_t *this) +{ + free(this->value.ptr); + free(this); +} + +/** + * Creates an ietfAttr_t object. + */ +static 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->compare = ietfAttr_compare; + this->destroy = ietfAttr_destroy; + + return this; +} + +/** + * Adds an ietfAttr_t object to a sorted linked list + */ +static void ietfAttr_add(linked_list_t *list, ietfAttr_t *attr) +{ + iterator_t *iterator = list->create_iterator(list, TRUE); + ietfAttr_t *current_attr; + bool found = FALSE; + + while (iterator->iterate(iterator, (void **)¤t_attr)) + { + int cmp = attr->compare(attr, current_attr); + + if (cmp > 0) + { + continue; + } + if (cmp == 0) + { + attr->destroy(attr); + } + else + { + iterator->insert_before(iterator, attr); + } + found = TRUE; + break; + } + iterator->destroy(iterator); + if (!found) + { + list->insert_last(list, attr); + } +} + +/* + * Described in header. + */ +bool ietfAttr_list_equals(linked_list_t *list_a, linked_list_t *list_b) +{ + bool result = TRUE; + + /* lists must have the same number of attributes */ + if (list_a->get_count(list_a) != list_b->get_count(list_b)) + { + return FALSE; + } + /* empty lists - no attributes */ + if (list_a->get_count(list_a) == 0) + { + return TRUE; + } + + /* compare two alphabetically-sorted lists */ + { + iterator_t *iterator_a = list_a->create_iterator(list_a, TRUE); + iterator_t *iterator_b = list_b->create_iterator(list_b, TRUE); + ietfAttr_t *attr_a, *attr_b; + + while (iterator_a->iterate(iterator_a, (void **)&attr_a) && + iterator_b->iterate(iterator_b, (void **)&attr_b)) + { + if (attr_a->compare(attr_a, attr_b) != 0) + { + /* we have a mismatch */ + result = FALSE; + break; + } + } + iterator_a->destroy(iterator_a); + iterator_b->destroy(iterator_b); + } + return result; +} + +/* + * Described in header. + */ +void ietfAttr_list_list(linked_list_t *list, FILE *out) +{ + iterator_t *iterator = list->create_iterator(list, TRUE); + ietfAttr_t *attr; + bool first = TRUE; + + while (iterator->iterate(iterator, (void **)&attr)) + { + if (first) + { + first = FALSE; + } + else + { + fprintf(out, ", "); + } + + switch (attr->kind) + { + case IETF_ATTRIBUTE_OCTETS: + case IETF_ATTRIBUTE_STRING: + fprintf(out, "%.*s", (int)attr->value.len, attr->value.ptr); + break; + case IETF_ATTRIBUTE_OID: + { + int oid = known_oid(attr->value); + + if (oid == OID_UNKNOWN) + { + fprintf(out, "0x#B", &attr->value); + } + else + { + fprintf(out, "%s", oid_names[oid]); + } + } + break; + default: + break; + } + } + iterator->destroy(iterator); +} + +/* + * Described in header. + */ +void ietfAttr_list_create_from_string(char *msg, linked_list_t *list) +{ + chunk_t line = { msg, strlen(msg) }; + + while (eat_whitespace(&line)) + { + chunk_t group; + + /* extract the next comma-separated group attribute */ + if (!extract_token(&group, ',', &line)) + { + group = line; + line.len = 0; + } + + /* remove any trailing spaces */ + while (group.len > 0 && *(group.ptr + group.len - 1) == ' ') + { + group.len--; + } + + /* add the group attribute to the list */ + if (group.len > 0) + { + ietfAttr_t *attr = ietfAttr_create(IETF_ATTRIBUTE_STRING, group); + + ietfAttr_add(list, attr); + } + } +} + +/** + * 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 + +/* + * Described in header. + */ +void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int level0) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, chunk, 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); + ietfAttr_add(list, attr); + } + break; + default: + break; + } + objectID++; + } +} + +/* + * Described in header. + */ +chunk_t ietfAttr_list_encode(linked_list_t *list) +{ + chunk_t ietfAttributes; + size_t size = 0; + u_char *pos; + iterator_t *iterator = list->create_iterator(list, TRUE); + ietfAttr_t *attr; + + /* precalculate the total size of all values */ + while (iterator->iterate(iterator, (void **)&attr)) + { + size_t len = attr->value.len; + + size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len; + } + iterator->destroy(iterator); + + pos = build_asn1_object(&ietfAttributes, ASN1_SEQUENCE, size); + + iterator = list->create_iterator(list, TRUE); + while (iterator->iterate(iterator, (void **)&attr)) + { + chunk_t ietfAttribute; + asn1_t type = ASN1_NULL; + + switch (attr->kind) + { + case IETF_ATTRIBUTE_OCTETS: + type = ASN1_OCTET_STRING; + break; + case IETF_ATTRIBUTE_STRING: + type = ASN1_UTF8STRING; + break; + case IETF_ATTRIBUTE_OID: + type = ASN1_OID; + break; + } + ietfAttribute = asn1_simple_object(type, attr->value); + + /* copy ietfAttribute into ietfAttributes chunk */ + memcpy(pos, ietfAttribute.ptr, ietfAttribute.len); + pos += ietfAttribute.len; + free(ietfAttribute.ptr); + } + iterator->destroy(iterator); + + return asn1_wrap(ASN1_SEQUENCE, "m", ietfAttributes); +} + +/* + * Described in header. + */ +void ietfAttr_list_destroy(linked_list_t *list) +{ + list->destroy_offset(list, offsetof(ietfAttr_t, destroy)); +} diff --git a/src/libstrongswan/plugins/x509/ietf_attr_list.h b/src/libstrongswan/plugins/x509/ietf_attr_list.h new file mode 100644 index 000000000..75407bbf6 --- /dev/null +++ b/src/libstrongswan/plugins/x509/ietf_attr_list.h @@ -0,0 +1,89 @@ +/** + * @file ietf_attr_list.h + * + * @brief Handling of ietfAttr_t linked lists + * + */ + +/* + * 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 IETF_ATTR_LIST_H_ +#define IETF_ATTR_LIST_H_ + +#include <library.h> +#include <utils/linked_list.h> + + +/** + * @brief Compare two linked lists of ietfAttr_t objects for equality + * + * @param list_a first alphabetically-sorted list + * @param list_b second alphabetically-sorted list + * @return TRUE if equal + * + * @ingroup crypto + */ +bool ietfAttr_list_equals(linked_list_t *list_a, linked_list_t *list_b); + +/** + * @brief Lists a linked list of ietfAttr_t objects + * + * @param list alphabetically-sorted linked list of attributes + @param out output file + * + * @ingroup crypto + */ +void ietfAttr_list_list(linked_list_t *list, FILE *out); + +/** + * @brief Create a linked list of ietfAttr_t objects from a string + * + * @param msg string with comma-separated group names + * @param list alphabetically-sorted linked list of attributes + * + * @ingroup crypto + */ +void ietfAttr_list_create_from_string(char *msg, linked_list_t *list); + +/** + * @brief Create a linked list of ietfAttr_t objects from an ASN.1-coded chunk + * + * @param chunk chunk containing ASN.1-coded attributes + * @param list alphabetically-sorted linked list of attributes + * @param level0 parsing level + */ +void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int level0); + +/** + * @brief Encode a linked list of ietfAttr_t objects into an ASN.1-coded chunk + * + * @param list alphabetically-sorted linked list of attributes + * @return chunk containing ASN.1-coded attributes + */ +chunk_t ietfAttr_list_encode(linked_list_t *list); + +/** + * @brief Destroys a linked list of ietfAttr_t objects + * + * @param list list to be destroyed + * + * @ingroup crypto + */ +void ietfAttr_list_destroy(linked_list_t *list); + +#endif /* IETF_ATTR_LIST_H_ */ + diff --git a/src/libstrongswan/plugins/x509/x509_ac.c b/src/libstrongswan/plugins/x509/x509_ac.c new file mode 100644 index 000000000..e09c0447d --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_ac.c @@ -0,0 +1,807 @@ +/* + * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler + * Copyright (C) 2003 Martin Berner, Lukas Suter + * Copyright (C) 2002-2008 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. + * + * $Id$ + */ + +#include "x509_ac.h" +#include "ietf_attr_list.h" + +#include <library.h> +#include <debug.h> +#include <asn1/oid.h> +#include <asn1/asn1.h> +#include <utils/identification.h> +#include <utils/linked_list.h> +#include <credentials/certificates/x509.h> + +typedef struct private_x509_ac_t private_x509_ac_t; + +/** + * private data of x509_ac_t object + */ +struct private_x509_ac_t { + + /** + * public functions + */ + x509_ac_t public; + + /** + * X.509 attribute certificate in DER format + */ + chunk_t encoding; + + /** + * 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 algorithm; + + /** + * 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 + */ + identification_t *authKeyIdentifier; + + /** + * Authority Key Serial Number + */ + chunk_t authKeySerialNumber; + + /** + * No revocation information available + */ + bool noRevAvail; + + /** + * Signature + */ + chunk_t signature; + + /** + * Holder certificate + */ + x509_t *holder_cert; + + /** + * Signer certificate + */ + x509_t *signer_cert; + + /** + * Signer private key; + */ + private_key_t *signer_key; + + /** + * reference count + */ + refcount_t ref; +}; + +static u_char ASN1_group_oid_str[] = { + 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a ,0x04 +}; + +static const chunk_t ASN1_group_oid = chunk_from_buf(ASN1_group_oid_str); + +static u_char ASN1_authorityKeyIdentifier_oid_str[] = { + 0x06, 0x03, + 0x55, 0x1d, 0x23 +}; + +static const chunk_t ASN1_authorityKeyIdentifier_oid = + chunk_from_buf(ASN1_authorityKeyIdentifier_oid_str); + +static u_char ASN1_noRevAvail_ext_str[] = { + 0x30, 0x09, + 0x06, 0x03, + 0x55, 0x1d, 0x38, + 0x04, 0x02, + 0x05, 0x00 +}; + +static const chunk_t ASN1_noRevAvail_ext = chunk_from_buf(ASN1_noRevAvail_ext_str); + +/** + * 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 + +/** + * build directoryName + */ +static chunk_t build_directoryName(asn1_t tag, chunk_t name) +{ + return asn1_wrap(tag, "m", + asn1_simple_object(ASN1_CONTEXT_C_4, name)); +} + +/** + * build holder + */ +static chunk_t build_holder(private_x509_ac_t *this) +{ + x509_t *x509 = this->holder_cert; + certificate_t *cert = &x509->interface; + + identification_t *issuer = cert->get_issuer(cert); + identification_t *subject = cert->get_subject(cert); + + return asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_wrap(ASN1_CONTEXT_C_0, "mm", + build_directoryName(ASN1_SEQUENCE, issuer->get_encoding(issuer)), + asn1_simple_object(ASN1_INTEGER, x509->get_serial(x509)) + ), + build_directoryName(ASN1_CONTEXT_C_1, subject->get_encoding(subject))); +} + +/** + * build v2Form + */ +static chunk_t build_v2_form(private_x509_ac_t *this) +{ + x509_t *x509 = this->signer_cert; + certificate_t *cert = &x509->interface; + identification_t *subject = cert->get_subject(cert); + + return asn1_wrap(ASN1_CONTEXT_C_0, "m", + build_directoryName(ASN1_SEQUENCE, subject->get_encoding(subject))); +} + +/** + * build attrCertValidityPeriod + */ +static chunk_t build_attr_cert_validity(private_x509_ac_t *this) +{ + return asn1_wrap(ASN1_SEQUENCE, "mm", + timetoasn1(&this->notBefore, ASN1_GENERALIZEDTIME), + timetoasn1(&this->notAfter, ASN1_GENERALIZEDTIME)); +} + + +/** + * build attribute type + */ +static chunk_t build_attribute_type(const chunk_t type, chunk_t content) +{ + return asn1_wrap(ASN1_SEQUENCE, "cm", + type, + asn1_wrap(ASN1_SET, "m", content)); +} + +/** + * build attributes + */ +static chunk_t build_attributes(private_x509_ac_t *this) +{ + return asn1_wrap(ASN1_SEQUENCE, "m", + build_attribute_type(ASN1_group_oid, ietfAttr_list_encode(this->groups))); +} + +/** + * build authorityKeyIdentifier + */ +static chunk_t build_authorityKeyIdentifier(private_x509_ac_t *this) +{ + x509_t *x509 = this->signer_cert; + certificate_t *cert = &x509->interface; + identification_t *issuer = cert->get_issuer(cert); + public_key_t *public = cert->get_public_key(cert); + chunk_t keyIdentifier; + chunk_t authorityCertIssuer; + chunk_t authorityCertSerialNumber; + + if (public) + { + this->authKeyIdentifier = public->get_id(public, ID_PUBKEY_SHA1); + public->destroy(public); + keyIdentifier = this->authKeyIdentifier->get_encoding(this->authKeyIdentifier); + } + else + { + keyIdentifier = chunk_empty; + } + + authorityCertIssuer = build_directoryName(ASN1_CONTEXT_C_1, + issuer->get_encoding(issuer)); + + authorityCertSerialNumber = asn1_simple_object(ASN1_CONTEXT_S_2, + x509->get_serial(x509)); + + return asn1_wrap(ASN1_SEQUENCE, "cm", + ASN1_authorityKeyIdentifier_oid, + asn1_wrap(ASN1_OCTET_STRING, "m", + asn1_wrap(ASN1_SEQUENCE, "mmm", + keyIdentifier, + authorityCertIssuer, + authorityCertSerialNumber + ) + ) + ); +} + +/** + * build extensions + */ +static chunk_t build_extensions(private_x509_ac_t *this) +{ + return asn1_wrap(ASN1_SEQUENCE, "mc", + build_authorityKeyID(this), + ASN1_noRevAvail_ext); +} + +/** + * build attributeCertificateInfo + */ +static chunk_t build_attr_cert_info(private_x509_ac_t *this) +{ + return asn1_wrap(ASN1_SEQUENCE, "cmmcmmmm", + ASN1_INTEGER_1, + build_holder(this), + build_v2_form(this), + asn1_algorithmIdentifier(OID_SHA1_WITH_RSA), + asn1_simple_object(ASN1_INTEGER, this->serialNumber), + build_attr_cert_validity(this), + build_attributes(this), + build_extensions(this)); +} + + +/** + * build an X.509 attribute certificate + */ +static chunk_t build_ac(private_x509_ac_t *this) +{ + chunk_t signatureValue; + chunk_t attributeCertificateInfo = build_attr_cert_info(this); +/* + signerkey->build_emsa_pkcs1_signature(signerkey, HASH_SHA1, + attributeCertificateInfo, &signatureValue); +*/ + return asn1_wrap(ASN1_SEQUENCE, "mcm", + attributeCertificateInfo, + asn1_algorithmIdentifier(OID_SHA1_WITH_RSA), + asn1_bitstring("m", signatureValue)); +} + +/** + * Implementation of certificate_t.get_type + */ +static certificate_type_t get_type(private_x509_ac_t *this) +{ + return CERT_X509_AC; +} + +/** + * Implementation of certificate_t.get_subject + */ +static identification_t* get_subject(private_x509_ac_t *this) +{ + return this->entityName; +} + +/** + * Implementation of certificate_t.get_issuer + */ +static identification_t* get_issuer(private_x509_ac_t *this) +{ + return this->issuerName; +} + +/** + * Implementation of certificate_t.has_subject. + */ +static id_match_t has_subject(private_x509_ac_t *this, identification_t *subject) +{ + return ID_MATCH_NONE; +} + +/** + * Implementation of certificate_t.has_issuer. + */ +static id_match_t has_issuer(private_x509_ac_t *this, identification_t *issuer) +{ + id_match_t match; + + if (issuer->get_type(issuer) == ID_PUBKEY_SHA1) + { + if (this->authKeyIdentifier) + { + match = issuer->matches(issuer, this->authKeyIdentifier); + } + else + { + match = ID_MATCH_NONE; + } + } + else + { + match = this->issuerName->matches(this->issuerName, issuer); + } + return match; +} + +/** + * Implementation of certificate_t.issued_by + */ +static bool issued_by(private_x509_ac_t *this, certificate_t *issuer, + bool sigcheck) +{ + public_key_t *key; + signature_scheme_t scheme; + bool valid; + x509_t *x509 = (x509_t*)issuer; + + /* check if issuer is an X.509 AA certificate */ + if (issuer->get_type(issuer) != CERT_X509) + { + return FALSE; + } + if (!(x509->get_flags(x509) & X509_AA)) + { + return FALSE; + } + + /* get the public key of the issuer */ + key = issuer->get_public_key(issuer); + + /* compare keyIdentifiers if available, otherwise use DNs */ + if (this->authKeyIdentifier && key) + { + identification_t *subjectKeyIdentifier = key->get_id(key, ID_PUBKEY_SHA1); + + if (!subjectKeyIdentifier->equals(subjectKeyIdentifier, + this->authKeyIdentifier)) + { + return FALSE; + } + } + else + { + if (!this->issuerName->equals(this->issuerName, issuer->get_subject(issuer))) + { + return FALSE; + } + } + + if (!sigcheck) + { + return TRUE; + } + /* TODO: generic OID to scheme mapper? */ + switch (this->algorithm) + { + case OID_MD5_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_MD5; + break; + case OID_SHA1_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + break; + case OID_SHA256_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA256; + break; + case OID_SHA384_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA384; + break; + case OID_SHA512_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA512; + break; + default: + return FALSE; + } + if (key == NULL) + { + return FALSE; + } + valid = key->verify(key, scheme, this->certificateInfo, this->signature); + key->destroy(key); + return valid; +} + +/** + * Implementation of certificate_t.get_public_key. + */ +static public_key_t* get_public_key(private_x509_ac_t *this) +{ + return NULL; +} + +/** + * Implementation of certificate_t.get_ref. + */ +static private_x509_ac_t* get_ref(private_x509_ac_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implementation of certificate_t.get_validity. + */ +static bool get_validity(private_x509_ac_t *this, time_t *when, + time_t *not_before, time_t *not_after) +{ + time_t t; + + if (when) + { + t = *when; + } + else + { + t = time(NULL); + } + if (not_before) + { + *not_before = this->notBefore; + } + if (not_after) + { + *not_after = this->notAfter; + } + return (t >= this->notBefore && t <= this->notAfter); +} + +/** + * Implementation of certificate_t.is_newer. + */ +static bool is_newer(private_x509_ac_t *this, ac_t *that) +{ + certificate_t *this_cert = &this->public.interface.certificate; + certificate_t *that_cert = &that->certificate; + time_t this_update, that_update, now = time(NULL); + bool new; + + this_cert->get_validity(this_cert, &now, &this_update, NULL); + that_cert->get_validity(that_cert, &now, &that_update, NULL); + new = this_update > that_update; + DBG1(" attr cert from %#T is %s - existing attr_cert from %#T %s", + &this_update, FALSE, new ? "newer":"not newer", + &that_update, FALSE, new ? "replaced":"retained"); + return new; +} + +/** + * Implementation of certificate_t.get_encoding. + */ +static chunk_t get_encoding(private_x509_ac_t *this) +{ + return chunk_clone(this->encoding); +} + +/** + * Implementation of certificate_t.equals. + */ +static bool equals(private_x509_ac_t *this, certificate_t *other) +{ + if ((certificate_t*)this == other) + { + return TRUE; + } + if (other->equals == (void*)equals) + { /* same implementation */ + return chunk_equals(this->signature, + ((private_x509_ac_t*)other)->signature); + } + /* TODO: compare against other implementations */ + return FALSE; +} + +/** + * Implementation of x509_ac_t.destroy + */ +static void destroy(private_x509_ac_t *this) +{ + if (ref_put(&this->ref)) + { + DESTROY_IF(this->holderIssuer); + DESTROY_IF(this->entityName); + DESTROY_IF(this->issuerName); + DESTROY_IF(this->authKeyIdentifier); + ietfAttr_list_destroy(this->charging); + ietfAttr_list_destroy(this->groups); + free(this->encoding.ptr); + free(this); + } +} + +/** + * create an empty but initialized X.509 attribute certificate + */ +static private_x509_ac_t *create_empty() +{ + private_x509_ac_t *this = malloc_thing(private_x509_ac_t); + + /* public functions */ + this->public.interface.certificate.get_type = (certificate_type_t (*)(certificate_t *this))get_type; + this->public.interface.certificate.get_subject = (identification_t* (*)(certificate_t *this))get_subject; + this->public.interface.certificate.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer; + this->public.interface.certificate.has_subject = (id_match_t(*)(certificate_t*, identification_t *subject))has_subject; + this->public.interface.certificate.has_issuer = (id_match_t(*)(certificate_t*, identification_t *issuer))has_issuer; + this->public.interface.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by; + this->public.interface.certificate.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key; + this->public.interface.certificate.get_validity = (bool(*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity; + this->public.interface.certificate.get_encoding = (chunk_t(*)(certificate_t*))get_encoding; + this->public.interface.certificate.equals = (bool(*)(certificate_t*, certificate_t *other))equals; + this->public.interface.certificate.get_ref = (certificate_t* (*)(certificate_t *this))get_ref; + this->public.interface.certificate.destroy = (void (*)(certificate_t *this))destroy; + + /* initialize */ + this->holderIssuer = NULL; + this->entityName = NULL; + this->issuerName = NULL; + this->authKeyIdentifier = NULL; + this->charging = linked_list_create(); + this->groups = linked_list_create(); + + return this; +} + +typedef struct private_builder_t private_builder_t; +/** + * Builder implementation for certificate loading + */ +struct private_builder_t { + /** implements the builder interface */ + builder_t public; + /** X.509 attribute certificate to build */ + private_x509_ac_t *ac; +}; + +/** + * Implementation of builder_t.build + */ +static x509_ac_t *build(private_builder_t *this) +{ + private_x509_ac_t *ac; + + ac = this->ac; + free(this); + if (ac->holder_cert && ac->signer_cert && ac->signer_key) + { + ac->encoding = build_ac(ac); + return &ac->public; + } + destroy(ac); + return NULL; +} + +/** + * Implementation of builder_t.add + */ +static void add(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + certificate_t *cert; + + va_start(args, part); + switch (part) + { + case BUILD_NOT_BEFORE_TIME: + this->ac->notBefore = *va_arg(args, time_t*); + break; + case BUILD_NOT_AFTER_TIME: + this->ac->notAfter = *va_arg(args, time_t*); + break; + case BUILD_CERT: + cert = va_arg(args, certificate_t*); + if (cert->get_type(cert) == CERT_X509) + { + this->ac->holder_cert = (x509_t*)cert; + } + else + { + cert->destroy(cert); + } + break; + case BUILD_SIGNING_CERT: + if (cert->get_type(cert) == CERT_X509) + { + this->ac->signer_cert = (x509_t*)cert; + } + else + { + cert->destroy(cert); + } + break; + case BUILD_SIGNING_KEY: + this->ac->signer_key = va_arg(args, private_key_t*); + break; + default: + DBG1("ignoring unsupported build part %N", builder_part_names, part); + break; + } + va_end(args); +} + +/** + * Builder construction function + */ +builder_t *x509_ac_builder(certificate_type_t type) +{ + private_builder_t *this; + + if (type != CERT_X509_AC) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->ac = create_empty(); + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; + this->public.build = (void*(*)(builder_t *this))build; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/x509/x509_ac.h b/src/libstrongswan/plugins/x509/x509_ac.h new file mode 100644 index 000000000..709e4531a --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_ac.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler + * Copyright (C) 2003 Martin Berner, Lukas Suter + * Copyright (C) 2002-2008 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. + * + * $Id$ + */ + +/** + * @defgroup x509_ac x509_ac + * @{ @ingroup x509_p + */ + +#ifndef X509_AC_H_ +#define X509_AC_H_ + +#include <credentials/certificates/ac.h> + +typedef struct x509_ac_t x509_ac_t; + +/** + * Implementation of ocsp_request_t using own ASN1 parser. + */ +struct x509_ac_t { + + /** + * Implements the ac_t interface + */ + ac_t interface; +}; + +/** + * Create the building facility for X.509 attribute certificates. + * + * The resulting builder accepts: + * BUILD_USER_CERT: user certificate, exactly one + * BUILD_SIGNER_CERT: signer certificate, exactly one + * BUILD_SIGNER_KEY: signer private key, exactly one + * BUILD_SERIAL: serial number, exactly one + * BUILD_GROUP_ATTR: group attribute, optional, several possible + * + * @param type certificate type, CERT_X509_AC only + * @return builder instance to build X.509 attribute certificates + */ +builder_t *x509_ac_builder(certificate_type_t type); + +#endif /* X509_AC_H_ @}*/ diff --git a/src/openac/Makefile.am b/src/openac/Makefile.am index 4b88d8b2d..1d8c8de9a 100644 --- a/src/openac/Makefile.am +++ b/src/openac/Makefile.am @@ -1,5 +1,5 @@ ipsec_PROGRAMS = openac -openac_SOURCES = openac.c build.c build.h +openac_SOURCES = openac.c dist_man_MANS = openac.8 INCLUDES = -I$(top_srcdir)/src/libstrongswan diff --git a/src/openac/build.c b/src/openac/build.c deleted file mode 100644 index 3dcd3f762..000000000 --- a/src/openac/build.c +++ /dev/null @@ -1,193 +0,0 @@ -/* Build a X.509 attribute certificate - * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler - * Copyright (C) 2004,2007 Andreas Steffen - * Hochschule fuer Technik Rapperswil, Switzerland - * - * 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. - * - * RCSID $Id$ - */ - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> - -#include <asn1/oid.h> -#include <asn1/asn1.h> -#include <crypto/ietf_attr_list.h> -#include <utils/identification.h> - -#include "build.h" - -static u_char ASN1_group_oid_str[] = { - 0x06, 0x08, - 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a ,0x04 -}; - -static const chunk_t ASN1_group_oid = chunk_from_buf(ASN1_group_oid_str); - -static u_char ASN1_authorityKeyIdentifier_oid_str[] = { - 0x06, 0x03, - 0x55, 0x1d, 0x23 -}; - -static const chunk_t ASN1_authorityKeyIdentifier_oid = - chunk_from_buf(ASN1_authorityKeyIdentifier_oid_str); - -static u_char ASN1_noRevAvail_ext_str[] = { - 0x30, 0x09, - 0x06, 0x03, - 0x55, 0x1d, 0x38, - 0x04, 0x02, - 0x05, 0x00 -}; - -static const chunk_t ASN1_noRevAvail_ext = chunk_from_buf(ASN1_noRevAvail_ext_str); - -/** - * build directoryName - */ -static chunk_t build_directoryName(asn1_t tag, chunk_t name) -{ - return asn1_wrap(tag, "m", - asn1_simple_object(ASN1_CONTEXT_C_4, name)); -} - -/** - * build holder - */ -static chunk_t build_holder(void) -{ - identification_t *issuer = usercert->get_issuer(usercert); - identification_t *subject = usercert->get_subject(usercert); - - return asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_wrap(ASN1_CONTEXT_C_0, "mm", - build_directoryName(ASN1_SEQUENCE, issuer->get_encoding(issuer)), - asn1_simple_object(ASN1_INTEGER, usercert->get_serialNumber(usercert)) - ), - build_directoryName(ASN1_CONTEXT_C_1, subject->get_encoding(subject))); -} - -/** - * build v2Form - */ -static chunk_t build_v2_form(void) -{ - identification_t *subject = signercert->get_subject(signercert); - - return asn1_wrap(ASN1_CONTEXT_C_0, "m", - build_directoryName(ASN1_SEQUENCE, subject->get_encoding(subject))); -} - -/** - * build attrCertValidityPeriod - */ -static chunk_t build_attr_cert_validity(void) -{ - return asn1_wrap(ASN1_SEQUENCE, "mm", - timetoasn1(¬Before, ASN1_GENERALIZEDTIME), - timetoasn1(¬After, ASN1_GENERALIZEDTIME)); -} - - -/** - * build attribute type - */ -static chunk_t build_attribute_type(const chunk_t type, chunk_t content) -{ - return asn1_wrap(ASN1_SEQUENCE, "cm", - type, - asn1_wrap(ASN1_SET, "m", content)); -} - -/** - * build attributes - */ -static chunk_t build_attributes(void) -{ - return asn1_wrap(ASN1_SEQUENCE, "m", - build_attribute_type(ASN1_group_oid, ietfAttr_list_encode(groups))); -} - -/** - * build authorityKeyIdentifier - */ -static chunk_t build_authorityKeyID(x509_t *signer) -{ - identification_t *issuer = signer->get_issuer(signer); - chunk_t subjectKeyID = signer->get_subjectKeyID(signer); - - chunk_t keyIdentifier = (subjectKeyID.ptr == NULL) - ? chunk_empty - : asn1_simple_object(ASN1_CONTEXT_S_0, subjectKeyID); - - chunk_t authorityCertIssuer = build_directoryName(ASN1_CONTEXT_C_1, - issuer->get_encoding(issuer)); - - chunk_t authorityCertSerialNumber = asn1_simple_object(ASN1_CONTEXT_S_2, - signer->get_serialNumber(signer)); - - return asn1_wrap(ASN1_SEQUENCE, "cm", - ASN1_authorityKeyIdentifier_oid, - asn1_wrap(ASN1_OCTET_STRING, "m", - asn1_wrap(ASN1_SEQUENCE, "mmm", - keyIdentifier, - authorityCertIssuer, - authorityCertSerialNumber - ) - ) - ); -} - -/** - * build extensions - */ -static chunk_t build_extensions(void) -{ - return asn1_wrap(ASN1_SEQUENCE, "mc", - build_authorityKeyID(signercert), - ASN1_noRevAvail_ext); -} - -/** - * build attributeCertificateInfo - */ -static chunk_t build_attr_cert_info(void) -{ - return asn1_wrap(ASN1_SEQUENCE, "cmmcmmmm", - ASN1_INTEGER_1, - build_holder(), - build_v2_form(), - asn1_algorithmIdentifier(OID_SHA1_WITH_RSA), - asn1_simple_object(ASN1_INTEGER, serial), - build_attr_cert_validity(), - build_attributes(), - build_extensions()); -} - - -/** - * build an X.509 attribute certificate - */ -chunk_t build_attr_cert(void) -{ - chunk_t signatureValue; - chunk_t attributeCertificateInfo = build_attr_cert_info(); - - signerkey->build_emsa_pkcs1_signature(signerkey, HASH_SHA1, - attributeCertificateInfo, &signatureValue); - - return asn1_wrap(ASN1_SEQUENCE, "mcm", - attributeCertificateInfo, - asn1_algorithmIdentifier(OID_SHA1_WITH_RSA), - asn1_bitstring("m", signatureValue)); -} diff --git a/src/openac/build.h b/src/openac/build.h deleted file mode 100644 index 66ec86213..000000000 --- a/src/openac/build.h +++ /dev/null @@ -1,45 +0,0 @@ -/* Build a X.509 attribute certificate - * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler - * Copyright (C) 2004,2007 Andreas Steffen - * Hochschule fuer Technik Rapperswil, Switzerland - * - * 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. - * - * RCSID $Id$ - */ - -#ifndef _BUILD_H -#define _BUILD_H - -#include <time.h> - -#include <library.h> -#include <crypto/x509.h> -#include <crypto/rsa/rsa_private_key.h> -#include <utils/linked_list.h> - -/* - * global variables accessible by both main() and build.c - */ -extern x509_t *usercert; -extern x509_t *signercert; -extern rsa_private_key_t *signerkey; -extern linked_list_t *groups; -extern time_t notBefore; -extern time_t notAfter; -extern chunk_t serial; - -/* - * exported functions - */ -extern chunk_t build_attr_cert(void); - -#endif /* _BUILD_H */ diff --git a/src/openac/openac.c b/src/openac/openac.c index 6f19effe7..c5a7cd26c 100755 --- a/src/openac/openac.c +++ b/src/openac/openac.c @@ -36,8 +36,8 @@ #include <debug.h> #include <asn1/asn1.h> #include <asn1/ttodata.h> -#include <crypto/ac.h> -#include <crypto/ietf_attr_list.h> +#include <credentials/certificates/x509.h> +#include <credentials/certificates/ac.h> #include <utils/optionsfrom.h> #ifdef INTEGRITY_TEST @@ -47,8 +47,10 @@ #include "build.h" -#define OPENAC_PATH IPSEC_CONFDIR "/openac" -#define OPENAC_SERIAL IPSEC_CONFDIR "/openac/serial" +#define OPENAC_PATH IPSEC_CONFDIR "/openac" +#define OPENAC_SERIAL IPSEC_CONFDIR "/openac/serial" + +#define DEFAULT_VALIDITY 24*3600 /* seconds */ /** * @brief prints the usage of the program to the stderr @@ -175,18 +177,79 @@ static void write_serial(chunk_t serial) } /** - * global variables accessible by both main() and build.c + * Load and parse a private key file */ -x509_t *usercert = NULL; -x509_t *signercert = NULL; +static private_key_t* private_key_create_from_file(char *path, chunk_t *secret) +{ + bool pgp = FALSE; + chunk_t chunk = chunk_empty; + private_key_t *key = NULL; + + if (!pem_asn1_load_file(path, &secret, &chunk, &pgp)) + { + DBG1(" could not load private key file '%s'", path); + return NULL; + } + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, + BUILD_BLOB_ASN1_DER, chunk, BUILD_END); + if (key == NULL) + { + DBG1(" could not parse loaded private key file '%s'", path); + return NULL; + } + DBG1(" loaded private key file '%s'", path); + return key; +} -linked_list_t *groups = NULL; -rsa_private_key_t *signerkey = NULL; +/** + * Load and parse an X.509 certificate file + */ +static x509_t* x509_create_from_file(char *path, char *label, x509_flag_t flag) +{ -time_t notBefore = UNDEFINED_TIME; -time_t notAfter = UNDEFINED_TIME; + bool pgp = FALSE; + chunk_t chunk; + x509_t *x509; + certificate_t *cert; + time_t notBefore, notAfter, now; + + if (!pem_asn1_load_file(path, NULL, &chunk, &pgp)) + { + DBG1(" could not load %s file '%s'", label, path); + return NULL; + } + x509 = (x509_t*)lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, chunk, + BUILD_X509_FLAG, flag, + BUILD_END); + if (x509 == NULL) + { + DBG1(" could not parse loaded %s file '%s'",label, path); + return NULL; + } + DBG1(" loaded %s file '%s'", label, path); + + /* check validity */ + cert = &x509->interface; + now = time(NULL); + cert->get_validity(cert, &now, ¬Before, ¬After); + if (now > notAfter) + { + DBG1(" certificate expired at %T, discarded", ¬After); + cert->destroy(cert); + return NULL; + } + if (now < notBefore) + { + DBG1(" certificate not valid before %T", ¬Before); + } + return x509; +} -chunk_t serial; +/** + * global variables accessible by both main() and build.c + */ static int debug_level = 1; static bool stderr_quiet = FALSE; @@ -220,18 +283,26 @@ static void openac_dbg(int level, char *fmt, ...) */ int main(int argc, char **argv) { + certificate_t *attr_cert = NULL; + certificate_t *user_cert = NULL; + certificate_t *signer_cert = NULL; + private_key_t *signer_key = NULL; + + time_t notBefore = UNDEFINED_TIME; + time_t notAfter = UNDEFINED_TIME; + time_t validity = 0; + char *keyfile = NULL; char *certfile = NULL; char *usercertfile = NULL; char *outfile = NULL; + char *groups = ""; char buf[BUF_LEN]; + chunk_t serial; chunk_t passphrase = { buf, 0 }; - chunk_t attr_cert = chunk_empty; - x509ac_t *ac = NULL; + chunk_t attr_chunk = chunk_empty; - const time_t default_validity = 24*3600; /* 24 hours */ - time_t validity = 0; int status = 1; options_t *options = options_create(); @@ -240,7 +311,6 @@ int main(int argc, char **argv) dbg = openac_dbg; passphrase.ptr[0] = '\0'; - groups = linked_list_create(); openlog("openac", 0, LOG_AUTHPRIV); @@ -337,7 +407,7 @@ int main(int argc, char **argv) continue; case 'g': /* --groups */ - ietfAttr_list_create_from_string(optarg, groups); + groups = optarg; continue; case 'D': /* --days */ @@ -449,9 +519,9 @@ int main(int argc, char **argv) /* load the signer's RSA private key */ if (keyfile != NULL) { - signerkey = rsa_private_key_create_from_file(keyfile, &passphrase); + signer_key = private_key_create_from_file(keyfile, &passphrase); - if (signerkey == NULL) + if (signer_key == NULL) { goto end; } @@ -460,41 +530,50 @@ int main(int argc, char **argv) /* load the signer's X.509 certificate */ if (certfile != NULL) { - signercert = x509_create_from_file(certfile, "signer cert"); + x509_t *x509 = x509_create_from_file(certfile, "signer cert", 0); - if (signercert == NULL) + if (x509 == NULL) { goto end; } + signer_cert = &x509->interface; } /* load the users's X.509 certificate */ if (usercertfile != NULL) { - usercert = x509_create_from_file(usercertfile, "user cert"); + x509_t *x509 = x509_create_from_file(usercertfile, "user cert", 0); - if (usercert == NULL) + if (x509 == NULL) { goto end; } + user_cert = &x509->interface; } /* compute validity interval */ - validity = (validity)? validity : default_validity; + validity = (validity)? validity : DEFAULT_VALIDITY; notBefore = (notBefore == UNDEFINED_TIME) ? time(NULL) : notBefore; notAfter = (notAfter == UNDEFINED_TIME) ? time(NULL) + validity : notAfter; /* build and parse attribute certificate */ - if (usercert != NULL && signercert != NULL && signerkey != NULL) + if (user_cert != NULL && signer_cert != NULL && signer_key != NULL) { /* read the serial number and increment it by one */ serial = read_serial(); - attr_cert = build_attr_cert(); - ac = x509ac_create_from_chunk(attr_cert); + attr_cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509_AC, + BUILD_CERT, user_cert, + BUILD_NOT_BEFORE_TIME, ¬Before, + BUILD_NOT_AFTER_TIME, ¬After, + BUILD_SIGNING_CERT, signer_cert, + BUILD_SIGNING_KEY, signer_key, + BUILD_END); + attr_chunk = attr_cert->get_encoding(attr_cert); /* write the attribute certificate to file */ - if (chunk_write(attr_cert, outfile, "attribute cert", 0022, TRUE)) + if (chunk_write(attr_chunk, outfile, "attribute cert", 0022, TRUE)) { write_serial(serial); status = 0; @@ -503,11 +582,11 @@ int main(int argc, char **argv) end: /* delete all dynamically allocated objects */ - DESTROY_IF(signerkey); - DESTROY_IF(signercert); - DESTROY_IF(usercert); - DESTROY_IF(ac); - ietfAttr_list_destroy(groups); + DESTROY_IF(signer_key); + DESTROY_IF(signer_cert); + DESTROY_IF(user_cert); + DESTROY_IF(attr_cert); + free(attr_chunk.ptr); free(serial.ptr); closelog(); dbg = dbg_default; |