- identification_t supports now almost all id types
authorMartin Willi <martin@strongswan.org>
Mon, 24 Apr 2006 10:40:10 +0000 (10:40 -0000)
committerMartin Willi <martin@strongswan.org>
Mon, 24 Apr 2006 10:40:10 +0000 (10:40 -0000)
- x509 certificates work with identification_t now
- fixes here, fixes there

26 files changed:
Source/charon/network/socket.c
Source/charon/threads/stroke_interface.c
Source/doc/Todo-list.txt
Source/lib/asn1/asn1.c
Source/lib/asn1/asn1.h
Source/lib/asn1/oid.c
Source/lib/asn1/oid.h
Source/lib/asn1/oid.pl
Source/lib/asn1/oid.txt
Source/lib/crypto/x509.c
Source/lib/crypto/x509.h
Source/lib/types.h
Source/lib/utils/identification.c
Source/lib/utils/identification.h
Source/lib/utils/logger.c
Source/lib/utils/logger.h
Source/scripts/complex1.der [new file with mode: 0644]
Source/scripts/complex2.der [new file with mode: 0644]
Source/testing/Makefile.testcases
Source/testing/certificate_test.c
Source/testing/connection_test.c
Source/testing/identification_test.c [new file with mode: 0644]
Source/testing/identification_test.h [new file with mode: 0644]
Source/testing/policy_test.c
Source/testing/rsa_test.c
Source/testing/testcases.c

index 79c7c42..32ff845 100644 (file)
@@ -133,7 +133,7 @@ struct private_socket_t{
 /**
  * implementation of socket_t.receive
  */
-status_t receiver(private_socket_t *this, packet_t **packet)
+static status_t receiver(private_socket_t *this, packet_t **packet)
 {
        char buffer[MAX_PACKET];
        chunk_t data;
index 274791b..2881cb2 100755 (executable)
@@ -309,8 +309,8 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
                my_host->destroy(my_host);
                return;
        }
-       my_id = identification_create_from_string(ID_IPV4_ADDR, 
-                                                                                         *msg->add_conn.me.id ? msg->add_conn.me.id : msg->add_conn.me.address);
+       my_id = identification_create_from_string(*msg->add_conn.me.id ? 
+                                                                                               msg->add_conn.me.id : msg->add_conn.me.address);
        if (my_id == NULL)
        {
                this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.me.id);
@@ -318,8 +318,8 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
                other_host->destroy(other_host);
                return;
        }
-       other_id = identification_create_from_string(ID_IPV4_ADDR, 
-                       *msg->add_conn.other.id ? msg->add_conn.other.id : msg->add_conn.other.address);
+       other_id = identification_create_from_string(*msg->add_conn.other.id ? 
+                       msg->add_conn.other.id : msg->add_conn.other.address);
        if (other_id == NULL)
        {
                my_host->destroy(my_host);
@@ -328,7 +328,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
                this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.other.id);
                return;
        }
-                               
+       
        my_subnet = host_create(AF_INET, *msg->add_conn.me.subnet ? msg->add_conn.me.subnet : msg->add_conn.me.address, 500);
        if (my_subnet == NULL)
        {
@@ -339,7 +339,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
                this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
                return;
        }
-                               
+       
        other_subnet = host_create(AF_INET, *msg->add_conn.other.subnet ? msg->add_conn.other.subnet : msg->add_conn.other.address, 500);
        if (other_subnet == NULL)
        {
index 2173213..44d8b98 100644 (file)
     + leak detective usable for charon and pluto and anything else
   + integrate asn1 parser/oid (asn1/oid)
   + integrate basic PEM loading
-  + port x509 stuff 
+  + port x509 stuff
 
 + doxygen cleanup (charon/lib)
 
-- implement 3DES to load encrypted pem files
-
-- ipsec.secrets parsing
-
 - useable certificate support
-  - certificate lookup via ID
+  + more id types (use atodn from pluto)
+  - rewrite certificate storage the clean way
   - certificate validation/chaining
   - certificate exchange
 
+- implement 3DES to load encrypted pem files
+- ipsec.secrets parsing
+
 - trapping
 - delete notify, when to send?
 - notifys on connection setup failure
index 85baf79..c847461 100644 (file)
@@ -18,7 +18,6 @@
 #include <time.h>
 
 #include "asn1.h"
-#include "oid.h"
 
 #include <utils/logger_manager.h>
 
index 4a99c9a..556bb2b 100644 (file)
@@ -20,6 +20,7 @@
 #include <gmp.h>
 
 #include <types.h>
+#include <asn1/oid.h>
 
 
 /* Defines some primitive ASN1 types */
index 7b0135d..4b0632d 100644 (file)
@@ -172,23 +172,26 @@ const oid_t oid_names[] = {
   {                0x03,       0, 0, "id-SHA-512"             },  /* 159 */
   {        0x86,               0, 1, ""                       },  /* 160 */
   {          0xf8,             0, 1, ""                       },  /* 161 */
-  {            0x42,         171, 1, "netscape"               },  /* 162 */
+  {            0x42,         174, 1, "netscape"               },  /* 162 */
   {              0x01,       169, 1, ""                       },  /* 163 */
   {                0x01,     165, 0, "nsCertType"             },  /* 164 */
   {                0x03,     166, 0, "nsRevocationUrl"        },  /* 165 */
   {                0x04,     167, 0, "nsCaRevocationUrl"      },  /* 166 */
   {                0x08,     168, 0, "nsCaPolicyUrl"          },  /* 167 */
   {                0x0d,       0, 0, "nsComment"              },  /* 168 */
-  {              0x04,         0, 1, "policy"                 },  /* 169 */
-  {                0x01,       0, 0, "nsSGC"                  },  /* 170 */
-  {            0x45,           0, 1, "verisign"               },  /* 171 */
-  {              0x01,         0, 1, "pki"                    },  /* 172 */
-  {                0x09,       0, 1, "attributes"             },  /* 173 */
-  {                  0x02,   175, 0, "messageType"            },  /* 174 */
-  {                  0x03,   176, 0, "pkiStatus"              },  /* 175 */
-  {                  0x04,   177, 0, "failInfo"               },  /* 176 */
-  {                  0x05,   178, 0, "senderNonce"            },  /* 177 */
-  {                  0x06,   179, 0, "recipientNonce"         },  /* 178 */
-  {                  0x07,   180, 0, "transID"                },  /* 179 */
-  {                  0x08,     0, 0, "extensionReq"           }   /* 180 */
+  {              0x03,       172, 1, "directory"              },  /* 169 */
+  {                0x01,       0, 1, ""                       },  /* 170 */
+  {                  0x03,     0, 0, "employeeNumber"         },  /* 171 */
+  {              0x04,         0, 1, "policy"                 },  /* 172 */
+  {                0x01,       0, 0, "nsSGC"                  },  /* 173 */
+  {            0x45,           0, 1, "verisign"               },  /* 174 */
+  {              0x01,         0, 1, "pki"                    },  /* 175 */
+  {                0x09,       0, 1, "attributes"             },  /* 176 */
+  {                  0x02,   178, 0, "messageType"            },  /* 177 */
+  {                  0x03,   179, 0, "pkiStatus"              },  /* 178 */
+  {                  0x04,   180, 0, "failInfo"               },  /* 179 */
+  {                  0x05,   181, 0, "senderNonce"            },  /* 180 */
+  {                  0x06,   182, 0, "recipientNonce"         },  /* 181 */
+  {                  0x07,   183, 0, "transID"                },  /* 182 */
+  {                  0x08,     0, 0, "extensionReq"           }   /* 183 */
 };
index 4096af3..a9265d4 100644 (file)
@@ -5,6 +5,9 @@
  * Do not edit manually!
  */
 
+#ifndef OID_H_
+#define OID_H_
+
 typedef struct {
     u_char octet;
     u_int  next;
@@ -67,9 +70,11 @@ extern const oid_t oid_names[];
 #define OID_NS_CA_REVOCATION_URL       166
 #define OID_NS_CA_POLICY_URL           167
 #define OID_NS_COMMENT                 168
-#define OID_PKI_MESSAGE_TYPE           174
-#define OID_PKI_STATUS                 175
-#define OID_PKI_FAIL_INFO              176
-#define OID_PKI_SENDER_NONCE           177
-#define OID_PKI_RECIPIENT_NONCE                178
-#define OID_PKI_TRANS_ID               179
+#define OID_PKI_MESSAGE_TYPE           177
+#define OID_PKI_STATUS                 178
+#define OID_PKI_FAIL_INFO              179
+#define OID_PKI_SENDER_NONCE           180
+#define OID_PKI_RECIPIENT_NONCE                181
+#define OID_PKI_TRANS_ID               182
+
+#endif /* OID_H_ */
index 52ac8ea..a3725e5 100644 (file)
@@ -30,6 +30,8 @@ print OID_H "/* Object identifiers (OIDs) used by FreeS/WAN\n",
            " * ", $automatic, "\n",
            " * ", $warning, "\n",
            " */\n\n",
+           "#ifndef OID_H_\n",
+           "#define OID_H_\n\n",
            "typedef struct {\n",
            "    u_char octet;\n",
            "    u_int  next;\n",
@@ -73,6 +75,8 @@ while ($line = <SRC>)
     $counter++;
 }
 
+print OID_H "\n#endif /* OID_H_ */\n";
+
 close SRC;
 close OID_H;
 
index ad05a12..eed46d5 100644 (file)
                 0x04         "nsCaRevocationUrl"       OID_NS_CA_REVOCATION_URL
                 0x08         "nsCaPolicyUrl"           OID_NS_CA_POLICY_URL
                 0x0d         "nsComment"               OID_NS_COMMENT
+              0x03           "directory"
+                0x01         ""
+                  0x03       "employeeNumber"
               0x04           "policy"
                 0x01         "nsSGC"
             0x45             "verisign"
index 2b99b2d..28e7d18 100755 (executable)
@@ -34,7 +34,6 @@
 
 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)
