- x509 certificate loading with pluto asn1 code
authorMartin Willi <martin@strongswan.org>
Wed, 19 Apr 2006 11:40:48 +0000 (11:40 -0000)
committerMartin Willi <martin@strongswan.org>
Wed, 19 Apr 2006 11:40:48 +0000 (11:40 -0000)
- x509 needs a lot more attention!

24 files changed:
Source/charon.kdevelop
Source/charon/daemon.c
Source/charon/threads/stroke_interface.c
Source/lib/Makefile.lib
Source/lib/asn1/Makefile.asn1
Source/lib/asn1/asn1.c
Source/lib/asn1/asn1.h
Source/lib/asn1/x509.c [deleted file]
Source/lib/asn1/x509.h [deleted file]
Source/lib/crypto/Makefile.transforms
Source/lib/crypto/certificate.c [deleted file]
Source/lib/crypto/certificate.h [deleted file]
Source/lib/crypto/rsa/rsa_private_key.c
Source/lib/crypto/rsa/rsa_public_key.c
Source/lib/crypto/x509.c [new file with mode: 0755]
Source/lib/crypto/x509.h [new file with mode: 0755]
Source/lib/types.c
Source/lib/types.h
Source/testing/Makefile.testcases
Source/testing/certificate_test.c
Source/testing/der_decoder_test.c [deleted file]
Source/testing/der_decoder_test.h [deleted file]
Source/testing/rsa_test.c
Source/testing/testcases.c

index b3156ad..270e815 100644 (file)
@@ -14,7 +14,7 @@
       <directoryradio>executable</directoryradio>
     </run>
     <general>
-      <activedir></activedir>
+      <activedir/>
     </general>
   </kdevcustomproject>
   <kdevdebugger>
index aafc86a..d726553 100644 (file)
@@ -266,7 +266,7 @@ void signal_handler(int signal)
                logger->log(logger, ERROR, "    %s", strings[i]);
        }
        free (strings);
-       /* kill ourselve the hard way, anything other may result in more SIGSEGVs*/
+       logger->log(logger, ERROR, "Killing ourself hard after SIGSEGV");
        kill(getpid(), SIGKILL);
 }
 
index 8302d1e..274791b 100755 (executable)
@@ -36,7 +36,7 @@
 #include <stroke.h>
 #include <types.h>
 #include <daemon.h>
-#include <crypto/certificate.h>
+#include <crypto/x509.h>
 #include <queues/jobs/initiate_ike_sa_job.h>
 
 
@@ -280,7 +280,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
        host_t *my_host, *other_host, *my_subnet, *other_subnet;
        proposal_t *proposal;
        traffic_selector_t *my_ts, *other_ts;
-       certificate_t *my_cert, *other_cert;
+       x509_t *my_cert, *other_cert;
        rsa_private_key_t *private_key = NULL;
        rsa_public_key_t *public_key = NULL;
                                
@@ -419,7 +419,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
                                
                                
        chdir(CERTIFICATE_DIR);
-       my_cert = certificate_create_from_file(msg->add_conn.me.cert);
+       my_cert = x509_create_from_file(msg->add_conn.me.cert);
        if (my_cert == NULL)
        {
                this->stroke_logger->log(this->stroke_logger, ERROR, "loading own certificate \"%s%s\" failed", 
@@ -442,7 +442,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
                }
                my_cert->destroy(my_cert);
        }
