refactored openac and its attribute certificate factory
authorAndreas Steffen <andreas.steffen@strongswan.org>
Thu, 20 Mar 2008 15:23:52 +0000 (15:23 -0000)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Thu, 20 Mar 2008 15:23:52 +0000 (15:23 -0000)
12 files changed:
src/libstrongswan/Makefile.am
src/libstrongswan/credentials/builder.h
src/libstrongswan/credentials/certificates/ac.h [new file with mode: 0644]
src/libstrongswan/plugins/x509/Makefile.am
src/libstrongswan/plugins/x509/ietf_attr_list.c [new file with mode: 0644]
src/libstrongswan/plugins/x509/ietf_attr_list.h [new file with mode: 0644]
src/libstrongswan/plugins/x509/x509_ac.c [new file with mode: 0644]
src/libstrongswan/plugins/x509/x509_ac.h [new file with mode: 0644]
src/openac/Makefile.am
src/openac/build.c [deleted file]
src/openac/build.h [deleted file]
src/openac/openac.c

index b858e25..5f2169c 100644 (file)
@@ -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 \
index fd1cc69..37259e6 100644 (file)
@@ -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 (file)
index 0000000..20c88b8
--- /dev/null
@@ -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_ @}*/
+
index 12441b3..3f9f85c 100644 (file)
@@ -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 (file)
index 0000000..1ecadf6
--- /dev/null
@@ -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 **)&current_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 (file)
index 0000000..75407bb
--- /dev/null
@@ -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 (file)
index 0000000..e09c044
--- /dev/null
@@ -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 (file)
index 0000000..709e453
--- /dev/null
@@ -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_ @}*/
index 4b88d8b..1d8c8de 100644 (file)
@@ -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 (file)
index 3dcd3f7..0000000
+++ /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(&notBefore, ASN1_GENERALIZEDTIME),
-                               timetoasn1(&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(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 (file)
index 66ec862..0000000
+++ /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 */
index 6f19eff..c5a7cd2 100755 (executable)
@@ -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
 
 #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, &notBefore, &notAfter);
+       if (now > notAfter)
+       {
+               DBG1("  certificate expired at %T, discarded", &notAfter);
+               cert->destroy(cert);
+               return NULL;
+       }
+       if (now < notBefore)
+       {
+               DBG1("  certificate not valid before %T", &notBefore);
+       }
+       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, &notBefore,
+                                                                          BUILD_NOT_AFTER_TIME, &notAfter,
+                                                                          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;