@@ -83,23 +82,62 @@ struct private_x509_t {
         */
        x509_t public;
        
+       /**
+        * Version of the X509 certificate
+        */
+       u_int version;
+       
+       /**
+        * ID representing the certificates subject
+        */
+       identification_t *subject;
+       
+       /**
+        * ID representing the certificate issuer
+        */
+       identification_t *issuer;
+       
+       /**
+        * List of identification_t's representing subjectAltNames
+        */
+       linked_list_t *subjectAltNames;
+       
+       /**
+        * List of identification_t's representing issuerAltNames
+        */
+       linked_list_t *issuerAltNames;
+       
+       /**
+        * List of identification_t's representing crlDistributionPoints
+        */
+       linked_list_t *crlDistributionPoints;
+       
+       /**
+        * Type of the subjects Key (currently RSA only)
+        */
+       auth_method_t subjectPublicKeyAlgorithm;
+       
+
+               /**
+                * Subjects RSA public key, if subjectPublicKeyAlgorithm == RSA
+                */
+               rsa_public_key_t *public_key;
+       
+       
+       
+       
        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 */
@@ -114,8 +152,6 @@ struct private_x509_t {
        chunk_t authKeyID;
        chunk_t authKeySerialNumber;
        chunk_t accessLocation; /* ocsp */
-       generalName_t *subjectAltName;
-       generalName_t *crlDistributionPoints;
        /* signatureAlgorithm */
        int algorithm;
        chunk_t signature;
@@ -207,53 +243,9 @@ static const asn1Object_t generalNamesObjects[] = {
 #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
+ * ASN.1 definition of crlDistributionPoints
  */
 static const asn1Object_t crlDistributionPointsObjects[] = {
        { 0, "crlDistributionPoints",   ASN1_SEQUENCE,          ASN1_LOOP                       }, /*  0 */
@@ -277,7 +269,7 @@ static const asn1Object_t crlDistributionPointsObjects[] = {
  * ASN.1 definition of an X.509v3 x509
  */
 static const asn1Object_t certObjects[] = {
-       { 0, "x509",                            ASN1_SEQUENCE,          ASN1_OBJ                        }, /*  0 */
+       { 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 */
@@ -327,115 +319,6 @@ static const asn1Object_t certObjects[] = {
 #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
 };
@@ -443,553 +326,6 @@ static u_char ASN1_subjectAltName_oid_str[] = {
 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
  */
@@ -1020,7 +356,8 @@ chunk_t build_subjectAltNames(generalName_t *subjectAltNames)
        gn = subjectAltNames;
        while (gn != NULL)
        {
-               chunkcpy(pos, gn->name);
+               memcpy(pos, gn->name.ptr, gn->name.len); 
+               pos += gn->name.len;
                gn = gn->next;
        }
 
@@ -1077,155 +414,29 @@ static bool parse_basicConstraints(chunk_t blob, int level0)
 }
 
 /**
- * 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)
+static void parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list)
 {
        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;
+                       return;
                
                if (objectID == GENERAL_NAMES_GN)
                {
-                       generalName_t *gn = parse_generalName(object, level+1);
-                       if (gn != NULL)
-                       {
-                               gn->next = top_gn;
-                               top_gn = gn;
-                       }
+                       list->insert_last(list, identification_create_from_encoding(ID_DER_ASN1_GN, object));
                }
                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;
+       return;
 }
 
 /**
@@ -1295,8 +506,7 @@ void parse_authorityKeyIdentifier(chunk_t blob, int level0 , chunk_t *authKeyID,
                                break;
                        case AUTH_KEY_ID_CERT_ISSUER:
                        {
-                               generalName_t *gn = parse_generalNames(object, level+1, TRUE);
-                               free_generalNames(gn, FALSE);
+                               /* TODO: parse_generalNames(object, level+1, TRUE); */
                                break;
                        }
                        case AUTH_KEY_ID_CERT_SERIAL:
@@ -1398,37 +608,28 @@ static bool parse_extendedKeyUsage(chunk_t blob, int level0)
  * extracts one or several crlDistributionPoints and puts them into
  * a chained list
  */
-static generalName_t* parse_crlDistributionPoints(chunk_t blob, int level0)
+static void parse_crlDistributionPoints(chunk_t blob, int level0, linked_list_t *list)
 {
        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;
+                       return;
                }
                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;
-                       }
+                       parse_generalNames(object, level+1, TRUE, list);
+
                }
                objectID++;
        }
-       return top_gn;
 }
 
 
@@ -1437,7 +638,6 @@ static generalName_t* parse_crlDistributionPoints(chunk_t blob, int level0)
  */
 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;
@@ -1472,9 +672,7 @@ bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert)
                                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);
+                               cert->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
                                break;
                        case X509_OBJ_NOT_BEFORE:
                                cert->notBefore = parse_time(object, level);
@@ -1483,9 +681,7 @@ bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert)
                                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);
+                               cert->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object);
                                break;
                        case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM:
                                if (parse_algorithmIdentifier(object, level, NULL) == OID_RSA_ENCRYPTION)