-       other_cert = certificate_create_from_file(msg->add_conn.other.cert);
+       other_cert = x509_create_from_file(msg->add_conn.other.cert);
        public_key = NULL;
        if (other_cert == NULL)
        {
index ff41072..389a31b 100644 (file)
@@ -25,4 +25,3 @@ $(BUILD_DIR)definitions.o :           $(LIB_DIR)definitions.c $(LIB_DIR)definitions.h
 include $(MAIN_DIR)lib/crypto/Makefile.transforms
 include $(MAIN_DIR)lib/utils/Makefile.utils
 include $(MAIN_DIR)lib/asn1/Makefile.asn1
-include $(MAIN_DIR)lib/asn1-pluto/Makefile.asn1
index 44726ff..3a5450d 100644 (file)
 # for more details.
 #
 
-ASN1_DIR= $(LIB_DIR)asn1-pluto/
+ASN1_DIR= $(LIB_DIR)asn1/
 
 
 LIB_OBJS+= $(BUILD_DIR)oid.o
 $(BUILD_DIR)oid.o :                                                    $(ASN1_DIR)oid.c $(ASN1_DIR)oid.h
                                                                                        $(CC) $(CFLAGS) -c -o $@ $<
-LIB_OBJS+= $(BUILD_DIR)asn1-pluto.o
-$(BUILD_DIR)asn1-pluto.o :                                     $(ASN1_DIR)asn1-pluto.c $(ASN1_DIR)asn1-pluto.h
+LIB_OBJS+= $(BUILD_DIR)asn1.o
+$(BUILD_DIR)asn1.o :                                           $(ASN1_DIR)asn1.c $(ASN1_DIR)asn1.h
                                                                                        $(CC) $(CFLAGS) -c -o $@ $<
 LIB_OBJS+= $(BUILD_DIR)pem.o
 $(BUILD_DIR)pem.o :                                                    $(ASN1_DIR)pem.c $(ASN1_DIR)pem.h
index 01deb5c..85baf79 100644 (file)
@@ -17,7 +17,7 @@
 #include <string.h>
 #include <time.h>
 
-#include "asn1-pluto.h"
+#include "asn1.h"
 #include "oid.h"
 
 #include <utils/logger_manager.h>
index 3edaa32..4a99c9a 100644 (file)
 
 
 /* Defines some primitive ASN1 types */
-
 typedef enum {
-    ASN1_EOC =                 0x00,
-    ASN1_BOOLEAN =             0x01,
-    ASN1_INTEGER =             0x02,
+    ASN1_EOC =                         0x00,
+    ASN1_BOOLEAN =                     0x01,
+    ASN1_INTEGER =                     0x02,
     ASN1_BIT_STRING =          0x03,
     ASN1_OCTET_STRING =        0x04,
-    ASN1_NULL =                0x05,
-    ASN1_OID =                 0x06,
+    ASN1_NULL =                        0x05,
+    ASN1_OID =                         0x06,
     ASN1_ENUMERATED =          0x0A,
     ASN1_UTF8STRING =          0x0C,
     ASN1_NUMERICSTRING =       0x12,
@@ -39,7 +38,7 @@ typedef enum {
     ASN1_T61STRING =           0x14,
     ASN1_VIDEOTEXSTRING =      0x15,
     ASN1_IA5STRING =           0x16,
-    ASN1_UTCTIME =             0x17,
+    ASN1_UTCTIME =                     0x17,
     ASN1_GENERALIZEDTIME =     0x18,
     ASN1_GRAPHICSTRING =       0x19,
     ASN1_VISIBLESTRING =       0x1A,
@@ -49,9 +48,9 @@ typedef enum {
 
     ASN1_CONSTRUCTED =         0x20,
 
-    ASN1_SEQUENCE =            0x30,
+    ASN1_SEQUENCE =                    0x30,
 
-    ASN1_SET =                 0x31,
+    ASN1_SET =                         0x31,
 
     ASN1_CONTEXT_S_0 =         0x80,
     ASN1_CONTEXT_S_1 =         0x81,
@@ -99,7 +98,7 @@ typedef struct {
     bool  implicit;
     u_int level0;
     u_int loopAddr[ASN1_MAX_LEVEL+1];
-    chunk_t  blobs[ASN1_MAX_LEVEL+2];
+    chunk_t blobs[ASN1_MAX_LEVEL+2];
 } asn1_ctx_t;
 
 /* some common prefabricated ASN.1 constants */
diff --git a/Source/lib/asn1/x509.c b/Source/lib/asn1/x509.c
deleted file mode 100644 (file)
index ee4767a..0000000
+++ /dev/null
@@ -1,2237 +0,0 @@
-/* Support of X.509 certificates
- * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
- * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
- * Copyright (C) 2002 Mario Strasser
- * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
- *
- * 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: x509.c,v 1.35 2006/02/28 19:12:19 as Exp $
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <time.h>
-#include <sys/types.h>
-
-#include <freeswan.h>
-#include <freeswan/ipsec_policy.h>
-
-#include "constants.h"
-#include "defs.h"
-#include "mp_defs.h"
-#include "log.h"
-#include "id.h"
-#include "asn1.h"
-#include "oid.h"
-#include "pkcs1.h"
-#include "x509.h"
-#include "crl.h"
-#include "ca.h"
-#include "certs.h"
-#include "keys.h"
-#include "whack.h"
-#include "fetch.h"
-#include "ocsp.h"
-#include "sha1.h"
-
-/* chained lists of X.509 end certificates */
-
-static x509cert_t *x509certs     = NULL;
-
-/* ASN.1 definition of a basicConstraints extension */
-
-static const asn1Object_t basicConstraintsObjects[] = {
-  { 0, "basicConstraints",             ASN1_SEQUENCE,     ASN1_NONE }, /*  0 */
-  { 1,   "CA",                         ASN1_BOOLEAN,      ASN1_DEF |
-                                                          ASN1_BODY }, /*  1 */
-  { 1,   "pathLenConstraint",          ASN1_INTEGER,      ASN1_OPT |
-                                                          ASN1_BODY }, /*  2 */
-  { 1,   "end opt",                    ASN1_EOC,          ASN1_END  }  /*  3 */
-};
-
-#define BASIC_CONSTRAINTS_CA   1
-#define BASIC_CONSTRAINTS_ROOF 4
-
-/* ASN.1 definition of time */
-
-static const asn1Object_t timeObjects[] = {
-  { 0,   "utcTime",                    ASN1_UTCTIME,         ASN1_OPT |
-                                                             ASN1_BODY }, /*  0 */
-  { 0,   "end opt",                    ASN1_EOC,             ASN1_END  }, /*  1 */
-  { 0,   "generalizeTime",             ASN1_GENERALIZEDTIME, ASN1_OPT |
-                                                             ASN1_BODY }, /*  2 */
-  { 0,   "end opt",                    ASN1_EOC,             ASN1_END  }  /*  3 */
-};
-
-#define TIME_UTC               0
-#define TIME_GENERALIZED       2
-#define TIME_ROOF              4
-
-/* ASN.1 definition of a keyIdentifier */
-
-static const asn1Object_t keyIdentifierObjects[] = {
-  { 0,   "keyIdentifier",              ASN1_OCTET_STRING, ASN1_BODY }  /*  0 */
-};
-
-/* ASN.1 definition of a authorityKeyIdentifier extension */
-
-static const asn1Object_t authorityKeyIdentifierObjects[] = {
-  { 0,   "authorityKeyIdentifier",     ASN1_SEQUENCE,     ASN1_NONE }, /*  0 */
-  { 1,     "keyIdentifier",            ASN1_CONTEXT_S_0,  ASN1_OPT |
-                                                          ASN1_OBJ  }, /*  1 */
-  { 1,     "end opt",                  ASN1_EOC,          ASN1_END  }, /*  2 */
-  { 1,     "authorityCertIssuer",      ASN1_CONTEXT_C_1,  ASN1_OPT |
-                                                          ASN1_OBJ  }, /*  3 */
-  { 1,     "end opt",                  ASN1_EOC,          ASN1_END  }, /*  4 */
-  { 1,     "authorityCertSerialNumber",        ASN1_CONTEXT_S_2,  ASN1_OPT |
-                                                          ASN1_BODY }, /*  5 */
-  { 1,     "end opt",                  ASN1_EOC,          ASN1_END  }  /*  6 */
-};
-
-#define AUTH_KEY_ID_KEY_ID             1
-#define AUTH_KEY_ID_CERT_ISSUER                3
-#define AUTH_KEY_ID_CERT_SERIAL                5
-#define AUTH_KEY_ID_ROOF               7
-
-/* ASN.1 definition of a authorityInfoAccess extension */
-
-static const asn1Object_t authorityInfoAccessObjects[] = {
-  { 0,   "authorityInfoAccess",         ASN1_SEQUENCE,     ASN1_LOOP }, /*  0 */
-  { 1,     "accessDescription",         ASN1_SEQUENCE,     ASN1_NONE }, /*  1 */
-  { 2,       "accessMethod",            ASN1_OID,          ASN1_BODY }, /*  2 */
-  { 2,       "accessLocation",          ASN1_EOC,          ASN1_RAW  }, /*  3 */
-  { 0,   "end loop",                    ASN1_EOC,          ASN1_END  }  /*  4 */
-};
-
-#define AUTH_INFO_ACCESS_METHOD                2
-#define AUTH_INFO_ACCESS_LOCATION      3
-#define AUTH_INFO_ACCESS_ROOF          5
-
-/* ASN.1 definition of a extendedKeyUsage extension */
-
-static const asn1Object_t extendedKeyUsageObjects[] = {
-  { 0, "extendedKeyUsage",             ASN1_SEQUENCE,     ASN1_LOOP }, /*  0 */
-  { 1,   "keyPurposeID",               ASN1_OID,          ASN1_BODY }, /*  1 */
-  { 0, "end loop",                     ASN1_EOC,          ASN1_END  }, /*  2 */
-};
-
-#define EXT_KEY_USAGE_PURPOSE_ID       1
-#define EXT_KEY_USAGE_ROOF             3
-
-/* ASN.1 definition of generalNames */
-
-static const asn1Object_t generalNamesObjects[] = {
-  { 0, "generalNames",                 ASN1_SEQUENCE,     ASN1_LOOP }, /*  0 */
-  { 1,   "generalName",                        ASN1_EOC,          ASN1_RAW  }, /*  1 */
-  { 0, "end loop",                     ASN1_EOC,          ASN1_END  }  /*  2 */
-};
-
-#define GENERAL_NAMES_GN       1
-#define GENERAL_NAMES_ROOF     3
-
-/* ASN.1 definition of generalName */
-
-static const asn1Object_t generalNameObjects[] = {
-  { 0,   "otherName",                  ASN1_CONTEXT_C_0,  ASN1_OPT |
-                                                          ASN1_BODY }, /*  0 */
-  { 0,   "end choice",                 ASN1_EOC,          ASN1_END  }, /*  1 */
-  { 0,   "rfc822Name",                 ASN1_CONTEXT_S_1,  ASN1_OPT |
-                                                          ASN1_BODY }, /*  2 */
-  { 0,   "end choice",                 ASN1_EOC,          ASN1_END  }, /*  3 */
-  { 0,   "dnsName",                    ASN1_CONTEXT_S_2,  ASN1_OPT |
-                                                          ASN1_BODY }, /*  4 */
-  { 0,   "end choice",                 ASN1_EOC,          ASN1_END  }, /*  5 */
-  { 0,   "x400Address",                        ASN1_CONTEXT_S_3,  ASN1_OPT |
-                                                          ASN1_BODY }, /*  6 */
-  { 0,   "end choice",                 ASN1_EOC,          ASN1_END  }, /*  7 */
-  { 0,   "directoryName",              ASN1_CONTEXT_C_4,  ASN1_OPT |
-                                                          ASN1_BODY }, /*  8 */
-  { 0,   "end choice",                 ASN1_EOC,          ASN1_END  }, /*  9 */
-  { 0,   "ediPartyName",               ASN1_CONTEXT_C_5,  ASN1_OPT |
-                                                          ASN1_BODY }, /* 10 */
-  { 0,   "end choice",                 ASN1_EOC,          ASN1_END  }, /* 11 */
-  { 0,   "uniformResourceIdentifier",  ASN1_CONTEXT_S_6,  ASN1_OPT |
-                                                          ASN1_BODY }, /* 12 */
-  { 0,   "end choice",                 ASN1_EOC,          ASN1_END  }, /* 13 */
-  { 0,   "ipAddress",                  ASN1_CONTEXT_S_7,  ASN1_OPT |
-                                                          ASN1_BODY }, /* 14 */
-  { 0,   "end choice",                 ASN1_EOC,          ASN1_END  }, /* 15 */
-  { 0,   "registeredID",               ASN1_CONTEXT_S_8,  ASN1_OPT |
-                                                          ASN1_BODY }, /* 16 */
-  { 0,   "end choice",                 ASN1_EOC,          ASN1_END  }  /* 17 */
-};
-
-#define GN_OBJ_OTHER_NAME       0
-#define GN_OBJ_RFC822_NAME      2
-#define GN_OBJ_DNS_NAME                 4
-#define GN_OBJ_X400_ADDRESS     6
-#define GN_OBJ_DIRECTORY_NAME   8
-#define GN_OBJ_EDI_PARTY_NAME  10
-#define GN_OBJ_URI             12
-#define GN_OBJ_IP_ADDRESS      14
-#define GN_OBJ_REGISTERED_ID   16
-#define GN_OBJ_ROOF            18
-
-/* ASN.1 definition of otherName */
-
-static const asn1Object_t otherNameObjects[] = {
-  {0, "type-id",                       ASN1_OID,          ASN1_BODY }, /*  0 */
-  {0, "value",                         ASN1_CONTEXT_C_0,  ASN1_BODY }  /*  1 */
-};
-
-#define ON_OBJ_ID_TYPE         0
-#define ON_OBJ_VALUE           1
-#define ON_OBJ_ROOF            2
-
-/* ASN.1 definition of crlDistributionPoints */
-
-static const asn1Object_t crlDistributionPointsObjects[] = {
-  { 0, "crlDistributionPoints",                ASN1_SEQUENCE,     ASN1_LOOP }, /*  0 */
-  { 1,   "DistributionPoint",          ASN1_SEQUENCE,     ASN1_NONE }, /*  1 */
-  { 2,     "distributionPoint",                ASN1_CONTEXT_C_0,  ASN1_OPT |
-                                                          ASN1_LOOP }, /*  2 */
-  { 3,       "fullName",               ASN1_CONTEXT_C_0,  ASN1_OPT |
-                                                          ASN1_OBJ  }, /*  3 */
-  { 3,       "end choice",             ASN1_EOC,          ASN1_END  }, /*  4 */
-  { 3,       "nameRelativeToCRLIssuer",        ASN1_CONTEXT_C_1,  ASN1_OPT |
-                                                          ASN1_BODY }, /*  5 */
-  { 3,       "end choice",             ASN1_EOC,          ASN1_END  }, /*  6 */
-  { 2,     "end opt",                  ASN1_EOC,          ASN1_END  }, /*  7 */
-  { 2,     "reasons",                  ASN1_CONTEXT_C_1,  ASN1_OPT |
-                                                          ASN1_BODY }, /*  8 */
-  { 2,     "end opt",                  ASN1_EOC,          ASN1_END  }, /*  9 */
-  { 2,     "crlIssuer",                        ASN1_CONTEXT_C_2,  ASN1_OPT |
-                                                          ASN1_BODY }, /* 10 */
-  { 2,     "end opt",                  ASN1_EOC,          ASN1_END  }, /* 11 */
-  { 0, "end loop",                     ASN1_EOC,          ASN1_END  }, /* 12 */
-};
-
-#define CRL_DIST_POINTS_FULLNAME        3
-#define CRL_DIST_POINTS_ROOF           13
-
-/* ASN.1 definition of an X.509v3 certificate */
-
-static const asn1Object_t certObjects[] = {
-  { 0, "certificate",                  ASN1_SEQUENCE,     ASN1_OBJ  }, /*  0 */
-  { 1,   "tbsCertificate",             ASN1_SEQUENCE,     ASN1_OBJ  }, /*  1 */
-  { 2,     "DEFAULT v1",               ASN1_CONTEXT_C_0,  ASN1_DEF  }, /*  2 */
-  { 3,       "version",                        ASN1_INTEGER,      ASN1_BODY }, /*  3 */
-  { 2,     "serialNumber",             ASN1_INTEGER,      ASN1_BODY }, /*  4 */
-  { 2,     "signature",                        ASN1_EOC,          ASN1_RAW  }, /*  5 */
-  { 2,     "issuer",                   ASN1_SEQUENCE,     ASN1_OBJ  }, /*  6 */
-  { 2,     "validity",                 ASN1_SEQUENCE,     ASN1_NONE }, /*  7 */
-  { 3,       "notBefore",              ASN1_EOC,          ASN1_RAW  }, /*  8 */
-  { 3,       "notAfter",               ASN1_EOC,          ASN1_RAW  }, /*  9 */
-  { 2,     "subject",                  ASN1_SEQUENCE,     ASN1_OBJ  }, /* 10 */
-  { 2,     "subjectPublicKeyInfo",     ASN1_SEQUENCE,     ASN1_NONE }, /* 11 */
-  { 3,       "algorithm",              ASN1_EOC,          ASN1_RAW  }, /* 12 */
-  { 3,       "subjectPublicKey",       ASN1_BIT_STRING,   ASN1_NONE }, /* 13 */
-  { 4,         "RSAPublicKey",         ASN1_SEQUENCE,     ASN1_OBJ  }, /* 14 */
-  { 5,           "modulus",            ASN1_INTEGER,      ASN1_BODY }, /* 15 */
-  { 5,           "publicExponent",     ASN1_INTEGER,      ASN1_BODY }, /* 16 */
-  { 2,     "issuerUniqueID",           ASN1_CONTEXT_C_1,  ASN1_OPT  }, /* 17 */
-  { 2,     "end opt",                  ASN1_EOC,          ASN1_END  }, /* 18 */
-  { 2,     "subjectUniqueID",          ASN1_CONTEXT_C_2,  ASN1_OPT  }, /* 19 */
-  { 2,     "end opt",                  ASN1_EOC,          ASN1_END  }, /* 20 */
-  { 2,     "optional extensions",      ASN1_CONTEXT_C_3,  ASN1_OPT  }, /* 21 */
-  { 3,       "extensions",             ASN1_SEQUENCE,     ASN1_LOOP }, /* 22 */
-  { 4,         "extension",            ASN1_SEQUENCE,     ASN1_NONE }, /* 23 */
-  { 5,           "extnID",             ASN1_OID,          ASN1_BODY }, /* 24 */
-  { 5,           "critical",           ASN1_BOOLEAN,      ASN1_DEF |
-                                                          ASN1_BODY }, /* 25 */
-  { 5,           "extnValue",          ASN1_OCTET_STRING, ASN1_BODY }, /* 26 */
-  { 3,       "end loop",               ASN1_EOC,          ASN1_END  }, /* 27 */
-  { 2,     "end opt",                  ASN1_EOC,          ASN1_END  }, /* 28 */
-  { 1,   "signatureAlgorithm",         ASN1_EOC,          ASN1_RAW  }, /* 29 */
-  { 1,   "signatureValue",             ASN1_BIT_STRING,   ASN1_BODY }  /* 30 */
-};
-
-#define X509_OBJ_CERTIFICATE                    0
-#define X509_OBJ_TBS_CERTIFICATE                1
-#define X509_OBJ_VERSION                        3
-#define X509_OBJ_SERIAL_NUMBER                  4
-#define X509_OBJ_SIG_ALG                        5
-#define X509_OBJ_ISSUER                         6
-#define X509_OBJ_NOT_BEFORE                     8
-#define X509_OBJ_NOT_AFTER                      9
-#define X509_OBJ_SUBJECT                       10
-#define X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM  12
-#define X509_OBJ_SUBJECT_PUBLIC_KEY            13
-#define X509_OBJ_RSA_PUBLIC_KEY                        14
-#define X509_OBJ_MODULUS                       15
-#define X509_OBJ_PUBLIC_EXPONENT               16
-#define X509_OBJ_EXTN_ID                       24
-#define X509_OBJ_CRITICAL                      25
-#define X509_OBJ_EXTN_VALUE                    26
-#define X509_OBJ_ALGORITHM                     29
-#define X509_OBJ_SIGNATURE                     30
-#define X509_OBJ_ROOF                          31
-
-
-const x509cert_t empty_x509cert = {
-      NULL        , /* *next */
-    UNDEFINED_TIME, /* installed */
-            0     , /* count */
-      FALSE       , /* smartcard */
-     AUTH_NONE    , /* authority_flags */
-    { NULL, 0 }   , /* certificate */
-    { NULL, 0 }   , /*   tbsCertificate */
-            1    , /*     version */
-    { NULL, 0 }   , /*     serialNumber */
-    OID_UNKNOWN   , /*     sigAlg */
-    { NULL, 0 }   , /*     issuer */
-                    /*     validity */
-            0     , /*       notBefore */
-            0     , /*       notAfter */
-    { NULL, 0 }   , /*     subject */
-                    /*     subjectPublicKeyInfo */
-    OID_UNKNOWN   , /*       subjectPublicKeyAlgorithm */
-    { NULL, 0 }   , /*       subjectPublicKey */
-    { NULL, 0 }   , /*         modulus */
-    { NULL, 0 }   , /*         publicExponent */
-                    /*     issuerUniqueID */
-                    /*     subjectUniqueID */
-                    /*     extensions */
-                    /*       extension */
-                    /*         extnID */
-                    /*         critical */
-                    /*         extnValue */
-      FALSE       , /*           isCA */
-      FALSE       , /*           isOcspSigner */
-    { NULL, 0 }   , /*           subjectKeyID */
-    { NULL, 0 }   , /*           authKeyID */
-    { NULL, 0 }   , /*           authKeySerialNumber */
-    { NULL, 0 }   , /*           accessLocation */
-      NULL        , /*           subjectAltName */
-      NULL        , /*           crlDistributionPoints */
-    OID_UNKNOWN   , /*   algorithm */
-    { NULL, 0 }     /*   signature */
-};
-
-/* coding of X.501 distinguished name */
-
-typedef struct {
-    const u_char *name;
-    chunk_t oid;
-    u_char type;
-} x501rdn_t;
-
-/* X.501 acronyms for well known object identifiers (OIDs) */
-
-static u_char oid_ND[]  = {0x02, 0x82, 0x06, 0x01,
-                          0x0A, 0x07, 0x14};
-static u_char oid_UID[] = {0x09, 0x92, 0x26, 0x89, 0x93,
-                          0xF2, 0x2C, 0x64, 0x01, 0x01};
-static u_char oid_DC[]  = {0x09, 0x92, 0x26, 0x89, 0x93,
-                          0xF2, 0x2C, 0x64, 0x01, 0x19};
-static u_char oid_CN[]  = {0x55, 0x04, 0x03};
-static u_char oid_S[]   = {0x55, 0x04, 0x04};
-static u_char oid_SN[]  = {0x55, 0x04, 0x05};
-static u_char oid_C[]   = {0x55, 0x04, 0x06};
-static u_char oid_L[]   = {0x55, 0x04, 0x07};
-static u_char oid_ST[]  = {0x55, 0x04, 0x08};
-static u_char oid_O[]   = {0x55, 0x04, 0x0A};
-static u_char oid_OU[]  = {0x55, 0x04, 0x0B};
-static u_char oid_T[]   = {0x55, 0x04, 0x0C};
-static u_char oid_D[]   = {0x55, 0x04, 0x0D};
-static u_char oid_N[]   = {0x55, 0x04, 0x29};
-static u_char oid_G[]   = {0x55, 0x04, 0x2A};
-static u_char oid_I[]   = {0x55, 0x04, 0x2B};
-static u_char oid_ID[]  = {0x55, 0x04, 0x2D};
-static u_char oid_E[]   = {0x2A, 0x86, 0x48, 0x86, 0xF7,
-                          0x0D, 0x01, 0x09, 0x01};
-static u_char oid_UN[]  = {0x2A, 0x86, 0x48, 0x86, 0xF7,
-                          0x0D, 0x01, 0x09, 0x02};
-static u_char oid_TCGID[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0x89,
-                            0x31, 0x01, 0x01, 0x02, 0x02, 0x4B};
-
-static const x501rdn_t x501rdns[] = {
-  {"ND"              , {oid_ND,     7}, ASN1_PRINTABLESTRING},
-  {"UID"             , {oid_UID,   10}, ASN1_PRINTABLESTRING},
-  {"DC"              , {oid_DC,    10}, ASN1_PRINTABLESTRING},
-  {"CN"              , {oid_CN,     3}, ASN1_PRINTABLESTRING},
-  {"S"               , {oid_S,      3}, ASN1_PRINTABLESTRING},
-  {"SN"              , {oid_SN,     3}, ASN1_PRINTABLESTRING},
-  {"serialNumber"    , {oid_SN,     3}, ASN1_PRINTABLESTRING},
-  {"C"               , {oid_C,      3}, ASN1_PRINTABLESTRING},
-  {"L"               , {oid_L,      3}, ASN1_PRINTABLESTRING},
-  {"ST"              , {oid_ST,     3}, ASN1_PRINTABLESTRING},
-  {"O"               , {oid_O,      3}, ASN1_PRINTABLESTRING},
-  {"OU"              , {oid_OU,     3}, ASN1_PRINTABLESTRING},
-  {"T"               , {oid_T,      3}, ASN1_PRINTABLESTRING},
-  {"D"               , {oid_D,      3}, ASN1_PRINTABLESTRING},
-  {"N"               , {oid_N,      3}, ASN1_PRINTABLESTRING},
-  {"G"               , {oid_G,      3}, ASN1_PRINTABLESTRING},
-  {"I"               , {oid_I,      3}, ASN1_PRINTABLESTRING},
-  {"ID"              , {oid_ID,     3}, ASN1_PRINTABLESTRING},
-  {"E"               , {oid_E,      9}, ASN1_IA5STRING},
-  {"Email"           , {oid_E,      9}, ASN1_IA5STRING},
-  {"emailAddress"    , {oid_E,      9}, ASN1_IA5STRING},
-  {"UN"              , {oid_UN,     9}, ASN1_IA5STRING},
-  {"unstructuredName", {oid_UN,     9}, ASN1_IA5STRING},
-  {"TCGID"           , {oid_TCGID, 12}, ASN1_PRINTABLESTRING}
-};
-
-#define X501_RDN_ROOF   24
-
-static u_char ASN1_subjectAltName_oid_str[] = {
-    0x06, 0x03, 0x55, 0x1D, 0x11
-};
-
-static const chunk_t ASN1_subjectAltName_oid = strchunk(ASN1_subjectAltName_oid_str);
-
-static void
-update_chunk(chunk_t *ch, int n)
-{
-    n = (n > -1 && n < (int)ch->len)? n : (int)ch->len-1;
-    ch->ptr += n; ch->len -= n;
-}
-
-
-/*
- *  Pointer is set to the first RDN in a DN
- */
-static err_t
-init_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *next)
-{
-    *rdn = empty_chunk;
-    *attribute = empty_chunk;
-
-    /* a DN is a SEQUENCE OF RDNs */
-
-    if (*dn.ptr != ASN1_SEQUENCE)
-    {
-       return "DN is not a SEQUENCE";
-    }
-
-    rdn->len = asn1_length(&dn);
-
-    if (rdn->len == ASN1_INVALID_LENGTH)
-       return "Invalid RDN length";
-
-    rdn->ptr = dn.ptr;
-
-    /* are there any RDNs ? */
-    *next = rdn->len > 0;
-
-    return NULL;
-}
-
-/*
- *  Fetches the next RDN in a DN
- */
-static err_t
-get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, chunk_t *value
-, asn1_t *type, bool *next)
-{
-    chunk_t body;
-
-    /* initialize return values */
-    *oid   = empty_chunk;
-    *value = empty_chunk;
-
-    /* if all attributes have been parsed, get next rdn */
-    if (attribute->len <= 0)
-    {
-       /* an RDN is a SET OF attributeTypeAndValue */
-       if (*rdn->ptr != ASN1_SET)
-           return "RDN is not a SET";
-
-       attribute->len = asn1_length(rdn);
-       
-       if (attribute->len == ASN1_INVALID_LENGTH)
-           return "Invalid attribute length";
-
-       attribute->ptr = rdn->ptr;
-
-       /* advance to start of next RDN */
-       rdn->ptr += attribute->len;
-       rdn->len -= attribute->len;
-    }
-
-    /* an attributeTypeAndValue is a SEQUENCE */
-    if (*attribute->ptr != ASN1_SEQUENCE)
-       return "attributeTypeAndValue is not a SEQUENCE";
-
-    /* extract the attribute body */
-    body.len = asn1_length(attribute);
-    
-    if (body.len == ASN1_INVALID_LENGTH)
-       return "Invalid attribute body length";
-
-    body.ptr = attribute->ptr;
-    
-    /* advance to start of next attribute */
-    attribute->ptr += body.len;
-    attribute->len -= body.len;
-
-    /* attribute type is an OID */
-    if (*body.ptr != ASN1_OID)
-       return "attributeType is not an OID";
-
-    /* extract OID */
-    oid->len = asn1_length(&body);
-    
-    if (oid->len == ASN1_INVALID_LENGTH)
-       return "Invalid attribute OID length";
-
-    oid->ptr = body.ptr;
-
-    /* advance to the attribute value */
-    body.ptr += oid->len;
-    body.len -= oid->len;
-
-    /* extract string type */
-    *type = *body.ptr;
-
-    /* extract string value */
-    value->len = asn1_length(&body);
-    
-    if (value->len == ASN1_INVALID_LENGTH)
-       return "Invalid attribute string length";
-
-    value->ptr = body.ptr;
-
-    /* are there any RDNs left? */
-    *next = rdn->len > 0 || attribute->len > 0;
-
-    return NULL;
-}
-
-/*
- *  Parses an ASN.1 distinguished name int its OID/value pairs
- */
-static err_t
-dn_parse(chunk_t dn, chunk_t *str)
-{
-    chunk_t rdn, oid, attribute, value;
-    asn1_t type;
-    int oid_code;
-    bool next;
-    bool first = TRUE;
-
-    err_t ugh = init_rdn(dn, &rdn, &attribute, &next);
-
-    if (ugh != NULL) /* a parsing error has occured */
-        return ugh;
-
-    while (next)
-    {
-       ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next);
-
-       if (ugh != NULL) /* a parsing error has occured */
-           return ugh;
-
-       if (first)              /* first OID/value pair */
-           first = FALSE;
-       else                    /* separate OID/value pair by a comma */
-           update_chunk(str, snprintf(str->ptr,str->len,", "));
-
-       /* print OID */
-       oid_code = known_oid(oid);
-       if (oid_code == OID_UNKNOWN)    /* OID not found in list */
-           hex_str(oid, str);
-       else
-           update_chunk(str, snprintf(str->ptr,str->len,"%s",
-                             oid_names[oid_code].name));
-
-       /* print value */
-       update_chunk(str, snprintf(str->ptr,str->len,"=%.*s",
-                             (int)value.len,value.ptr));
-    }
-    return NULL;
-}
-
-/*
- *  Count the number of wildcard RDNs in a distinguished name
- */
-int
-dn_count_wildcards(chunk_t dn)
-{
-    chunk_t rdn, attribute, oid, value;
-    asn1_t type;
-    bool next;
-    int wildcards = 0;
-
-    err_t ugh = init_rdn(dn, &rdn, &attribute, &next);
-
-    if (ugh != NULL) /* a parsing error has occured */
-        return -1;
-
-    while (next)
-    {
-       ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next);
-
-       if (ugh != NULL) /* a parsing error has occured */
-           return -1;
-       if (value.len == 1 && *value.ptr == '*')
-           wildcards++; /* we have found a wildcard RDN */
-    }
-    return wildcards;
-}
-
-/*
- * Prints a binary string in hexadecimal form
- */
-void
-hex_str(chunk_t bin, chunk_t *str)
-{
-    u_int i;
-    update_chunk(str, snprintf(str->ptr,str->len,"0x"));
-    for (i=0; i < bin.len; i++)
-       update_chunk(str, snprintf(str->ptr,str->len,"%02X",*bin.ptr++));
-}
-
-
-/*  Converts a binary DER-encoded ASN.1 distinguished name
- *  into LDAP-style human-readable ASCII format
- */
-int
-dntoa(char *dst, size_t dstlen, chunk_t dn)
-{
-    err_t ugh = NULL;
-    chunk_t str;
-
-    str.ptr = dst;
-    str.len = dstlen;
-    ugh = dn_parse(dn, &str);
-
-    if (ugh != NULL) /* error, print DN as hex string */
-    {
-       DBG(DBG_PARSING,
-           DBG_log("error in DN parsing: %s", ugh)
-       )
-       str.ptr = dst;
-       str.len = dstlen;
-       hex_str(dn, &str);
-    }
-    return (int)(dstlen - str.len);
-}
-
-/*
- * Same as dntoa but prints a special string for a null dn
- */
-int
-dntoa_or_null(char *dst, size_t dstlen, chunk_t dn, const char* null_dn)
-{
-    if (dn.ptr == NULL)
-       return snprintf(dst, dstlen, "%s", null_dn);
-    else
-       return dntoa(dst, dstlen, dn);
-}
-
-/*  Converts an LDAP-style human-readable ASCII-encoded
- *  ASN.1 distinguished name into binary DER-encoded format
- */
-err_t
-atodn(char *src, chunk_t *dn)
-{
-  /* finite state machine for atodn */
-
-    typedef enum {
-       SEARCH_OID =    0,
-       READ_OID =      1,
-       SEARCH_NAME =   2,
-       READ_NAME =     3,
-        UNKNOWN_OID =  4
-    } state_t;
-
-    u_char oid_len_buf[3];
-    u_char name_len_buf[3];
-    u_char rdn_seq_len_buf[3];
-    u_char rdn_set_len_buf[3];
-    u_char dn_seq_len_buf[3];
-
-    chunk_t asn1_oid_len     = { oid_len_buf,     0 };
-    chunk_t asn1_name_len    = { name_len_buf,    0 };
-    chunk_t asn1_rdn_seq_len = { rdn_seq_len_buf, 0 };
-    chunk_t asn1_rdn_set_len = { rdn_set_len_buf, 0 };
-    chunk_t asn1_dn_seq_len  = { dn_seq_len_buf,  0 };
-    chunk_t oid  = empty_chunk;
-    chunk_t name = empty_chunk;
-
-    int whitespace  = 0;
-    int rdn_seq_len = 0;
-    int rdn_set_len = 0;
-    int dn_seq_len  = 0;
-    int pos         = 0;
-
-    err_t ugh = NULL;
-
-    u_char *dn_ptr = dn->ptr + 4;
-
-    state_t state = SEARCH_OID;
-
-    do
-    {
-        switch (state)
-       {
-       case SEARCH_OID:
-           if (*src != ' ' && *src != '/' && *src !=  ',')
-           {
-               oid.ptr = src;
-               oid.len = 1;
-               state = READ_OID;
-           }
-           break;
-       case READ_OID:
-           if (*src != ' ' && *src != '=')
-               oid.len++;
-           else
-           {
-               for (pos = 0; pos < X501_RDN_ROOF; pos++)
-               {
-                   if (strlen(x501rdns[pos].name) == oid.len &&
-                       strncasecmp(x501rdns[pos].name, oid.ptr, oid.len) == 0)
-                       break; /* found a valid OID */
-               }
-               if (pos == X501_RDN_ROOF)
-               {
-                   ugh = "unknown OID in distinguished name";
-                   state = UNKNOWN_OID;
-                   break;
-               }
-               code_asn1_length(x501rdns[pos].oid.len, &asn1_oid_len);
-
-               /* reset oid and change state */
-               oid = empty_chunk;
-               state = SEARCH_NAME;
-           }
-           break;
-       case SEARCH_NAME:
-           if (*src != ' ' && *src != '=')
-           {
-               name.ptr = src;
-               name.len = 1;
-               whitespace = 0;
-               state = READ_NAME;
-           }
-           break;
-       case READ_NAME:
-           if (*src != ',' && *src != '/' && *src != '\0')
-           {
-               name.len++;
-               if (*src == ' ')
-                   whitespace++;
-               else
-                   whitespace = 0;
-           }
-           else
-           {
-               name.len -= whitespace;
-               code_asn1_length(name.len, &asn1_name_len);
-
-               /* compute the length of the relative distinguished name sequence */
-               rdn_seq_len = 1 + asn1_oid_len.len + x501rdns[pos].oid.len +
-                             1 + asn1_name_len.len + name.len;
-               code_asn1_length(rdn_seq_len, &asn1_rdn_seq_len);
-
-               /* compute the length of the relative distinguished name set */
-               rdn_set_len = 1 + asn1_rdn_seq_len.len + rdn_seq_len;
-               code_asn1_length(rdn_set_len, &asn1_rdn_set_len);
-
-               /* encode the relative distinguished name */
-               *dn_ptr++ = ASN1_SET;
-               chunkcpy(dn_ptr, asn1_rdn_set_len);
-               *dn_ptr++ = ASN1_SEQUENCE;
-               chunkcpy(dn_ptr, asn1_rdn_seq_len);
-               *dn_ptr++ = ASN1_OID;
-               chunkcpy(dn_ptr, asn1_oid_len);
-               chunkcpy(dn_ptr, x501rdns[pos].oid);
-               /* encode the ASN.1 character string type of the name */
-               *dn_ptr++ = (x501rdns[pos].type == ASN1_PRINTABLESTRING
-                   && !is_printablestring(name))? ASN1_T61STRING : x501rdns[pos].type;
-               chunkcpy(dn_ptr, asn1_name_len);
-               chunkcpy(dn_ptr, name);
-
-               /* accumulate the length of the distinguished name sequence */
-               dn_seq_len += 1 + asn1_rdn_set_len.len + rdn_set_len;
-
-               /* reset name and change state */
-               name = empty_chunk;
-               state = SEARCH_OID;
-           }
-           break;
-       case UNKNOWN_OID:
-           break;
-       }
-    } while (*src++ != '\0');
-
-    /* complete the distinguished name sequence*/
-    code_asn1_length(dn_seq_len, &asn1_dn_seq_len);
-    dn->ptr += 3 - asn1_dn_seq_len.len;
-    dn->len =  1 + asn1_dn_seq_len.len + dn_seq_len;
-    dn_ptr = dn->ptr;
-    *dn_ptr++ = ASN1_SEQUENCE;
-    chunkcpy(dn_ptr, asn1_dn_seq_len);
-    return ugh;
-}
-
-/*  compare two distinguished names by
- *  comparing the individual RDNs
- */
-bool
-same_dn(chunk_t a, chunk_t b)
-{
-    chunk_t rdn_a, rdn_b, attribute_a, attribute_b;
-    chunk_t oid_a, oid_b, value_a, value_b;
-    asn1_t type_a, type_b;
-    bool next_a, next_b;
-
-    /* same lengths for the DNs */
-    if (a.len != b.len)
-       return FALSE;
-
-    /* try a binary comparison first */
-    if (memcmp(a.ptr, b.ptr, b.len) == 0)
-       return TRUE;
-    /* initialize DN parsing */
-    if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != NULL
-    ||  init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL)
-       return FALSE;
-
-    /* fetch next RDN pair */
-    while (next_a && next_b)
-    {
-       /* parse next RDNs and check for errors */
-       if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != NULL
-       ||  get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL)
-       {
-           return FALSE;
-       }
-
-       /* OIDs must agree */
-       if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0)
-           return FALSE;
-
-       /* same lengths for values */
-       if (value_a.len != value_b.len)
-           return FALSE;
-
-       /* printableStrings and email RDNs require uppercase comparison */
-       if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING ||
-          (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL)))
-       {
-           if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
-               return FALSE;
-       }
-       else
-       {
-           if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
-               return FALSE;
-       }
-    }
-    /* both DNs must have same number of RDNs */
-    if (next_a || next_b)
-       return FALSE;
-
-    /* the two DNs are equal! */
-    return TRUE;
-}
-
-
-/*  compare two distinguished names by comparing the individual RDNs.
- *  A single'*' character designates a wildcard RDN in DN b.
- */
-bool
-match_dn(chunk_t a, chunk_t b, int *wildcards)
-{
-    chunk_t rdn_a, rdn_b, attribute_a, attribute_b;
-    chunk_t oid_a, oid_b, value_a, value_b;
-    asn1_t type_a,  type_b;
-    bool next_a, next_b;
-
-    /* initialize wildcard counter */
-    *wildcards = 0;
-
-    /* initialize DN parsing */
-    if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != NULL
-    ||  init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL)
-       return FALSE;
-
-    /* fetch next RDN pair */
-    while (next_a && next_b)
-    {
-       /* parse next RDNs and check for errors */
-       if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != NULL
-       ||  get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL)
-       {
-           return FALSE;
-       }
-
-       /* OIDs must agree */
-       if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0)
-           return FALSE;
-
-       /* does rdn_b contain a wildcard? */
-       if (value_b.len == 1 && *value_b.ptr == '*')
-       {
-           (*wildcards)++;
-           continue;
-       }
-
-       /* same lengths for values */
-       if (value_a.len != value_b.len)
-           return FALSE;
-
-       /* printableStrings and email RDNs require uppercase comparison */
-       if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING ||
-          (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL)))
-       {
-           if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
-               return FALSE;
-       }
-       else
-       {
-           if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
-               return FALSE;
-       }
-    }
-    /* both DNs must have same number of RDNs */
-    if (next_a || next_b)
-       return FALSE;
-
-    /* the two DNs match! */
-    return TRUE;
-}
-
-/*
- *  compare two X.509 certificates by comparing their signatures
- */
-bool
-same_x509cert(const x509cert_t *a, const x509cert_t *b)
-{
-    return same_chunk(a->signature, b->signature);
-}
-
-/*  for each link pointing to the certificate
- "  increase the count by one
- */
-void
-share_x509cert(x509cert_t *cert)
-{
-    if (cert != NULL)
-       cert->count++;
-}
-
-/*
- *  add a X.509 user/host certificate to the chained list
- */
-x509cert_t*
-add_x509cert(x509cert_t *cert)
-{
-    x509cert_t *c = x509certs;
-
-    while (c != NULL)
-    {
-       if (same_x509cert(c, cert)) /* already in chain, free cert */
-       {
-           free_x509cert(cert);
-           return c;
-       }
-       c = c->next;
-    }
-
-    /* insert new cert at the root of the chain */
-    lock_certs_and_keys("add_x509cert");
-    cert->next = x509certs;
-    x509certs = cert;
-    DBG(DBG_CONTROL | DBG_PARSING,
-       DBG_log("  x509 cert inserted")
-    )
-    unlock_certs_and_keys("add_x509cert");
-    return cert;
-}
-
-/*
- * choose either subject DN or a subjectAltName as connection end ID
- */
-void
-select_x509cert_id(x509cert_t *cert, struct id *end_id)
-{
-    bool copy_subject_dn = TRUE;        /* ID is subject DN */
-
-    if (end_id->kind != ID_NONE) /* check for matching subjectAltName */
-    {
-       generalName_t *gn = cert->subjectAltName;
-
-       while (gn != NULL)
-       {
-           struct id id = empty_id;
-
-           gntoid(&id, gn);
-           if (same_id(&id, end_id))
-           {
-               copy_subject_dn = FALSE; /* take subjectAltName instead */
-               break;
-           }
-           gn = gn->next;
-       }
-    }
-
-    if (copy_subject_dn)
-    {
-       if (end_id->kind != ID_NONE && end_id->kind != ID_DER_ASN1_DN)
-       {
-            char buf[BUF_LEN];
-
-            idtoa(end_id, buf, BUF_LEN);
-            plog("  no subjectAltName matches ID '%s', replaced by subject DN", buf);
-       }
-       end_id->kind = ID_DER_ASN1_DN;
-       end_id->name.len = cert->subject.len;
-       end_id->name.ptr = temporary_cyclic_buffer();
-       memcpy(end_id->name.ptr, cert->subject.ptr, cert->subject.len);
-    }
-}
-
-/*
- * check for equality between two key identifiers
- */
-bool
-same_keyid(chunk_t a, chunk_t b)
-{
-    if (a.ptr == NULL || b.ptr == NULL)
-       return FALSE;
-
-    return same_chunk(a, b);
-}
-
-/*
- * check for equality between two serial numbers
- */
-bool
-same_serial(chunk_t a, chunk_t b)
-{
-    /* do not compare serial numbers if one of them is not defined */
-    if (a.ptr == NULL || b.ptr == NULL)
-       return TRUE;
-
-    return same_chunk(a, b);
-}
-
-/*
- *  get a X.509 certificate with a given issuer found at a certain position
- */
-x509cert_t*
-get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid, x509cert_t *chain)
-{
-    x509cert_t *cert = (chain != NULL)? chain->next : x509certs;
-
-    while (cert != NULL)
-    {
-       if ((keyid.ptr != NULL) ? same_keyid(keyid, cert->authKeyID)
-           : (same_dn(issuer, cert->issuer)
-              && same_serial(serial, cert->authKeySerialNumber)))
-       {
-           return cert;
-       }
-       cert = cert->next;
-    }
-    return NULL;
-}
-
-/*
- * encode a linked list of subjectAltNames
- */
-chunk_t
-build_subjectAltNames(generalName_t *subjectAltNames)
-{
-    u_char *pos;
-    chunk_t names;
-    size_t len = 0;
-    generalName_t *gn = subjectAltNames;
-       
-   /* compute the total size of the ASN.1 attributes object */
-    while (gn != NULL)
-    {
-       len += gn->name.len;
-       gn = gn->next;
-    }
-
-    pos = build_asn1_object(&names, ASN1_SEQUENCE, len);
-
-    gn = subjectAltNames;
-    while (gn != NULL)
-    {
-       chunkcpy(pos, gn->name);
-       gn = gn->next;
-    }
-
-    return asn1_wrap(ASN1_SEQUENCE, "cm"
-               , ASN1_subjectAltName_oid
-               , asn1_wrap(ASN1_OCTET_STRING, "m", names));
-}
-
-/*
- * build a to-be-signed X.509 certificate body
- */
-static chunk_t
-build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
-{
-    /* version is always X.509v3 */
-    chunk_t version = asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2);
-
-    chunk_t extensions = empty_chunk;
-
-    if (cert->subjectAltName != NULL)
-    {
-       extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m"
-               , asn1_wrap(ASN1_SEQUENCE, "m"
-               , build_subjectAltNames(cert->subjectAltName)));
-    }
-
-    return asn1_wrap(ASN1_SEQUENCE, "mmccmcmm"
-               , version
-               , asn1_simple_object(ASN1_INTEGER, cert->serialNumber)
-               , asn1_algorithmIdentifier(cert->sigAlg)
-               , cert->issuer
-               , asn1_wrap(ASN1_SEQUENCE, "mm"
-                   , timetoasn1(&cert->notBefore, ASN1_UTCTIME) 
-                   , timetoasn1(&cert->notAfter,  ASN1_UTCTIME)
-                 )
-               , cert->subject
-               , pkcs1_build_publicKeyInfo(rsa)
-               , extensions
-          );
-}
-
-/*
- * build a DER-encoded X.509 certificate
- */
-void
-build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key
-, const RSA_private_key_t *signer_key)
-{
-    chunk_t tbs_cert = build_tbs_x509cert(cert, cert_key);
-
-    chunk_t signature = pkcs1_build_signature(tbs_cert, cert->sigAlg
-                           , signer_key, TRUE);
-
-    cert->certificate = asn1_wrap(ASN1_SEQUENCE, "mcm"
-                               , tbs_cert
-                               , asn1_algorithmIdentifier(cert->sigAlg)
-                               , signature);
-}
-
-/*
- *  free the dynamic memory used to store generalNames
- */
-void
-free_generalNames(generalName_t* gn, bool free_name)
-{
-    while (gn != NULL)
-    {
-       generalName_t *gn_top = gn;
-       if (free_name)
-       {
-           pfree(gn->name.ptr);
-       }
-       gn = gn->next;
-       pfree(gn_top);
-    }
-}
-
-/*
- *  free a X.509 certificate
- */
-void
-free_x509cert(x509cert_t *cert)
-{
-    if (cert != NULL)
-    {
-       free_generalNames(cert->subjectAltName, FALSE);
-       free_generalNames(cert->crlDistributionPoints, FALSE);
-       pfreeany(cert->certificate.ptr);
-       pfree(cert);
-       cert = NULL;
-    }
-}
-
-/*  release of a certificate decreases the count by one
- "  the certificate is freed when the counter reaches zero
- */
-void
-release_x509cert(x509cert_t *cert)
-{
-    if (cert != NULL && --cert->count == 0)
-    {
-       x509cert_t **pp = &x509certs;
-       while (*pp != cert)
-           pp = &(*pp)->next;
-        *pp = cert->next;
-       free_x509cert(cert);
-    }
-}
-
-
-/*
- * stores a chained list of end certs and CA certs
- */
-void
-store_x509certs(x509cert_t **firstcert, bool strict)
-{
-    x509cert_t *cacerts = NULL;
-    x509cert_t **pp = firstcert;
-
-    /* first extract CA certs, discarding root CA certs */
-
-    while (*pp != NULL)
-    {
-       x509cert_t *cert = *pp;
-
-       if (cert->isCA)
-       {
-           *pp = cert->next;
-           
-           /* we don't accept self-signed CA certs */
-           if (same_dn(cert->issuer, cert->subject))
-           {
-               plog("self-signed cacert rejected");
-               free_x509cert(cert);
-           }
-           else
-           {
-               /* insertion into temporary chain of candidate CA certs */
-               cert->next = cacerts;
-               cacerts = cert;
-           }
-       }
-       else
-           pp = &cert->next;
-    }
-
-    /* now verify the candidate CA certs */
-    
-    while (cacerts != NULL)
-    {
-       x509cert_t *cert = cacerts;
-       
-       cacerts = cacerts->next;
-
-       if (trust_authcert_candidate(cert, cacerts))
-       {
-           add_authcert(cert, AUTH_CA);
-       }
-       else
-       {
-           plog("intermediate cacert rejected");
-           free_x509cert(cert);
-       }
-    }
-    
-    /* now verify the end certificates */
-
-    pp = firstcert;
-
-    while (*pp != NULL)
-    {
-       time_t valid_until;
-       x509cert_t *cert = *pp;
-
-       if (verify_x509cert(cert, strict, &valid_until))
-       {
-           DBG(DBG_CONTROL | DBG_PARSING,
-               DBG_log("public key validated")
-           )
-           add_x509_public_key(cert, valid_until, DAL_SIGNED);
-       }
-       else
-       {
-           plog("X.509 certificate rejected");
-       }
-       *pp = cert->next;
-       free_x509cert(cert);
-    }
-}
-
-/*
- *  decrypts an RSA signature using the issuer's certificate
- */
-static bool
-decrypt_sig(chunk_t sig, int alg, const x509cert_t *issuer_cert,
-           chunk_t *digest)
-{
-    switch (alg)
-    {
-       chunk_t decrypted;
-
-       case OID_RSA_ENCRYPTION:
-       case OID_MD2_WITH_RSA:
-       case OID_MD5_WITH_RSA:
-       case OID_SHA1_WITH_RSA:
-       case OID_SHA1_WITH_RSA_OIW:
-       case OID_SHA256_WITH_RSA:
-       case OID_SHA384_WITH_RSA:
-       case OID_SHA512_WITH_RSA:
-       {
-           mpz_t s;
-           RSA_public_key_t rsa;
-
-           init_RSA_public_key(&rsa, issuer_cert->publicExponent
-                                   , issuer_cert->modulus);
-
-           /* decrypt the signature s = s^e mod n */
-           n_to_mpz(s, sig.ptr, sig.len);
-           mpz_powm(s, s, &rsa.e, &rsa.n);
-
-           /* convert back to bytes */
-           decrypted = mpz_to_n(s, rsa.k);
-           DBG(DBG_PARSING,
-               DBG_dump_chunk("  decrypted signature: ", decrypted)
-           )
-
-           /*  copy the least significant bits of decrypted signature
-            *  into the digest string
-           */
-           memcpy(digest->ptr, decrypted.ptr + decrypted.len - digest->len,
-                  digest->len);
-
-           /* free memory */
-           free_RSA_public_content(&rsa);
-           pfree(decrypted.ptr);
-           mpz_clear(s);
-           return TRUE;
-       }
-       default:
-           digest->len = 0;
-           return FALSE;
-    }
-}
-
-/*
- *   Check if a signature over binary blob is genuine
- */
-bool
-check_signature(chunk_t tbs, chunk_t sig, int digest_alg, int enc_alg
-, const x509cert_t *issuer_cert)
-{
-    u_char digest_buf[MAX_DIGEST_LEN];
-    u_char decrypted_buf[MAX_DIGEST_LEN];
-    chunk_t digest = {digest_buf, MAX_DIGEST_LEN};
-    chunk_t decrypted = {decrypted_buf, MAX_DIGEST_LEN};
-
-    DBG(DBG_PARSING,
-       if (digest_alg != OID_UNKNOWN)
-           DBG_log("signature digest algorithm: '%s'",oid_names[digest_alg].name);
-       else
-           DBG_log("unknown signature digest algorithm");
-    )
-
-    if (!compute_digest(tbs, digest_alg, &digest))
-    {
-       plog("  digest algorithm not supported");
-       return FALSE;
-    }
-
-    DBG(DBG_PARSING,
-       DBG_dump_chunk("  digest:", digest)
-    )
-
-    decrypted.len = digest.len; /* we want the same digest length */
-
-    DBG(DBG_PARSING,
-       if (enc_alg != OID_UNKNOWN)
-           DBG_log("signature encryption algorithm: '%s'",oid_names[enc_alg].name);
-       else
-           DBG_log("unknown signature encryption algorithm");
-    )
-
-    if (!decrypt_sig(sig, enc_alg, issuer_cert, &decrypted))
-    {
-       plog("  decryption algorithm not supported");
-       return FALSE;
-    }
-
-    /* check if digests are equal */
-    return !memcmp(decrypted.ptr, digest.ptr, digest.len);
-}
-
-/*
- * extracts the basicConstraints extension
- */
-static bool
-parse_basicConstraints(chunk_t blob, int level0)
-{
-    asn1_ctx_t ctx;
-    chunk_t object;
-    u_int level;
-    int objectID = 0;
-    bool isCA = FALSE;
-
-    asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
-
-    while (objectID < BASIC_CONSTRAINTS_ROOF) {
-
-       if (!extract_object(basicConstraintsObjects, &objectID,
-                           &object,&level, &ctx))
-            break;
-
-       if (objectID == BASIC_CONSTRAINTS_CA)
-       {
-           isCA = object.len && *object.ptr;
-           DBG(DBG_PARSING,
-               DBG_log("  %s",(isCA)?"TRUE":"FALSE");
-           )
-       }
-       objectID++;
-    }
-    return isCA;
-}
-
-/*
- *  Converts a X.500 generalName into an ID
- */
-void
-gntoid(struct id *id, const generalName_t *gn)
-{
-    switch(gn->kind)
-    {
-    case GN_DNS_NAME:          /* ID type: ID_FQDN */
-       id->kind = ID_FQDN;
-       id->name = gn->name;
-       break;
-    case GN_IP_ADDRESS:                /* ID type: ID_IPV4_ADDR */
-       {
-           const struct af_info *afi = &af_inet4_info;
-           err_t ugh = NULL;
-
-           id->kind = afi->id_addr;
-           ugh = initaddr(gn->name.ptr, gn->name.len, afi->af, &id->ip_addr);
-       }
-       break;
-    case GN_RFC822_NAME:       /* ID type: ID_USER_FQDN */
-       id->kind = ID_USER_FQDN;
-       id->name = gn->name;
-       break;
-    default:
-       id->kind = ID_NONE;
-       id->name = empty_chunk;
-    }
-}
-
-/* compute the subjectKeyIdentifier according to section 4.2.1.2 of RFC 3280
- * as the 160 bit SHA-1 hash of the public key
- */
-void
-compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID)
-{
-    SHA1_CTX context;
-
-    SHA1Init(&context);
-    SHA1Update(&context
-             , cert->subjectPublicKey.ptr
-             , cert->subjectPublicKey.len);
-    SHA1Final(subjectKeyID.ptr, &context);
-    subjectKeyID.len = SHA1_DIGEST_SIZE;
-}
-
-/*
- * extracts an otherName
- */
-static bool
-parse_otherName(chunk_t blob, int level0)
-{
-    asn1_ctx_t ctx;
-    chunk_t object;
-    int objectID = 0;
-    u_int level;
-    int oid = OID_UNKNOWN;
-
-    asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
-
-    while (objectID < ON_OBJ_ROOF)
-    {
-       if (!extract_object(otherNameObjects, &objectID, &object, &level, &ctx))
-            return FALSE;
-
-       switch (objectID)
-       {
-       case ON_OBJ_ID_TYPE:
-           oid = known_oid(object);
-           break;
-       case ON_OBJ_VALUE:
-           if (oid == OID_XMPP_ADDR)
-           {
-               if (!parse_asn1_simple_object(&object, ASN1_UTF8STRING
-                                            , level + 1, "xmppAddr"))
-               {
-                   return FALSE;
-               }
-           }
-           break;
-       default:
-           break;
-       }
-       objectID++;
-    }
-    return TRUE;
-}
-
-
-/*
- * extracts a generalName
- */
-static generalName_t*
-parse_generalName(chunk_t blob, int level0)
-{
-    u_char buf[BUF_LEN];
-    asn1_ctx_t ctx;
-    chunk_t object;
-    int objectID = 0;
-    u_int level;
-
-    asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
-
-    while (objectID < GN_OBJ_ROOF)
-    {
-       bool valid_gn = FALSE;
-       
-       if (!extract_object(generalNameObjects, &objectID, &object, &level, &ctx))
-            return NULL;
-
-       switch (objectID) {
-       case GN_OBJ_RFC822_NAME:
-       case GN_OBJ_DNS_NAME:
-       case GN_OBJ_URI:
-           DBG(DBG_PARSING,
-               DBG_log("  '%.*s'", (int)object.len, object.ptr);
-           )
-           valid_gn = TRUE;
-           break;
-       case GN_OBJ_DIRECTORY_NAME:
-           DBG(DBG_PARSING,
-               dntoa(buf, BUF_LEN, object);
-               DBG_log("  '%s'", buf)
-           )
-           valid_gn = TRUE;
-           break;
-       case GN_OBJ_IP_ADDRESS:
-           DBG(DBG_PARSING,
-               DBG_log("  '%d.%d.%d.%d'", *object.ptr, *(object.ptr+1),
-                                     *(object.ptr+2), *(object.ptr+3));
-           )
-           valid_gn = TRUE;
-           break;
-       case GN_OBJ_OTHER_NAME:
-           if (!parse_otherName(object, level + 1))
-               return NULL;
-           break;
-       case GN_OBJ_X400_ADDRESS:
-       case GN_OBJ_EDI_PARTY_NAME:
-       case GN_OBJ_REGISTERED_ID:
-           break;
-       default:
-           break;
-       }
-
-       if (valid_gn)
-       {
-           generalName_t *gn = alloc_thing(generalName_t, "generalName");
-           gn->kind = (objectID - GN_OBJ_OTHER_NAME) / 2;
-           gn->name = object;
-           gn->next = NULL;
-           return gn;
-        }
-       objectID++;
-    }
-    return NULL;
-}
-
-
-/*
- * extracts one or several GNs and puts them into a chained list
- */
-static generalName_t*
-parse_generalNames(chunk_t blob, int level0, bool implicit)
-{
-    asn1_ctx_t ctx;
-    chunk_t object;
-    u_int level;
-    int objectID = 0;
-
-    generalName_t *top_gn = NULL;
-
-    asn1_init(&ctx, blob, level0, implicit, DBG_RAW);
-
-    while (objectID < GENERAL_NAMES_ROOF)
-    {
-       if (!extract_object(generalNamesObjects, &objectID, &object, &level, &ctx))
-            return NULL;
-            
-       if (objectID == GENERAL_NAMES_GN)
-       {
-           generalName_t *gn = parse_generalName(object, level+1);
-           if (gn != NULL)
-           {
-               gn->next = top_gn;
-               top_gn = gn;
-           }
-       }
-       objectID++;
-    }
-    return top_gn;
-}
-
-/*
- * returns a directoryName
- */
-chunk_t get_directoryName(chunk_t blob, int level, bool implicit)
-{
-    chunk_t name = empty_chunk;
-    generalName_t * gn = parse_generalNames(blob, level, implicit);
-
-    if (gn != NULL && gn->kind == GN_DIRECTORY_NAME)
-       name= gn->name;
-
-    free_generalNames(gn, FALSE);
-
-    return name;
-}
-
-/*
- * extracts and converts a UTCTIME or GENERALIZEDTIME object
- */
-time_t
-parse_time(chunk_t blob, int level0)
-{
-    asn1_ctx_t ctx;
-    chunk_t object;
-    u_int level;
-    int objectID = 0;
-
-    asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
-
-    while (objectID < TIME_ROOF)
-    {
-       if (!extract_object(timeObjects, &objectID, &object, &level, &ctx))
-            return UNDEFINED_TIME;
-
-       if (objectID == TIME_UTC || objectID == TIME_GENERALIZED)
-       {
-           return asn1totime(&object, (objectID == TIME_UTC)
-                       ? ASN1_UTCTIME : ASN1_GENERALIZEDTIME);
-       }
-       objectID++;
-    }
-    return UNDEFINED_TIME;
- }
-
-/*
- * extracts a keyIdentifier
- */
-static chunk_t
-parse_keyIdentifier(chunk_t blob, int level0, bool implicit)
-{
-    asn1_ctx_t ctx;
-    chunk_t object;
-    u_int level;
-    int objectID = 0;
-
-    asn1_init(&ctx, blob, level0, implicit, DBG_RAW);
-
-    extract_object(keyIdentifierObjects, &objectID, &object, &level, &ctx);
-    return object;
-}
-
-/*
- * extracts an authoritykeyIdentifier
- */
-void
-parse_authorityKeyIdentifier(chunk_t blob, int level0
-    , chunk_t *authKeyID, chunk_t *authKeySerialNumber)
-{
-    asn1_ctx_t ctx;
-    chunk_t object;
-    u_int level;
-    int objectID = 0;
-
-    asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
-
-    while (objectID < AUTH_KEY_ID_ROOF)
-    {
-       if (!extract_object(authorityKeyIdentifierObjects, &objectID, &object, &level, &ctx))
-            return;
-
-       switch (objectID) {
-       case AUTH_KEY_ID_KEY_ID:
-           *authKeyID = parse_keyIdentifier(object, level+1, TRUE);
-           break;
-       case AUTH_KEY_ID_CERT_ISSUER:
-           {
-               generalName_t * gn = parse_generalNames(object, level+1, TRUE);
-
-               free_generalNames(gn, FALSE);
-           }
-           break;
-       case AUTH_KEY_ID_CERT_SERIAL:
-           *authKeySerialNumber = object;
-           break;
-       default:
-           break;
-       }
-       objectID++;
-    }
-}
-
-/*
- * extracts an authorityInfoAcess location
- */
-static void
-parse_authorityInfoAccess(chunk_t blob, int level0, chunk_t *accessLocation)
-{
-    asn1_ctx_t ctx;
-    chunk_t object;
-    u_int level;
-    int objectID = 0;
-
-    u_int accessMethod = OID_UNKNOWN;
-
-    asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
-
-    while (objectID < AUTH_INFO_ACCESS_ROOF)
-    {
-       if (!extract_object(authorityInfoAccessObjects, &objectID, &object, &level, &ctx))
-            return;
-
-       switch (objectID) {
-       case AUTH_INFO_ACCESS_METHOD:
-           accessMethod = known_oid(object);
-           break;
-       case AUTH_INFO_ACCESS_LOCATION:
-           {
-               switch (accessMethod)
-               {
-               case OID_OCSP:
-                   if (*object.ptr == ASN1_CONTEXT_S_6)
-                   {
-                       if (asn1_length(&object) == ASN1_INVALID_LENGTH)
-                           return;
-
-                       DBG(DBG_PARSING,
-                           DBG_log("  '%.*s'",(int)object.len, object.ptr)
-                       )
-
-                       /* only HTTP(S) URIs accepted */
-                       if (strncasecmp(object.ptr, "http", 4) == 0)
-                       {
-                           *accessLocation = object;
-                           return;
-                       }
-                   }
-                   plog("warning: ignoring OCSP InfoAccessLocation with unkown protocol");
-                   break;
-               default:
-                   /* unkown accessMethod, ignoring */
-                   break;
-               }
-           }
-           break;
-       default:
-           break;
-       }
-       objectID++;
-    }
-
-}
-
-/*
- * extracts extendedKeyUsage OIDs
- */
-static bool
-parse_extendedKeyUsage(chunk_t blob, int level0)
-{
-    asn1_ctx_t ctx;
-    chunk_t object;
-    u_int level;
-    int objectID = 0;
-
-    asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
-
-    while (objectID < EXT_KEY_USAGE_ROOF)
-    {
-       if (!extract_object(extendedKeyUsageObjects, &objectID
-                           , &object, &level, &ctx))
-            return FALSE;
-
-       if (objectID == EXT_KEY_USAGE_PURPOSE_ID
-       && known_oid(object) == OID_OCSP_SIGNING)
-           return TRUE;
-       objectID++;
-    }
-    return FALSE;
-}
-
-/*  extracts one or several crlDistributionPoints and puts them into
- *  a chained list
- */
-static generalName_t*
-parse_crlDistributionPoints(chunk_t blob, int level0)
-{
-    asn1_ctx_t ctx;
-    chunk_t object;
-    u_int level;
-    int objectID = 0;
-
-    generalName_t *top_gn = NULL;      /* top of the chained list */
-    generalName_t **tail_gn = &top_gn; /* tail of the chained list */
-
-    asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
-
-    while (objectID < CRL_DIST_POINTS_ROOF)
-    {
-       if (!extract_object(crlDistributionPointsObjects, &objectID,
-                           &object, &level, &ctx))
-            return NULL;
-
-       if (objectID == CRL_DIST_POINTS_FULLNAME)
-       {
-           generalName_t *gn = parse_generalNames(object, level+1, TRUE);
-           /* append extracted generalNames to existing chained list */
-           *tail_gn = gn;
-           /* find new tail of the chained list */
-            while (gn != NULL)
-           {
-               tail_gn = &gn->next;  gn = gn->next;
-           }
-       }
-       objectID++;
-    }
-    return top_gn;
-}
-
-
-/*
- *  Parses an X.509v3 certificate
- */
-bool
-parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert)
-{
-    u_char  buf[BUF_LEN];
-    asn1_ctx_t ctx;
-    bool critical;
-    chunk_t object;
-    u_int level;
-    u_int extn_oid = OID_UNKNOWN;
-    int objectID = 0;
-
-    asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
-
-    while (objectID < X509_OBJ_ROOF)
-    {
-       if (!extract_object(certObjects, &objectID, &object, &level, &ctx))
-            return FALSE;
-
-       /* those objects which will parsed further need the next higher level */
-       level++;
-
-       switch (objectID) {
-       case X509_OBJ_CERTIFICATE:
-           cert->certificate = object;
-           break;
-       case X509_OBJ_TBS_CERTIFICATE:
-           cert->tbsCertificate = object;
-           break;
-       case X509_OBJ_VERSION:
-           cert->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
-           DBG(DBG_PARSING,
-               DBG_log("  v%d", cert->version);
-           )
-           break;
-       case X509_OBJ_SERIAL_NUMBER:
-           cert->serialNumber = object;
-           break;
-       case X509_OBJ_SIG_ALG:
-           cert->sigAlg = parse_algorithmIdentifier(object, level, NULL);
-           break;
-       case X509_OBJ_ISSUER:
-           cert->issuer = object;
-           DBG(DBG_PARSING,
-               dntoa(buf, BUF_LEN, object);
-               DBG_log("  '%s'",buf)
-           )
-           break;
-       case X509_OBJ_NOT_BEFORE:
-           cert->notBefore = parse_time(object, level);
-           break;
-       case X509_OBJ_NOT_AFTER:
-           cert->notAfter = parse_time(object, level);
-           break;
-       case X509_OBJ_SUBJECT:
-           cert->subject = object;
-           DBG(DBG_PARSING,
-               dntoa(buf, BUF_LEN, object);
-               DBG_log("  '%s'",buf)
-           )
-           break;
-       case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM:
-           if (parse_algorithmIdentifier(object, level, NULL) == OID_RSA_ENCRYPTION)
-               cert->subjectPublicKeyAlgorithm = PUBKEY_ALG_RSA;
-           else
-           {
-               plog("  unsupported public key algorithm");
-               return FALSE;
-           }
-           break;
-       case X509_OBJ_SUBJECT_PUBLIC_KEY:
-           if (ctx.blobs[4].len > 0 && *ctx.blobs[4].ptr == 0x00)
-           {
-               /* skip initial bit string octet defining 0 unused bits */
-               ctx.blobs[4].ptr++; ctx.blobs[4].len--;
-           }
-           else
-           {
-               plog("  invalid RSA public key format");
-               return FALSE;
-           }
-           break;
-       case X509_OBJ_RSA_PUBLIC_KEY:
-           cert->subjectPublicKey = object;
-           break;
-       case X509_OBJ_MODULUS:
-           if (object.len < RSA_MIN_OCTETS + 1)
-           {
-               plog("  " RSA_MIN_OCTETS_UGH);
-               return FALSE;
-           }
-           if (object.len > RSA_MAX_OCTETS + (size_t)(*object.ptr == 0x00))
-           {
-               plog("  " RSA_MAX_OCTETS_UGH);
-               return FALSE;
-           }
-           cert->modulus = object;
-           break;
-       case X509_OBJ_PUBLIC_EXPONENT:
-           cert->publicExponent = object;
-           break;
-       case X509_OBJ_EXTN_ID:
-           extn_oid = known_oid(object);
-           break;
-       case X509_OBJ_CRITICAL:
-           critical = object.len && *object.ptr;
-           DBG(DBG_PARSING,
-               DBG_log("  %s",(critical)?"TRUE":"FALSE");
-           )
-           break;
-       case X509_OBJ_EXTN_VALUE:
-           {
-               switch (extn_oid) {
-               case OID_SUBJECT_KEY_ID:
-                   cert->subjectKeyID =
-                       parse_keyIdentifier(object, level, FALSE);
-                   break;
-               case OID_SUBJECT_ALT_NAME:
-                   cert->subjectAltName =
-                       parse_generalNames(object, level, FALSE);
-                   break;
-               case OID_BASIC_CONSTRAINTS:
-                   cert->isCA =
-                       parse_basicConstraints(object, level);
-                   break;
-               case OID_CRL_DISTRIBUTION_POINTS:
-                   cert->crlDistributionPoints =
-                       parse_crlDistributionPoints(object, level);
-                   break;
-                case OID_AUTHORITY_KEY_ID:
-                   parse_authorityKeyIdentifier(object, level
-                       , &cert->authKeyID, &cert->authKeySerialNumber);
-                   break;
-               case OID_AUTHORITY_INFO_ACCESS:
-                   parse_authorityInfoAccess(object, level, &cert->accessLocation);
-                   break;
-               case OID_EXTENDED_KEY_USAGE:
-                   cert->isOcspSigner = parse_extendedKeyUsage(object, level);
-                   break;
-               case OID_NS_REVOCATION_URL:
-               case OID_NS_CA_REVOCATION_URL:
-               case OID_NS_CA_POLICY_URL:
-               case OID_NS_COMMENT:
-                   if (!parse_asn1_simple_object(&object, ASN1_IA5STRING
-                   , level, oid_names[extn_oid].name))
-                   {
-                       return FALSE;
-                   }
-                   break;
-               default:
-                   break;
-               }
-           }
-           break;
-       case X509_OBJ_ALGORITHM:
-           cert->algorithm = parse_algorithmIdentifier(object, level, NULL);
-           break;
-       case X509_OBJ_SIGNATURE:
-           cert->signature = object;
-           break;
-       default:
-           break;
-       }
-       objectID++;
-    }
-    time(&cert->installed);
-    return TRUE;
-}
-
-/* verify the validity of a certificate by
- * checking the notBefore and notAfter dates
- */
-err_t
-check_validity(const x509cert_t *cert, time_t *until)
-{
-    time_t current_time;
-
-    time(&current_time);
-    DBG(DBG_CONTROL | DBG_PARSING ,
-       DBG_log("  not before  : %s", timetoa(&cert->notBefore, TRUE));
-       DBG_log("  current time: %s", timetoa(&current_time, TRUE));
-       DBG_log("  not after   : %s", timetoa(&cert->notAfter, TRUE));
-    )
-
-    if (cert->notAfter < *until) *until = cert->notAfter;
-
-    if (current_time < cert->notBefore)
-       return "certificate is not valid yet";
-    if (current_time > cert->notAfter)
-       return "certificate has expired";
-    else
-       return NULL;
-}
-
-/*
- *  verifies a X.509 certificate
- */
-bool
-verify_x509cert(const x509cert_t *cert, bool strict, time_t *until)
-{
-    int pathlen;
-
-    *until = cert->notAfter;
-
-    for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
-    {
-       x509cert_t *issuer_cert;
-       u_char buf[BUF_LEN];
-       err_t ugh = NULL;
-
-       DBG(DBG_CONTROL,
-           dntoa(buf, BUF_LEN, cert->subject);
-           DBG_log("subject: '%s'",buf);
-           dntoa(buf, BUF_LEN, cert->issuer);
-           DBG_log("issuer:  '%s'",buf);
-           if (cert->authKeyID.ptr != NULL)
-           {
-               datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
-                   , buf, BUF_LEN);
-               DBG_log("authkey:  %s", buf);
-           }
-       )
-
-       ugh = check_validity(cert, until);
-
-       if (ugh != NULL)
-       {
-           plog("%s", ugh);
-           return FALSE;
-       }
-
-       DBG(DBG_CONTROL,
-           DBG_log("certificate is valid")
-       )
-
-       lock_authcert_list("verify_x509cert");
-       issuer_cert = get_authcert(cert->issuer, cert->authKeySerialNumber
-           , cert->authKeyID, AUTH_CA);
-
-       if (issuer_cert == NULL)
-       {
-           plog("issuer cacert not found");
-           unlock_authcert_list("verify_x509cert");
-           return FALSE;
-       }
-       DBG(DBG_CONTROL,
-           DBG_log("issuer cacert found")
-       )
-
-       if (!check_signature(cert->tbsCertificate, cert->signature
-                          , cert->algorithm, cert->algorithm, issuer_cert))
-       {
-           plog("certificate signature is invalid");
-           unlock_authcert_list("verify_x509cert");
-           return FALSE;
-       }
-       DBG(DBG_CONTROL,
-           DBG_log("certificate signature is valid")
-       )
-       unlock_authcert_list("verify_x509cert");
-
-       /* check if cert is a self-signed root ca */
-       if (pathlen > 0 && same_dn(cert->issuer, cert->subject))
-       {
-           DBG(DBG_CONTROL,
-               DBG_log("reached self-signed root ca")
-           )
-           return TRUE;
-       }
-       else
-       {
-           time_t nextUpdate = *until;
-           time_t revocationDate = UNDEFINED_TIME;
-           crl_reason_t revocationReason = REASON_UNSPECIFIED;
-
-           /* first check certificate revocation using ocsp */
-           cert_status_t status = verify_by_ocsp(cert, &nextUpdate
-               , &revocationDate, &revocationReason);
-
-           /* if ocsp service is not available then fall back to crl */
-           if ((status == CERT_UNDEFINED)
-           ||  (status == CERT_UNKNOWN && strict))
-           {
-               status = verify_by_crl(cert, &nextUpdate, &revocationDate
-                   , &revocationReason);
-           }
-           switch (status)
-           {
-           case CERT_GOOD:
-               /* if status information is stale */
-               if (strict && nextUpdate < time(NULL))
-               {
-                   DBG(DBG_CONTROL,
-                       DBG_log("certificate is good but status is stale")
-                   )
-                   remove_x509_public_key(cert);
-                   return FALSE;
-               }
-               DBG(DBG_CONTROL,
-                   DBG_log("certificate is good")
-               )
-               
-               /* with strict crl policy the public key must have the same
-                * lifetime as the validity of the ocsp status or crl lifetime
-                */
-               if (strict && nextUpdate < *until)
-                   *until = nextUpdate;
-               break;
-           case CERT_REVOKED:
-               plog("certificate was revoked on %s, reason: %s"
-                   , timetoa(&revocationDate, TRUE)
-                   , enum_name(&crl_reason_names, revocationReason));
-               remove_x509_public_key(cert);
-               return FALSE;
-           case CERT_UNKNOWN:
-           case CERT_UNDEFINED:
-           default:
-               plog("certificate status unknown");
-               if (strict)
-               {
-                   remove_x509_public_key(cert);
-                   return FALSE;
-               }
-               break;
-           }
-       }
-
-       /* go up one step in the trust chain */
-       cert = issuer_cert;
-    }
-    plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN);
-    return FALSE;
-}
-
-/*
- *  list all X.509 certs in a chained list
- */
-void
-list_x509cert_chain(const char *caption, x509cert_t* cert, u_char auth_flags
- , bool utc)
-{
-    bool first = TRUE;
-    time_t now;
-
-    /* determine the current time */
-    time(&now);
-
-    while (cert != NULL)
-    {
-       if (auth_flags == AUTH_NONE || (auth_flags & cert->authority_flags))
-       {
-           unsigned keysize;
-           char keyid[KEYID_BUF];
-           u_char buf[BUF_LEN];
-           cert_t c;
-
-           c.type = CERT_X509_SIGNATURE;
-           c.u.x509 = cert;
-
-           if (first)
-           {
-               whack_log(RC_COMMENT, " ");
-               whack_log(RC_COMMENT, "List of X.509 %s Certificates:", caption);
-               whack_log(RC_COMMENT, " ");
-               first = FALSE;
-           }
-
-           whack_log(RC_COMMENT, "%s, count: %d", timetoa(&cert->installed, utc),
-               cert->count);
-           dntoa(buf, BUF_LEN, cert->subject);
-           whack_log(RC_COMMENT, "       subject:  '%s'", buf);
-           dntoa(buf, BUF_LEN, cert->issuer);
-           whack_log(RC_COMMENT, "       issuer:   '%s'", buf);
-           datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':'
-               , buf, BUF_LEN);
-           whack_log(RC_COMMENT, "       serial:    %s", buf);
-           form_keyid(cert->publicExponent, cert->modulus, keyid, &keysize);
-           whack_log(RC_COMMENT, "       pubkey:    %4d RSA Key %s%s"
-               , 8*keysize, keyid
-               , cert->smartcard ? ", on smartcard" :
-               (has_private_key(c)? ", has private key" : ""));
-           whack_log(RC_COMMENT, "       validity:  not before %s %s",
-               timetoa(&cert->notBefore, utc),
-               (cert->notBefore < now)?"ok":"fatal (not valid yet)");
-           whack_log(RC_COMMENT, "                  not after  %s %s",
-               timetoa(&cert->notAfter, utc),
-               check_expiry(cert->notAfter, CA_CERT_WARNING_INTERVAL, TRUE));
-           if (cert->subjectKeyID.ptr != NULL)
-           {
-               datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':'
-                   , buf, BUF_LEN);
-               whack_log(RC_COMMENT, "       subjkey:   %s", buf);
-           }
-           if (cert->authKeyID.ptr != NULL)
-           {
-               datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
-                   , buf, BUF_LEN);
-               whack_log(RC_COMMENT, "       authkey:   %s", buf);
-           }
-           if (cert->authKeySerialNumber.ptr != NULL)
-           {
-               datatot(cert->authKeySerialNumber.ptr, cert->authKeySerialNumber.len
-                   , ':', buf, BUF_LEN);
-               whack_log(RC_COMMENT, "       aserial:   %s", buf);
-           }
-       }
-       cert = cert->next;
-    }
-}
-
-/*
- *  list all X.509 end certificates in a chained list
- */
-void
-list_x509_end_certs(bool utc)
-{
-    list_x509cert_chain("End", x509certs, AUTH_NONE, utc);
-}
diff --git a/Source/lib/asn1/x509.h b/Source/lib/asn1/x509.h
deleted file mode 100644 (file)
index d15b3da..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/* Support of X.509 certificates
- * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
- * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
- * Copyright (C) 2002 Mario Strasser
- * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
- *
- * 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: x509.h,v 1.10 2005/12/06 22:52:44 as Exp $
- */
-
-#ifndef _X509_H
-#define _X509_H
-
-#include "pkcs1.h"
-#include "id.h"
-
-/* Definition of generalNames kinds */
-
-typedef enum {
-    GN_OTHER_NAME =            0,
-    GN_RFC822_NAME =           1,
-    GN_DNS_NAME =              2,
-    GN_X400_ADDRESS =          3,
-    GN_DIRECTORY_NAME =                4,
-    GN_EDI_PARTY_NAME =        5,
-    GN_URI =                   6,
-    GN_IP_ADDRESS =            7,
-    GN_REGISTERED_ID =         8
-} generalNames_t;
-
-/* access structure for a GeneralName */
-
-typedef struct generalName generalName_t;
-
-struct generalName {
-    generalName_t   *next;
-    generalNames_t  kind;
-    chunk_t         name;
-};
-
-/* access structure for an X.509v3 certificate */
-
-typedef struct x509cert x509cert_t;
-
-struct x509cert {
-  x509cert_t     *next;
-  time_t        installed;
-  int           count;
-  bool          smartcard;
-  u_char        authority_flags;
-  chunk_t       certificate;
-  chunk_t          tbsCertificate;
-  u_int              version;
-  chunk_t            serialNumber;
-                /*   signature */
-  int                  sigAlg;
-  chunk_t            issuer;
-                /*   validity */
-  time_t               notBefore;
-  time_t               notAfter;
-  chunk_t            subject;
-                /*   subjectPublicKeyInfo */
-  enum pubkey_alg      subjectPublicKeyAlgorithm;
-  chunk_t              subjectPublicKey;
-  chunk_t                modulus;
-  chunk_t                publicExponent;
-                /*   issuerUniqueID */
-                /*   subjectUniqueID */
-                /*   v3 extensions */
-                /*   extension */
-                /*     extension */
-                /*       extnID */
-                /*       critical */
-                /*       extnValue */
-  bool                    isCA;
-  bool                    isOcspSigner; /* ocsp */
-  chunk_t                 subjectKeyID;
-  chunk_t                 authKeyID;
-  chunk_t                 authKeySerialNumber;
-  chunk_t                 accessLocation; /* ocsp */
-  generalName_t                   *subjectAltName;
-  generalName_t                   *crlDistributionPoints;
-               /* signatureAlgorithm */
-  int                algorithm;
-  chunk_t          signature;
-};
-
-/* used for initialization */
-extern const x509cert_t empty_x509cert;
-
-extern bool same_serial(chunk_t a, chunk_t b);
-extern bool same_keyid(chunk_t a, chunk_t b);
-extern bool same_dn(chunk_t a, chunk_t b);
-extern bool match_dn(chunk_t a, chunk_t b, int *wildcards);
-extern bool same_x509cert(const x509cert_t *a, const x509cert_t *b);
-extern void hex_str(chunk_t bin, chunk_t *str);
-extern int dn_count_wildcards(chunk_t dn);
-extern int dntoa(char *dst, size_t dstlen, chunk_t dn);
-extern int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn
-    , const char* null_dn);
-extern err_t atodn(char *src, chunk_t *dn);
-extern void gntoid(struct id *id, const generalName_t *gn);
-extern void compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID);
-extern void select_x509cert_id(x509cert_t *cert, struct id *end_id);
-extern bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert);
-extern time_t parse_time(chunk_t blob, int level0);
-extern void parse_authorityKeyIdentifier(chunk_t blob, int level0
-    , chunk_t *authKeyID, chunk_t *authKeySerialNumber);
-extern chunk_t get_directoryName(chunk_t blob, int level, bool implicit);
-extern err_t check_validity(const x509cert_t *cert, time_t *until);
-extern bool check_signature(chunk_t tbs, chunk_t sig, int digest_alg
-    , int enc_alg, const x509cert_t *issuer_cert);
-extern bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until);
-extern x509cert_t* add_x509cert(x509cert_t *cert);
-extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid
-    , x509cert_t* chain);
-extern void build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key
-    , const RSA_private_key_t *signer_key);
-extern chunk_t build_subjectAltNames(generalName_t *subjectAltNames);
-extern void share_x509cert(x509cert_t *cert);
-extern void release_x509cert(x509cert_t *cert);
-extern void free_x509cert(x509cert_t *cert);
-extern void store_x509certs(x509cert_t **firstcert, bool strict);
-extern void list_x509cert_chain(const char *caption, x509cert_t* cert
-    , u_char auth_flags, bool utc);
-extern void list_x509_end_certs(bool utc);
-extern void free_generalNames(generalName_t* gn, bool free_name);
-
-#endif /* _X509_H */
index 0ffb107..af0b147 100644 (file)
@@ -32,6 +32,6 @@ LIB_OBJS+= $(BUILD_DIR)prf_plus.o
 $(BUILD_DIR)prf_plus.o :               $(CRYPTO_DIR)prf_plus.c $(CRYPTO_DIR)prf_plus.h
                                                                $(CC) $(CFLAGS) -c -o $@ $<
 
