aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/charon/network/socket.c2
-rwxr-xr-xSource/charon/threads/stroke_interface.c12
-rw-r--r--Source/doc/Todo-list.txt12
-rw-r--r--Source/lib/asn1/asn1.c1
-rw-r--r--Source/lib/asn1/asn1.h1
-rw-r--r--Source/lib/asn1/oid.c29
-rw-r--r--Source/lib/asn1/oid.h17
-rw-r--r--Source/lib/asn1/oid.pl4
-rw-r--r--Source/lib/asn1/oid.txt3
-rwxr-xr-xSource/lib/crypto/x509.c981
-rwxr-xr-xSource/lib/crypto/x509.h12
-rw-r--r--Source/lib/types.h1
-rw-r--r--Source/lib/utils/identification.c1005
-rw-r--r--Source/lib/utils/identification.h67
-rw-r--r--Source/lib/utils/logger.c1
-rw-r--r--Source/lib/utils/logger.h1
-rw-r--r--Source/scripts/complex1.derbin0 -> 934 bytes
-rw-r--r--Source/scripts/complex2.derbin0 -> 956 bytes
-rw-r--r--Source/testing/Makefile.testcases4
-rw-r--r--Source/testing/certificate_test.c30
-rw-r--r--Source/testing/connection_test.c4
-rw-r--r--Source/testing/identification_test.c166
-rw-r--r--Source/testing/identification_test.h37
-rw-r--r--Source/testing/policy_test.c4
-rw-r--r--Source/testing/rsa_test.c4
-rw-r--r--Source/testing/testcases.c2
26 files changed, 1381 insertions, 1019 deletions
diff --git a/Source/charon/network/socket.c b/Source/charon/network/socket.c
index 79c7c421d..32ff84538 100644
--- a/Source/charon/network/socket.c
+++ b/Source/charon/network/socket.c
@@ -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;
diff --git a/Source/charon/threads/stroke_interface.c b/Source/charon/threads/stroke_interface.c
index 274791bcf..2881cb26a 100755
--- a/Source/charon/threads/stroke_interface.c
+++ b/Source/charon/threads/stroke_interface.c
@@ -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)
{
diff --git a/Source/doc/Todo-list.txt b/Source/doc/Todo-list.txt
index 2173213fa..44d8b985c 100644
--- a/Source/doc/Todo-list.txt
+++ b/Source/doc/Todo-list.txt
@@ -27,19 +27,19 @@
+ 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
diff --git a/Source/lib/asn1/asn1.c b/Source/lib/asn1/asn1.c
index 85baf7965..c847461b6 100644
--- a/Source/lib/asn1/asn1.c
+++ b/Source/lib/asn1/asn1.c
@@ -18,7 +18,6 @@
#include <time.h>
#include "asn1.h"
-#include "oid.h"
#include <utils/logger_manager.h>
diff --git a/Source/lib/asn1/asn1.h b/Source/lib/asn1/asn1.h
index 4a99c9a34..556bb2b05 100644
--- a/Source/lib/asn1/asn1.h
+++ b/Source/lib/asn1/asn1.h
@@ -20,6 +20,7 @@
#include <gmp.h>
#include <types.h>
+#include <asn1/oid.h>
/* Defines some primitive ASN1 types */
diff --git a/Source/lib/asn1/oid.c b/Source/lib/asn1/oid.c
index 7b0135d5e..4b0632de2 100644
--- a/Source/lib/asn1/oid.c
+++ b/Source/lib/asn1/oid.c
@@ -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 */
};
diff --git a/Source/lib/asn1/oid.h b/Source/lib/asn1/oid.h
index 4096af357..a9265d43f 100644
--- a/Source/lib/asn1/oid.h
+++ b/Source/lib/asn1/oid.h
@@ -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_ */
diff --git a/Source/lib/asn1/oid.pl b/Source/lib/asn1/oid.pl
index 52ac8eae0..a3725e57d 100644
--- a/Source/lib/asn1/oid.pl
+++ b/Source/lib/asn1/oid.pl
@@ -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;
diff --git a/Source/lib/asn1/oid.txt b/Source/lib/asn1/oid.txt
index ad05a1270..eed46d59d 100644
--- a/Source/lib/asn1/oid.txt
+++ b/Source/lib/asn1/oid.txt
@@ -167,6 +167,9 @@
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"
diff --git a/Source/lib/crypto/x509.c b/Source/lib/crypto/x509.c
index 2b99b2d03..28e7d1898 100755
--- a/Source/lib/crypto/x509.c
+++ b/Source/lib/crypto/x509.c
@@ -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))
diff --git a/Source/lib/crypto/x509.h b/Source/lib/crypto/x509.h
index cd2f08ee1..077238eab 100755
--- a/Source/lib/crypto/x509.h
+++ b/Source/lib/crypto/x509.h
@@ -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);
diff --git a/Source/lib/types.h b/Source/lib/types.h
index 7125a01d2..0e0782b31 100644
--- a/Source/lib/types.h
+++ b/Source/lib/types.h
@@ -30,7 +30,6 @@
#include <definitions.h>
-
/**
* General purpose boolean type.
*/
diff --git a/Source/lib/utils/identification.c b/Source/lib/utils/identification.c
index 05d9d76f9..d99d0e453 100644
--- a/Source/lib/utils/identification.c
+++ b/Source/lib/utils/identification.c
@@ -20,13 +20,18 @@
* 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);
}
diff --git a/Source/lib/utils/identification.h b/Source/lib/utils/identification.h
index 87ac2a8b2..4df665c09 100644
--- a/Source/lib/utils/identification.h
+++ b/Source/lib/utils/identification.h
@@ -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);
diff --git a/Source/lib/utils/logger.c b/Source/lib/utils/logger.c
index 4e6832243..663ccaec5 100644
--- a/Source/lib/utils/logger.c
+++ b/Source/lib/utils/logger.c
@@ -29,7 +29,6 @@
#include "logger.h"
-#include <daemon.h>
/**
* Maximum length of a log entry (only used for logger_s.log).
diff --git a/Source/lib/utils/logger.h b/Source/lib/utils/logger.h
index 9f9a37cba..322bb3264 100644
--- a/Source/lib/utils/logger.h
+++ b/Source/lib/utils/logger.h
@@ -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
index 000000000..ba460cbee
--- /dev/null
+++ b/Source/scripts/complex1.der
Binary files differ
diff --git a/Source/scripts/complex2.der b/Source/scripts/complex2.der
new file mode 100644
index 000000000..160b21f47
--- /dev/null
+++ b/Source/scripts/complex2.der
Binary files differ
diff --git a/Source/testing/Makefile.testcases b/Source/testing/Makefile.testcases
index 2a0dbf234..49ec84a95 100644
--- a/Source/testing/Makefile.testcases
+++ b/Source/testing/Makefile.testcases
@@ -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
diff --git a/Source/testing/certificate_test.c b/Source/testing/certificate_test.c
index 025893c0b..be8a8f7cf 100644
--- a/Source/testing/certificate_test.c
+++ b/Source/testing/certificate_test.c
@@ -20,14 +20,15 @@
* 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);*/
}
diff --git a/Source/testing/connection_test.c b/Source/testing/connection_test.c
index 909136c01..2b2a4d4d8 100644
--- a/Source/testing/connection_test.c
+++ b/Source/testing/connection_test.c
@@ -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
index 000000000..b148b53e0
--- /dev/null
+++ b/Source/testing/identification_test.c
@@ -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
index 000000000..b1078c52f
--- /dev/null
+++ b/Source/testing/identification_test.h
@@ -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_ */
diff --git a/Source/testing/policy_test.c b/Source/testing/policy_test.c
index 0b09877e0..38fc7cd53 100644
--- a/Source/testing/policy_test.c
+++ b/Source/testing/policy_test.c
@@ -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");
diff --git a/Source/testing/rsa_test.c b/Source/testing/rsa_test.c
index a3ab3e4ea..696901531 100644
--- a/Source/testing/rsa_test.c
+++ b/Source/testing/rsa_test.c
@@ -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");
diff --git a/Source/testing/testcases.c b/Source/testing/testcases.c
index 0f4201b42..72ba52c3f 100644
--- a/Source/testing/testcases.c
+++ b/Source/testing/testcases.c
@@ -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;