@@ -1527,13 +723,13 @@ bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert)
                                                cert->subjectKeyID = parse_keyIdentifier(object, level, FALSE);
                                                break;
                                        case OID_SUBJECT_ALT_NAME:
-                                               cert->subjectAltName = parse_generalNames(object, level, FALSE);
+                                               parse_generalNames(object, level, FALSE, cert->subjectAltNames);
                                                break;
                                        case OID_BASIC_CONSTRAINTS:
                                                cert->isCA = parse_basicConstraints(object, level);
                                                break;
                                        case OID_CRL_DISTRIBUTION_POINTS:
-                                               cert->crlDistributionPoints = parse_crlDistributionPoints(object, level);
+                                               parse_crlDistributionPoints(object, level, cert->crlDistributionPoints);
                                                break;
                                        case OID_AUTHORITY_KEY_ID:
                                                parse_authorityKeyIdentifier(object, level , &cert->authKeyID, &cert->authKeySerialNumber);
@@ -1601,18 +797,59 @@ err_t check_validity(const private_x509_t *cert, time_t *until)
        }
 }
 
+/**
+ * Implements x509_t.get_public_key
+ */
 static rsa_public_key_t *get_public_key(private_x509_t *this)
 {
        return this->public_key->clone(this->public_key);;
 }
 
 /**
+ * Implements x509_t.get_subject
+ */
+static identification_t *get_subject(private_x509_t *this)
+{
+       return this->subject;
+}
+
+/**
+ * Implements x509_t.get_issuer
+ */
+static identification_t *get_issuer(private_x509_t *this)
+{
+       return this->issuer;
+}
+
+/**
  * destroy
  */
 static void destroy(private_x509_t *this)
 {
-       free_generalNames(this->subjectAltName, FALSE);
-       free_generalNames(this->crlDistributionPoints, FALSE);
+       identification_t *id;
+       while (this->subjectAltNames->remove_last(this->subjectAltNames, (void**)&id) == SUCCESS)
+       {
+               id->destroy(id);
+       }
+       this->subjectAltNames->destroy(this->subjectAltNames);
+       while (this->issuerAltNames->remove_last(this->issuerAltNames, (void**)&id) == SUCCESS)
+       {
+               id->destroy(id);
+       }
+       this->issuerAltNames->destroy(this->issuerAltNames);
+       while (this->crlDistributionPoints->remove_last(this->crlDistributionPoints, (void**)&id) == SUCCESS)
+       {
+               id->destroy(id);
+       }
+       this->crlDistributionPoints->destroy(this->crlDistributionPoints);
+       if (this->issuer)
+       {
+               this->issuer->destroy(this->issuer);
+       }
+       if (this->subject)
+       {
+               this->subject->destroy(this->subject);
+       }
        if (this->public_key)
        {
                this->public_key->destroy(this->public_key);
@@ -1631,13 +868,19 @@ x509_t *x509_create_from_chunk(chunk_t chunk)
        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;
+       this->public.get_subject = (identification_t* (*) (x509_t*))get_subject;
+       this->public.get_issuer = (identification_t* (*) (x509_t*))get_issuer;
        
        /* initialize */
        this->subjectPublicKey = CHUNK_INITIALIZER;
        this->public_key = NULL;
-       this->subjectAltName = NULL;
-       this->crlDistributionPoints = NULL;
+       this->subject = NULL;
+       this->issuer = NULL;
+       this->subjectAltNames = linked_list_create(this->subjectAltNames);
+       this->issuerAltNames = linked_list_create(this->issuerAltNames);
+       this->crlDistributionPoints = linked_list_create(this->crlDistributionPoints);
        
+       /* we do not use a per-instance logger right now, since its not always accessible */
        logger = logger_manager->get_logger(logger_manager, ASN1);
        
        if (!parse_x509cert(chunk, 0, this))
index cd2f08e..077238e 100755 (executable)
@@ -58,14 +58,22 @@ struct x509_t {
        /**
         * @brief Get the certificate issuers ID.
         * 
-        * @todo implement!
+        * The resulting ID is always a identification_t
+        * of type ID_DER_ASN1_DN.
+        * 
+        * @param this                          calling object
+        * @return                                      issuers ID
         */
        identification_t *(*get_issuer) (x509_t *this);
                
        /**
         * @brief Get the subjects ID.
         * 
-        * @todo implement!
+        * The resulting ID is always a identification_t
+        * of type ID_DER_ASN1_DN. 
+        * 
+        * @param this                          calling object
+        * @return                                      subjects ID
         */
        identification_t *(*get_subject) (x509_t *this);
        
index 7125a01..0e0782b 100644 (file)
@@ -30,7 +30,6 @@
 
 #include <definitions.h>
 
-
 /**
  * General purpose boolean type.
  */
index 05d9d76..d99d0e4 100644 (file)
  * for more details.
  */
 
+#define _GNU_SOURCE
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <string.h>
+#include <stdio.h>
+#include <ctype.h>
 
 #include "identification.h"
 
+#include <asn1/asn1.h>
+
 /** 
  * String mappings for id_type_t.
  */
@@ -38,10 +43,184 @@ mapping_t id_type_m[] = {
        {ID_DER_ASN1_DN, "ID_DER_ASN1_DN"},
        {ID_DER_ASN1_GN, "ID_DER_ASN1_GN"},
        {ID_KEY_ID, "ID_KEY_ID"},
+       {ID_ANY, "ID_ANY"},
        {MAPPING_END, NULL}
 };
 
 
+/**
+ * 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_EN[]  = {
+       0x60, 0x86, 0x48, 0x01, 0x86,
+       0xF8, 0x42, 0x03, 0x01, 0x03
+};
+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},
+       {"EN",                          {oid_EN,    10}, ASN1_PRINTABLESTRING},
+       {"employeeNumber",      {oid_EN,    10}, 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   26
+
+/**
+ * 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,
+};
+
+/**
+ * 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
+
 typedef struct private_identification_t private_identification_t;
 
 /**
@@ -71,6 +250,539 @@ struct private_identification_t {
 
 static private_identification_t *identification_create();
 
+
+/**
+ * updates a chunk (!????)
+ * TODO: We should reconsider this stuff, its not really clear
+ */
+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 status_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)
+       {
+               /* DN is not a SEQUENCE */
+               return FAILED;
+       }
+       
+       rdn->len = asn1_length(&dn);
+       
+       if (rdn->len == ASN1_INVALID_LENGTH)
+       {
+               /* Invalid RDN length */
+               return FAILED;
+       }
+       
+       rdn->ptr = dn.ptr;
+       
+       /* are there any RDNs ? */
+       *next = rdn->len > 0;
+       
+       return SUCCESS;
+}
+
+/**
+ * Fetches the next RDN in a DN
+ */
+static status_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)
+               {
+                       /* RDN is not a SET */
+                       return FAILED;
+               }
+               attribute->len = asn1_length(rdn);
+               if (attribute->len == ASN1_INVALID_LENGTH)
+               {
+                       /* Invalid attribute length */
+                       return FAILED;
+               }
+               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)
+       {
+               /* attributeTypeAndValue is not a SEQUENCE */
+               return FAILED;
+       }
+       
+       /* extract the attribute body */
+       body.len = asn1_length(attribute);
+       
+       if (body.len == ASN1_INVALID_LENGTH)
+       {
+               /* Invalid attribute body length */
+               return FAILED;
+       }
+       
+       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)
+       {
+               /* attributeType is not an OID */
+               return FAILED;
+       }
+       /* extract OID */
+       oid->len = asn1_length(&body);
+       
+       if (oid->len == ASN1_INVALID_LENGTH)
+       {
+               /* Invalid attribute OID length */
+               return FAILED;
+       }
+       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)
+       {
+               /* Invalid attribute string length */
+               return FAILED;
+       }
+       value->ptr = body.ptr;
+       
+       /* are there any RDNs left? */
+       *next = rdn->len > 0 || attribute->len > 0;
+       return SUCCESS;
+}
+
+/**
+ * Parses an ASN.1 distinguished name int its OID/value pairs
+ */
+static status_t dntoa(chunk_t dn, chunk_t *str)
+{
+       chunk_t rdn, oid, attribute, value;
+       asn1_t type;
+       int oid_code;
+       bool next;
+       bool first = TRUE;
+
+       status_t status = init_rdn(dn, &rdn, &attribute, &next);
+
+       if (status != SUCCESS)
+       {/* a parsing error has occured */
+               return status;
+       }
+
+       while (next)
+       {
+               status = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next);
+
+               if (status != SUCCESS)
+               {/* a parsing error has occured */
+                       return status;
+               }
+
+               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 SUCCESS;
+}
+
+/**
+ * compare two distinguished names by
+ * comparing the individual RDNs
+ */
+static 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) != SUCCESS ||
+               init_rdn(b, &rdn_b, &attribute_b, &next_b) != SUCCESS)
+       {
+               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) != SUCCESS ||  
+                       get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != SUCCESS)
+               {
+                       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.
+ * TODO: Add support for different RDN order in DN !!
+ */
+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) != SUCCESS ||
+               init_rdn(b, &rdn_b, &attribute_b, &next_b) != SUCCESS)
+       {
+               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) != SUCCESS ||
+                       get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != SUCCESS)
+               {
+                       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;
+}
+
+/**
+ * get string representation of a general name
+ * TODO: Add support for gn types
+ */
+static char *gntoa(chunk_t blob)
+{
+       asn1_ctx_t ctx;
+       chunk_t object;
+       int objectID = 0;
+       u_int level;
+       char buf[128];
+
+       asn1_init(&ctx, blob, 0, FALSE);
+
+       while (objectID < GN_OBJ_ROOF)
+       {
+               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:
+                               snprintf(buf, sizeof(buf), "%.*s", object.len, object.ptr);
+                               return strdup(buf);
+                       case GN_OBJ_IP_ADDRESS:
+                               if (object.len == 4 &&
+                                       inet_ntop(AF_INET, object.ptr, buf, sizeof(buf)))
+                               {
+                                       return strdup(buf);
+                               }
+                               return NULL;
+                               break;
+                       case GN_OBJ_OTHER_NAME:
+                               return strdup("(other name)");
+                       case GN_OBJ_X400_ADDRESS:
+                               return strdup("(X400 Address)");
+                       case GN_OBJ_EDI_PARTY_NAME:
+                               return strdup("(EDI party name)");
+                       case GN_OBJ_REGISTERED_ID:
+                               return strdup("(registered ID)");
+                       case GN_OBJ_DIRECTORY_NAME:
+                               return strdup("(directory name)");
+                       default:
+                               break;
+               }
+               objectID++;
+       }
+       return NULL;
+}
+
+/**
+ * Converts an LDAP-style human-readable ASCII-encoded
+ * ASN.1 distinguished name into binary DER-encoded format
+ */
+static status_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;
+       
+       char *wrap_mode;
+       chunk_t oid  = CHUNK_INITIALIZER;
+       chunk_t name = CHUNK_INITIALIZER;
+       chunk_t names[25]; /* max to 25 rdns */
+       int name_count = 0;
+       int whitespace = 0;
+       int pos = 0;
+       asn1_t rdn_type;
+       state_t state = SEARCH_OID;
+       status_t status = SUCCESS;
+       
+       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)
+                                       {
+                                               status = NOT_SUPPORTED;
+                                               state = UNKNOWN_OID;
+                                               break;
+                                       }
+                                       /* 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;
+                                       rdn_type = (x501rdns[pos].type == ASN1_PRINTABLESTRING
+                                                       && !is_printablestring(name))? ASN1_T61STRING : x501rdns[pos].type;
+                                       
+                                       if (name_count < 25)
+                                       {
+                                               names[name_count++] = 
+                                                               asn1_wrap(ASN1_SET, "m",
+                                                                                 asn1_wrap(ASN1_SEQUENCE, "mm",
+                                                                                                 asn1_wrap(ASN1_OID, "c", x501rdns[pos].oid),
+                                                                                                 asn1_wrap(rdn_type, "c", name)
+                                                                                                  )
+                                                                                );
+                                       }
+                                       else
+                                       {
+                                               status = OUT_OF_RES;
+                                       }
+                                       /* reset name and change state */
+                                       name = CHUNK_INITIALIZER;
+                                       state = SEARCH_OID;
+                               }
+                               break;
+                       case UNKNOWN_OID:
+                               break;
+               }
+       } while (*src++ != '\0');
+
+       
+       /* build the distinguished name sequence */
+       wrap_mode = alloca(26);
+       memset(wrap_mode, 0, 26);
+       memset(wrap_mode, 'm', name_count);
+       *dn = asn1_wrap(ASN1_SEQUENCE, wrap_mode, 
+                                       names[0], names[1], names[2], names[3], names[4], 
+                                       names[5], names[6], names[7], names[8], names[9],
+                                       names[10], names[11], names[12], names[13], names[14], 
+                                       names[15], names[16], names[17], names[18], names[19], 
+                                       names[20], names[21], names[22], names[23], names[24]);
+       if (status != SUCCESS)
+       {
+               free(dn->ptr);
+               *dn = CHUNK_INITIALIZER;
+       }
+       return status;
+}
+
 /**
  * Implementation of identification_t.get_encoding.
  */