-LIB_OBJS+= $(BUILD_DIR)certificate.o
-$(BUILD_DIR)certificate.o :            $(CRYPTO_DIR)certificate.c $(CRYPTO_DIR)certificate.h
+LIB_OBJS+= $(BUILD_DIR)x509.o
+$(BUILD_DIR)x509.o :                   $(CRYPTO_DIR)x509.c $(CRYPTO_DIR)x509.h
                                                                $(CC) $(CFLAGS) -c -o $@ $<
diff --git a/Source/lib/crypto/certificate.c b/Source/lib/crypto/certificate.c
deleted file mode 100755 (executable)
index 34c82e8..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/**
- * @file certificate.c
- * 
- * @brief Implementation of certificate_t.
- * 
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * 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 <gmp.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "certificate.h"
-
-#include <daemon.h>
-#include <asn1/der_decoder.h>
-
-
-typedef struct private_certificate_t private_certificate_t;
-
-/**
- * Private data of a certificate_t object.
- */
-struct private_certificate_t {
-       /**
-        * Public interface for this signer.
-        */
-       certificate_t public;
-       
-       u_int version;
-       
-       u_int serial;
-       
-       chunk_t sign_alg;
-       
-       time_t not_before;
-       
-       time_t not_after;
-       
-       chunk_t pubkey;
-       
-       chunk_t pubkey_alg;
-       
-       bool has_issuer_uid;
-       chunk_t issuer_uid;
-       
-       bool has_subject_uid;
-       chunk_t subject_uid;
-       
-       chunk_t tbs_cert;
-       chunk_t signature;
-       
-       rsa_public_key_t *public_key;
-};
-
-#define OSET(x) offsetof(private_certificate_t, x)
-
-/**
- * Rules for de-/encoding of a certificate from/in ASN1 
- */
-static asn1_rule_t certificate_rules[] = {
-       {ASN1_SEQUENCE,                         0,                                              0,                                      0                                       }, /* certificate */
-       { ASN1_SEQUENCE,                        ASN1_RAW,                               OSET(tbs_cert),         0                                       }, /*  tbsCertificate */
-       {  ASN1_TAG_E_0,                        ASN1_DEFAULT,                   OSET(version),          0                                       }, /*   EXPLICIT */
-       {   ASN1_INTEGER,                       ASN1_DEFAULT,                   OSET(version),          0                                       }, /*    version DEFAULT v1(0) */
-       {  ASN1_INTEGER,                        0,                                              OSET(serial),           0                                       }, /*   serialNumber */
-       {  ASN1_SEQUENCE,                       0,                                              0,                                      0                                       }, /*   signature */
-       {   ASN1_OID,                           0,                                              OSET(sign_alg),         0                                       }, /*    algorithm-oid */
-       {   ASN1_NULL,                          0,                                              0,                                      0                                       }, /*    parameters */
-       {  ASN1_END,                            0,                                              0,                                      0                                       }, /*   signature */
-       {  ASN1_SEQUENCE,                       ASN1_OF,                                0,                                      0                                       }, /*   issuer */
-//     {   ASN1_SET,                           ASN1_OF,                                0,                                      0,                                      }, /*    RelativeDistinguishedName */
-//     {    ASN1_SEQUENCE,                     0,                                              0,                                      0,                                      }, /*     AttributeTypeAndValue */
-//     {     ASN1_OID,                         0,                                              0,                                      0                                       }, /*      AttributeType */
-//     {     ASN1_ANY,                         0,                                              0,                                      0                                       }, /*      AttributeValue */
-//     {    ASN1_END,                          0,                                              0,                                      0                                       }, /*     AttributeTypeAndValue */
-//     {   ASN1_END,                           0,                                              0,                                      0                                       }, /*    RelativeDistinguishedName */
-       {  ASN1_END,                            0,                                              0,                                      0                                       }, /*   issuer */
-       {  ASN1_SEQUENCE,                       0,                                              0,                                      0                                       }, /*   validity */
-       {   ASN1_CHOICE,                        0,                                              0,                                      0                                       }, /*    notBefore */
-       {     ASN1_UTCTIME,             0,                                              OSET(not_before),       0                                       }, /*     utcTime */
-       {     ASN1_GENERALIZEDTIME, 0,                                          OSET(not_before),       0                                       }, /*     generalTime */
-       {   ASN1_END,                           0,                                              0,                                      0                                       }, /*    notBefore */
-       {   ASN1_CHOICE,                        0,                                              0,                                      0                                       }, /*    notAfter */
-       {    ASN1_UTCTIME,                      0,                                              OSET(not_after),        0                                       }, /*     utcTime */
-       {    ASN1_GENERALIZEDTIME,      0,                                              OSET(not_after),        0                                       }, /*     generalTime */
-       {   ASN1_END,                           0,                                              0,                                      0                                       }, /*    notAfter */
-       {  ASN1_END,                            0,                                              0,                                      0                                       }, /*   validity */
-       {  ASN1_SEQUENCE,                       ASN1_OF,                                0,                                      0                                       }, /*   subject */
-//     {   ASN1_SET,                           ASN1_OF,                                0,                                      0,                                      }, /*    RelativeDistinguishedName */
-//     {    ASN1_SEQUENCE,                     0,                                              0,                                      0,                                      }, /*     AttributeTypeAndValue */
-//     {     ASN1_OID,                         0,                                              0,                                      0                                       }, /*      AttributeType */
-//     {     ASN1_ANY,                         0,                                              0,                                      0                                       }, /*      AttributeValue */
-//     {    ASN1_END,                          0,                                              0,                                      0                                       }, /*     AttributeTypeAndValue */
-//     {   ASN1_END,                           0,                                              0,                                      0                                       }, /*    RelativeDistinguishedName */
-       {  ASN1_END,                            0,                                              0,                                      0                                       }, /*   subject */
-       {  ASN1_SEQUENCE,                       0,                                              0,                                      0                                       }, /*   subjectPublicKeyInfo */
-       {   ASN1_SEQUENCE,                      0,                                              0,                                      0                                       }, /*    algorithm */
-       {    ASN1_OID,                          0,                                              OSET(pubkey_alg),       0                                       }, /*     algorithm-oid */
-       {    ASN1_NULL,                         0,                                              0,                                      0                                       }, /*     parameters */
-       {   ASN1_END,                           0,                                              0,                                      0                                       }, /*    algorithm */
-       {   ASN1_BITSTRING,             0,                                              OSET(pubkey),           0                                       }, /*    subjectPublicKey */
-       {  ASN1_END,                            0,                                              0,                                      0                                       }, /*   subjectPublicKeyInfo */
-       {  ASN1_TAG_I_1,                        ASN1_OPTIONAL,                  0,                                      OSET(has_issuer_uid)}, /*   IMPLICIT */
-       {   ASN1_BITSTRING,                     ASN1_OPTIONAL,                  OSET(issuer_uid),       0                                       }, /*    issuerUniqueID OPTIONAL */
-       {  ASN1_TAG_I_2,                        ASN1_OPTIONAL,                  0,                                      OSET(has_subject_uid)},/*   IMPLICIT */
-       {   ASN1_BITSTRING,                     ASN1_OPTIONAL,                  OSET(subject_uid),      0                                       }, /*    subjectUniqueID OPTIONAL */
-       {  ASN1_TAG_E_3,                        ASN1_OPTIONAL,                  0,                                      0                                       }, /*   EXPLICIT */
-       {   ASN1_SEQUENCE,                      ASN1_OF|ASN1_OPTIONAL,  0,                                      0                                       }, /*    extensions OPTIONAL */
-//     {    ASN1_SEQUENCE,                     0,                                              0,                                      0,                                      }, /*     extension */
-//     {     ASN1_OID,                         0,                                              0,                                      0                                       }, /*      extnID */
-//     {     ASN1_BOOLEAN,                     ASN1_DEFAULT,                   0,                                      FALSE                           }, /*      critical */
-//     {     ASN1_OCTETSTRING,         0,                                              0,                                      0,                                      }, /*      extnValue */
-//     {    ASN1_END,                          0,                                              0,                                      0,                                      }, /*     extension */
-       {   ASN1_END,                           0,                                              0,                                      0,                                      }, /*    extensions */
-       { ASN1_END,                             0,                                              0,                                      0                                       }, /*  tbsCertificate */
-       { ASN1_SEQUENCE,                        0,                                              0,                                      0                                       }, /*  signatureAlgorithm */
-       {  ASN1_OID,                            0,                                              OSET(sign_alg),         0                                       }, /*   algorithm-oid */
-       {  ASN1_NULL,                           0,                                              0,                                      0                                       }, /*   parameters */
-       { ASN1_END,                             0,                                              0,                                      0                                       }, /*  signatureAlgorithm */
-       { ASN1_BITSTRING,                       0,                                              OSET(signature),        0                                       }, /*  signatureValue */
-       {ASN1_END,                                      0,                                              0,                                      0                                       }, /* certificate */
-};
-
-/**
- * Implementation of certificate.get_public_key.
- */
-static rsa_public_key_t *get_public_key(private_certificate_t *this)
-{
-       return this->public_key->clone(this->public_key);
-}
-
-/**
- * Implementation of certificate.destroy.
- */
-static void destroy(private_certificate_t *this)
-{
-       this->public_key->destroy(this->public_key);
-       free(this->pubkey.ptr);
-       free(this->signature.ptr);
-       free(this->tbs_cert.ptr);
-       free(this);
-}
-
-/*
- * Described in header.
- */
-certificate_t *certificate_create_from_chunk(chunk_t chunk)
-{
-       private_certificate_t *this = malloc_thing(private_certificate_t);
-       der_decoder_t *dd;
-       
-       /* public functions */
-       this->public.get_public_key = (rsa_public_key_t *(*) (certificate_t*))get_public_key;
-       this->public.destroy = (void (*) (certificate_t*))destroy;
-       
-       /* initialize */
-       this->pubkey = CHUNK_INITIALIZER;
-       this->signature = CHUNK_INITIALIZER;
-       this->tbs_cert = CHUNK_INITIALIZER;
-       
-       dd = der_decoder_create(certificate_rules);
-       
-       if (dd->decode(dd, chunk, this) != SUCCESS)
-       {
-               free(this);
-               dd->destroy(dd);
-               return NULL;
-       }
-       dd->destroy(dd);
-       
-       this->public_key = rsa_public_key_create_from_chunk(this->pubkey);
-       if (this->public_key == NULL)
-       {
-               free(this->pubkey.ptr);
-               free(this);
-               return NULL;
-       }
-       
-       return &this->public;
-}
-
-/*
- * Described in header.
- */
-certificate_t *certificate_create_from_file(char *filename)
-{
-       struct stat stb;
-       FILE *file;
-       char *buffer;
-       chunk_t chunk;
-       
-       if (stat(filename, &stb) == -1)
-       {
-               return NULL;
-       }
-       
-       buffer = alloca(stb.st_size);
-       
-       file = fopen(filename, "r");
-       if (file == NULL)
-       {
-               return NULL;
-       }
-       
-       if (fread(buffer, stb.st_size, 1, file) == -1)
-       {
-               fclose(file);
-               return NULL;
-       }
-       fclose(file);
-       
-       chunk.ptr = buffer;
-       chunk.len = stb.st_size;
-       
-       return certificate_create_from_chunk(chunk);
-}
diff --git a/Source/lib/crypto/certificate.h b/Source/lib/crypto/certificate.h
deleted file mode 100755 (executable)
index 8dc88e0..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * @file certificate.h
- * 
- * @brief Interface of certificate_t.
- * 
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * 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 CERTIFICATE_H_
-#define CERTIFICATE_H_
-
-#include <types.h>
-#include <definitions.h>
-#include <crypto/rsa/rsa_public_key.h>
-#include <utils/identification.h>
-#include <utils/iterator.h>
-
-
-typedef struct certificate_t certificate_t;
-
-/**
- * @brief X509 certificate.
- * 
- * @b Constructors:
- *  - certificate_create_from_chunk()
- *
- * @ingroup transforms
- */
-struct certificate_t {
-
-       /**
-        * @brief Get the RSA public key from the certificate.
-        * 
-        * @param this                          calling object
-        * @return                                      public_key
-        */
-       rsa_public_key_t *(*get_public_key) (certificate_t *this);
-
-       identification_t *(*get_issuer) (certificate_t *this);
-       identification_t *(*get_subject) (certificate_t *this);
-       iterator_t *(*create_subjectaltname_iter) (certificate_t *this);
-       iterator_t *(*create_issueraltname_iter) (certificate_t *this);
-       bool (*belongs_to) (certificate_t *this, identification_t *subject);
-       bool (*issued_by) (certificate_t *this, identification_t *issuer);
-       bool (*validate) (certificate_t *this, rsa_public_key_t *signer);
-       
-       /**
-        * @brief Destroys the private key.
-        * 
-        * @param this                          private key to destroy
-        */
-       void (*destroy) (certificate_t *this);
-};
-
-/**
- * @brief Read a certificate from a blob.
- * 
- * @return created certificate_t.
- * 
- * @ingroup transforms
- */
-certificate_t *certificate_create_from_chunk(chunk_t chunk);
-
-certificate_t *certificate_create_from_file(char *filename);
-
-#endif /* CERTIFICATE_H_ */
index c53dac3..8286612 100644 (file)
 #include "rsa_private_key.h"
 
 #include <daemon.h>
-#ifdef NEW_ASN1
-# include <asn1/asn1.h>
-# include <asn1/der_decoder.h>
-#else
-# include <asn1-pluto/asn1-pluto.h>
-#endif
-
+#include <asn1/asn1.h>
 
 /* 
  * Oids for hash algorithms are defined in
@@ -143,41 +137,8 @@ struct private_rsa_private_key_t {
        
 };
 
-#ifdef NEW_ASN1
-/**
- * Rules for de-/encoding of a private key from/in ASN1 
- */
-static asn1_rule_t rsa_private_key_rules[] = {
-       {ASN1_SEQUENCE, 0, 0, 0},
-       {       ASN1_INTEGER, 0,                offsetof(private_rsa_private_key_t, version), 0},
-       {       ASN1_INTEGER, ASN1_MPZ, offsetof(private_rsa_private_key_t, n), 0},
-       {       ASN1_INTEGER, ASN1_MPZ, offsetof(private_rsa_private_key_t, e), 0},
-       {       ASN1_INTEGER, ASN1_MPZ, offsetof(private_rsa_private_key_t, d), 0},
-       {       ASN1_INTEGER, ASN1_MPZ, offsetof(private_rsa_private_key_t, p), 0},
-       {       ASN1_INTEGER, ASN1_MPZ, offsetof(private_rsa_private_key_t, q), 0},
-       {       ASN1_INTEGER, ASN1_MPZ, offsetof(private_rsa_private_key_t, exp1), 0},
-       {       ASN1_INTEGER, ASN1_MPZ, offsetof(private_rsa_private_key_t, exp2), 0},
-       {       ASN1_INTEGER, ASN1_MPZ, offsetof(private_rsa_private_key_t, coeff), 0},
-       {ASN1_END, 0, 0, 0},
-};
-#else
-struct {
-       const char *name;
-       size_t offset;
-} RSA_private_field[] = {
-       { "Modulus",         offsetof(private_rsa_private_key_t, n) },
-       { "PublicExponent",  offsetof(private_rsa_private_key_t, e) },
-       { "PrivateExponent", offsetof(private_rsa_private_key_t, d) },
-       { "Prime1",          offsetof(private_rsa_private_key_t, p) },
-       { "Prime2",          offsetof(private_rsa_private_key_t, q) },
-       { "Exponent1",       offsetof(private_rsa_private_key_t, exp1) },
-       { "Exponent2",       offsetof(private_rsa_private_key_t, exp2) },
-       { "Coefficient",     offsetof(private_rsa_private_key_t, coeff) },
-};
-
 /* ASN.1 definition of a PKCS#1 RSA private key */