@@ -96,17 +808,15 @@ static char *get_string(private_identification_t *this)
 }
 
 /**
- * Implementation of identification_t.equals.
+ * Default implementation of identification_t.equals and identification_t.belongs_to.
+ * compares encoded chunk for equality.
  */
-static bool equals (private_identification_t *this,private_identification_t *other)
+static bool equals_binary(private_identification_t *this,private_identification_t *other)
 {
        if (this->type == other->type)
        {
-               if (this->encoded.len != other->encoded.len)
-               {
-                       return FALSE;
-               }
-               if (memcmp(this->encoded.ptr,other->encoded.ptr,this->encoded.len) == 0)
+               if (this->encoded.len == other->encoded.len &&
+                       memcmp(this->encoded.ptr, other->encoded.ptr, this->encoded.len) == 0)
                {
                        return TRUE;
                }
@@ -115,23 +825,74 @@ static bool equals (private_identification_t *this,private_identification_t *oth
 }
 
 /**
- * Implementation of identification_t.belongs_to.
+ * Special implementation of identification_t.equals for ID_DER_ASN1_DN
  */
-static bool belongs_to(private_identification_t *this, private_identification_t *other)
+static bool equals_dn(private_identification_t *this, private_identification_t *other)
 {
-       if (this->public.equals(&this->public, &other->public))
+       return same_dn(this->encoded, other->encoded);
+}
+
+/**
+ * Special implementation of identification_t.belongs_to for ID_RFC822_ADDR/ID_FQDN.
+ * checks for a wildcard in other-string, and compares it against this-string.
+ */
+static bool belongs_to_wc_string(private_identification_t *this, private_identification_t *other)
+{
+       char *this_str, *other_str, *pos;
+       
+       if (this->type == other->type)
        {
-               return TRUE;
+               /* try a binary comparison first */
+               if (equals_binary(this, other))
+               {
+                       return TRUE;
+               }
        }
-       
-       if (this->type == other->type && this->type == ID_IPV4_ADDR)
+       if (other->encoded.len > 0 &&
+                  *(other->encoded.ptr) == '*')
        {
-               /* is this %any (0.0.0.0)?*/
-               if (*((u_int32_t*)this->encoded.ptr) == 0)
+               if (other->encoded.len == 1)
                {
+                       /* other contains just a wildcard, and therefore matches anything */
                        return TRUE;
                }
-               /* TODO: Do we need subnet support? */
+               /* We strdup chunks, since they are NOT null-terminated */
+               this_str = strndupa(this->encoded.ptr, this->encoded.len);
+               other_str = strndupa(other->encoded.ptr + 1, other->encoded.len - 1);
+               pos = strstr(this_str, other_str);
+               if (pos != NULL)
+               {
+                       /* ok, other is contained in this, but there may be more characters, so check it */
+                       if (strlen(pos) == strlen(other_str))
+                       {
+                               return TRUE;
+                       }
+               }
+       }
+       
+       return FALSE;
+}
+
+/**
+ * Special implementation of identification_t.belongs_to for ID_ANY.
+ * ANY matches any, even ANY, thats why its there...
+ */
+static bool belongs_to_any(private_identification_t *this, private_identification_t *other)
+{
+       return TRUE;
+}
+
+/**
+ * Special implementation of identification_t.belongs_to for ID_DER_ASN1_DN.
+ * ANY matches any, even ANY, thats why its there...
+ */
+static bool belongs_to_dn(private_identification_t *this, private_identification_t *other)
+{
+       int wildcards;
+       
+       if (this->type == other->type)
+       {
+               return match_dn(this->encoded, other->encoded, &wildcards);
        }
        return FALSE;
 }
@@ -161,22 +922,21 @@ static void destroy(private_identification_t *this)
        free(this);     
 }
 
-/*
+/**
  * Generic constructor used for the other constructors.
- * 
- * @return             private_identification_t object
  */
 static private_identification_t *identification_create()
 {
        private_identification_t *this = malloc_thing(private_identification_t);
        
-       this->public.equals = (bool (*) (identification_t*,identification_t*))equals;
-       this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to;
        this->public.get_encoding = (chunk_t (*) (identification_t*))get_encoding;
        this->public.get_type = (id_type_t (*) (identification_t*))get_type;
        this->public.get_string = (char* (*) (identification_t*))get_string;
        this->public.clone = (identification_t* (*) (identification_t*))clone;
        this->public.destroy = (void (*) (identification_t*))destroy;
+       /* we use these as defaults, the may be overloaded for special ID types */
+       this->public.equals = (bool (*) (identification_t*,identification_t*))equals_binary;
+       this->public.belongs_to = (bool (*) (identification_t*,identification_t*))equals_binary;
        
        this->string = NULL;
        this->encoded = CHUNK_INITIALIZER;
@@ -184,44 +944,110 @@ static private_identification_t *identification_create()
        return this;
 }
 
-
 /*
  * Described in header.
  */
-identification_t *identification_create_from_string(id_type_t type, char *string)
+identification_t *identification_create_from_string(char *string)
 {
        private_identification_t *this = identification_create();
        
-       this->type = type;
-       switch (type)
+       if (strchr(string, '=') != NULL)
        {
-               case ID_IPV4_ADDR:
+               /* we interpret this as an ASCII X.501 ID_DER_ASN1_DN.
+                * convert from LDAP style or openssl x509 -subject style to ASN.1 DN
+                * discard optional @ character in front of DN
+                */
+               if (atodn((*string == '@') ? string + 1 : string, &this->encoded) != SUCCESS)
                {
-                       /* convert string */
-                       this->encoded.len = 4;
-                       this->encoded.ptr = malloc(this->encoded.len);
-                       if (inet_aton(string, ((struct in_addr*)(this->encoded.ptr))) == 0)
+                       free(this);
+                       return NULL;
+               }
+               this->string = strdup(string);
+               this->type = ID_DER_ASN1_DN;
+               this->public.equals = (bool (*) (identification_t*,identification_t*))equals_dn;
+               this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_dn;
+               return &this->public;
+       }
+       else if (strchr(string, '@') == NULL)
+       {
+               if (strcmp(string, "%any") == 0 ||
+                       strcmp(string, "0.0.0.0") == 0 ||
+                       strcmp(string, "*") == 0 ||
+                       strcmp(string, "::") == 0||
+                       strcmp(string, "0::0") == 0)
+               {
+                       /* any ID will be accepted */
+                       this->type = ID_ANY;
+                       this->string = strdup("%any");
+                       this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_any;
+                       return &this->public;
+               }
+               else
+               {
+                       /* TODO: Pluto resolve domainnames without '@' to IPv4/6 address. Is this really needed? */
+                       
+                       if (strchr(string, ':') == NULL)
+                       {
+                               /* try IPv4 */
+                               struct in_addr address;
+                               chunk_t chunk = {(void*)&address, sizeof(address)};
+                               
+                               if (inet_pton(AF_INET, string, &address) <= 0)
+                               {
+                                       free(this);
+                                       return NULL;
+                               }
+                               this->encoded = chunk_clone(chunk);
+                               this->string = strdup(string);
+                               this->type = ID_IPV4_ADDR;
+                               return &(this->public);
+                       }
+                       else
+                       {
+                               /* try IPv6 */
+                               struct in6_addr address;
+                               chunk_t chunk = {(void*)&address, sizeof(address)};
+                               
+                               if (inet_pton(AF_INET6, string, &address) <= 0)
+                               {
+                                       free(this);
+                                       return NULL;
+                               }
+                               this->encoded = chunk_clone(chunk);
+                               this->string = strdup(string);
+                               this->type = ID_IPV6_ADDR;
+                               return &(this->public);
+                       }
+               }
+       }
+       else
+       {
+               if (*string == '@')
+               {
+                       if (*(string + 1) == '#')
                        {
-                               free(this->encoded.ptr);
+                               /* TODO: Pluto handles '#' as hex encoded ASN1/KEY ID. Do we need this, too? */
                                free(this);
                                return NULL;
                        }
-                       /* clone string */
-                       this->string = malloc(strlen(string)+1);
-                       strcpy(this->string, string);
-                       return &(this->public);
+                       else
+                       {
+                               this->type = ID_FQDN;
+                               this->string = strdup(string + 1); /* discard @ */
+                               this->encoded.ptr = strdup(string + 1);
+                               this->encoded.len = strlen(string + 1);
+                               this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
+                               return &(this->public);
+                       }
                }
-               case ID_IPV6_ADDR:
-               case ID_FQDN:
-               case ID_RFC822_ADDR:
-               case ID_DER_ASN1_DN:
-               case ID_DER_ASN1_GN:
-               case ID_KEY_ID:
-               default:
+               else
                {
-                       /* not supported */
-                       free(this);
-                       return NULL;
+                       this->type = ID_RFC822_ADDR;
+                       this->string = strdup(string);
+                       this->encoded.ptr = strdup(string);
+                       this->encoded.len = strlen(string);
+                       this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
+                       return &(this->public);
                }
        }
 }
@@ -231,60 +1057,83 @@ identification_t *identification_create_from_string(id_type_t type, char *string
  */
 identification_t *identification_create_from_encoding(id_type_t type, chunk_t encoded)
 {
-       char *string;
        private_identification_t *this = identification_create();
-       
-       this->encoded = chunk_clone(encoded);
+       char buf[256];
+       chunk_t buf_chunk = chunk_from_buf(buf);
+       char *pos;
        
        this->type = type;
        switch (type)
        {
+               case ID_ANY:
+                       this->string = strdup("%any");
+                       this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_any;
+                       break;
                case ID_IPV4_ADDR:
-               {
-                       string = inet_ntoa(*((struct in_addr*)(encoded.ptr)));
+                       if (encoded.len < sizeof(struct in_addr) ||
+                               inet_ntop(AF_INET, encoded.ptr, buf, sizeof(buf)) == NULL)
+                       {
+                               this->string = strdup("(invalid ID_IPV4_ADDR)");
+                       }
+                       else
+                       {
+                               this->string = strdup(buf);
+                       }
                        break;
-               }
                case ID_IPV6_ADDR:
-               {
-                       string = "[ID_IPV6_ADDR]";
+                       if (encoded.len < sizeof(struct in6_addr) ||
+                               inet_ntop(AF_INET6, encoded.ptr, buf, INET6_ADDRSTRLEN) == NULL)
+                       {
+                               this->string = strdup("(invalid ID_IPV6_ADDR)");
+                       }
+                       else
+                       {
+                               this->string = strdup(buf);
+                       }
                        break;
-               }
                case ID_FQDN:
-               {
-                       string = "[ID_FQDN]";
+                       snprintf(buf, sizeof(buf), "@%.*s", encoded.len, encoded.ptr);
+                       this->string = strdup(buf);
+                       this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
                        break;
-               }
                case ID_RFC822_ADDR:
-               {
-                       string = "[ID_RFC822_ADDR]";
+                       snprintf(buf, sizeof(buf), "%.*s", encoded.len, encoded.ptr);
+                       this->string = strdup(buf);
+                       this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
                        break;
-               }
                case ID_DER_ASN1_DN:
-               {
-                       string = "[ID_DER_ASN1_DN]";
+                       snprintf(buf, sizeof(buf), "%.*s", encoded.len, encoded.ptr);
+                       /* TODO: whats returned on failure */
+                       dntoa(encoded, &buf_chunk);
+                       this->string = strdup(buf);
+                       this->public.equals = (bool (*) (identification_t*,identification_t*))equals_dn;
+                       this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_dn;
                        break;
-               }
                case ID_DER_ASN1_GN:
-               {
-                       string = "[ID_DER_ASN1_GN]";
+                       this->string = gntoa(encoded);
                        break;
-               }
                case ID_KEY_ID:
-               {
-                       string = "[ID_KEY_ID]";
+                       this->string = strdup("(unparsed KEY_ID)");
                        break;
-               }
                default:
-               {
-                       string = "[unknown id_type_t]";
-               }
-       }                       
+                       snprintf(buf, sizeof(buf), "(invalid ID type: %d)", type);
+                       this->string = strdup(buf);
+                       break;
+       }
        
-       /* build string, must be cloned since 
-        * inet_ntoa points to a subsequently 
-        * overwritten buffer */
-       this->string = malloc(strlen(string)+1);
-       strcpy(this->string, string);
+       /* apply encoded chunk */
+       if (type != ID_ANY)
+       {
+               this->encoded = chunk_clone(encoded);
+       }
        
+       /* remove unprintable chars in string */
+       for (pos = this->string; *pos != '\0'; pos++)
+       {
+               if (!isprint(*pos))
+               {
+                       *pos = '?';
+               }
+       }
        return &(this->public);
 }
index 87ac2a8..4df665c 100644 (file)
@@ -31,11 +31,7 @@ typedef enum id_type_t id_type_t;
 
 /**
  * @brief ID Types in a ID payload.
- * 
- * @see 
- *                     - identification_t
- *                     - id_payload_t
- * 
+ *
  * @ingroup utils
  */
 enum id_type_t {
@@ -81,7 +77,12 @@ enum id_type_t {
      * specific information necessary to do certain proprietary
      * types of identification.
      */
-       ID_KEY_ID = 11
+       ID_KEY_ID = 11,
+       
+       /**
+        * Special type of PRIVATE USE which matches to any other id.
+        */
+       ID_ANY = 201,
 };
 
 /**
@@ -95,20 +96,20 @@ typedef struct identification_t identification_t;
  * @brief Generic identification, such as used in ID payload.
  * 
  * The following types are possible:
- * - ID_IPV4_ADDR 
- * - ID_FQDN*
- * - ID_RFC822_ADDR*
- * - ID_IPV6_ADDR*
- * - ID_DER_ASN1_DN*
- * - ID_DER_ASN1_GN*
- * - ID_KEY_ID*
- * (* = string conversion not supported)
+ * - ID_IPV4_ADDR
+ * - ID_FQDN
+ * - ID_RFC822_ADDR
+ * - ID_IPV6_ADDR
+ * - ID_DER_ASN1_DN
+ * - ID_DER_ASN1_GN
+ * - ID_KEY_ID
  * 
  * @b Constructors:
  * - identification_create_from_string()
  * - identification_create_from_encoding()
  * 
- * @todo Support for other ID types then ID_IPV4_ADDR. 
+ * @todo Support for ID_DER_ASN1_GN is minimal right now. Comparison
+ * between them and ID_IPV4_ADDR/RFC822_ADDR would be nice.
  *
  * @ingroup utils
  */
@@ -158,10 +159,13 @@ struct identification_t {
         * An identification_t may contain wildcards, such as
         * *@strongswan.org. This call checks if a given ID
         * (e.g. tester@strongswan.org) belongs to a such wildcard
-        * ID. Returns TRUE if IDs are identical.
+        * ID. Returns TRUE if
+        * - IDs are identical
+        * - other is of type ID_ANY
+        * - other contains a wildcard and matches this
         * 
-        * @param this          the ID containing a wildcard
-        * @param other         the ID without wildcard
+        * @param this          the ID without wildcard
+        * @param other         the ID containing a wildcard
         * @return                      TRUE if other belongs to this
         */
        bool (*belongs_to) (identification_t *this, identification_t *other);
@@ -185,15 +189,31 @@ struct identification_t {
 /**
  * @brief Creates an identification_t object from a string.
  * 
- * @param type         type of this id, such as ID_IPV4_ADDR
  * @param string       input string, which will be converted
  * @return
  *                                     - created identification_t object, or
- *                                     - NULL if type not supported.
+ *                                     - NULL if unsupported string supplied.
+ *
+ * The input string may be e.g. one of the following:
+ * - ID_IPV4_ADDR:             192.168.0.1
+ * - ID_IPV6_ADDR:             2001:0db8:85a3:08d3:1319:8a2e:0370:7345
+ * - ID_FQDN:                  @www.strongswan.org (@indicates FQDN)
+ * - ID_RFC822_ADDR:   alice@wonderland.org
+ * - ID_DER_ASN1_DN:   C=CH, O=Linux strongSwan, CN=bob
+ *
+ * In favour of pluto, domainnames are prepended with an @, since
+ * pluto resolves domainnames without an @ to IPv4 addresses. Since
+ * we use a seperate host_t class for addresses, this doesn't
+ * make sense for us.
  * 
+ * A distinguished name may contain one or more of the following RDNs:
+ * ND, UID, DC, CN, S, SN, serialNumber, C, L, ST, O, OU, T, D,
+ * N, G, I, ID, EN, EmployeeNumber, E, Email, emailAddress, UN, 
+ * unstructuredName, TCGID.
+ *
  * @ingroup utils
  */
-identification_t * identification_create_from_string(id_type_t type, char *string);
+identification_t * identification_create_from_string(char *string);
 
 /**
  * @brief Creates an identification_t object from an encoded chunk.
@@ -201,7 +221,10 @@ identification_t * identification_create_from_string(id_type_t type, char *strin
  * @param type         type of this id, such as ID_IPV4_ADDR
  * @param encoded      encoded bytes, such as from identification_t.get_encoding
  * @return                     identification_t object
- * 
+ *
+ * In contrast to identification_create_from_string(), this constructor never
+ * returns NULL, even when the conversion to a sring representation fails.
+ *
  * @ingroup utils
  */
 identification_t * identification_create_from_encoding(id_type_t type, chunk_t encoded);
index 4e68322..663ccae 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "logger.h"
 
-#include <daemon.h>
 
 /**
  * Maximum length of a log entry (only used for logger_s.log).
index 9f9a37c..322bb32 100644 (file)
@@ -27,7 +27,6 @@
 
 #include <types.h>
 
-
 typedef enum log_level_t log_level_t;
 
 /**
diff --git a/Source/scripts/complex1.der b/Source/scripts/complex1.der
new file mode 100644 (file)
index 0000000..ba460cb
Binary files /dev/null and b/Source/scripts/complex1.der differ
diff --git a/Source/scripts/complex2.der b/Source/scripts/complex2.der
new file mode 100644 (file)
index 0000000..160b21f
Binary files /dev/null and b/Source/scripts/complex2.der differ
index 2a0dbf2..49ec84a 100644 (file)
@@ -136,4 +136,8 @@ $(BUILD_DIR)certificate_test.o :    $(TESTCASES_DIR)certificate_test.c $(TESTCASES_
 
 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 $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)identification_test.o
+$(BUILD_DIR)identification_test.o :    $(TESTCASES_DIR)identification_test.c $(TESTCASES_DIR)identification_test.h
                                                                        $(CC) $(CFLAGS) -c -o $@ $<
\ No newline at end of file
index 025893c..be8a8f7 100644 (file)
  * for more details.
  */
 
+#include <string.h>
+
 #include "certificate_test.h"
 
 #include <daemon.h>
-#include <crypto/certificate.h>
+#include <crypto/x509.h>
 #include <utils/logger.h>
 
 
-
 static char certificate_buffer[] = {
        0x30,0x82,0x02,0xf9,0x30,0x82,0x01,0xe1,0xa0,0x03,0x02,0x01,0x02,0x02,0x11,0x00,
        0xfe,0xae,0xe3,0xcf,0x00,0x27,0x8d,0xa0,0xe1,0xfa,0xb2,0x07,0xd4,0x15,0x40,0x93,
@@ -85,10 +86,27 @@ static char certificate_buffer[] = {
 void test_certificate(protected_tester_t *tester)
 {
        chunk_t certificate = {certificate_buffer, sizeof(certificate_buffer)};
+       identification_t *id;
+       x509_t *cert;
        
-       x509_t *cert = x509_create_from_chunk(certificate);
-       
-       //certificate_t *cert = certificate_create_from_file("myCert.der");
-       
+       cert = x509_create_from_chunk(certificate);
+       id = cert->get_subject(cert);
+       tester->assert_true(tester, strcmp(id->get_string(id), "C=CH, O=Linux strongSwan, CN=maeno") == 0, "subject");
+       id = cert->get_issuer(cert);
+       tester->assert_true(tester, strcmp(id->get_string(id), "C=CH, O=Linux strongSwan, CN=maeno") == 0, "issuer");
+       cert->destroy(cert);
+       /*
+       cert = x509_create_from_file("scripts/complex1.der");
+       id = cert->get_subject(cert);
+       printf("Subject: %s\n", id->get_string(id));
+       id = cert->get_issuer(cert);
+       printf("Issuer: %s\n", id->get_string(id));
        cert->destroy(cert);
+       
+       cert = x509_create_from_file("scripts/complex2.der");
+       id = cert->get_subject(cert);
+       printf("Subject: %s\n", id->get_string(id));
+       id = cert->get_issuer(cert);
+       printf("Issuer: %s\n", id->get_string(id));
+       cert->destroy(cert);*/
 }
index 909136c..2b2a4d4 100644 (file)
@@ -33,8 +33,8 @@ void test_connection(protected_tester_t *tester)
 {
        host_t *alice = host_create(AF_INET, "192.168.0.1", 500);
        host_t *bob = host_create(AF_INET, "192.168.0.2", 500);
-       identification_t *alice_id = identification_create_from_string(AF_INET, "192.168.0.1");
-       identification_t *bob_id = identification_create_from_string(AF_INET, "192.168.0.2");
+       identification_t *alice_id = identification_create_from_string("192.168.0.1");
+       identification_t *bob_id = identification_create_from_string("192.168.0.2");
        connection_t *connection = connection_create(alice, bob, alice_id, bob_id, RSA_DIGITAL_SIGNATURE);
        proposal_t *prop1, *prop2, *prop3, *prop4;
        linked_list_t *list;
diff --git a/Source/testing/identification_test.c b/Source/testing/identification_test.c
new file mode 100644 (file)
index 0000000..b148b53
--- /dev/null
@@ -0,0 +1,166 @@
+/**
+ * @file identification_test.c
+ * 
+ * @brief Tests for the identification_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 <string.h>
+
+#include "identification_test.h"
+
+#include <utils/identification.h>
+#include <utils/logger.h>
+
+/*
+ * described in Header-File
+ */
+void test_identification(protected_tester_t *tester)
+{
+       identification_t *a, *b, *c, *d;
+       bool result;
+       
+       { /* test RFC822_ADDR */
+               char *bob_string = "bob@wonderland.net";
+               chunk_t bob_chunk = {bob_string, strlen(bob_string)};
+               
+               a = identification_create_from_string("alice@wonderland.net");
+               b = identification_create_from_encoding(ID_RFC822_ADDR, bob_chunk);
+               c = identification_create_from_string("*@wonderland.net");
+               d = identification_create_from_string("*@badlands.com");
+               
+               result = a->belongs_to(a, c);
+               tester->assert_true(tester, result, "alice belongs to wonderland");
+               result = b->belongs_to(b, c);
+               tester->assert_true(tester, result, "bob belongs to wonderland");
+               result = a->belongs_to(a, d);
+               tester->assert_false(tester, result, "alice does not belong to badlands");
+               result = b->belongs_to(b, d);
+               tester->assert_false(tester, result, "bob does not belong to badlands");
+               result = c->belongs_to(c, d);
+               tester->assert_false(tester, result, "wonderland is not in badlands");
+               result = a->belongs_to(a, a);
+               tester->assert_true(tester, result, "alice belongs to alice alice");
+               result = a->equals(a, a);
+               tester->assert_true(tester, result, "alice is alice");
+               result = a->equals(a, b);
+               tester->assert_false(tester, result, "alice is not bob");
+               
+               a->destroy(a);
+               b->destroy(b);
+               c->destroy(c);
+               d->destroy(d);
+       }
+       
+       { /* test FQDN */
+               char *bob_string = "@dave.nirvana.org";
+               chunk_t bob_chunk = {bob_string, strlen(bob_string)};
+               
+               a = identification_create_from_string("@carol.nirvana.org");
+               b = identification_create_from_encoding(ID_FQDN, bob_chunk);
+               c = identification_create_from_string("@*.nirvana.org");
+               d = identification_create_from_string("@*.samsara.com");
+               
+               result = a->belongs_to(a, c);
+               tester->assert_true(tester, result, "carol belongs to nirvana");
+               result = b->belongs_to(b, c);
+               tester->assert_true(tester, result, "dave belongs to nirvana");
+               result = a->belongs_to(a, d);
+               tester->assert_false(tester, result, "carol does not belong to samsara");
+               result = b->belongs_to(b, d);
+               tester->assert_false(tester, result, "dave does not belong to samsara");
+               result = c->belongs_to(c, d);
+               tester->assert_false(tester, result, "nirvana is not in samsara");
+               result = a->belongs_to(a, a);
+               tester->assert_true(tester, result, "carol belongs to carol carol");
+               result = a->equals(a, a);
+               tester->assert_true(tester, result, "carol is carol");
+               result = a->equals(a, b);
+               tester->assert_false(tester, result, "carol is not dave");
+               
+               a->destroy(a);
+               b->destroy(b);
+               c->destroy(c);
+               d->destroy(d);
+       }
+       
+       
+       { /* test ID IPV4 ADDR, no wildcards yet */
+               char bob_addr[] = {192,168,0,2};
+               chunk_t bob_chunk = chunk_from_buf(bob_addr);
+               
+               a = identification_create_from_string("192.168.0.1");
+               b = identification_create_from_encoding(ID_IPV4_ADDR, bob_chunk);
+               c = identification_create_from_string("192.168.0.2"); /* as bob */
+               
+               result = a->equals(a, a);
+               tester->assert_true(tester, result, "IPV4_ADDR of alice equals IPV4_ADDR of alice");
+               result = b->equals(b, c);
+               tester->assert_true(tester, result, "IPV4_ADDR of bob equals IPV4_ADDR of carol");
+               result = a->equals(a, b);
+               tester->assert_false(tester, result, "IPV4_ADDR of alice doesn't equal IPV4_ADDR of bob");
+               
+               a->destroy(a);
+               b->destroy(b);
+               c->destroy(c);
+       }
+       
+       { /* test ID IPV6 ADDR, no wildcards yet */
+               char bob_addr[] = {0x20,0x01,0x0d,0xb8,0x85,0xa3,0x08,0xd3,0x13,0x19,0x8a,0x2e,0x03,0x70,0x73,0x44};
+               chunk_t bob_chunk = chunk_from_buf(bob_addr);
+               
+               a = identification_create_from_string("2001:0db8:85a3:08d3:1319:8a2e:0370:7345");
+               b = identification_create_from_encoding(ID_IPV6_ADDR, bob_chunk);
+               c = identification_create_from_string("2001:0db8:85a3:08d3:1319:8a2e:0370:7344"); /* as bob */
+               
+               result = a->equals(a, a);
+               tester->assert_true(tester, result, "IPV6_ADDR of alice equals IPV6_ADDR of alice");
+               result = b->equals(b, c);
+               tester->assert_true(tester, result, "IPV6_ADDR of bob equals IPV6_ADDR of carol");
+               result = a->equals(a, b);
+               tester->assert_false(tester, result, "IPV6_ADDR of alice doesn't equal IPV6_ADDR of bob");
+               
+               a->destroy(a);
+               b->destroy(b);
+               c->destroy(c);
+       }
+       
+       { /* test ID DER_ASN1_DN */
+               a = identification_create_from_string("C=CH, O=Linux strongSwan, CN=alice");
+               b = identification_create_from_string("O=Linux strongSwan, C=CH, CN=bob");
+               c = identification_create_from_string("C=CH, O=Linux strongSwan, CN=*");
+               d = identification_create_from_string("C=CH, O=Linux openswan, CN=*");
+               
+               result = a->equals(a, a);
+               tester->assert_true(tester, result, "DN of alice equals DN of alice");
+               result = a->equals(a, b);
+               tester->assert_false(tester, result, "DN of alice doesn't equal DN of bob");
+               result = a->belongs_to(a, c);
+               tester->assert_true(tester, result, "DN of alice belongs to DN of carol");
+               /* TODO: This does NOT work, wildcard check should work with unordered RDNs */
+               result = b->belongs_to(b, c);
+               tester->assert_true(tester, result, "DN of bob belongs to DN of carol");
+               result = b->belongs_to(b, d);
+               tester->assert_false(tester, result, "DN of bob doesn't belong to DN of dave");
+               
+               a->destroy(a);
+               b->destroy(b);
+               c->destroy(c);
+               d->destroy(d);
+       }
+}
diff --git a/Source/testing/identification_test.h b/Source/testing/identification_test.h
new file mode 100644 (file)
index 0000000..b1078c5
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+ * @file identification_test.h
+ * 
+ * @brief Tests for the identification_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 IDENTIFICATION_TEST_H_
+#define IDENTIFICATION_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the identification functionality.
+ *
+ * @param tester associated tester object
+ * 
+ * @ingroup testcases
+ */
+void test_identification(protected_tester_t *tester);
+
+#endif /* IDENTIFICATION_TEST_H_ */
index 0b09877..38fc7cd 100644 (file)
@@ -46,8 +46,8 @@ void test_policy(protected_tester_t *tester)
        logger = logger_manager->get_logger(logger_manager, TESTER);
        logger->disable_level(logger, FULL);
        
-       alice = identification_create_from_string(ID_IPV4_ADDR, "152.96.193.131");
-       bob = identification_create_from_string(ID_IPV4_ADDR, "152.96.193.130");
+       alice = identification_create_from_string("152.96.193.131");
+       bob = identification_create_from_string("152.96.193.130");
        policy = policy_create(alice, bob);
        
        tester->assert_true(tester, (policy != NULL), "policy construction");
index a3ab3e4..6969015 100644 (file)
@@ -26,7 +26,7 @@
 
 #include <daemon.h>
 #include <utils/logger.h>
-#include <crypto/certificate.h>
+#include <crypto/x509.h>
 
 char private_key_buffer[] = {
        0x30,0x82,0x04,0xa2,0x02,0x00,0x02,0x82,0x01,0x00,0x6f,0x25,0x74,0x63,0x2a,0x2f,
@@ -205,7 +205,7 @@ void test_rsa(protected_tester_t *tester)
        /* key loading */
        private_key = rsa_private_key_create_from_file("alice.der", NULL);
        tester->assert_true(tester, private_key != NULL, "loading private key from file");
-       certificate = certificate_create_from_file("alice-cert.der");
+       certificate = x509_create_from_file("alice-cert.der");
        tester->assert_true(tester, public_key != NULL, "loading certificate from file");
        public_key = certificate->get_public_key(certificate);
        tester->assert_true(tester, public_key != NULL, "loading public key from certificate");
index 0f4201b..72ba52c 100644 (file)
@@ -63,6 +63,7 @@
 #include "child_sa_test.h"
 #include "certificate_test.h"
 #include "leak_detective_test.h"
+#include "identification_test.h"
 
 /* output for test messages */
 extern FILE * stderr;
@@ -131,6 +132,7 @@ test_t kernel_interface_test = {test_kernel_interface, "Kernel Interface"};
 test_t child_sa_test = {test_child_sa, "Child SA"};
 test_t certificate_test = {test_certificate, "X509 Certificate"};
 test_t leak_detective_test = {test_leak_detective, "LEAK detective"};
+test_t identification_test = {test_identification, "identification"};
 
 
 daemon_t* charon;