-
-static const asn1Object_t privkeyObjects[] = {
+static const asn1Object_t privkey_objects[] = {
        { 0, "RSAPrivateKey",           ASN1_SEQUENCE,     ASN1_NONE }, /*  0 */
        { 1,   "version",                       ASN1_INTEGER,      ASN1_BODY }, /*  1 */
        { 1,   "modulus",                       ASN1_INTEGER,      ASN1_BODY }, /*  2 */
@@ -197,13 +158,16 @@ static const asn1Object_t privkeyObjects[] = {
        { 1,   "end opt or loop",       ASN1_EOC,          ASN1_END  }  /* 15 */
 };
 
-#define PKCS1_PRIV_KEY_VERSION          1
-#define PKCS1_PRIV_KEY_MODULUS          2
-#define PKCS1_PRIV_KEY_PUB_EXP          3
-#define PKCS1_PRIV_KEY_COEFF            9
-#define PKCS1_PRIV_KEY_ROOF                    16
-#endif
-
+#define PRIV_KEY_VERSION                1
+#define PRIV_KEY_MODULUS                2
+#define PRIV_KEY_PUB_EXP                3
+#define PRIV_KEY_PRIV_EXP               4
+#define PRIV_KEY_PRIME1                         5
+#define PRIV_KEY_PRIME2                         6
+#define PRIV_KEY_EXP1                   7
+#define PRIV_KEY_EXP2                   8
+#define PRIV_KEY_COEFF                  9
+#define PRIV_KEY_ROOF                  16
 
 static private_rsa_private_key_t *rsa_private_key_create_empty();
 
@@ -628,7 +592,6 @@ rsa_private_key_t *rsa_private_key_create(size_t key_size)
                return NULL;
        }
        
-       
        mpz_init(t);    
        mpz_init(n);
        mpz_init(d);
@@ -636,7 +599,6 @@ rsa_private_key_t *rsa_private_key_create(size_t key_size)
        mpz_init(exp2);
        mpz_init(coeff);
        
-
        /* Swapping Primes so p is larger then q */
        if (mpz_cmp(p, q) < 0)
        {
@@ -692,48 +654,6 @@ rsa_private_key_t *rsa_private_key_create(size_t key_size)
        return &this->public;
 }
 
-#ifdef NEW_ASN1
-/*
- * see header
- */
-rsa_private_key_t *rsa_private_key_create_from_chunk(chunk_t chunk)
-{
-       private_rsa_private_key_t *this;
-       der_decoder_t *dd;
-       status_t status;
-       
-       this = rsa_private_key_create_empty();
-       
-       mpz_init(this->n);
-       mpz_init(this->e);
-       mpz_init(this->p);
-       mpz_init(this->q);
-       mpz_init(this->d);
-       mpz_init(this->exp1);
-       mpz_init(this->exp2);
-       mpz_init(this->coeff);
-       
-       dd = der_decoder_create(rsa_private_key_rules);
-       status = dd->decode(dd, chunk, this);
-       dd->destroy(dd);
-       if (status != SUCCESS)
-       {
-               destroy(this);
-               return NULL;
-       }
-       this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
-       
-       if (check(this) != SUCCESS)
-       {
-               destroy(this);
-               return NULL;
-       }
-       else
-       {
-               return &this->public;
-       }
-}
-#else
 /*
  * see header
  */
@@ -758,28 +678,46 @@ rsa_private_key_t *rsa_private_key_create_from_chunk(chunk_t blob)
        
        asn1_init(&ctx, blob, 0, FALSE);
        
-       while (objectID < PKCS1_PRIV_KEY_ROOF) 
+       while (objectID < PRIV_KEY_ROOF) 
        {
-               if (!extract_object(privkeyObjects, &objectID, &object, &level, &ctx))
+               if (!extract_object(privkey_objects, &objectID, &object, &level, &ctx))
                {
                        destroy(this);
                        return FALSE;
                }
-               if (objectID == PKCS1_PRIV_KEY_VERSION)
-               {
-                       if (object.len > 0 && *object.ptr != 0)
-                       {
-                               destroy(this);
-                               return NULL;
-                       }
-               }
-               else if (objectID >= PKCS1_PRIV_KEY_MODULUS &&
-                                          objectID <= PKCS1_PRIV_KEY_COEFF)
+               switch (objectID)
                {
-                       mpz_t *u = (mpz_t *) ((char *)this
-                                       + RSA_private_field[objectID - PKCS1_PRIV_KEY_MODULUS].offset);
-                       
-                       mpz_import(*u, object.len, 1, 1, 1, 0, object.ptr);
+                       case PRIV_KEY_VERSION:
+                               if (object.len > 0 && *object.ptr != 0)
+                               {
+                                       destroy(this);
+                                       return NULL;
+                               }
+                               break;
+                       case PRIV_KEY_MODULUS:
+                               mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr);
+                               break;
+                       case PRIV_KEY_PUB_EXP:
+                               mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr);
+                               break;
+                       case PRIV_KEY_PRIV_EXP:
+                               mpz_import(this->d, object.len, 1, 1, 1, 0, object.ptr);
+                               break;
+                       case PRIV_KEY_PRIME1:
+                               mpz_import(this->p, object.len, 1, 1, 1, 0, object.ptr);
+                               break;
+                       case PRIV_KEY_PRIME2:
+                               mpz_import(this->q, object.len, 1, 1, 1, 0, object.ptr);
+                               break;
+                       case PRIV_KEY_EXP1:
+                               mpz_import(this->exp1, object.len, 1, 1, 1, 0, object.ptr);
+                               break;
+                       case PRIV_KEY_EXP2:
+                               mpz_import(this->exp2, object.len, 1, 1, 1, 0, object.ptr);
+                               break;
+                       case PRIV_KEY_COEFF:
+                               mpz_import(this->coeff, object.len, 1, 1, 1, 0, object.ptr);
+                               break;
                }
                objectID++;
        }
@@ -796,7 +734,6 @@ rsa_private_key_t *rsa_private_key_create_from_chunk(chunk_t blob)
                return &this->public;
        }
 }
-#endif
 
 /*
  * see header
index 61739dd..6b6988b 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <daemon.h>
 #include <crypto/hashers/hasher.h>
-#include <asn1/der_decoder.h>
+#include <asn1/asn1.h>
 
 /* 
  * For simplicity,
@@ -75,6 +75,17 @@ u_int8_t sha512_oid[] = {
        0x00,0x04,0x40
 };
 
+/* ASN.1 definition public key */
+static const asn1Object_t pubkey_objects[] = {
+       { 0, "RSAPublicKey",            ASN1_SEQUENCE,     ASN1_OBJ  }, /*  0 */
+       { 1,   "modulus",                       ASN1_INTEGER,      ASN1_BODY }, /*  1 */
+       { 1,   "publicExponent",        ASN1_INTEGER,      ASN1_BODY }, /*  2 */
+};
+
+#define PUB_KEY_RSA_PUBLIC_KEY         0
+#define PUB_KEY_MODULUS                                1
+#define PUB_KEY_EXPONENT                       2
+#define PUB_KEY_ROOF                           3
 
 typedef struct private_rsa_public_key_t private_rsa_public_key_t;
 
@@ -139,29 +150,6 @@ struct rsa_public_key_info_t {
        chunk_t public_key;
 };
 
-/**
- * Rules for de-/encoding of a public key from/in ASN1 
- */
-static asn1_rule_t rsa_public_key_rules[] = {
-       {ASN1_SEQUENCE, 0, 0, 0},
-       {       ASN1_INTEGER, ASN1_MPZ, offsetof(private_rsa_public_key_t, n), 0},
-       {       ASN1_INTEGER, ASN1_MPZ, offsetof(private_rsa_public_key_t, e), 0},
-       {ASN1_END, 0, 0, 0},
-};
-
-/**
- * Rules for de-/encoding of a PublicKeyInfo from/in ASN1 
- */
-static asn1_rule_t rsa_public_key_info_rules[] = {
-       {ASN1_SEQUENCE, 0, 0, 0},
-       {       ASN1_SEQUENCE, 0, 0, 0},
-       {               ASN1_OID, 0, offsetof(rsa_public_key_info_t, algorithm_oid), 0},
-       {               ASN1_NULL, 0, 0, 0},
-       {       ASN1_END, 0, 0, 0},
-       {       ASN1_BITSTRING, 0, offsetof(rsa_public_key_info_t, public_key), 0},
-       {ASN1_END, 0, 0, 0},
-};
-
 private_rsa_public_key_t *rsa_public_key_create_empty();
 
 /**
@@ -398,24 +386,39 @@ private_rsa_public_key_t *rsa_public_key_create_empty()
 /*
  * See header
  */
-rsa_public_key_t *rsa_public_key_create_from_chunk(chunk_t chunk)
+rsa_public_key_t *rsa_public_key_create_from_chunk(chunk_t blob)
 {
-       der_decoder_t *dd;
-       status_t status;
+       asn1_ctx_t ctx;
+       chunk_t object;
+       u_int level;
+       int objectID = 0;
        private_rsa_public_key_t *this;
        
        this = rsa_public_key_create_empty();
        mpz_init(this->n);
        mpz_init(this->e);
        
-       dd = der_decoder_create(rsa_public_key_rules);
-       status = dd->decode(dd, chunk, this);
-       dd->destroy(dd);
-       if (status != SUCCESS)
+       asn1_init(&ctx, blob, 0, FALSE);
+       
+       while (objectID < PUB_KEY_ROOF) 
        {
-               destroy(this);
-               return NULL;
+               if (!extract_object(pubkey_objects, &objectID, &object, &level, &ctx))
+               {
+                       destroy(this);
+                       return FALSE;
+               }
+               switch (objectID)
+               {
+                       case PUB_KEY_MODULUS:
+                               mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr);
+                               break;
+                       case PUB_KEY_EXPONENT:
+                               mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr);
+                               break;
+               }
+               objectID++;
        }
+       
        this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
        return &this->public;
 }
@@ -429,10 +432,6 @@ rsa_public_key_t *rsa_public_key_create_from_file(char *filename)
        FILE *file;
        char *buffer;
        chunk_t chunk;
-       rsa_public_key_info_t key_info = {CHUNK_INITIALIZER, CHUNK_INITIALIZER};
-       der_decoder_t *dd;
-       status_t status;
-       rsa_public_key_t *public_key = NULL;
        
        if (stat(filename, &stb) == -1)
        {
@@ -455,15 +454,5 @@ rsa_public_key_t *rsa_public_key_create_from_file(char *filename)
        chunk.ptr = buffer;
        chunk.len = stb.st_size;
        
-       /* parse public key info first */
-       dd = der_decoder_create(rsa_public_key_info_rules);
-       status = dd->decode(dd, chunk, &key_info);
-       dd->destroy(dd);
-       chunk_free(&key_info.algorithm_oid);
-       if (status == SUCCESS)
-       {
-               public_key = rsa_public_key_create_from_chunk(chunk);
-       }
-       chunk_free(&key_info.public_key);
-       return public_key;
+       return rsa_public_key_create_from_chunk(chunk);
 }
diff --git a/Source/lib/crypto/x509.c b/Source/lib/crypto/x509.c
new file mode 100755 (executable)
index 0000000..1f2e729
--- /dev/null
@@ -0,0 +1,1691 @@
+/**
+ * @file x509.c
+ * 
+ * @brief Implementation of x509_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * 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 <gmp.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "x509.h"
+
+#include <daemon.h>
+#include <asn1/asn1.h>
+#include <asn1/oid.h>
+#include <utils/logger_manager.h>
+
+typedef const char *err_t;     /* error message, or NULL for success */
+
+#define chunkcpy(dst, chunk) { memcpy(dst, chunk.ptr, chunk.len); dst += chunk.len;}
+
+#define BUF_LEN 512
+#define RSA_MIN_OCTETS (512 / 8)
+#define RSA_MIN_OCTETS_UGH     "RSA modulus too small for security: less than 512 bits"
+#define RSA_MAX_OCTETS (8192 / 8)
+#define RSA_MAX_OCTETS_UGH     "RSA modulus too large: more than 8192 bits"
+
+logger_t *logger;
+
+typedef enum generalNames_t generalNames_t;
+
+/**
+ * Different kinds of generalNames
+ */
+enum generalNames_t {
+    GN_OTHER_NAME =            0,
+       GN_RFC822_NAME =        1,
+       GN_DNS_NAME =           2,
+       GN_X400_ADDRESS =       3,
+       GN_DIRECTORY_NAME =     4,
+       GN_EDI_PARTY_NAME = 5,
+       GN_URI =                        6,
+       GN_IP_ADDRESS =         7,
+       GN_REGISTERED_ID =      8,
+};
+
+typedef struct generalName_t generalName_t;
+
+/**
+ * A generalName, chainable in a list
+ */
+struct generalName_t {
+       generalName_t *next;
+       generalNames_t kind;
+       chunk_t name;
+};
+
+typedef struct private_x509_t private_x509_t;
+
+/**
+ * Private data of a x509_t object.
+ */
+struct private_x509_t {
+       /**
+        * Public interface for this certificate.
+        */
+       x509_t public;
+       
+       time_t installed;
+       u_char authority_flags;
+       chunk_t x509;
+       chunk_t tbsCertificate;
+       u_int version;
+       chunk_t serialNumber;
+       /*   signature */
+       int sigAlg;
+       chunk_t issuer;
+       /*   validity */
+       time_t notBefore;
+       time_t notAfter;
+       chunk_t subject;
+       /* subjectPublicKeyInfo */
+       auth_method_t subjectPublicKeyAlgorithm;
+       chunk_t subjectPublicKey;
+       rsa_public_key_t *public_key;
+       /*   issuerUniqueID */
+       /*   subjectUniqueID */
+       /*   v3 extensions */
+       /*   extension */
+       /*     extension */
+       /*       extnID */
+       /*       critical */
+       /*       extnValue */
+       bool isCA;
+       bool isOcspSigner; /* ocsp */
+       chunk_t subjectKeyID;
+       chunk_t authKeyID;
+       chunk_t authKeySerialNumber;
+       chunk_t accessLocation; /* ocsp */
+       generalName_t *subjectAltName;
+       generalName_t *crlDistributionPoints;
+       /* signatureAlgorithm */
+       int algorithm;
+       chunk_t signature;
+};
+
+/**
+ * ASN.1 definition of a basicConstraints extension 
+ */
+static const asn1Object_t basicConstraintsObjects[] = {
+       { 0, "basicConstraints",        ASN1_SEQUENCE,  ASN1_NONE                       }, /*  0 */
+       { 1,   "CA",                            ASN1_BOOLEAN,   ASN1_DEF|ASN1_BODY      }, /*  1 */
+       { 1,   "pathLenConstraint",     ASN1_INTEGER,   ASN1_OPT|ASN1_BODY      }, /*  2 */
+       { 1,   "end opt",                       ASN1_EOC,               ASN1_END                        }  /*  3 */
+};
+#define BASIC_CONSTRAINTS_CA   1
+#define BASIC_CONSTRAINTS_ROOF 4
+
+/**
+ * ASN.1 definition of time
+ */
+static const asn1Object_t timeObjects[] = {
+       { 0,   "utcTime",               ASN1_UTCTIME,                   ASN1_OPT|ASN1_BODY      }, /*  0 */
+       { 0,   "end opt",               ASN1_EOC,                               ASN1_END                        }, /*  1 */
+       { 0,   "generalizeTime",ASN1_GENERALIZEDTIME,   ASN1_OPT|ASN1_BODY      }, /*  2 */
+       { 0,   "end opt",               ASN1_EOC,                               ASN1_END                        }  /*  3 */
+};
+#define TIME_UTC                       0
+#define TIME_GENERALIZED       2
+#define TIME_ROOF                      4
+
+/** 
+ * ASN.1 definition of a keyIdentifier 
+ */
+static const asn1Object_t keyIdentifierObjects[] = {
+       { 0,   "keyIdentifier", ASN1_OCTET_STRING,      ASN1_BODY }  /*  0 */
+};
+
+/**
+ * ASN.1 definition of a authorityKeyIdentifier extension 
+ */
+static const asn1Object_t authorityKeyIdentifierObjects[] = {
+       { 0,   "authorityKeyIdentifier",        ASN1_SEQUENCE,          ASN1_NONE                       }, /*  0 */
+       { 1,     "keyIdentifier",                       ASN1_CONTEXT_S_0,       ASN1_OPT|ASN1_OBJ       }, /*  1 */
+       { 1,     "end opt",                                     ASN1_EOC,                       ASN1_END                        }, /*  2 */
+       { 1,     "authorityCertIssuer",         ASN1_CONTEXT_C_1,       ASN1_OPT|ASN1_OBJ       }, /*  3 */
+       { 1,     "end opt",                                     ASN1_EOC,                       ASN1_END                        }, /*  4 */
+       { 1,     "authorityCertSerialNumber",ASN1_CONTEXT_S_2,  ASN1_OPT|ASN1_BODY      }, /*  5 */
+       { 1,     "end opt",                                     ASN1_EOC,                       ASN1_END                        }  /*  6 */
+};
+#define AUTH_KEY_ID_KEY_ID                     1
+#define AUTH_KEY_ID_CERT_ISSUER                3
+#define AUTH_KEY_ID_CERT_SERIAL                5
+#define AUTH_KEY_ID_ROOF                       7
+
+/**
+ * ASN.1 definition of a authorityInfoAccess extension 
+ */
+static const asn1Object_t authorityInfoAccessObjects[] = {
+       { 0,   "authorityInfoAccess",   ASN1_SEQUENCE,  ASN1_LOOP }, /*  0 */
+       { 1,     "accessDescription",   ASN1_SEQUENCE,  ASN1_NONE }, /*  1 */
+       { 2,       "accessMethod",              ASN1_OID,               ASN1_BODY }, /*  2 */
+       { 2,       "accessLocation",    ASN1_EOC,               ASN1_RAW  }, /*  3 */
+       { 0,   "end loop",                              ASN1_EOC,               ASN1_END  }  /*  4 */
+};
+#define AUTH_INFO_ACCESS_METHOD                2
+#define AUTH_INFO_ACCESS_LOCATION      3
+#define AUTH_INFO_ACCESS_ROOF          5
+
+/**
+ * ASN.1 definition of a extendedKeyUsage extension
+ */
+static const asn1Object_t extendedKeyUsageObjects[] = {
+       { 0, "extendedKeyUsage",        ASN1_SEQUENCE,  ASN1_LOOP }, /*  0 */
+       { 1,   "keyPurposeID",          ASN1_OID,               ASN1_BODY }, /*  1 */
+       { 0, "end loop",                        ASN1_EOC,               ASN1_END  }, /*  2 */
+};
+
+#define EXT_KEY_USAGE_PURPOSE_ID       1
+#define EXT_KEY_USAGE_ROOF                     3
+
+/**
+ * ASN.1 definition of generalNames 
+ */
+static const asn1Object_t generalNamesObjects[] = {
+       { 0, "generalNames",    ASN1_SEQUENCE,  ASN1_LOOP }, /*  0 */
+       { 1,   "generalName",   ASN1_EOC,               ASN1_RAW  }, /*  1 */
+       { 0, "end loop",                ASN1_EOC,               ASN1_END  }  /*  2 */
+};
+#define GENERAL_NAMES_GN       1
+#define GENERAL_NAMES_ROOF     3
+
+/**
+ * ASN.1 definition of generalName 
+ */
+static const asn1Object_t generalNameObjects[] = {
+  { 0,   "otherName",          ASN1_CONTEXT_C_0,  ASN1_OPT|ASN1_BODY   }, /*  0 */
+  { 0,   "end choice",         ASN1_EOC,          ASN1_END                             }, /*  1 */
+  { 0,   "rfc822Name",         ASN1_CONTEXT_S_1,  ASN1_OPT|ASN1_BODY   }, /*  2 */
+  { 0,   "end choice",         ASN1_EOC,          ASN1_END                     }, /*  3 */
+  { 0,   "dnsName",                    ASN1_CONTEXT_S_2,  ASN1_OPT|ASN1_BODY   }, /*  4 */
+  { 0,   "end choice",         ASN1_EOC,          ASN1_END                             }, /*  5 */
+  { 0,   "x400Address",                ASN1_CONTEXT_S_3,  ASN1_OPT|ASN1_BODY   }, /*  6 */
+  { 0,   "end choice",         ASN1_EOC,          ASN1_END                             }, /*  7 */
+  { 0,   "directoryName",      ASN1_CONTEXT_C_4,  ASN1_OPT|ASN1_BODY   }, /*  8 */
+  { 0,   "end choice",         ASN1_EOC,          ASN1_END                             }, /*  9 */
+  { 0,   "ediPartyName",       ASN1_CONTEXT_C_5,  ASN1_OPT|ASN1_BODY   }, /* 10 */
+  { 0,   "end choice",         ASN1_EOC,          ASN1_END                             }, /* 11 */
+  { 0,   "URI",                                ASN1_CONTEXT_S_6,  ASN1_OPT|ASN1_BODY   }, /* 12 */
+  { 0,   "end choice",         ASN1_EOC,          ASN1_END                             }, /* 13 */
+  { 0,   "ipAddress",          ASN1_CONTEXT_S_7,  ASN1_OPT|ASN1_BODY   }, /* 14 */
+  { 0,   "end choice",         ASN1_EOC,          ASN1_END                             }, /* 15 */
+  { 0,   "registeredID",       ASN1_CONTEXT_S_8,  ASN1_OPT|ASN1_BODY   }, /* 16 */
+  { 0,   "end choice",         ASN1_EOC,          ASN1_END                             }  /* 17 */
+};
+#define GN_OBJ_OTHER_NAME               0
+#define GN_OBJ_RFC822_NAME              2
+#define GN_OBJ_DNS_NAME                         4
+#define GN_OBJ_X400_ADDRESS             6
+#define GN_OBJ_DIRECTORY_NAME   8
+#define GN_OBJ_EDI_PARTY_NAME  10
+#define GN_OBJ_URI                             12
+#define GN_OBJ_IP_ADDRESS              14
+#define GN_OBJ_REGISTERED_ID   16
+#define GN_OBJ_ROOF                            18
+
+/**
+ * ASN.1 definition of otherName 
+ */
+static const asn1Object_t otherNameObjects[] = {
+       {0, "type-id",  ASN1_OID,                       ASN1_BODY       }, /*  0 */
+       {0, "value",    ASN1_CONTEXT_C_0,       ASN1_BODY       }  /*  1 */
+};
+#define ON_OBJ_ID_TYPE         0
+#define ON_OBJ_VALUE           1
+#define ON_OBJ_ROOF                    2
+
+/**
+ * SN.1 definition of crlDistributionPoints
+ */
+static const asn1Object_t crlDistributionPointsObjects[] = {
+       { 0, "crlDistributionPoints",   ASN1_SEQUENCE,          ASN1_LOOP                       }, /*  0 */
+       { 1,   "DistributionPoint",             ASN1_SEQUENCE,          ASN1_NONE                       }, /*  1 */
+       { 2,     "distributionPoint",   ASN1_CONTEXT_C_0,       ASN1_OPT|ASN1_LOOP      }, /*  2 */
+       { 3,       "fullName",                  ASN1_CONTEXT_C_0,       ASN1_OPT|ASN1_OBJ       }, /*  3 */
+       { 3,       "end choice",                ASN1_EOC,                       ASN1_END                        }, /*  4 */
+       { 3,       "nameRelToCRLIssuer",ASN1_CONTEXT_C_1,       ASN1_OPT|ASN1_BODY      }, /*  5 */
+       { 3,       "end choice",                ASN1_EOC,                       ASN1_END                        }, /*  6 */
+       { 2,     "end opt",                             ASN1_EOC,                       ASN1_END                        }, /*  7 */
+       { 2,     "reasons",                             ASN1_CONTEXT_C_1,       ASN1_OPT|ASN1_BODY      }, /*  8 */
+       { 2,     "end opt",                             ASN1_EOC,                       ASN1_END                        }, /*  9 */
+       { 2,     "crlIssuer",                   ASN1_CONTEXT_C_2,       ASN1_OPT|ASN1_BODY      }, /* 10 */
+       { 2,     "end opt",                             ASN1_EOC,                       ASN1_END                        }, /* 11 */
+       { 0, "end loop",                                ASN1_EOC,                       ASN1_END                        }, /* 12 */
+};
+#define CRL_DIST_POINTS_FULLNAME        3
+#define CRL_DIST_POINTS_ROOF           13
+
+/**
+ * ASN.1 definition of an X.509v3 x509
+ */
+static const asn1Object_t certObjects[] = {
+       { 0, "x509",                            ASN1_SEQUENCE,          ASN1_OBJ                        }, /*  0 */
+       { 1,   "tbsCertificate",                ASN1_SEQUENCE,          ASN1_OBJ                        }, /*  1 */
+       { 2,     "DEFAULT v1",                  ASN1_CONTEXT_C_0,       ASN1_DEF                        }, /*  2 */
+       { 3,       "version",                   ASN1_INTEGER,           ASN1_BODY                       }, /*  3 */
+       { 2,     "serialNumber",                ASN1_INTEGER,           ASN1_BODY                       }, /*  4 */
+       { 2,     "signature",                   ASN1_EOC,                       ASN1_RAW                        }, /*  5 */
+       { 2,     "issuer",                              ASN1_SEQUENCE,          ASN1_OBJ                        }, /*  6 */
+       { 2,     "validity",                    ASN1_SEQUENCE,          ASN1_NONE                       }, /*  7 */
+       { 3,       "notBefore",                 ASN1_EOC,                       ASN1_RAW                        }, /*  8 */
+       { 3,       "notAfter",                  ASN1_EOC,                       ASN1_RAW                        }, /*  9 */
+       { 2,     "subject",                             ASN1_SEQUENCE,          ASN1_OBJ                        }, /* 10 */
+       { 2,     "subjectPublicKeyInfo",ASN1_SEQUENCE,          ASN1_NONE                       }, /* 11 */
+       { 3,       "algorithm",                 ASN1_EOC,                       ASN1_RAW                        }, /* 12 */
+       { 3,       "subjectPublicKey",  ASN1_BIT_STRING,        ASN1_NONE                       }, /* 13 */
+       { 4,         "RSAPublicKey",    ASN1_SEQUENCE,          ASN1_RAW                        }, /* 14 */
+       { 2,     "issuerUniqueID",              ASN1_CONTEXT_C_1,       ASN1_OPT                        }, /* 15 */
+       { 2,     "end opt",                             ASN1_EOC,                       ASN1_END                        }, /* 16 */
+       { 2,     "subjectUniqueID",             ASN1_CONTEXT_C_2,       ASN1_OPT                        }, /* 17 */
+       { 2,     "end opt",                             ASN1_EOC,                       ASN1_END                        }, /* 18 */
+       { 2,     "optional extensions", ASN1_CONTEXT_C_3,       ASN1_OPT                        }, /* 19 */
+       { 3,       "extensions",                ASN1_SEQUENCE,          ASN1_LOOP                       }, /* 20 */
+       { 4,         "extension",               ASN1_SEQUENCE,          ASN1_NONE                       }, /* 21 */
+       { 5,           "extnID",                ASN1_OID,                       ASN1_BODY                       }, /* 22 */
+       { 5,           "critical",              ASN1_BOOLEAN,           ASN1_DEF|ASN1_BODY      }, /* 23 */
+       { 5,           "extnValue",             ASN1_OCTET_STRING,      ASN1_BODY                       }, /* 24 */
+       { 3,       "end loop",                  ASN1_EOC,                       ASN1_END                        }, /* 25 */
+       { 2,     "end opt",                             ASN1_EOC,                       ASN1_END                        }, /* 26 */
+       { 1,   "signatureAlgorithm",    ASN1_EOC,                       ASN1_RAW                        }, /* 27 */
+       { 1,   "signatureValue",                ASN1_BIT_STRING,        ASN1_BODY                       }  /* 28 */
+};
+#define X509_OBJ_CERTIFICATE                                    0
+#define X509_OBJ_TBS_CERTIFICATE                                1
+#define X509_OBJ_VERSION                                                3
+#define X509_OBJ_SERIAL_NUMBER                                  4
+#define X509_OBJ_SIG_ALG                                                5
+#define X509_OBJ_ISSUER                                                 6
+#define X509_OBJ_NOT_BEFORE                                             8
+#define X509_OBJ_NOT_AFTER                                              9
+#define X509_OBJ_SUBJECT                                               10
+#define X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM  12
+#define X509_OBJ_SUBJECT_PUBLIC_KEY                            13
+#define X509_OBJ_RSA_PUBLIC_KEY                                        14
+#define X509_OBJ_EXTN_ID                                               22
+#define X509_OBJ_CRITICAL                                              23
+#define X509_OBJ_EXTN_VALUE                                            24
+#define X509_OBJ_ALGORITHM                                             27
+#define X509_OBJ_SIGNATURE                                             28
+#define X509_OBJ_ROOF                                                  29
+
+
+
+/**
+ * X.501 acronyms for well known object identifiers (OIDs)
+ */
+static u_char oid_ND[]  = {
+       0x02, 0x82, 0x06, 0x01, 
+       0x0A, 0x07, 0x14
+};
+static u_char oid_UID[] = {
+       0x09, 0x92, 0x26, 0x89, 0x93,
+       0xF2, 0x2C, 0x64, 0x01, 0x01
+};
+static u_char oid_DC[]  = {
+       0x09, 0x92, 0x26, 0x89, 0x93,
+       0xF2, 0x2C, 0x64, 0x01, 0x19
+};
+static u_char oid_CN[] = {
+       0x55, 0x04, 0x03
+};
+static u_char oid_S[] = {
+       0x55, 0x04, 0x04
+};
+static u_char oid_SN[] = {
+       0x55, 0x04, 0x05
+};
+static u_char oid_C[] = {
+       0x55, 0x04, 0x06
+};
+static u_char oid_L[] = {
+       0x55, 0x04, 0x07
+};
+static u_char oid_ST[] = {
+       0x55, 0x04, 0x08
+};
+static u_char oid_O[] = {
+       0x55, 0x04, 0x0A
+};
+static u_char oid_OU[] = {
+       0x55, 0x04, 0x0B
+};
+static u_char oid_T[] = {
+       0x55, 0x04, 0x0C
+};
+static u_char oid_D[] = {
+       0x55, 0x04, 0x0D
+};
+static u_char oid_N[] = {
+       0x55, 0x04, 0x29
+};
+static u_char oid_G[] = {
+       0x55, 0x04, 0x2A
+};
+static u_char oid_I[] = {
+       0x55, 0x04, 0x2B
+};
+static u_char oid_ID[] = {
+       0x55, 0x04, 0x2D
+};
+static u_char oid_E[] = {
+       0x2A, 0x86, 0x48, 0x86, 0xF7,
+       0x0D, 0x01, 0x09, 0x01
+};
+static u_char oid_UN[]  = {
+       0x2A, 0x86, 0x48, 0x86, 0xF7,
+       0x0D, 0x01, 0x09, 0x02
+};
+static u_char oid_TCGID[] = {
+       0x2B, 0x06, 0x01, 0x04, 0x01, 0x89,
+       0x31, 0x01, 0x01, 0x02, 0x02, 0x4B
+};
+
+/**
+ * coding of X.501 distinguished name 
+ */
+typedef struct {
+       const u_char *name;
+       chunk_t oid;
+       u_char type;
+} x501rdn_t;
+
+static const x501rdn_t x501rdns[] = {
+       {"ND",                          {oid_ND,     7}, ASN1_PRINTABLESTRING},
+       {"UID",                         {oid_UID,   10}, ASN1_PRINTABLESTRING},
+       {"DC",                          {oid_DC,    10}, ASN1_PRINTABLESTRING},
+       {"CN",                          {oid_CN,     3}, ASN1_PRINTABLESTRING},
+       {"S",                           {oid_S,      3}, ASN1_PRINTABLESTRING},
+       {"SN",                          {oid_SN,     3}, ASN1_PRINTABLESTRING},
+       {"serialNumber",        {oid_SN,     3}, ASN1_PRINTABLESTRING},
+       {"C",                           {oid_C,      3}, ASN1_PRINTABLESTRING},
+       {"L",                           {oid_L,      3}, ASN1_PRINTABLESTRING},
+       {"ST",                          {oid_ST,     3}, ASN1_PRINTABLESTRING},
+       {"O",                           {oid_O,      3}, ASN1_PRINTABLESTRING},
+       {"OU",                          {oid_OU,     3}, ASN1_PRINTABLESTRING},
+       {"T",                           {oid_T,      3}, ASN1_PRINTABLESTRING},
+       {"D",                           {oid_D,      3}, ASN1_PRINTABLESTRING},
+       {"N",                           {oid_N,      3}, ASN1_PRINTABLESTRING},
+       {"G",                           {oid_G,      3}, ASN1_PRINTABLESTRING},
+       {"I",                           {oid_I,      3}, ASN1_PRINTABLESTRING},
+       {"ID",                          {oid_ID,     3}, ASN1_PRINTABLESTRING},
+       {"E",                           {oid_E,      9}, ASN1_IA5STRING},
+       {"Email",                       {oid_E,      9}, ASN1_IA5STRING},
+       {"emailAddress",        {oid_E,      9}, ASN1_IA5STRING},
+       {"UN",                          {oid_UN,     9}, ASN1_IA5STRING},
+       {"unstructuredName",{oid_UN,     9}, ASN1_IA5STRING},
+       {"TCGID",                       {oid_TCGID, 12}, ASN1_PRINTABLESTRING}
+};
+
+#define X501_RDN_ROOF   24
+
+static u_char ASN1_subjectAltName_oid_str[] = {
+       0x06, 0x03, 0x55, 0x1D, 0x11
+};
+
+static const chunk_t ASN1_subjectAltName_oid = chunk_from_buf(ASN1_subjectAltName_oid_str);
+
+
+static void update_chunk(chunk_t *ch, int n)
+{
+       n = (n > -1 && n < (int)ch->len)? n : (int)ch->len-1;
+       ch->ptr += n; ch->len -= n;
+}
+
+/**
+ * Prints a binary string in hexadecimal form
+ */
+void hex_str(chunk_t bin, chunk_t *str)
+{
+       u_int i;
+       update_chunk(str, snprintf(str->ptr,str->len,"0x"));
+       for (i=0; i < bin.len; i++)
+       {
+               update_chunk(str, snprintf(str->ptr,str->len,"%02X",*bin.ptr++));
+       }
+}
+
+/**
+ * Pointer is set to the first RDN in a DN
+ */
+static err_t init_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *next)
+{
+       *rdn = CHUNK_INITIALIZER;
+       *attribute = CHUNK_INITIALIZER;
+       
+       /* a DN is a SEQUENCE OF RDNs */
+       if (*dn.ptr != ASN1_SEQUENCE)
+       {
+               return "DN is not a SEQUENCE";
+       }
+       
+       rdn->len = asn1_length(&dn);
+       
+       if (rdn->len == ASN1_INVALID_LENGTH)
+               return "Invalid RDN length";
+       
+       rdn->ptr = dn.ptr;
+       
+       /* are there any RDNs ? */
+       *next = rdn->len > 0;
+       
+       return NULL;
+}
+
+/**
+ * Fetches the next RDN in a DN
+ */
+static err_t get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, chunk_t *value, asn1_t *type, bool *next)
+{
+       chunk_t body;
+
+       /* initialize return values */
+       *oid   = CHUNK_INITIALIZER;
+       *value = CHUNK_INITIALIZER;
+
+       /* if all attributes have been parsed, get next rdn */
+       if (attribute->len <= 0)
+       {
+               /* an RDN is a SET OF attributeTypeAndValue */
+               if (*rdn->ptr != ASN1_SET)
+               {
+                       return "RDN is not a SET";
+               }
+               attribute->len = asn1_length(rdn);
+               if (attribute->len == ASN1_INVALID_LENGTH)
+               {
+                       return "Invalid attribute length";
+               }
+               attribute->ptr = rdn->ptr;
+               /* advance to start of next RDN */
+               rdn->ptr += attribute->len;
+               rdn->len -= attribute->len;
+       }
+       
+       /* an attributeTypeAndValue is a SEQUENCE */
+       if (*attribute->ptr != ASN1_SEQUENCE)
+       {
+               return "attributeTypeAndValue is not a SEQUENCE";
+       }
+       
+       /* extract the attribute body */
+       body.len = asn1_length(attribute);
+       
+       if (body.len == ASN1_INVALID_LENGTH)
+       {
+               return "Invalid attribute body length";
+       }
+       
+       body.ptr = attribute->ptr;
+       
+       /* advance to start of next attribute */
+       attribute->ptr += body.len;
+       attribute->len -= body.len;
+       
+       /* attribute type is an OID */
+       if (*body.ptr != ASN1_OID)
+       {
+               return "attributeType is not an OID";
+       }
+       /* extract OID */
+       oid->len = asn1_length(&body);
+       
+       if (oid->len == ASN1_INVALID_LENGTH)
+       {
+               return "Invalid attribute OID length";
+       }
+       oid->ptr = body.ptr;
+       
+       /* advance to the attribute value */
+       body.ptr += oid->len;
+       body.len -= oid->len;
+
+       /* extract string type */
+       *type = *body.ptr;
+       
+       /* extract string value */
+       value->len = asn1_length(&body);
+       
+       if (value->len == ASN1_INVALID_LENGTH)
+       {
+               return "Invalid attribute string length";
+       }
+       value->ptr = body.ptr;
+       
+       /* are there any RDNs left? */
+       *next = rdn->len > 0 || attribute->len > 0;
+       return NULL;
+}
+
+/**
+ *  Parses an ASN.1 distinguished name int its OID/value pairs
+ */
+static err_t dn_parse(chunk_t dn, chunk_t *str)
+{
+       chunk_t rdn, oid, attribute, value;
+       asn1_t type;
+       int oid_code;
+       bool next;
+       bool first = TRUE;
+
+       err_t ugh = init_rdn(dn, &rdn, &attribute, &next);
+
+       if (ugh != NULL)
+       {/* a parsing error has occured */
+               return ugh;
+       }
+
+       while (next)
+       {
+               ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next);
+
+               if (ugh != NULL)
+               { /* a parsing error has occured */
+                       return ugh;
+               }
+
+               if (first) 
+               { /* first OID/value pair */
+                       first = FALSE;
+               }
+               else
+               { /* separate OID/value pair by a comma */
+                       update_chunk(str, snprintf(str->ptr,str->len,", "));
+               }
+
+               /* print OID */
+               oid_code = known_oid(oid);
+               if (oid_code == OID_UNKNOWN) 
+               { /* OID not found in list */
+                       hex_str(oid, str);
+               }
+               else
+               {
+                       update_chunk(str, snprintf(str->ptr,str->len,"%s", oid_names[oid_code].name));
+               }
+               /* print value */
+               update_chunk(str, snprintf(str->ptr,str->len,"=%.*s", (int)value.len,value.ptr));
+       }
+       return NULL;
+}
+
+/**
+ * Count the number of wildcard RDNs in a distinguished name
+ */
+int dn_count_wildcards(chunk_t dn)
+{
+       chunk_t rdn, attribute, oid, value;
+       asn1_t type;
+       bool next;
+       int wildcards = 0;
+
+       err_t ugh = init_rdn(dn, &rdn, &attribute, &next);
+
+       if (ugh != NULL) 
+       { /* a parsing error has occured */
+               return -1;
+       }
+       
+       while (next)
+       {
+               ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next);
+               if (ugh != NULL) 
+               {/* a parsing error has occured */
+                       return -1;
+               }
+               if (value.len == 1 && *value.ptr == '*')
+               {
+                       wildcards++; /* we have found a wildcard RDN */
+               }
+       }
+       return wildcards;
+}
+
+
+/**
+ * Converts a binary DER-encoded ASN.1 distinguished name
+ * into LDAP-style human-readable ASCII format
+ */
+int dntoa(char *dst, size_t dstlen, chunk_t dn)
+{
+       err_t ugh = NULL;
+       chunk_t str;
+
+       str.ptr = dst;
+       str.len = dstlen;
+       ugh = dn_parse(dn, &str);
+
+       if (ugh != NULL) /* error, print DN as hex string */
+       {
+               logger->log(logger, ERROR|LEVEL1, "error in DN parsing: %s", ugh);
+               str.ptr = dst;
+               str.len = dstlen;
+               hex_str(dn, &str);
+       }
+       return (int)(dstlen - str.len);
+}
+
+/**
+ * Same as dntoa but prints a special string for a null dn
+ */
+int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn, const char* null_dn)
+{
+       if (dn.ptr == NULL)
+       {
+               return snprintf(dst, dstlen, "%s", null_dn);
+       }
+       else
+       {
+               return dntoa(dst, dstlen, dn);
+       }
+}
+
+/**
+ * Converts an LDAP-style human-readable ASCII-encoded
+ * ASN.1 distinguished name into binary DER-encoded format
+ */
+err_t atodn(char *src, chunk_t *dn)
+{
+       /* finite state machine for atodn */
+       typedef enum {
+               SEARCH_OID =    0,
+               READ_OID =              1,
+               SEARCH_NAME =   2,
+               READ_NAME =             3,
+               UNKNOWN_OID =   4
+       } state_t;
+
+       u_char oid_len_buf[3];
+       u_char name_len_buf[3];
+       u_char rdn_seq_len_buf[3];
+       u_char rdn_set_len_buf[3];
+       u_char dn_seq_len_buf[3];
+       
+       chunk_t asn1_oid_len     = { oid_len_buf,     0 };
+       chunk_t asn1_name_len    = { name_len_buf,    0 };
+       chunk_t asn1_rdn_seq_len = { rdn_seq_len_buf, 0 };
+       chunk_t asn1_rdn_set_len = { rdn_set_len_buf, 0 };
+       chunk_t asn1_dn_seq_len  = { dn_seq_len_buf,  0 };
+       chunk_t oid  = CHUNK_INITIALIZER;
+       chunk_t name = CHUNK_INITIALIZER;
+       
+       int whitespace  = 0;
+       int rdn_seq_len = 0;
+       int rdn_set_len = 0;
+       int dn_seq_len  = 0;
+       int pos         = 0;
+       
+       err_t ugh = NULL;
+       
+       u_char *dn_ptr = dn->ptr + 4;
+       
+       state_t state = SEARCH_OID;
+       
+       do
+       {
+               switch (state)
+               {
+                       case SEARCH_OID:
+                               if (*src != ' ' && *src != '/' && *src !=  ',')
+                               {
+                                       oid.ptr = src;
+                                       oid.len = 1;
+                                       state = READ_OID;
+                               }
+                               break;
+                       case READ_OID:
+                               if (*src != ' ' && *src != '=')
+                                       oid.len++;
+                               else
+                               {
+                                       for (pos = 0; pos < X501_RDN_ROOF; pos++)
+                                       {
+                                               if (strlen(x501rdns[pos].name) == oid.len &&
+                                                       strncasecmp(x501rdns[pos].name, oid.ptr, oid.len) == 0)
+                                               {
+                                                       break; /* found a valid OID */
+                                               }
+                                       }
+                                       if (pos == X501_RDN_ROOF)
+                                       {
+                                               ugh = "unknown OID in distinguished name";
+                                               state = UNKNOWN_OID;
+                                               break;
+                                       }
+                                       code_asn1_length(x501rdns[pos].oid.len, &asn1_oid_len);
+
+                                       /* reset oid and change state */
+                                       oid = CHUNK_INITIALIZER;
+                                       state = SEARCH_NAME;
+                               }
+                               break;
+                       case SEARCH_NAME:
+                               if (*src != ' ' && *src != '=')
+                               {
+                                       name.ptr = src;
+                                       name.len = 1;
+                                       whitespace = 0;
+                                       state = READ_NAME;
+                               }
+                               break;
+                       case READ_NAME:
+                               if (*src != ',' && *src != '/' && *src != '\0')
+                               {
+                                       name.len++;
+                                       if (*src == ' ')
+                                               whitespace++;
+                                       else
+                                               whitespace = 0;
+                               }
+                               else
+                               {
+                                       name.len -= whitespace;
+                                       code_asn1_length(name.len, &asn1_name_len);
+
+                                       /* compute the length of the relative distinguished name sequence */
+                                       rdn_seq_len = 1 + asn1_oid_len.len + x501rdns[pos].oid.len +
+                                                       1 + asn1_name_len.len + name.len;
+                                       code_asn1_length(rdn_seq_len, &asn1_rdn_seq_len);
+
+                                       /* compute the length of the relative distinguished name set */
+                                       rdn_set_len = 1 + asn1_rdn_seq_len.len + rdn_seq_len;
+                                       code_asn1_length(rdn_set_len, &asn1_rdn_set_len);
+
+                                       /* encode the relative distinguished name */
+                                       *dn_ptr++ = ASN1_SET;
+                                       chunkcpy(dn_ptr, asn1_rdn_set_len);
+                                       *dn_ptr++ = ASN1_SEQUENCE;
+                                       chunkcpy(dn_ptr, asn1_rdn_seq_len);
+                                       *dn_ptr++ = ASN1_OID;
+                                       chunkcpy(dn_ptr, asn1_oid_len);
+                                       chunkcpy(dn_ptr, x501rdns[pos].oid);
+                                       /* encode the ASN.1 character string type of the name */
+                                       *dn_ptr++ = (x501rdns[pos].type == ASN1_PRINTABLESTRING
+                                                       && !is_printablestring(name))? ASN1_T61STRING : x501rdns[pos].type;
+                                       chunkcpy(dn_ptr, asn1_name_len);
+                                       chunkcpy(dn_ptr, name);
+
+                                       /* accumulate the length of the distinguished name sequence */
+                                       dn_seq_len += 1 + asn1_rdn_set_len.len + rdn_set_len;
+
+                                       /* reset name and change state */
+                                       name = CHUNK_INITIALIZER;
+                                       state = SEARCH_OID;
+                               }
+                               break;
+                       case UNKNOWN_OID:
+                               break;
+               }
+       } while (*src++ != '\0');
+
+       /* complete the distinguished name sequence */
+       code_asn1_length(dn_seq_len, &asn1_dn_seq_len);
+       dn->ptr += 3 - asn1_dn_seq_len.len;
+       dn->len =  1 + asn1_dn_seq_len.len + dn_seq_len;
+       dn_ptr = dn->ptr;
+       *dn_ptr++ = ASN1_SEQUENCE;
+       chunkcpy(dn_ptr, asn1_dn_seq_len);
+       return ugh;
+}
+
+/**
+ * compare two distinguished names by
+ * comparing the individual RDNs
+ */
+bool same_dn(chunk_t a, chunk_t b)
+{
+       chunk_t rdn_a, rdn_b, attribute_a, attribute_b;
+       chunk_t oid_a, oid_b, value_a, value_b;
+       asn1_t type_a, type_b;
+       bool next_a, next_b;
+
+       /* same lengths for the DNs */
+       if (a.len != b.len)
+       {
+               return FALSE;
+       }
+       /* try a binary comparison first */
+       if (memcmp(a.ptr, b.ptr, b.len) == 0)
+       {
+               return TRUE;
+       }
+       /* initialize DN parsing */
+       if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != NULL ||
+               init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL)
+       {
+               return FALSE;
+       }
+
+       /* fetch next RDN pair */
+       while (next_a && next_b)
+       {
+               /* parse next RDNs and check for errors */
+               if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != NULL
+                                 ||  get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL)
+               {
+                       return FALSE;
+               }
+               /* OIDs must agree */
+               if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0)
+               {
+                       return FALSE;
+               }
+               /* same lengths for values */
+               if (value_a.len != value_b.len)
+               {
+                       return FALSE;
+               }
+               /* printableStrings and email RDNs require uppercase comparison */
+               if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING ||
+                                 (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL)))
+               {
+                       if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
+                       {
+                               return FALSE;
+                       }
+               }
+               else
+               {
+                       if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
+                       {
+                               return FALSE;
+                       }
+               }
+       }
+       /* both DNs must have same number of RDNs */
+       if (next_a || next_b)
+               return FALSE;
+
+       /* the two DNs are equal! */
+       return TRUE;
+}
+
+
+/**
+ * compare two distinguished names by comparing the individual RDNs.
+ * A single'*' character designates a wildcard RDN in DN b.
+ */
+bool match_dn(chunk_t a, chunk_t b, int *wildcards)
+{
+       chunk_t rdn_a, rdn_b, attribute_a, attribute_b;
+       chunk_t oid_a, oid_b, value_a, value_b;
+       asn1_t type_a,  type_b;
+       bool next_a, next_b;
+
+       /* initialize wildcard counter */
+       *wildcards = 0;
+
+       /* initialize DN parsing */
+       if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != NULL ||
+               init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL)
+       {
+               return FALSE;
+       }
+       /* fetch next RDN pair */
+       while (next_a && next_b)
+       {
+               /* parse next RDNs and check for errors */
+               if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != NULL ||
+                       get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL)
+               {
+                       return FALSE;
+               }
+               /* OIDs must agree */
+               if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0)
+               {
+                       return FALSE;
+               }
+               /* does rdn_b contain a wildcard? */
+               if (value_b.len == 1 && *value_b.ptr == '*')
+               {
+                       (*wildcards)++;
+                       continue;
+               }
+               /* same lengths for values */
+               if (value_a.len != value_b.len)
+               {
+                       return FALSE;
+               }
+               /* printableStrings and email RDNs require uppercase comparison */
+               if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING ||
+                       (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL)))
+               {
+                       if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
+                       {
+                               return FALSE;
+                       }
+               }
+               else
+               {
+                       if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
+                       {
+                               return FALSE;
+                       }
+               }
+       }
+       /* both DNs must have same number of RDNs */
+       if (next_a || next_b)
+       {
+               return FALSE;
+       }
+       /* the two DNs match! */
+       return TRUE;
+}
+
+/**
+ * compare two X.509 x509s by comparing their signatures
+ */
+static bool equals(private_x509_t *this, private_x509_t *other)
+{
+       return chunk_equals(this->signature, other->signature);
+}
+
+/**
+ * encode a linked list of subjectAltNames
+ */
+chunk_t build_subjectAltNames(generalName_t *subjectAltNames)
+{
+       u_char *pos;
+       chunk_t names;
+       size_t len = 0;
+       generalName_t *gn = subjectAltNames;
+       
+       /* compute the total size of the ASN.1 attributes object */
+       while (gn != NULL)
+       {
+               len += gn->name.len;
+               gn = gn->next;
+       }
+
+       pos = build_asn1_object(&names, ASN1_SEQUENCE, len);
+
+       gn = subjectAltNames;
+       while (gn != NULL)
+       {
+               chunkcpy(pos, gn->name);
+               gn = gn->next;
+       }
+
+       return asn1_wrap(ASN1_SEQUENCE, "cm",
+                                        ASN1_subjectAltName_oid,
+                                        asn1_wrap(ASN1_OCTET_STRING, "m", names)
+                                       );
+}
+
+/**
+ * free the dynamic memory used to store generalNames
+ */
+void free_generalNames(generalName_t* gn, bool free_name)
+{
+       while (gn != NULL)
+       {
+               generalName_t *gn_top = gn;
+               if (free_name)
+               {
+                       free(gn->name.ptr);
+               }
+               gn = gn->next;
+               free(gn_top);
+       }
+}
+
+/**
+ * extracts the basicConstraints extension
+ */
+static bool parse_basicConstraints(chunk_t blob, int level0)
+{
+       asn1_ctx_t ctx;
+       chunk_t object;
+       u_int level;
+       int objectID = 0;
+       bool isCA = FALSE;
+
+       asn1_init(&ctx, blob, level0, FALSE);
+
+       while (objectID < BASIC_CONSTRAINTS_ROOF) {
+
+               if (!extract_object(basicConstraintsObjects, &objectID, &object,&level, &ctx))
+               {
+                       break;
+               }
+               if (objectID == BASIC_CONSTRAINTS_CA)
+               {
+                       isCA = object.len && *object.ptr;
+                       logger->log(logger, RAW|LEVEL1, "  %s", isCA ? "TRUE" : "FALSE");
+               }
+               objectID++;
+       }
+       return isCA;
+}
+
+/**
+ * extracts an otherName
+ */
+static bool parse_otherName(chunk_t blob, int level0)
+{
+       asn1_ctx_t ctx;
+       chunk_t object;
+       int objectID = 0;
+       u_int level;
+       int oid = OID_UNKNOWN;
+
+       asn1_init(&ctx, blob, level0, FALSE);
+
+       while (objectID < ON_OBJ_ROOF)
+       {
+               if (!extract_object(otherNameObjects, &objectID, &object, &level, &ctx))
+                       return FALSE;
+
+               switch (objectID)
+               {
+                       case ON_OBJ_ID_TYPE:
+                               oid = known_oid(object);
+                               break;
+                       case ON_OBJ_VALUE:
+                               if (oid == OID_XMPP_ADDR)
+                               {
+                                       if (!parse_asn1_simple_object(&object, ASN1_UTF8STRING, level + 1, "xmppAddr"))
+                                       {
+                                               return FALSE;
+                                       }
+                               }
+                               break;
+                       default:
+                               break;
+               }
+               objectID++;
+       }
+       return TRUE;
+}
+
+
+/**
+ * extracts a generalName
+ */
+static generalName_t* parse_generalName(chunk_t blob, int level0)
+{
+       asn1_ctx_t ctx;
+       chunk_t object;
+       int objectID = 0;
+       u_int level;
+
+       asn1_init(&ctx, blob, level0, FALSE);
+
+       while (objectID < GN_OBJ_ROOF)
+       {
+               bool valid_gn = FALSE;
+       
+               if (!extract_object(generalNameObjects, &objectID, &object, &level, &ctx))
+                       return NULL;
+
+               switch (objectID) {
+                       case GN_OBJ_RFC822_NAME:
+                       case GN_OBJ_DNS_NAME:
+                       case GN_OBJ_URI:
+                               logger->log(logger, RAW|LEVEL1, "  '%.*s'", (int)object.len, object.ptr);
+                               valid_gn = TRUE;
+                               break;
+                       case GN_OBJ_DIRECTORY_NAME:
+                               valid_gn = TRUE;
+                               break;
+                       case GN_OBJ_IP_ADDRESS:
+                               logger->log(logger, RAW|LEVEL1, "  '%d.%d.%d.%d'", 
+                                                       *object.ptr, *(object.ptr+1),
+                                                       *(object.ptr+2), *(object.ptr+3));
+                               valid_gn = TRUE;
+                               break;
+                       case GN_OBJ_OTHER_NAME:
+                               if (!parse_otherName(object, level + 1))
+                                       return NULL;
+                               break;
+                       case GN_OBJ_X400_ADDRESS:
+                       case GN_OBJ_EDI_PARTY_NAME:
+                       case GN_OBJ_REGISTERED_ID:
+                               break;
+                       default:
+                               break;
+               }
+
+               if (valid_gn)
+               {
+                       generalName_t *gn = malloc_thing(generalName_t);
+                       gn->kind = (objectID - GN_OBJ_OTHER_NAME) / 2;
+                       gn->name = object;
+                       gn->next = NULL;
+                       return gn;
+               }
+               objectID++;
+       }
+       return NULL;
+}
+
+/**
+ * extracts one or several GNs and puts them into a chained list
+ */
+static generalName_t* parse_generalNames(chunk_t blob, int level0, bool implicit)
+{
+       asn1_ctx_t ctx;
+       chunk_t object;
+       u_int level;
+       int objectID = 0;
+
+       generalName_t *top_gn = NULL;
+
+       asn1_init(&ctx, blob, level0, implicit);
+
+       while (objectID < GENERAL_NAMES_ROOF)
+       {
+               if (!extract_object(generalNamesObjects, &objectID, &object, &level, &ctx))
+                       return NULL;
+               
+               if (objectID == GENERAL_NAMES_GN)
+               {
+                       generalName_t *gn = parse_generalName(object, level+1);
+                       if (gn != NULL)
+                       {
+                               gn->next = top_gn;
+                               top_gn = gn;
+                       }
+               }
+               objectID++;
+       }
+       return top_gn;
+}
+
+/**
+ * returns a directoryName
+ */
+chunk_t get_directoryName(chunk_t blob, int level, bool implicit)
+{
+       chunk_t name = CHUNK_INITIALIZER;
+       generalName_t * gn = parse_generalNames(blob, level, implicit);
+
+       if (gn != NULL && gn->kind == GN_DIRECTORY_NAME)
+       {
+               name= gn->name;
+       }
+
+       free_generalNames(gn, FALSE);
+
+       return name;
+}
+
+/**
+ * extracts and converts a UTCTIME or GENERALIZEDTIME object
+ */
+time_t parse_time(chunk_t blob, int level0)
+{
+       asn1_ctx_t ctx;
+       chunk_t object;
+       u_int level;
+       int objectID = 0;
+       
+       asn1_init(&ctx, blob, level0, FALSE);
+       
+       while (objectID < TIME_ROOF)
+       {
+               if (!extract_object(timeObjects, &objectID, &object, &level, &ctx))
+                       return 0;
+               
+               if (objectID == TIME_UTC || objectID == TIME_GENERALIZED)
+               {
+                       return asn1totime(&object, (objectID == TIME_UTC)
+                                       ? ASN1_UTCTIME : ASN1_GENERALIZEDTIME);
+               }
+               objectID++;
+       }
+       return 0;
+}
+
+/**
+ * extracts a keyIdentifier
+ */
+static chunk_t parse_keyIdentifier(chunk_t blob, int level0, bool implicit)
+{
+       asn1_ctx_t ctx;
+       chunk_t object;
+       u_int level;
+       int objectID = 0;
+       
+       asn1_init(&ctx, blob, level0, implicit);
+       
+       extract_object(keyIdentifierObjects, &objectID, &object, &level, &ctx);
+       return object;
+}
+
+/**
+ * extracts an authoritykeyIdentifier
+ */
+void parse_authorityKeyIdentifier(chunk_t blob, int level0 , chunk_t *authKeyID, chunk_t *authKeySerialNumber)
+{
+       asn1_ctx_t ctx;
+       chunk_t object;
+       u_int level;
+       int objectID = 0;
+       
+       asn1_init(&ctx, blob, level0, FALSE);
+       while (objectID < AUTH_KEY_ID_ROOF)
+       {
+               if (!extract_object(authorityKeyIdentifierObjects, &objectID, &object, &level, &ctx))
+               {
+                       return;
+               }
+               switch (objectID) 
+               {
+                       case AUTH_KEY_ID_KEY_ID:
+                               *authKeyID = parse_keyIdentifier(object, level+1, TRUE);
+                               break;
+                       case AUTH_KEY_ID_CERT_ISSUER:
+                       {
+                               generalName_t *gn = parse_generalNames(object, level+1, TRUE);
+                               free_generalNames(gn, FALSE);
+                               break;
+                       }
+                       case AUTH_KEY_ID_CERT_SERIAL:
+                               *authKeySerialNumber = object;
+                               break;
+                       default:
+                               break;
+               }
+               objectID++;
+       }
+}
+
+/**
+ * extracts an authorityInfoAcess location
+ */
+static void parse_authorityInfoAccess(chunk_t blob, int level0, chunk_t *accessLocation)
+{
+       asn1_ctx_t ctx;
+       chunk_t object;
+       u_int level;
+       int objectID = 0;
+       
+       u_int accessMethod = OID_UNKNOWN;
+       
+       asn1_init(&ctx, blob, level0, FALSE);
+       while (objectID < AUTH_INFO_ACCESS_ROOF)
+       {
+               if (!extract_object(authorityInfoAccessObjects, &objectID, &object, &level, &ctx))
+               {
+                       return;
+               }
+               switch (objectID) 
+               {
+                       case AUTH_INFO_ACCESS_METHOD:
+                               accessMethod = known_oid(object);
+                               break;
+                       case AUTH_INFO_ACCESS_LOCATION:
+                       {
+                               switch (accessMethod)
+                               {
+                                       case OID_OCSP:
+                                               if (*object.ptr == ASN1_CONTEXT_S_6)
+                                               {
+                                                       if (asn1_length(&object) == ASN1_INVALID_LENGTH)
+                                                       {
+                                                               return;
+                                                       }
+                                                       logger->log(logger, RAW|LEVEL1, "  '%.*s'",(int)object.len, object.ptr);
+                                                       /* only HTTP(S) URIs accepted */
+                                                       if (strncasecmp(object.ptr, "http", 4) == 0)
+                                                       {
+                                                               *accessLocation = object;
+                                                               return;
+                                                       }
+                                               }
+                                               logger->log(logger, ERROR|LEVEL2, "ignoring OCSP InfoAccessLocation with unkown protocol");
+                                               break;
+                                       default:
+                                               /* unkown accessMethod, ignoring */
+                                               break;
+                               }
+                               break;
+                       }
+                       default:
+                               break;
+               }
+               objectID++;
+       }
+}
+
+/**
+ * extracts extendedKeyUsage OIDs
+ */
+static bool parse_extendedKeyUsage(chunk_t blob, int level0)
+{
+       asn1_ctx_t ctx;
+       chunk_t object;
+       u_int level;
+       int objectID = 0;
+       
+       asn1_init(&ctx, blob, level0, FALSE);
+       while (objectID < EXT_KEY_USAGE_ROOF)
+       {
+               if (!extract_object(extendedKeyUsageObjects, &objectID, &object, &level, &ctx))
+               {
+                       return FALSE;
+               }
+               if (objectID == EXT_KEY_USAGE_PURPOSE_ID && 
+                       known_oid(object) == OID_OCSP_SIGNING)
+               {
+                       return TRUE;
+               }
+               objectID++;
+       }
+       return FALSE;
+}
+
+/**
+ * extracts one or several crlDistributionPoints and puts them into
+ * a chained list
+ */
+static generalName_t* parse_crlDistributionPoints(chunk_t blob, int level0)
+{
+       asn1_ctx_t ctx;
+       chunk_t object;
+       u_int level;
+       int objectID = 0;
+       
+       generalName_t *top_gn = NULL;      /* top of the chained list */
+       generalName_t **tail_gn = &top_gn; /* tail of the chained list */
+       
+       asn1_init(&ctx, blob, level0, FALSE);
+       while (objectID < CRL_DIST_POINTS_ROOF)
+       {
+               if (!extract_object(crlDistributionPointsObjects, &objectID, &object, &level, &ctx))
+               {
+                       return NULL;
+               }
+               if (objectID == CRL_DIST_POINTS_FULLNAME)
+               {
+                       generalName_t *gn = parse_generalNames(object, level+1, TRUE);
+                       /* append extracted generalNames to existing chained list */
+                       *tail_gn = gn;
+                       /* find new tail of the chained list */
+                       while (gn != NULL)
+                       {
+                               tail_gn = &gn->next;  gn = gn->next;
+                       }
+               }
+               objectID++;
+       }
+       return top_gn;
+}
+
+
+/**
+ * Parses an X.509v3 x509
+ */
+bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert)
+{
+       u_char buf[BUF_LEN];
+       asn1_ctx_t ctx;
+       bool critical;
+       chunk_t object;
+       u_int level;
+       u_int extn_oid = OID_UNKNOWN;
+       int objectID = 0;
+       
+       asn1_init(&ctx, blob, level0, FALSE);
+       while (objectID < X509_OBJ_ROOF)
+       {
+               if (!extract_object(certObjects, &objectID, &object, &level, &ctx))
+               {
+                       return FALSE;
+               }
+               /* those objects which will parsed further need the next higher level */
+               level++;
+               switch (objectID) {
+                       case X509_OBJ_CERTIFICATE:
+                               cert->x509 = object;
+                               break;
+                       case X509_OBJ_TBS_CERTIFICATE:
+                               cert->tbsCertificate = object;
+                               break;
+                       case X509_OBJ_VERSION:
+                               cert->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
+                               logger->log(logger, RAW|LEVEL1, "  v%d", cert->version);
+                               break;
+                       case X509_OBJ_SERIAL_NUMBER:
+                               cert->serialNumber = object;
+                               break;
+                       case X509_OBJ_SIG_ALG:
+                               cert->sigAlg = parse_algorithmIdentifier(object, level, NULL);
+                               break;
+                       case X509_OBJ_ISSUER:
+                               cert->issuer = object;
+                               dntoa(buf, BUF_LEN, object);
+                               logger->log(logger, RAW|LEVEL1, "  '%s'", buf);
+                               break;
+                       case X509_OBJ_NOT_BEFORE:
+                               cert->notBefore = parse_time(object, level);
+                               break;
+                       case X509_OBJ_NOT_AFTER:
+                               cert->notAfter = parse_time(object, level);
+                               break;
+                       case X509_OBJ_SUBJECT:
+                               cert->subject = object;
+                               dntoa(buf, BUF_LEN, object);
+                               logger->log(logger, RAW|LEVEL1, "  '%s'", buf);
+                               break;
+                       case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM:
+                               if (parse_algorithmIdentifier(object, level, NULL) == OID_RSA_ENCRYPTION)
+                               {
+                                       cert->subjectPublicKeyAlgorithm = RSA_DIGITAL_SIGNATURE;
+                               }
+                               else
+                               {
+                                       logger->log(logger, ERROR|LEVEL1, "  unsupported public key algorithm");
+                                       return FALSE;
+                               }
+                               break;
+                       case X509_OBJ_SUBJECT_PUBLIC_KEY:
+                               if (ctx.blobs[4].len > 0 && *ctx.blobs[4].ptr == 0x00)
+                               {
+                                       /* skip initial bit string octet defining 0 unused bits */
+                                       ctx.blobs[4].ptr++; ctx.blobs[4].len--;
+                               }
+                               else
+                               {
+                                       logger->log(logger, ERROR|LEVEL1, "  invalid RSA public key format");
+                                       return FALSE;
+                               }
+                               break;
+                       case X509_OBJ_RSA_PUBLIC_KEY:
+                               cert->subjectPublicKey = object;
+                               break;
+                       case X509_OBJ_EXTN_ID:
+                               extn_oid = known_oid(object);
+                               break;
+                       case X509_OBJ_CRITICAL:
+                               critical = object.len && *object.ptr;
+                               logger->log(logger, ERROR|LEVEL1, "  %s", critical ? "TRUE" : "FALSE");
+                               break;
+                       case X509_OBJ_EXTN_VALUE:
+                       {
+                               switch (extn_oid) {
+                                       case OID_SUBJECT_KEY_ID:
+                                               cert->subjectKeyID = parse_keyIdentifier(object, level, FALSE);
+                                               break;
+                                       case OID_SUBJECT_ALT_NAME:
+                                               cert->subjectAltName = parse_generalNames(object, level, FALSE);
+                                               break;
+                                       case OID_BASIC_CONSTRAINTS:
+                                               cert->isCA = parse_basicConstraints(object, level);
+                                               break;
+                                       case OID_CRL_DISTRIBUTION_POINTS:
+                                               cert->crlDistributionPoints = parse_crlDistributionPoints(object, level);
+                                               break;
+                                       case OID_AUTHORITY_KEY_ID:
+                                               parse_authorityKeyIdentifier(object, level , &cert->authKeyID, &cert->authKeySerialNumber);
+                                               break;
+                                       case OID_AUTHORITY_INFO_ACCESS:
+                                               parse_authorityInfoAccess(object, level, &cert->accessLocation);
+                                               break;
+                                       case OID_EXTENDED_KEY_USAGE:
+                                               cert->isOcspSigner = parse_extendedKeyUsage(object, level);
+                                               break;
+                                       case OID_NS_REVOCATION_URL:
+                                       case OID_NS_CA_REVOCATION_URL:
+                                       case OID_NS_CA_POLICY_URL:
+                                       case OID_NS_COMMENT:
+                                               if (!parse_asn1_simple_object(&object, ASN1_IA5STRING , level, oid_names[extn_oid].name))
+                                               {
+                                                       return FALSE;
+                                               }
+                                               break;
+                                       default:
+                                               break;
+                               }
+                               break;
+                       }
+                       case X509_OBJ_ALGORITHM:
+                               cert->algorithm = parse_algorithmIdentifier(object, level, NULL);
+                               break;
+                       case X509_OBJ_SIGNATURE:
+                               cert->signature = object;
+                               break;
+                       default:
+                               break;
+               }
+               objectID++;
+       }
+       time(&cert->installed);
+       return TRUE;
+}
+
+/**
+ * verify the validity of a x509 by
+ * checking the notBefore and notAfter dates
+ */
+err_t check_validity(const private_x509_t *cert, time_t *until)
+{
+       time_t current_time;
+       
+       time(&current_time);
+       
+       if (cert->notAfter < *until) 
+       {
+               *until = cert->notAfter;
+       }
+       if (current_time < cert->notBefore)
+       {
+               return "x509 is not valid yet";
+       }
+       if (current_time > cert->notAfter)
+       {
+               return "x509 has expired";
+       }
+       else
+       {
+               return NULL;
+       }
+}
+
+static rsa_public_key_t *get_public_key(private_x509_t *this)
+{
+       return this->public_key->clone(this->public_key);;
+}
+
+/**
+ * destroy
+ */
+static void destroy(private_x509_t *this)
+{
+       free_generalNames(this->subjectAltName, FALSE);
+       free_generalNames(this->crlDistributionPoints, FALSE);
+       if (this->public_key)
+       {
+               this->public_key->destroy(this->public_key);
+       }
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+x509_t *x509_create_from_chunk(chunk_t chunk)
+{
+       private_x509_t *this = malloc_thing(private_x509_t);
+       
+       /* public functions */
+       this->public.equals = (bool (*) (x509_t*,x509_t*))equals;
+       this->public.destroy = (void (*) (x509_t*))destroy;
+       this->public.get_public_key = (rsa_public_key_t* (*) (x509_t*))get_public_key;
+       
+       /* initialize */
+       this->subjectPublicKey = CHUNK_INITIALIZER;
+       this->public_key = NULL;
+       this->subjectAltName = NULL;
+       this->crlDistributionPoints = NULL;
+       
+       if (!parse_x509cert(chunk, 0, this))
+       {
+               destroy(this);
+               return NULL;
+       }
+       
+       this->public_key = rsa_public_key_create_from_chunk(this->subjectPublicKey);
+       if (this->public_key == NULL)
+       {
+               destroy(this);
+               return NULL;
+       }
+       
+       return &this->public;
+}
+
+/*
+ * Described in header.
+ */
+x509_t *x509_create_from_file(char *filename)
+{
+       struct stat stb;
+       FILE *file;
+       char *buffer;
+       chunk_t chunk;
+       
+       if (stat(filename, &stb) == -1)
+       {
+               return NULL;
+       }
+       
+       buffer = alloca(stb.st_size);
+       
+       file = fopen(filename, "r");
+       if (file == NULL)
+       {
+               return NULL;
+       }
+       
+       if (fread(buffer, stb.st_size, 1, file) == -1) 
+       {
+               fclose(file);
+               return NULL;
+       }
+       fclose(file);
+       
+       chunk.ptr = buffer;
+       chunk.len = stb.st_size;
+       
+       return x509_create_from_chunk(chunk);
+}
diff --git a/Source/lib/crypto/x509.h b/Source/lib/crypto/x509.h
new file mode 100755 (executable)
index 0000000..cd2f08e
--- /dev/null
@@ -0,0 +1,128 @@
+/**
+ * @file x509.h
+ * 
+ * @brief Interface of x509_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * 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 X509_H_
+#define X509_H_
+
+#include <types.h>
+#include <definitions.h>
+#include <crypto/rsa/rsa_public_key.h>
+#include <utils/identification.h>
+#include <utils/iterator.h>
+
+
+typedef struct x509_t x509_t;
+
+/**
+ * @brief X509 certificate.
+ * 
+ * @b Constructors:
+ *  - x509_create_from_chunk()
+ *  - x509_create_from_file()
+ * 
+ * @todo more code cleanup needed!
+ * @todo fix unimplemented functions...
+ * @todo handle memory management
+ *
+ * @ingroup transforms
+ */
+struct x509_t {
+
+       /**
+        * @brief Get the RSA public key from the certificate.
+        * 
+        * @param this                          calling object
+        * @return                                      public_key
+        */
+       rsa_public_key_t *(*get_public_key) (x509_t *this);
+               
+       /**
+        * @brief Get the certificate issuers ID.
+        * 
+        * @todo implement!
+        */
+       identification_t *(*get_issuer) (x509_t *this);
+               
+       /**
+        * @brief Get the subjects ID.
+        * 
+        * @todo implement!
+        */
+       identification_t *(*get_subject) (x509_t *this);
+       
+       /**
+        * @brief Check if a certificate is valid.
+        * 
+        * This function uses the issuers public key to verify 
+        * the validity of a certificate.
+        * 
+        * @todo implement!
+        */
+       bool (*verify) (x509_t *this, rsa_public_key_t *signer);
+       
+       /**
+        * @brief Get the key identifier of the public key.
+        * 
+        * @todo implement!
+        */
+       chunk_t (*get_subject_key_identifier) (x509_t *this);
+       
+       /**
+        * @brief Compare two certificates.
+        * 
+        * Comparison is done via the certificates signature.
+        * 
+        * @param this                  first cert for compare
+        * @param other                 second cert for compare
+        * @return                              TRUE if signature is equal
+        */
+       bool (*equals) (x509_t *this, x509_t *other);
+       
+       /**
+        * @brief Destroys the certificate.
+        * 
+        * @param this                  certificate to destroy
+        */
+       void (*destroy) (x509_t *this);
+};
+
+/**
+ * @brief Read a x509 certificate from a DER encoded blob.
+ * 
+ * @param chunk        chunk containing DER encoded data
+ * @return                     created x509_t certificate, or NULL if invalid.
+ * 
+ * @ingroup transforms
+ */
+x509_t *x509_create_from_chunk(chunk_t chunk);
+
+/**
+ * @brief Read a x509 certificate from a DER encoded file.
+ * 
+ * @param filename     file containing DER encoded data
+ * @return                     created x509_t certificate, or NULL if invalid.
+ * 
+ * @ingroup transforms
+ */
+x509_t *x509_create_from_file(char *filename);
+
+#endif /* X509_H_ */
index 22f29df..09ebf73 100644 (file)
@@ -87,13 +87,25 @@ chunk_t chunk_alloc(size_t bytes)
        return new_chunk;
 }
 
+/**
+ * Described in header.
+ */
+bool chunk_equals(chunk_t a, chunk_t b)
+{
+       if (a.ptr == NULL || b.ptr == NULL ||
+               a.len != b.len ||
+               memcmp(a.ptr, b.ptr, a.len) != 0)
+       {
+               return FALSE;
+       }
+       return TRUE;
+}
 
 /**
  * Described in header.
  */
 void *clalloc(void * pointer, size_t size)
 {
-       
        void *data;
        data = malloc(size);
        
index d75d673..7125a01 100644 (file)
 #include <definitions.h>
 
 
+/**
+ * General purpose boolean type.
+ */
+typedef int bool;
+#define FALSE  0
+#define TRUE   1
+
 typedef enum status_t status_t;
 
 /**
@@ -166,16 +173,15 @@ void chunk_free(chunk_t *chunk);
 chunk_t chunk_alloc(size_t bytes);
 
 /**
- * Clone a data to a newly allocated buffer
+ * Compare two chunks for equality,
+ * NULL chunks are never equal.
  */
-void *clalloc(void *pointer, size_t size);
-
+bool chunk_equals(chunk_t a, chunk_t b);
 
 /**
- * General purpose boolean type.
+ * Clone a data to a newly allocated buffer
  */
-typedef int bool;
-#define FALSE  0
-#define TRUE   1
+void *clalloc(void *pointer, size_t size);
+
 
 #endif /*TYPES_H_*/
index 9a450de..2a0dbf2 100644 (file)
@@ -130,15 +130,10 @@ TEST_OBJS+= $(BUILD_DIR)child_sa_test.o
 $(BUILD_DIR)child_sa_test.o :          $(TESTCASES_DIR)child_sa_test.c $(TESTCASES_DIR)child_sa_test.h
                                                                        $(CC) $(CFLAGS) -c -o $@ $<
 
-TEST_OBJS+= $(BUILD_DIR)der_decoder_test.o
-$(BUILD_DIR)der_decoder_test.o :       $(TESTCASES_DIR)der_decoder_test.c $(TESTCASES_DIR)der_decoder_test.h
-                                                                       $(CC) $(CFLAGS) -c -o $@ $<
-
 TEST_OBJS+= $(BUILD_DIR)certificate_test.o
 $(BUILD_DIR)certificate_test.o :       $(TESTCASES_DIR)certificate_test.c $(TESTCASES_DIR)certificate_test.h
                                                                        $(CC) $(CFLAGS) -c -o $@ $<
 
 TEST_OBJS+= $(BUILD_DIR)leak_detective_test.o
 $(BUILD_DIR)leak_detective_test.o :    $(TESTCASES_DIR)leak_detective_test.c $(TESTCASES_DIR)leak_detective_test.h
-                                                                       $(CC) $(CFLAGS) -c -o $@ $<
-                                                                       
\ No newline at end of file
+                                                                       $(CC) $(CFLAGS) -c -o $@ $<
\ No newline at end of file
index 24143ae..025893c 100644 (file)
@@ -86,7 +86,7 @@ void test_certificate(protected_tester_t *tester)
 {
        chunk_t certificate = {certificate_buffer, sizeof(certificate_buffer)};
        
-       certificate_t *cert = certificate_create_from_chunk(certificate);
+       x509_t *cert = x509_create_from_chunk(certificate);
        
        //certificate_t *cert = certificate_create_from_file("myCert.der");
        
diff --git a/Source/testing/der_decoder_test.c b/Source/testing/der_decoder_test.c
deleted file mode 100644 (file)
index fc07cc1..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- * @file der_decoder_test.c
- *
- * @brief Tests for the der_decoder_t class.
- *
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * 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 "der_decoder_test.h"
-
-#include <daemon.h>
-#include <asn1/der_decoder.h>
-#include <utils/logger.h>
-
-
-
-static char private_key_buffer[] = {
-       0x30,0x82,0x04,0xa2,0x02,0x00,0x02,0x82,0x01,0x01,0x00,0x9b,0x28,0x10,0x02,0xd2,
-       0x43,0x5b,0x2b,0x7c,0x81,0xce,0x2b,0x77,0xb4,0xbf,0x5f,0x2a,0x9a,0x96,0xc9,0xa4,
-       0xd7,0xbb,0xb3,0xfb,0xc1,0x8a,0xad,0xbe,0x21,0x4e,0xd7,0x15,0xc4,0x8c,0x0a,0x88,
-       0x5b,0x02,0xa9,0xcd,0x2e,0xee,0xd3,0x5e,0xb9,0xfd,0x27,0x0b,0xdb,0xf6,0xe7,0xb7,
-       0x39,0xc1,0xfa,0x34,0x3f,0xa7,0xe4,0x04,0xaf,0xa8,0xc2,0x36,0x4e,0xf5,0x0c,0xf1,
-       0x9b,0x92,0x26,0x32,0x20,0xdb,0x04,0xf5,0xb8,0x2e,0xf5,0xfc,0x47,0xd3,0x2a,0xa1,
-       0x2d,0x5b,0x68,0x2c,0x5e,0xc6,0xc9,0x35,0x57,0x7b,0x65,0x17,0xd7,0x5d,0x10,0x5c,
-       0x51,0xfb,0xcb,0x95,0xd1,0x17,0x42,0xa9,0xfd,0xd1,0xc4,0x32,0x1f,0x13,0xf2,0xeb,
-       0x6b,0x91,0x01,0xe9,0x89,0x19,0x3a,0x2b,0x6d,0xae,0x91,0x27,0xe2,0x5e,0x06,0x5b,
-       0x99,0xfb,0x20,0x3c,0xc4,0x92,0x20,0xc4,0x68,0x24,0x6b,0x74,0xdc,0x6d,0xf7,0xa8,
-       0x10,0x1b,0xdf,0x20,0xed,0x4e,0x90,0x0e,0x3d,0xf6,0xef,0x3a,0x94,0x8b,0x12,0x61,
-       0xac,0xed,0x95,0xbc,0xe2,0xed,0xb9,0x22,0xc2,0xdd,0xc7,0x19,0x68,0x09,0x14,0x71,
-       0xb0,0x37,0xf7,0xbd,0x65,0x11,0x31,0x9d,0x89,0x6e,0x21,0xcf,0x60,0xc1,0x8d,0xbe,
-       0x31,0x96,0xd2,0xdd,0x0e,0x20,0x38,0x07,0xd5,0xea,0xda,0xc8,0x9a,0x47,0x5b,0x05,
-       0xce,0x7d,0xf7,0x4e,0xcd,0xbb,0x89,0xdd,0x46,0x16,0x8f,0x39,0x9d,0x32,0x19,0xaf,
-       0x6e,0xc4,0xb3,0x6c,0x79,0x5a,0x70,0x11,0x8f,0xe2,0x75,0x33,0x09,0xc8,0xf6,0xd7,
-       0x40,0x25,0xe7,0xa3,0xf0,0x6f,0x9a,0xdb,0x35,0x74,0xc1,0x02,0x03,0x01,0x00,0x01,
-       0x02,0x82,0x01,0x00,0x12,0x42,0x38,0x58,0x21,0xfc,0x51,0x34,0xa0,0x8b,0x4f,0x58,
-       0x28,0x2c,0x7a,0x14,0xd8,0x98,0xfb,0xee,0x5b,0x85,0x69,0x0e,0x63,0x83,0x16,0xd9,
-       0xc9,0x5f,0xcc,0x12,0x5d,0xa5,0x15,0x41,0xd6,0xb8,0x0c,0x6b,0xda,0x67,0x3a,0x83,
-       0x09,0xf3,0xb8,0x89,0xd4,0x1d,0xc7,0x99,0x8f,0x23,0x59,0xe3,0x78,0x2b,0x41,0x8b,
-       0xab,0x78,0x2c,0x7e,0x3b,0xbb,0xe0,0xf4,0x96,0xa8,0xd3,0x1d,0xc6,0xea,0x67,0x91,
-       0x2c,0x30,0x1c,0xe9,0x4f,0xb8,0xa2,0xc3,0x5d,0x2c,0xf9,0x99,0x1c,0x6c,0xee,0xd7,
-       0x16,0x28,0x3c,0x5a,0x32,0x35,0xb8,0x3a,0xf3,0xa7,0xa6,0x35,0x02,0xba,0xbf,0x67,
-       0xab,0x44,0xe1,0x09,0x9b,0x48,0x5d,0xa5,0x9e,0xf4,0xb7,0xf4,0xd1,0xfc,0x68,0x9e,
-       0x98,0x26,0x69,0x28,0xcc,0x19,0x75,0xf2,0x61,0x0e,0x23,0xeb,0xf9,0x6d,0x2c,0x2b,
-       0x01,0x3f,0x4d,0x18,0x41,0xc5,0x31,0x9d,0x1c,0x20,0x81,0x4e,0x38,0x92,0xd5,0xbb,
-       0xd7,0xe7,0x49,0x0c,0x3a,0xf3,0x8f,0x9e,0xf0,0xb3,0x32,0x1e,0xa7,0x77,0xe8,0x9c,
-       0xf3,0xce,0x88,0x66,0xcc,0xe8,0x16,0xbb,0xfd,0xbc,0x62,0xc7,0xc3,0xeb,0x0a,0xf5,
-       0xd8,0x53,0x02,0x6c,0x45,0xcb,0x1d,0xa3,0x96,0xfb,0xa5,0x26,0x18,0x7f,0x04,0x9f,
-       0x80,0x4a,0xdb,0x3b,0x74,0xcf,0x0d,0x45,0xf4,0xd5,0x49,0xe9,0x27,0x54,0x9c,0x57,
-       0x92,0x48,0x78,0x52,0xb6,0x40,0x89,0x3f,0xf3,0x95,0x06,0x3d,0x90,0xab,0xa0,0x8a,
-       0xc7,0x54,0xf1,0x63,0xcf,0xa6,0xd2,0x83,0x1e,0x69,0x54,0xe0,0x77,0x2c,0x9e,0x3a,
-       0x4f,0xdd,0x14,0x6d,0x02,0x81,0x81,0x00,0xd9,0x40,0x76,0x90,0x7c,0xe7,0x3b,0xa3,
-       0x59,0x23,0x14,0x6b,0xf3,0x5f,0x6e,0x6b,0x82,0x34,0xf6,0xbd,0x3e,0xfb,0x65,0xac,
-       0x2f,0x46,0xd5,0x6e,0x9b,0xb8,0x62,0x80,0xc3,0x0c,0xa9,0xa6,0x00,0xd6,0xb8,0x1c,
-       0x12,0x8d,0x4d,0xd0,0x64,0x29,0x4c,0xac,0x38,0xe8,0x6c,0xe4,0x82,0x02,0x4e,0x10,
-       0xd5,0x39,0x19,0x29,0x0c,0x58,0x3f,0x68,0xa0,0x11,0x0e,0x11,0x74,0x22,0x2b,0x7e,
-       0xc2,0xa7,0x88,0xe3,0x33,0xe8,0xb4,0x50,0x6e,0x0c,0x54,0xc5,0x3f,0xb7,0x16,0xcb,
-       0x39,0xed,0x23,0xd0,0x66,0x26,0x57,0xf9,0xcb,0xc9,0xac,0xe2,0xa4,0xb8,0xba,0xd8,
-       0xd2,0x1f,0x4a,0xed,0x73,0x89,0xda,0x42,0x27,0x5a,0x26,0x30,0x33,0xc8,0x42,0x2a,
-       0x3d,0xc5,0xf3,0xc2,0x29,0x3d,0x58,0x67,0x02,0x81,0x81,0x00,0xb6,0xd4,0x61,0x05,
-       0x49,0xcb,0xf4,0x29,0x8a,0x22,0xd3,0xa3,0x7c,0x9c,0xd2,0x07,0xa4,0x66,0xe4,0x36,
-       0xfa,0x5e,0xf6,0x64,0xb7,0x59,0x74,0x2f,0x36,0x6d,0x12,0xd0,0xc9,0x4d,0xf8,0xd1,
-       0xba,0xd1,0xee,0xd2,0x78,0xcd,0x51,0x69,0x33,0x6a,0x03,0xff,0xc2,0x35,0x1d,0x0d,
-       0x9c,0x0a,0x87,0x5e,0x09,0xa3,0x23,0x4c,0xab,0xc3,0x4c,0x4a,0x1c,0xa4,0xc5,0xe2,
-       0x70,0x42,0x1c,0xcf,0xea,0x79,0xfb,0xb9,0x87,0x67,0x4d,0xc3,0xfc,0xcc,0x86,0x9d,
-       0xfa,0xea,0x99,0xa5,0x1b,0xc1,0x96,0xf4,0x79,0x4d,0x66,0x12,0x8f,0x90,0x98,0xb4,
-       0xa1,0x3b,0xd6,0x2f,0x64,0xb4,0x5f,0x8f,0x47,0x7f,0x43,0xa5,0x6d,0xeb,0x06,0x58,
-       0xfb,0x04,0x9e,0xef,0xaf,0x88,0x35,0x88,0xa1,0x15,0x30,0x97,0x02,0x81,0x80,0x59,
-       0xbe,0xe0,0x7b,0xc5,0xad,0x3c,0x1c,0xb9,0x98,0xdd,0x39,0xce,0xfa,0xd0,0x41,0x87,
-       0x33,0x5b,0xee,0x47,0x93,0x50,0xa7,0xf5,0x8b,0xbc,0x65,0x89,0xdc,0x7c,0x8c,0x96,
-       0x86,0xa7,0x9a,0x54,0xe4,0x5e,0x7f,0xf2,0x45,0xff,0x2c,0x24,0x04,0x4f,0x91,0x21,
-       0x9d,0x1a,0x46,0xb7,0x52,0x3e,0x6f,0x83,0xb5,0xa7,0xa8,0x26,0x5a,0x5a,0x2f,0x5d,
-       0x58,0x4e,0x48,0x75,0x82,0x1c,0x17,0xac,0x4f,0xcb,0x23,0x98,0x70,0xfb,0xf3,0xf1,
-       0xd2,0x14,0x3e,0xbb,0x98,0x65,0xc9,0x24,0x2f,0xcb,0x48,0xae,0xba,0x0e,0x43,0xb9,
-       0xa4,0xa1,0x4f,0xab,0x1e,0x48,0xc9,0x82,0xdb,0xbc,0x77,0x24,0xf0,0x80,0x82,0x2d,
-       0x81,0x77,0x1f,0x18,0x75,0x14,0xa8,0x20,0x86,0xa2,0xb0,0xc5,0x9a,0x7a,0xe7,0x02,
-       0x81,0x80,0x1b,0x6d,0xb1,0x40,0x81,0xd9,0xbf,0x3f,0x9c,0x21,0xad,0x6e,0x91,0x7b,
-       0x55,0x67,0x20,0x1a,0xef,0x91,0xef,0xed,0xdf,0x39,0x2c,0xe8,0x96,0xad,0x9e,0x94,
-       0xae,0x85,0xf4,0x2d,0x66,0x6e,0xd0,0x80,0x3e,0x3c,0x05,0x33,0x88,0x4b,0x28,0x13,
-       0x77,0x96,0x1f,0x24,0xa8,0xbf,0x29,0xf1,0xca,0x6d,0x29,0x34,0xf8,0x4e,0xc0,0x56,
-       0x04,0x53,0xfa,0x08,0x1e,0x47,0xe2,0x5f,0x88,0xc3,0x08,0x82,0x54,0x69,0x79,0x0e,
-       0xde,0x73,0xd0,0xb1,0x3e,0x60,0xe5,0x0b,0xdd,0x11,0x10,0x20,0xf2,0xec,0xaa,0x66,
-       0x1a,0x32,0x1e,0xa7,0xaa,0xc1,0x2e,0x8f,0x33,0x8a,0xd8,0xa8,0xd6,0xcd,0x40,0x04,
-       0xaf,0xb9,0x59,0xcc,0x30,0x9f,0x98,0xc9,0x10,0xaf,0x14,0xbe,0x72,0x89,0x94,0xe1,
-       0x00,0xf1,0x02,0x81,0x81,0x00,0xd6,0xac,0x26,0xd2,0x42,0x5b,0x16,0xa9,0x39,0x02,
-       0x63,0x76,0xa4,0xf5,0x40,0x3a,0xde,0xfa,0xea,0xd8,0xd3,0x12,0xee,0x44,0x00,0xfe,
-       0xcb,0xa1,0x78,0x18,0xaa,0xa7,0x08,0xea,0x5e,0x36,0x52,0x28,0x0d,0x02,0x5a,0x9e,
-       0x2d,0xc1,0x22,0x29,0x08,0x4f,0xed,0xff,0xa9,0xa6,0x08,0x8d,0x77,0xa4,0x5c,0xae,
-       0xa7,0x8a,0x19,0x90,0xc2,0x12,0xc8,0x0f,0xb8,0x24,0xb5,0xba,0x45,0x2f,0xa6,0xc2,
-       0x10,0x4c,0x0d,0x7e,0xf2,0xfd,0x11,0x26,0x16,0x34,0xbe,0x08,0x25,0x41,0x8b,0xcc,
-       0x60,0xe7,0x02,0x3e,0x6a,0x54,0x05,0x80,0x66,0x2d,0x55,0x06,0xe6,0xbe,0x9b,0x15,
-       0x9d,0xd3,0x5d,0xc4,0x6b,0x3f,0x74,0xa6,0x24,0xbc,0x7f,0x13,0xdf,0xe3,0x51,0x86,
-       0x64,0x0f,0x1d,0x1f,0xf2,0x1e,
-};
-
-asn1_rule_t private_key_rules[] = {
-       {ASN1_SEQUENCE, 0, 0, 0},
-       {       ASN1_INTEGER, 0,                0, 0},
-       {       ASN1_INTEGER, ASN1_MPZ, 0, 0},
-       {       ASN1_INTEGER, ASN1_MPZ, 0, 0},
-       {       ASN1_INTEGER, ASN1_MPZ, 0, 0},
-       {       ASN1_INTEGER, ASN1_MPZ, 0, 0},
-       {       ASN1_INTEGER, ASN1_MPZ, 0, 0},
-       {       ASN1_INTEGER, ASN1_MPZ, 0, 0},
-       {       ASN1_INTEGER, ASN1_MPZ, 0, 0},
-       {       ASN1_INTEGER, ASN1_MPZ, 0, 0},
-       {ASN1_END, 0, 0, 0},
-};
-
-/**
- * Described in header.
- */
-void test_der_decoder(protected_tester_t *tester)
-{
-       chunk_t private_key = {private_key_buffer, sizeof(private_key_buffer)};
-       
-       der_decoder_t *dd = der_decoder_create(private_key_rules);
-       
-       dd->decode(dd, private_key, NULL);
-       
-       dd->destroy(dd);
-       
-}
-
-
-
diff --git a/Source/testing/der_decoder_test.h b/Source/testing/der_decoder_test.h
deleted file mode 100644 (file)
index e7a7b7b..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * @file der_decoder_test.h
- *
- * @brief Tests for the der_decoder_t class.
- *
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * 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 DER_DECODER_TEST_H_
-#define DER_DECODER_TEST_H_
-
-#include <utils/tester.h>
-
-/**
- * @brief Test function used to test the der_decoder_t functionality.
- *
- * @param tester associated protected_tester_t object
- * 
- * @ingroup testcases
- */
-void test_der_decoder(protected_tester_t *tester);
-
-#endif /* DER_DECODER_TEST_H_ */
-
-
-
-
index e0c601e..a3ab3e4 100644 (file)
@@ -137,7 +137,7 @@ void test_rsa(protected_tester_t *tester)
 {
        rsa_private_key_t *private_key;
        rsa_public_key_t *public_key;
-       certificate_t *certificate;
+       x509_t *certificate;
        chunk_t data, signature;
        chunk_t der_private_key = {private_key_buffer, sizeof(private_key_buffer)};
        chunk_t der_public_key = {public_key_buffer, sizeof(public_key_buffer)};
index 61eba69..0f4201b 100644 (file)
@@ -61,7 +61,6 @@
 #include "rsa_test.h"
 #include "kernel_interface_test.h"
 #include "child_sa_test.h"
-#include "der_decoder_test.h"
 #include "certificate_test.h"
 #include "leak_detective_test.h"
 
@@ -130,7 +129,6 @@ test_t proposal_test = {test_proposal, "proposal_t test"};
 test_t rsa_test = {test_rsa, "RSA private/public key test"};
 test_t kernel_interface_test = {test_kernel_interface, "Kernel Interface"};
 test_t child_sa_test = {test_child_sa, "Child SA"};
-test_t der_decoder_test = {test_der_decoder, "DER decoder"};
 test_t certificate_test = {test_certificate, "X509 Certificate"};
 test_t leak_detective_test = {test_leak_detective, "LEAK detective"};
 
@@ -255,7 +253,7 @@ int main()
        tester_t *tester = tester_create(test_output, FALSE);
        
        //tester->perform_tests(tester,all_tests);
-       tester->perform_test(tester,&leak_detective_test);
+       tester->perform_test(tester,&certificate_test);
        
        
        tester->destroy(tester);