summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.pc/.quilt_patches1
-rw-r--r--.pc/.quilt_series1
-rw-r--r--.pc/.version1
-rw-r--r--.pc/applied-patches1
-rw-r--r--.pc/snprintf-fix-4.4.0.patch/.timestamp0
-rw-r--r--.pc/snprintf-fix-4.4.0.patch/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c533
-rw-r--r--.pc/snprintf-fix-4.4.0.patch/src/libstrongswan/utils/identification.c1032
-rw-r--r--.pc/snprintf-fix-4.4.0.patch/src/pluto/x509.c459
-rw-r--r--debian/patches/snprintf-fix-4.4.0.patch48
-rw-r--r--src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c11
-rw-r--r--src/libstrongswan/utils/identification.c12
-rw-r--r--src/pluto/x509.c4
12 files changed, 2075 insertions, 28 deletions
diff --git a/.pc/.quilt_patches b/.pc/.quilt_patches
new file mode 100644
index 000000000..6857a8d44
--- /dev/null
+++ b/.pc/.quilt_patches
@@ -0,0 +1 @@
+debian/patches
diff --git a/.pc/.quilt_series b/.pc/.quilt_series
new file mode 100644
index 000000000..c2067066a
--- /dev/null
+++ b/.pc/.quilt_series
@@ -0,0 +1 @@
+series
diff --git a/.pc/.version b/.pc/.version
new file mode 100644
index 000000000..0cfbf0888
--- /dev/null
+++ b/.pc/.version
@@ -0,0 +1 @@
+2
diff --git a/.pc/applied-patches b/.pc/applied-patches
new file mode 100644
index 000000000..326403814
--- /dev/null
+++ b/.pc/applied-patches
@@ -0,0 +1 @@
+snprintf-fix-4.4.0.patch
diff --git a/.pc/snprintf-fix-4.4.0.patch/.timestamp b/.pc/snprintf-fix-4.4.0.patch/.timestamp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/.pc/snprintf-fix-4.4.0.patch/.timestamp
diff --git a/.pc/snprintf-fix-4.4.0.patch/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c b/.pc/snprintf-fix-4.4.0.patch/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c
new file mode 100644
index 000000000..ff3ddeb6f
--- /dev/null
+++ b/.pc/snprintf-fix-4.4.0.patch/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright (C) 2007-2009 Andreas Steffen
+ *
+ * HSR 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 <asn1/oid.h>
+#include <asn1/asn1.h>
+#include <asn1/asn1_parser.h>
+#include <utils/linked_list.h>
+#include <utils/lexparser.h>
+
+#include "ietf_attributes.h"
+
+/**
+ * Private definition of IETF attribute types
+ */
+typedef enum {
+ IETF_ATTRIBUTE_OCTETS = 0,
+ IETF_ATTRIBUTE_OID = 1,
+ IETF_ATTRIBUTE_STRING = 2
+} ietf_attribute_type_t;
+
+typedef struct ietf_attr_t ietf_attr_t;
+
+/**
+ * Private definition of an IETF attribute
+ */
+struct ietf_attr_t {
+ /**
+ * IETF attribute type
+ */
+ ietf_attribute_type_t type;
+
+ /**
+ * IETF attribute value
+ */
+ chunk_t value;
+
+ /**
+ * Compares two IETF attributes
+ *
+ * return -1 if this is earlier in the alphabet than other
+ * return 0 if this equals other
+ * return +1 if this is later in the alphabet than other
+ *
+ * @param other other object
+ */
+ int (*compare) (ietf_attr_t *this, ietf_attr_t *other);
+
+ /**
+ * Destroys an ietf_attr_t object.
+ */
+ void (*destroy) (ietf_attr_t *this);
+};
+
+/**
+ * Implements ietf_attr_t.compare.
+ */
+static int ietf_attr_compare(ietf_attr_t *this, ietf_attr_t *other)
+{
+ int cmp_len, len, cmp_value;
+
+ /* OID attributes are appended after STRING and OCTETS attributes */
+ if (this->type != IETF_ATTRIBUTE_OID && other->type == IETF_ATTRIBUTE_OID)
+ {
+ return -1;
+ }
+ if (this->type == IETF_ATTRIBUTE_OID && other->type != IETF_ATTRIBUTE_OID)
+ {
+ return 1;
+ }
+
+ cmp_len = this->value.len - other->value.len;
+ len = (cmp_len < 0) ? this->value.len : other->value.len;
+ cmp_value = memcmp(this->value.ptr, other->value.ptr, len);
+
+ return (cmp_value == 0) ? cmp_len : cmp_value;
+}
+
+/**
+ * Implements ietf_attr_t.destroy.
+ */
+static void ietf_attr_destroy(ietf_attr_t *this)
+{
+ free(this->value.ptr);
+ free(this);
+}
+
+/**
+ * Creates an ietf_attr_t object.
+ */
+static ietf_attr_t* ietf_attr_create(ietf_attribute_type_t type, chunk_t value)
+{
+ ietf_attr_t *this = malloc_thing(ietf_attr_t);
+
+ /* initialize */
+ this->type = type;
+ this->value = chunk_clone(value);
+
+ /* function */
+ this->compare = ietf_attr_compare;
+ this->destroy = ietf_attr_destroy;
+
+ return this;
+}
+
+typedef struct private_ietf_attributes_t private_ietf_attributes_t;
+
+/**
+ * Private data of an ietf_attributes_t object.
+ */
+struct private_ietf_attributes_t {
+ /**
+ * Public interface.
+ */
+ ietf_attributes_t public;
+
+ /**
+ * Printable representation of the IETF attributes
+ */
+ char *string;
+
+ /**
+ * Linked list of IETF attributes.
+ */
+ linked_list_t *list;
+
+ /**
+ * reference count
+ */
+ refcount_t ref;
+};
+
+/**
+ * Implementation of ietf_attributes_t.get_string.
+ */
+static char* get_string(private_ietf_attributes_t *this)
+{
+ if (this->string == NULL)
+ {
+ char buf[BUF_LEN];
+ char *pos = buf;
+ int len = BUF_LEN;
+ bool first = TRUE;
+ ietf_attr_t *attr;
+ enumerator_t *enumerator;
+
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ int written = 0;
+
+ if (first)
+ {
+ first = FALSE;
+ }
+ else
+ {
+ written = snprintf(pos, len, ", ");
+ pos += written;
+ len -= written;
+ }
+
+ switch (attr->type)
+ {
+ case IETF_ATTRIBUTE_OCTETS:
+ case IETF_ATTRIBUTE_STRING:
+ written = snprintf(pos, len, "%.*s", (int)attr->value.len,
+ attr->value.ptr);
+ break;
+ case IETF_ATTRIBUTE_OID:
+ {
+ int oid = asn1_known_oid(attr->value);
+
+ if (oid == OID_UNKNOWN)
+ {
+ written = snprintf(pos, len, "0x#B", &attr->value);
+ }
+ else
+ {
+ written = snprintf(pos, len, "%s", oid_names[oid]);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ pos += written;
+ len -= written;
+ }
+ enumerator->destroy(enumerator);
+ if (len < BUF_LEN)
+ {
+ this->string = strdup(buf);
+ }
+ }
+ return this->string;
+}
+
+/**
+ * Implementation of ietf_attributes_t.get_encoding.
+ */
+static chunk_t get_encoding(private_ietf_attributes_t *this)
+{
+ chunk_t values;
+ size_t size = 0;
+ u_char *pos;
+ ietf_attr_t *attr;
+ enumerator_t *enumerator;
+
+ /* precalculate the total size of all values */
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ size_t len = attr->value.len;
+
+ size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len;
+ }
+ enumerator->destroy(enumerator);
+
+ pos = asn1_build_object(&values, ASN1_SEQUENCE, size);
+
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ chunk_t ietfAttribute;
+ asn1_t type = ASN1_NULL;
+
+ switch (attr->type)
+ {
+ case IETF_ATTRIBUTE_OCTETS:
+ type = ASN1_OCTET_STRING;
+ break;
+ case IETF_ATTRIBUTE_STRING:
+ type = ASN1_UTF8STRING;
+ break;
+ case IETF_ATTRIBUTE_OID:
+ type = ASN1_OID;
+ break;
+ }
+ ietfAttribute = asn1_simple_object(type, attr->value);
+
+ /* copy ietfAttribute into values chunk */
+ memcpy(pos, ietfAttribute.ptr, ietfAttribute.len);
+ pos += ietfAttribute.len;
+ free(ietfAttribute.ptr);
+ }
+ enumerator->destroy(enumerator);
+
+ return asn1_wrap(ASN1_SEQUENCE, "m", values);
+}
+
+static bool equals(private_ietf_attributes_t *this, private_ietf_attributes_t *other)
+{
+ bool result = TRUE;
+
+ /* lists must have the same number of attributes */
+ if (other == NULL ||
+ this->list->get_count(this->list) != other->list->get_count(other->list))
+ {
+ return FALSE;
+ }
+
+ /* compare two alphabetically-sorted lists */
+ {
+ ietf_attr_t *attr_a, *attr_b;
+ enumerator_t *enum_a, *enum_b;
+
+ enum_a = this->list->create_enumerator(this->list);
+ enum_b = other->list->create_enumerator(other->list);
+ while (enum_a->enumerate(enum_a, &attr_a) &&
+ enum_b->enumerate(enum_b, &attr_b))
+ {
+ if (attr_a->compare(attr_a, attr_b) != 0)
+ {
+ /* we have a mismatch */
+ result = FALSE;
+ break;
+ }
+ }
+ enum_a->destroy(enum_a);
+ enum_b->destroy(enum_b);
+ }
+ return result;
+}
+
+static bool matches(private_ietf_attributes_t *this, private_ietf_attributes_t *other)
+{
+ bool result = FALSE;
+ ietf_attr_t *attr_a, *attr_b;
+ enumerator_t *enum_a, *enum_b;
+
+ /* always match if this->list does not contain any attributes */
+ if (this->list->get_count(this->list) == 0)
+ {
+ return TRUE;
+ }
+
+ /* never match if other->list does not contain any attributes */
+ if (other == NULL || other->list->get_count(other->list) == 0)
+ {
+ return FALSE;
+ }
+
+ /* get first attribute from both lists */
+ enum_a = this->list->create_enumerator(this->list);
+ enum_a->enumerate(enum_a, &attr_a);
+ enum_b = other->list->create_enumerator(other->list);
+ enum_b->enumerate(enum_b, &attr_b);
+
+ /* look for at least one common attribute */
+ while (TRUE)
+ {
+ bool cmp = attr_a->compare(attr_a, attr_b);
+
+ if (cmp == 0)
+ {
+ /* we have a match */
+ result = TRUE;
+ break;
+ }
+ if (cmp == -1)
+ {
+ /* attr_a is earlier in the alphabet, get next attr_a */
+ if (!enum_a->enumerate(enum_a, &attr_a))
+ {
+ /* we have reached the end of enum_a */
+ break;
+ }
+ }
+ else
+ {
+ /* attr_a is later in the alphabet, get next attr_b */
+ if (!enum_b->enumerate(enum_b, &attr_b))
+ {
+ /* we have reached the end of enum_b */
+ break;
+ }
+ }
+ }
+ enum_a->destroy(enum_a);
+ enum_b->destroy(enum_b);
+
+ return result;
+}
+
+/**
+ * Implementation of ietf_attributes_t.get_ref
+ */
+static private_ietf_attributes_t* get_ref(private_ietf_attributes_t *this)
+{
+ ref_get(&this->ref);
+ return this;
+}
+
+/**
+ * Implementation of ietf_attributes_t.destroy.
+ */
+static void destroy(private_ietf_attributes_t *this)
+{
+ if (ref_put(&this->ref))
+ {
+ this->list->destroy_offset(this->list, offsetof(ietf_attr_t, destroy));
+ free(this->string);
+ free(this);
+ }
+}
+
+static private_ietf_attributes_t* create_empty(void)
+{
+ private_ietf_attributes_t *this = malloc_thing(private_ietf_attributes_t);
+
+ this->public.get_string = (char* (*)(ietf_attributes_t*))get_string;
+ this->public.get_encoding = (chunk_t (*)(ietf_attributes_t*))get_encoding;
+ this->public.equals = (bool (*)(ietf_attributes_t*,ietf_attributes_t*))equals;
+ this->public.matches = (bool (*)(ietf_attributes_t*,ietf_attributes_t*))matches;
+ this->public.get_ref = (ietf_attributes_t* (*)(ietf_attributes_t*))get_ref;
+ this->public.destroy = (void (*)(ietf_attributes_t*))destroy;
+
+ this->list = linked_list_create();
+ this->string = NULL;
+ this->ref = 1;
+ return this;
+}
+
+/**
+ * Adds an ietf_attr_t object to a sorted linked list
+ */
+static void ietf_attributes_add(private_ietf_attributes_t *this,
+ ietf_attr_t *attr)
+{
+ ietf_attr_t *current_attr;
+ bool found = FALSE;
+ iterator_t *iterator;
+
+ iterator = this->list->create_iterator(this->list, TRUE);
+ while (iterator->iterate(iterator, (void **)&current_attr))
+ {
+ int cmp = attr->compare(attr, current_attr);
+
+ if (cmp > 0)
+ {
+ continue;
+ }
+ if (cmp == 0)
+ {
+ attr->destroy(attr);
+ }
+ else
+ {
+ iterator->insert_before(iterator, attr);
+ }
+ found = TRUE;
+ break;
+ }
+ iterator->destroy(iterator);
+ if (!found)
+ {
+ this->list->insert_last(this->list, attr);
+ }
+}
+
+/*
+ * Described in header.
+ */
+ietf_attributes_t *ietf_attributes_create_from_string(char *string)
+{
+ private_ietf_attributes_t *this = create_empty();
+
+ chunk_t line = { string, strlen(string) };
+
+ while (eat_whitespace(&line))
+ {
+ chunk_t group;
+
+ /* extract the next comma-separated group attribute */
+ if (!extract_token(&group, ',', &line))
+ {
+ group = line;
+ line.len = 0;
+ }
+
+ /* remove any trailing spaces */
+ while (group.len > 0 && *(group.ptr + group.len - 1) == ' ')
+ {
+ group.len--;
+ }
+
+ /* add the group attribute to the list */
+ if (group.len > 0)
+ {
+ ietf_attr_t *attr = ietf_attr_create(IETF_ATTRIBUTE_STRING, group);
+
+ ietf_attributes_add(this, attr);
+ }
+ }
+
+ return &(this->public);
+}
+
+/**
+ * ASN.1 definition of ietfAttrSyntax
+ */
+static const asn1Object_t ietfAttrSyntaxObjects[] =
+{
+ { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_BODY }, /* 1 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
+ { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */
+ { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT |
+ ASN1_BODY }, /* 4 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
+ { 2, "oid", ASN1_OID, ASN1_OPT |
+ ASN1_BODY }, /* 6 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
+ { 2, "string", ASN1_UTF8STRING, ASN1_OPT |
+ ASN1_BODY }, /* 8 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
+ { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+#define IETF_ATTR_OCTETS 4
+#define IETF_ATTR_OID 6
+#define IETF_ATTR_STRING 8
+
+/*
+ * Described in header.
+ */
+ietf_attributes_t *ietf_attributes_create_from_encoding(chunk_t encoded)
+{
+ private_ietf_attributes_t *this = create_empty();
+ asn1_parser_t *parser;
+ chunk_t object;
+ int objectID;
+
+ parser = asn1_parser_create(ietfAttrSyntaxObjects, encoded);
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ switch (objectID)
+ {
+ case IETF_ATTR_OCTETS:
+ case IETF_ATTR_OID:
+ case IETF_ATTR_STRING:
+ {
+ ietf_attribute_type_t type;
+ ietf_attr_t *attr;
+
+ type = (objectID - IETF_ATTR_OCTETS) / 2;
+ attr = ietf_attr_create(type, object);
+ ietf_attributes_add(this, attr);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ parser->destroy(parser);
+
+ return &(this->public);
+}
+
diff --git a/.pc/snprintf-fix-4.4.0.patch/src/libstrongswan/utils/identification.c b/.pc/snprintf-fix-4.4.0.patch/src/libstrongswan/utils/identification.c
new file mode 100644
index 000000000..6a3c3936c
--- /dev/null
+++ b/.pc/snprintf-fix-4.4.0.patch/src/libstrongswan/utils/identification.c
@@ -0,0 +1,1032 @@
+/*
+ * Copyright (C) 2009 Tobias Brunner
+ * Copyright (C) 2005-2009 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "identification.h"
+
+#include <asn1/oid.h>
+#include <asn1/asn1.h>
+#include <crypto/hashers/hasher.h>
+
+ENUM_BEGIN(id_match_names, ID_MATCH_NONE, ID_MATCH_MAX_WILDCARDS,
+ "MATCH_NONE",
+ "MATCH_ANY",
+ "MATCH_MAX_WILDCARDS");
+ENUM_NEXT(id_match_names, ID_MATCH_PERFECT, ID_MATCH_PERFECT, ID_MATCH_MAX_WILDCARDS,
+ "MATCH_PERFECT");
+ENUM_END(id_match_names, ID_MATCH_PERFECT);
+
+ENUM_BEGIN(id_type_names, ID_ANY, ID_KEY_ID,
+ "ID_ANY",
+ "ID_IPV4_ADDR",
+ "ID_FQDN",
+ "ID_RFC822_ADDR",
+ "ID_IPV4_ADDR_SUBNET",
+ "ID_IPV6_ADDR",
+ "ID_IPV6_ADDR_SUBNET",
+ "ID_IPV4_ADDR_RANGE",
+ "ID_IPV6_ADDR_RANGE",
+ "ID_DER_ASN1_DN",
+ "ID_DER_ASN1_GN",
+ "ID_KEY_ID");
+ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_MYID, ID_KEY_ID,
+ "ID_DER_ASN1_GN_URI"
+ "ID_IETF_ATTR_STRING"
+ "ID_MYID");
+ENUM_END(id_type_names, ID_MYID);
+
+/**
+ * coding of X.501 distinguished name
+ */
+typedef struct {
+ const u_char *name;
+ int oid;
+ u_char type;
+} x501rdn_t;
+
+static const x501rdn_t x501rdns[] = {
+ {"ND", OID_NAME_DISTINGUISHER, ASN1_PRINTABLESTRING},
+ {"UID", OID_PILOT_USERID, ASN1_PRINTABLESTRING},
+ {"DC", OID_PILOT_DOMAIN_COMPONENT, ASN1_PRINTABLESTRING},
+ {"CN", OID_COMMON_NAME, ASN1_PRINTABLESTRING},
+ {"S", OID_SURNAME, ASN1_PRINTABLESTRING},
+ {"SN", OID_SERIAL_NUMBER, ASN1_PRINTABLESTRING},
+ {"serialNumber", OID_SERIAL_NUMBER, ASN1_PRINTABLESTRING},
+ {"C", OID_COUNTRY, ASN1_PRINTABLESTRING},
+ {"L", OID_LOCALITY, ASN1_PRINTABLESTRING},
+ {"ST", OID_STATE_OR_PROVINCE, ASN1_PRINTABLESTRING},
+ {"O", OID_ORGANIZATION, ASN1_PRINTABLESTRING},
+ {"OU", OID_ORGANIZATION_UNIT, ASN1_PRINTABLESTRING},
+ {"T", OID_TITLE, ASN1_PRINTABLESTRING},
+ {"D", OID_DESCRIPTION, ASN1_PRINTABLESTRING},
+ {"N", OID_NAME, ASN1_PRINTABLESTRING},
+ {"G", OID_GIVEN_NAME, ASN1_PRINTABLESTRING},
+ {"I", OID_INITIALS, ASN1_PRINTABLESTRING},
+ {"ID", OID_UNIQUE_IDENTIFIER, ASN1_PRINTABLESTRING},
+ {"EN", OID_EMPLOYEE_NUMBER, ASN1_PRINTABLESTRING},
+ {"employeeNumber", OID_EMPLOYEE_NUMBER, ASN1_PRINTABLESTRING},
+ {"E", OID_EMAIL_ADDRESS, ASN1_IA5STRING},
+ {"Email", OID_EMAIL_ADDRESS, ASN1_IA5STRING},
+ {"emailAddress", OID_EMAIL_ADDRESS, ASN1_IA5STRING},
+ {"UN", OID_UNSTRUCTURED_NAME, ASN1_IA5STRING},
+ {"unstructuredName",OID_UNSTRUCTURED_NAME, ASN1_IA5STRING},
+ {"TCGID", OID_TCGID, ASN1_PRINTABLESTRING}
+};
+
+/**
+ * maximum number of RDNs in atodn()
+ */
+#define RDN_MAX 20
+
+
+typedef struct private_identification_t private_identification_t;
+
+/**
+ * Private data of an identification_t object.
+ */
+struct private_identification_t {
+ /**
+ * Public interface.
+ */
+ identification_t public;
+
+ /**
+ * Encoded representation of this ID.
+ */
+ chunk_t encoded;
+
+ /**
+ * Type of this ID.
+ */
+ id_type_t type;
+};
+
+/**
+ * Enumerator over RDNs
+ */
+typedef struct {
+ /* implements enumerator interface */
+ enumerator_t public;
+ /* next set to parse, if any */
+ chunk_t sets;
+ /* next sequence in set, if any */
+ chunk_t seqs;
+} rdn_enumerator_t;
+
+METHOD(enumerator_t, rdn_enumerate, bool,
+ rdn_enumerator_t *this, chunk_t *oid, u_char *type, chunk_t *data)
+{
+ chunk_t rdn;
+
+ /* a DN contains one or more SET, each containing one or more SEQUENCES,
+ * each containing a OID/value RDN */
+ if (!this->seqs.len)
+ {
+ /* no SEQUENCEs in current SET, parse next SET */
+ if (asn1_unwrap(&this->sets, &this->seqs) != ASN1_SET)
+ {
+ return FALSE;
+ }
+ }
+ if (asn1_unwrap(&this->seqs, &rdn) == ASN1_SEQUENCE &&
+ asn1_unwrap(&rdn, oid) == ASN1_OID)
+ {
+ int t = asn1_unwrap(&rdn, data);
+
+ if (t != ASN1_INVALID)
+ {
+ *type = t;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Create an enumerator over all RDNs (oid, string type, data) of a DN
+ */
+static enumerator_t* create_rdn_enumerator(chunk_t dn)
+{
+ rdn_enumerator_t *e;
+
+ INIT(e,
+ .public = {
+ .enumerate = (void*)_rdn_enumerate,
+ .destroy = (void*)free,
+ },
+ );
+
+ /* a DN is a SEQUENCE, get the first SET of it */
+ if (asn1_unwrap(&dn, &e->sets) == ASN1_SEQUENCE)
+ {
+ e->seqs = chunk_empty;
+ return &e->public;
+ }
+ free(e);
+ return enumerator_create_empty();
+}
+
+/**
+ * Part enumerator over RDNs
+ */
+typedef struct {
+ /* implements enumerator interface */
+ enumerator_t public;
+ /* inner RDN enumerator */
+ enumerator_t *inner;
+} rdn_part_enumerator_t;
+
+METHOD(enumerator_t, rdn_part_enumerate, bool,
+ rdn_part_enumerator_t *this, id_part_t *type, chunk_t *data)
+{
+ int i, known_oid, strtype;
+ chunk_t oid, inner_data;
+ static const struct {
+ int oid;
+ id_part_t type;
+ } oid2part[] = {
+ {OID_COMMON_NAME, ID_PART_RDN_CN},
+ {OID_SURNAME, ID_PART_RDN_S},
+ {OID_SERIAL_NUMBER, ID_PART_RDN_SN},
+ {OID_COUNTRY, ID_PART_RDN_C},
+ {OID_LOCALITY, ID_PART_RDN_L},
+ {OID_STATE_OR_PROVINCE, ID_PART_RDN_ST},
+ {OID_ORGANIZATION, ID_PART_RDN_O},
+ {OID_ORGANIZATION_UNIT, ID_PART_RDN_OU},
+ {OID_TITLE, ID_PART_RDN_T},
+ {OID_DESCRIPTION, ID_PART_RDN_D},
+ {OID_NAME, ID_PART_RDN_N},
+ {OID_GIVEN_NAME, ID_PART_RDN_G},
+ {OID_INITIALS, ID_PART_RDN_I},
+ {OID_UNIQUE_IDENTIFIER, ID_PART_RDN_ID},
+ {OID_EMAIL_ADDRESS, ID_PART_RDN_E},
+ {OID_EMPLOYEE_NUMBER, ID_PART_RDN_EN},
+ };
+
+ while (this->inner->enumerate(this->inner, &oid, &strtype, &inner_data))
+ {
+ known_oid = asn1_known_oid(oid);
+ for (i = 0; i < countof(oid2part); i++)
+ {
+ if (oid2part[i].oid == known_oid)
+ {
+ *type = oid2part[i].type;
+ *data = inner_data;
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+METHOD(enumerator_t, rdn_part_enumerator_destroy, void,
+ rdn_part_enumerator_t *this)
+{
+ this->inner->destroy(this->inner);
+ free(this);
+}
+
+METHOD(identification_t, create_part_enumerator, enumerator_t*,
+ private_identification_t *this)
+{
+ switch (this->type)
+ {
+ case ID_DER_ASN1_DN:
+ {
+ rdn_part_enumerator_t *e;
+
+ INIT(e,
+ .inner = create_rdn_enumerator(this->encoded),
+ .public = {
+ .enumerate = (void*)_rdn_part_enumerate,
+ .destroy = _rdn_part_enumerator_destroy,
+ },
+ );
+ return &e->public;
+ }
+ case ID_RFC822_ADDR:
+ /* TODO */
+ case ID_FQDN:
+ /* TODO */
+ default:
+ return enumerator_create_empty();
+ }
+}
+
+/**
+ * Print a DN with all its RDN in a buffer to present it to the user
+ */
+static void dntoa(chunk_t dn, char *buf, size_t len)
+{
+ enumerator_t *e;
+ chunk_t oid_data, data, printable;
+ u_char type;
+ int oid, written;
+ bool finished = FALSE;
+
+ e = create_rdn_enumerator(dn);
+ while (e->enumerate(e, &oid_data, &type, &data))
+ {
+ oid = asn1_known_oid(oid_data);
+
+ if (oid == OID_UNKNOWN)
+ {
+ written = snprintf(buf, len, "%#B=", &oid_data);
+ }
+ else
+ {
+ written = snprintf(buf, len,"%s=", oid_names[oid].name);
+ }
+ buf += written;
+ len -= written;
+
+ chunk_printable(data, &printable, '?');
+ written = snprintf(buf, len, "%.*s", printable.len, printable.ptr);
+ chunk_free(&printable);
+ buf += written;
+ len -= written;
+
+ if (data.ptr + data.len != dn.ptr + dn.len)
+ {
+ written = snprintf(buf, len, ", ");
+ buf += written;
+ len -= written;
+ }
+ else
+ {
+ finished = TRUE;
+ break;
+ }
+ }
+ if (!finished)
+ {
+ snprintf(buf, len, "(invalid ID_DER_ASN1_DN)");
+ }
+ e->destroy(e);
+}
+
+/**
+ * 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;
+
+ chunk_t oid = chunk_empty;
+ chunk_t name = chunk_empty;
+ chunk_t rdns[RDN_MAX];
+ int rdn_count = 0;
+ int dn_len = 0;
+ int whitespace = 0;
+ int i = 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
+ {
+ bool found = FALSE;
+
+ for (i = 0; i < countof(x501rdns); i++)
+ {
+ if (strlen(x501rdns[i].name) == oid.len &&
+ strncasecmp(x501rdns[i].name, oid.ptr, oid.len) == 0)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found)
+ {
+ status = NOT_SUPPORTED;
+ state = UNKNOWN_OID;
+ break;
+ }
+ /* reset oid and change state */
+ oid = chunk_empty;
+ 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[i].type == ASN1_PRINTABLESTRING
+ && !asn1_is_printablestring(name))
+ ? ASN1_T61STRING : x501rdns[i].type;
+
+ if (rdn_count < RDN_MAX)
+ {
+ chunk_t rdn_oid;
+
+ rdn_oid = asn1_build_known_oid(x501rdns[i].oid);
+ if (rdn_oid.len)
+ {
+ rdns[rdn_count] =
+ asn1_wrap(ASN1_SET, "m",
+ asn1_wrap(ASN1_SEQUENCE, "mm",
+ rdn_oid,
+ asn1_wrap(rdn_type, "c", name)
+ )
+ );
+ dn_len += rdns[rdn_count++].len;
+ }
+ else
+ {
+ status = INVALID_ARG;
+ }
+ }
+ else
+ {
+ status = OUT_OF_RES;
+ }
+ /* reset name and change state */
+ name = chunk_empty;
+ state = SEARCH_OID;
+ }
+ break;
+ case UNKNOWN_OID:
+ break;
+ }
+ } while (*src++ != '\0');
+
+ /* build the distinguished name sequence */
+ {
+ int i;
+ u_char *pos = asn1_build_object(dn, ASN1_SEQUENCE, dn_len);
+
+ for (i = 0; i < rdn_count; i++)
+ {
+ memcpy(pos, rdns[i].ptr, rdns[i].len);
+ pos += rdns[i].len;
+ free(rdns[i].ptr);
+ }
+ }
+
+ if (status != SUCCESS)
+ {
+ free(dn->ptr);
+ *dn = chunk_empty;
+ }
+ return status;
+}
+
+METHOD(identification_t, get_encoding, chunk_t,
+ private_identification_t *this)
+{
+ return this->encoded;
+}
+
+METHOD(identification_t, get_type, id_type_t,
+ private_identification_t *this)
+{
+ return this->type;
+}
+
+METHOD(identification_t, contains_wildcards_dn, bool,
+ private_identification_t *this)
+{
+ enumerator_t *enumerator;
+ bool contains = FALSE;
+ id_part_t type;
+ chunk_t data;
+
+ enumerator = create_part_enumerator(this);
+ while (enumerator->enumerate(enumerator, &type, &data))
+ {
+ if (data.len == 1 && data.ptr[0] == '*')
+ {
+ contains = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return contains;
+}
+
+METHOD(identification_t, contains_wildcards_memchr, bool,
+ private_identification_t *this)
+{
+ return memchr(this->encoded.ptr, '*', this->encoded.len) != NULL;
+}
+
+METHOD(identification_t, equals_binary, bool,
+ private_identification_t *this, identification_t *other)
+{
+ if (this->type == other->get_type(other))
+ {
+ if (this->type == ID_ANY)
+ {
+ return TRUE;
+ }
+ return chunk_equals(this->encoded, other->get_encoding(other));
+ }
+ return FALSE;
+}
+
+/**
+ * Compare to DNs, for equality if wc == NULL, for match otherwise
+ */
+static bool compare_dn(chunk_t t_dn, chunk_t o_dn, int *wc)
+{
+ enumerator_t *t, *o;
+ chunk_t t_oid, o_oid, t_data, o_data;
+ u_char t_type, o_type;
+ bool t_next, o_next, finished = FALSE;
+
+ if (wc)
+ {
+ *wc = 0;
+ }
+ else
+ {
+ if (t_dn.len != o_dn.len)
+ {
+ return FALSE;
+ }
+ }
+ /* try a binary compare */
+ if (memeq(t_dn.ptr, o_dn.ptr, t_dn.len))
+ {
+ return TRUE;
+ }
+
+ t = create_rdn_enumerator(t_dn);
+ o = create_rdn_enumerator(o_dn);
+ while (TRUE)
+ {
+ t_next = t->enumerate(t, &t_oid, &t_type, &t_data);
+ o_next = o->enumerate(o, &o_oid, &o_type, &o_data);
+
+ if (!o_next && !t_next)
+ {
+ break;
+ }
+ finished = FALSE;
+ if (o_next != t_next)
+ {
+ break;
+ }
+ if (!chunk_equals(t_oid, o_oid))
+ {
+ break;
+ }
+ if (wc && o_data.len == 1 && o_data.ptr[0] == '*')
+ {
+ (*wc)++;
+ }
+ else
+ {
+ if (t_data.len != o_data.len)
+ {
+ break;
+ }
+ if (t_type == o_type &&
+ (t_type == ASN1_PRINTABLESTRING ||
+ (t_type == ASN1_IA5STRING &&
+ asn1_known_oid(t_oid) == OID_EMAIL_ADDRESS)))
+ { /* ignore case for printableStrings and email RDNs */
+ if (strncasecmp(t_data.ptr, o_data.ptr, t_data.len) != 0)
+ {
+ break;
+ }
+ }
+ else
+ { /* respect case and length for everything else */
+ if (!memeq(t_data.ptr, o_data.ptr, t_data.len))
+ {
+ break;
+ }
+ }
+ }
+ /* the enumerator returns FALSE on parse error, we are finished
+ * if we have reached the end of the DN only */
+ if ((t_data.ptr + t_data.len == t_dn.ptr + t_dn.len) &&
+ (o_data.ptr + o_data.len == o_dn.ptr + o_dn.len))
+ {
+ finished = TRUE;
+ }
+ }
+ t->destroy(t);
+ o->destroy(o);
+ return finished;
+}
+
+METHOD(identification_t, equals_dn, bool,
+ private_identification_t *this, identification_t *other)
+{
+ return compare_dn(this->encoded, other->get_encoding(other), NULL);
+}
+
+METHOD(identification_t, equals_strcasecmp, bool,
+ private_identification_t *this, identification_t *other)
+{
+ chunk_t encoded = other->get_encoding(other);
+
+ /* we do some extra sanity checks to check for invalid IDs with a
+ * terminating null in it. */
+ if (this->encoded.len == encoded.len &&
+ memchr(this->encoded.ptr, 0, this->encoded.len) == NULL &&
+ memchr(encoded.ptr, 0, encoded.len) == NULL &&
+ strncasecmp(this->encoded.ptr, encoded.ptr, this->encoded.len) == 0)
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+METHOD(identification_t, matches_binary, id_match_t,
+ private_identification_t *this, identification_t *other)
+{
+ if (other->get_type(other) == ID_ANY)
+ {
+ return ID_MATCH_ANY;
+ }
+ if (this->type == other->get_type(other) &&
+ chunk_equals(this->encoded, other->get_encoding(other)))
+ {
+ return ID_MATCH_PERFECT;
+ }
+ return ID_MATCH_NONE;
+}
+
+METHOD(identification_t, matches_string, id_match_t,
+ private_identification_t *this, identification_t *other)
+{
+ chunk_t encoded = other->get_encoding(other);
+ u_int len = encoded.len;
+
+ if (other->get_type(other) == ID_ANY)
+ {
+ return ID_MATCH_ANY;
+ }
+ if (this->type != other->get_type(other))
+ {
+ return ID_MATCH_NONE;
+ }
+ /* try a equals check first */
+ if (equals_strcasecmp(this, other))
+ {
+ return ID_MATCH_PERFECT;
+ }
+ if (len == 0 || this->encoded.len < len)
+ {
+ return ID_MATCH_NONE;
+ }
+
+ /* check for single wildcard at the head of the string */
+ if (*encoded.ptr == '*')
+ {
+ /* single asterisk matches any string */
+ if (len-- == 1)
+ { /* not better than ID_ANY */
+ return ID_MATCH_ANY;
+ }
+ if (strncasecmp(this->encoded.ptr + this->encoded.len - len,
+ encoded.ptr + 1, len) == 0)
+ {
+ return ID_MATCH_ONE_WILDCARD;
+ }
+ }
+ return ID_MATCH_NONE;
+}
+
+METHOD(identification_t, matches_any, id_match_t,
+ private_identification_t *this, identification_t *other)
+{
+ if (other->get_type(other) == ID_ANY)
+ {
+ return ID_MATCH_ANY;
+ }
+ return ID_MATCH_NONE;
+}
+
+METHOD(identification_t, matches_dn, id_match_t,
+ private_identification_t *this, identification_t *other)
+{
+ int wc;
+
+ if (other->get_type(other) == ID_ANY)
+ {
+ return ID_MATCH_ANY;
+ }
+
+ if (this->type == other->get_type(other))
+ {
+ if (compare_dn(this->encoded, other->get_encoding(other), &wc))
+ {
+ wc = min(wc, ID_MATCH_ONE_WILDCARD - ID_MATCH_MAX_WILDCARDS);
+ return ID_MATCH_PERFECT - wc;
+ }
+ }
+ return ID_MATCH_NONE;
+}
+
+/**
+ * Described in header.
+ */
+int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
+ const void *const *args)
+{
+ private_identification_t *this = *((private_identification_t**)(args[0]));
+ chunk_t proper;
+ char buf[512];
+
+ if (this == NULL)
+ {
+ return print_in_hook(dst, len, "%*s", spec->width, "(null)");
+ }
+
+ switch (this->type)
+ {
+ case ID_ANY:
+ snprintf(buf, sizeof(buf), "%%any");
+ break;
+ case ID_IPV4_ADDR:
+ if (this->encoded.len < sizeof(struct in_addr) ||
+ inet_ntop(AF_INET, this->encoded.ptr, buf, sizeof(buf)) == NULL)
+ {
+ snprintf(buf, sizeof(buf), "(invalid ID_IPV4_ADDR)");
+ }
+ break;
+ case ID_IPV6_ADDR:
+ if (this->encoded.len < sizeof(struct in6_addr) ||
+ inet_ntop(AF_INET6, this->encoded.ptr, buf, INET6_ADDRSTRLEN) == NULL)
+ {
+ snprintf(buf, sizeof(buf), "(invalid ID_IPV6_ADDR)");
+ }
+ break;
+ case ID_FQDN:
+ case ID_RFC822_ADDR:
+ case ID_DER_ASN1_GN_URI:
+ case ID_IETF_ATTR_STRING:
+ chunk_printable(this->encoded, &proper, '?');
+ snprintf(buf, sizeof(buf), "%.*s", proper.len, proper.ptr);
+ chunk_free(&proper);
+ break;
+ case ID_DER_ASN1_DN:
+ dntoa(this->encoded, buf, sizeof(buf));
+ break;
+ case ID_DER_ASN1_GN:
+ snprintf(buf, sizeof(buf), "(ASN.1 general Name");
+ break;
+ case ID_KEY_ID:
+ if (chunk_printable(this->encoded, NULL, '?') &&
+ this->encoded.len != HASH_SIZE_SHA1)
+ { /* fully printable, use ascii version */
+ snprintf(buf, sizeof(buf), "%.*s",
+ this->encoded.len, this->encoded.ptr);
+ }
+ else
+ { /* not printable, hex dump */
+ snprintf(buf, sizeof(buf), "%#B", &this->encoded);
+ }
+ break;
+ case ID_MYID:
+ snprintf(buf, sizeof(buf), "%%myid");
+ break;
+ default:
+ snprintf(buf, sizeof(buf), "(unknown ID type: %d)", this->type);
+ break;
+ }
+ if (spec->minus)
+ {
+ return print_in_hook(dst, len, "%-*s", spec->width, buf);
+ }
+ return print_in_hook(dst, len, "%*s", spec->width, buf);
+}
+
+METHOD(identification_t, clone_, identification_t*,
+ private_identification_t *this)
+{
+ private_identification_t *clone = malloc_thing(private_identification_t);
+
+ memcpy(clone, this, sizeof(private_identification_t));
+ if (this->encoded.len)
+ {
+ clone->encoded = chunk_clone(this->encoded);
+ }
+ return &clone->public;
+}
+
+METHOD(identification_t, destroy, void,
+ private_identification_t *this)
+{
+ chunk_free(&this->encoded);
+ free(this);
+}
+
+/**
+ * Generic constructor used for the other constructors.
+ */
+static private_identification_t *identification_create(id_type_t type)
+{
+ private_identification_t *this;
+
+ INIT(this,
+ .public = {
+ .get_encoding = _get_encoding,
+ .get_type = _get_type,
+ .create_part_enumerator = _create_part_enumerator,
+ .clone = _clone_,
+ .destroy = _destroy,
+ },
+ .type = type,
+ );
+
+ switch (type)
+ {
+ case ID_ANY:
+ this->public.matches = _matches_any;
+ this->public.equals = _equals_binary;
+ this->public.contains_wildcards = return_true;
+ break;
+ case ID_FQDN:
+ case ID_RFC822_ADDR:
+ this->public.matches = _matches_string;
+ this->public.equals = _equals_strcasecmp;
+ this->public.contains_wildcards = _contains_wildcards_memchr;
+ break;
+ case ID_DER_ASN1_DN:
+ this->public.equals = _equals_dn;
+ this->public.matches = _matches_dn;
+ this->public.contains_wildcards = _contains_wildcards_dn;
+ break;
+ default:
+ this->public.equals = _equals_binary;
+ this->public.matches = _matches_binary;
+ this->public.contains_wildcards = return_false;
+ break;
+ }
+ return this;
+}
+
+/*
+ * Described in header.
+ */
+identification_t *identification_create_from_string(char *string)
+{
+ private_identification_t *this;
+ chunk_t encoded;
+
+ if (string == NULL)
+ {
+ string = "%any";
+ }
+ if (strchr(string, '=') != NULL)
+ {
+ /* 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
+ */
+ if (atodn(string, &encoded) == SUCCESS)
+ {
+ this = identification_create(ID_DER_ASN1_DN);
+ this->encoded = encoded;
+ }
+ else
+ {
+ this = identification_create(ID_KEY_ID);
+ this->encoded = chunk_clone(chunk_create(string, strlen(string)));
+ }
+ return &this->public;
+ }
+ else if (strchr(string, '@') == NULL)
+ {
+ if (streq(string, "%any")
+ || streq(string, "%any6")
+ || streq(string, "0.0.0.0")
+ || streq(string, "*")
+ || streq(string, "::")
+ || streq(string, "0::0"))
+ {
+ /* any ID will be accepted */
+ this = identification_create(ID_ANY);
+ return &this->public;
+ }
+ else
+ {
+ if (strchr(string, ':') == NULL)
+ {
+ struct in_addr address;
+ chunk_t chunk = {(void*)&address, sizeof(address)};
+
+ if (inet_pton(AF_INET, string, &address) > 0)
+ { /* is IPv4 */
+ this = identification_create(ID_IPV4_ADDR);
+ this->encoded = chunk_clone(chunk);
+ }
+ else
+ { /* not IPv4, mostly FQDN */
+ this = identification_create(ID_FQDN);
+ this->encoded = chunk_create(strdup(string), strlen(string));
+ }
+ return &this->public;
+ }
+ else
+ {
+ struct in6_addr address;
+ chunk_t chunk = {(void*)&address, sizeof(address)};
+
+ if (inet_pton(AF_INET6, string, &address) > 0)
+ { /* is IPv6 */
+ this = identification_create(ID_IPV6_ADDR);
+ this->encoded = chunk_clone(chunk);
+ }
+ else
+ { /* not IPv4/6 fallback to KEY_ID */
+ this = identification_create(ID_KEY_ID);
+ this->encoded = chunk_create(strdup(string), strlen(string));
+ }
+ return &this->public;
+ }
+ }
+ }
+ else
+ {
+ if (*string == '@')
+ {
+ if (*(string + 1) == '#')
+ {
+ this = identification_create(ID_KEY_ID);
+ string += 2;
+ this->encoded = chunk_from_hex(
+ chunk_create(string, strlen(string)), NULL);
+ return &this->public;
+ }
+ else
+ {
+ this = identification_create(ID_FQDN);
+ string += 1;
+ this->encoded = chunk_create(strdup(string), strlen(string));
+ return &this->public;
+ }
+ }
+ else
+ {
+ this = identification_create(ID_RFC822_ADDR);
+ this->encoded = chunk_create(strdup(string), strlen(string));
+ return &this->public;
+ }
+ }
+}
+
+/*
+ * Described in header.
+ */
+identification_t * identification_create_from_data(chunk_t data)
+{
+ char buf[data.len + 1];
+
+ /* use string constructor */
+ snprintf(buf, sizeof(buf), "%.*s", data.len, data.ptr);
+ return identification_create_from_string(buf);
+}
+
+/*
+ * Described in header.
+ */
+identification_t *identification_create_from_encoding(id_type_t type,
+ chunk_t encoded)
+{
+ private_identification_t *this = identification_create(type);
+
+ /* apply encoded chunk */
+ if (type != ID_ANY)
+ {
+ this->encoded = chunk_clone(encoded);
+ }
+ return &(this->public);
+}
+
+/*
+ * Described in header.
+ */
+identification_t *identification_create_from_sockaddr(sockaddr_t *sockaddr)
+{
+ switch (sockaddr->sa_family)
+ {
+ case AF_INET:
+ {
+ struct in_addr *addr = &(((struct sockaddr_in*)sockaddr)->sin_addr);
+
+ return identification_create_from_encoding(ID_IPV4_ADDR,
+ chunk_create((u_char*)addr, sizeof(struct in_addr)));
+ }
+ case AF_INET6:
+ {
+ struct in6_addr *addr = &(((struct sockaddr_in6*)sockaddr)->sin6_addr);
+
+ return identification_create_from_encoding(ID_IPV6_ADDR,
+ chunk_create((u_char*)addr, sizeof(struct in6_addr)));
+ }
+ default:
+ {
+ private_identification_t *this = identification_create(ID_ANY);
+
+ return &(this->public);
+ }
+ }
+}
+
diff --git a/.pc/snprintf-fix-4.4.0.patch/src/pluto/x509.c b/.pc/snprintf-fix-4.4.0.patch/src/pluto/x509.c
new file mode 100644
index 000000000..0a29830ea
--- /dev/null
+++ b/.pc/snprintf-fix-4.4.0.patch/src/pluto/x509.c
@@ -0,0 +1,459 @@
+/* Support of X.509 certificates
+ * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
+ * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
+ * Copyright (C) 2002 Mario Strasser
+ * Copyright (C) 2000-2009 Andreas Steffen - Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+
+#include <asn1/asn1.h>
+#include <crypto/hashers/hasher.h>
+#include <utils/enumerator.h>
+#include <utils/identification.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "x509.h"
+#include "crl.h"
+#include "ca.h"
+#include "certs.h"
+#include "keys.h"
+#include "whack.h"
+#include "fetch.h"
+#include "ocsp.h"
+
+/**
+ * Check for equality between two key identifiers
+ */
+bool same_keyid(chunk_t a, chunk_t b)
+{
+ if (a.ptr == NULL || b.ptr == NULL)
+ {
+ return FALSE;
+ }
+ return chunk_equals(a, b);
+}
+
+/**
+ * Stores a chained list of end certs and CA certs
+ */
+void store_x509certs(linked_list_t *certs, bool strict)
+{
+ cert_t *x509cert, *cacerts = NULL;
+ certificate_t *cert;
+ enumerator_t *enumerator;
+
+ /* first extract CA certs, ignoring self-signed root CA certs */
+
+ enumerator = certs->create_enumerator(certs);
+ while (enumerator->enumerate(enumerator, &cert))
+ {
+ x509_t *x509 = (x509_t*)cert;
+ x509_flag_t flags;
+
+ flags = x509->get_flags(x509);
+ if (flags & X509_CA)
+ {
+ /* we don't accept self-signed CA certs */
+ if (flags & X509_SELF_SIGNED)
+ {
+ plog("self-signed cacert rejected");
+ }
+ else
+ {
+ /* insertion into temporary chain of candidate CA certs */
+ x509cert = malloc_thing(cert_t);
+ *x509cert = cert_empty;
+ x509cert->cert = cert->get_ref(cert);
+ x509cert->next = cacerts;
+ cacerts = x509cert;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ /* now verify the candidate CA certs */
+
+ while (cacerts)
+ {
+ cert_t *cert = cacerts;
+
+ cacerts = cacerts->next;
+
+ if (trust_authcert_candidate(cert, cacerts))
+ {
+ add_authcert(cert, X509_CA);
+ }
+ else
+ {
+ plog("intermediate cacert rejected");
+ cert_free(cert);
+ }
+ }
+
+ /* now verify the end certificates */
+
+ enumerator = certs->create_enumerator(certs);
+ while (enumerator->enumerate(enumerator, &cert))
+ {
+ time_t valid_until;
+ x509_t *x509 = (x509_t*)cert;
+
+ if (!(x509->get_flags(x509) & X509_CA))
+ {
+ x509cert = malloc_thing(cert_t);
+ *x509cert = cert_empty;
+ x509cert->cert = cert->get_ref(cert);
+
+ if (verify_x509cert(x509cert, strict, &valid_until))
+ {
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log("public key validated")
+ )
+ add_public_key_from_cert(x509cert, valid_until, DAL_SIGNED);
+ }
+ else
+ {
+ plog("X.509 certificate rejected");
+ cert_free(x509cert);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Check if a signature over binary blob is genuine
+ */
+bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm,
+ certificate_t *issuer_cert)
+{
+ bool success;
+ public_key_t *key;
+ signature_scheme_t scheme;
+
+ scheme = signature_scheme_from_oid(algorithm);
+ if (scheme == SIGN_UNKNOWN)
+ {
+ return FALSE;
+ }
+
+ key = issuer_cert->get_public_key(issuer_cert);
+ if (key == NULL)
+ {
+ return FALSE;
+ }
+ success = key->verify(key, scheme, tbs, sig);
+ key->destroy(key);
+
+ return success;
+}
+
+/**
+ * Build an ASN.1 encoded PKCS#1 signature over a binary blob
+ */
+chunk_t x509_build_signature(chunk_t tbs, int algorithm, private_key_t *key,
+ bool bit_string)
+{
+ chunk_t signature;
+ signature_scheme_t scheme = signature_scheme_from_oid(algorithm);
+
+ if (scheme == SIGN_UNKNOWN || !key->sign(key, scheme, tbs, &signature))
+ {
+ return chunk_empty;
+ }
+ return (bit_string) ? asn1_bitstring("m", signature)
+ : asn1_wrap(ASN1_OCTET_STRING, "m", signature);
+}
+
+/**
+ * Verifies a X.509 certificate
+ */
+bool verify_x509cert(cert_t *cert, bool strict, time_t *until)
+{
+ int pathlen, pathlen_constraint;
+
+ *until = 0;
+
+ for (pathlen = -1; pathlen <= X509_MAX_PATH_LEN; pathlen++)
+ {
+ certificate_t *certificate = cert->cert;
+ identification_t *subject = certificate->get_subject(certificate);
+ identification_t *issuer = certificate->get_issuer(certificate);
+ x509_t *x509 = (x509_t*)certificate;
+ chunk_t authKeyID = x509->get_authKeyIdentifier(x509);
+ cert_t *issuer_cert;
+ time_t notBefore, notAfter;
+ bool valid;
+
+ DBG(DBG_CONTROL,
+ DBG_log("subject: '%Y'", subject);
+ DBG_log("issuer: '%Y'", issuer);
+ if (authKeyID.ptr)
+ {
+ DBG_log("authkey: %#B", &authKeyID);
+ }
+ )
+
+ valid = certificate->get_validity(certificate, NULL,
+ &notBefore, &notAfter);
+ if (*until == UNDEFINED_TIME || notAfter < *until)
+ {
+ *until = notAfter;
+ }
+ if (!valid)
+ {
+ plog("certificate is invalid (valid from %T to %T)",
+ &notBefore, FALSE, &notAfter, FALSE);
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("certificate is valid")
+ )
+
+ lock_authcert_list("verify_x509cert");
+ issuer_cert = get_authcert(issuer, authKeyID, X509_CA);
+ if (issuer_cert == NULL)
+ {
+ plog("issuer cacert not found");
+ unlock_authcert_list("verify_x509cert");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("issuer cacert found")
+ )
+
+ if (!certificate->issued_by(certificate, issuer_cert->cert))
+ {
+ plog("certificate signature is invalid");
+ unlock_authcert_list("verify_x509cert");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("certificate signature is valid")
+ )
+ unlock_authcert_list("verify_x509cert");
+
+ /* check path length constraint */
+ pathlen_constraint = x509->get_pathLenConstraint(x509);
+ if (pathlen_constraint != X509_NO_PATH_LEN_CONSTRAINT &&
+ pathlen > pathlen_constraint)
+ {
+ plog("path length of %d violates constraint of %d",
+ pathlen, pathlen_constraint);
+ return FALSE;
+ }
+
+ /* check if cert is a self-signed root ca */
+ if (pathlen >= 0 && (x509->get_flags(x509) & X509_SELF_SIGNED))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("reached self-signed root ca with a path length of %d",
+ pathlen)
+ )
+ return TRUE;
+ }
+ else
+ {
+ time_t nextUpdate = *until;
+ time_t revocationDate = UNDEFINED_TIME;
+ crl_reason_t revocationReason = CRL_REASON_UNSPECIFIED;
+
+ /* first check certificate revocation using ocsp */
+ cert_status_t status = verify_by_ocsp(cert, &nextUpdate
+ , &revocationDate, &revocationReason);
+
+ /* if ocsp service is not available then fall back to crl */
+ if ((status == CERT_UNDEFINED)
+ || (status == CERT_UNKNOWN && strict))
+ {
+ status = verify_by_crl(cert, &nextUpdate, &revocationDate
+ , &revocationReason);
+ }
+
+ switch (status)
+ {
+ case CERT_GOOD:
+ /* if status information is stale */
+ if (strict && nextUpdate < time(NULL))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("certificate is good but status is stale")
+ )
+ remove_x509_public_key(cert);
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("certificate is good")
+ )
+
+ /* with strict crl policy the public key must have the same
+ * lifetime as the validity of the ocsp status or crl lifetime
+ */
+ if (strict && nextUpdate < *until)
+ {
+ *until = nextUpdate;
+ }
+ break;
+ case CERT_REVOKED:
+ plog("certificate was revoked on %T, reason: %N"
+ , &revocationDate, TRUE
+ , crl_reason_names, revocationReason);
+ remove_x509_public_key(cert);
+ return FALSE;
+ case CERT_UNKNOWN:
+ case CERT_UNDEFINED:
+ default:
+ plog("certificate status unknown");
+ if (strict)
+ {
+ remove_x509_public_key(cert);
+ return FALSE;
+ }
+ break;
+ }
+ }
+
+ /* go up one step in the trust chain */
+ cert = issuer_cert;
+ }
+ plog("maximum path length of %d exceeded", X509_MAX_PATH_LEN);
+ return FALSE;
+}
+
+/**
+ * List all X.509 certs in a chained list
+ */
+void list_x509cert_chain(const char *caption, cert_t* cert,
+ x509_flag_t flags, bool utc)
+{
+ bool first = TRUE;
+ time_t now;
+
+ /* determine the current time */
+ time(&now);
+
+ while (cert)
+ {
+ certificate_t *certificate = cert->cert;
+ x509_t *x509 = (x509_t*)certificate;
+
+ if (certificate->get_type(certificate) == CERT_X509 &&
+ (flags == X509_NONE || (flags & x509->get_flags(x509))))
+ {
+ enumerator_t *enumerator;
+ char buf[BUF_LEN];
+ char *pos = buf;
+ int len = BUF_LEN, pathlen;
+ bool first_altName = TRUE;
+ identification_t *id;
+ time_t notBefore, notAfter;
+ public_key_t *key;
+ chunk_t serial, keyid, subjkey, authkey;
+
+ if (first)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of X.509 %s Certificates:", caption);
+ first = FALSE;
+ }
+ whack_log(RC_COMMENT, " ");
+
+ enumerator = x509->create_subjectAltName_enumerator(x509);
+ while (enumerator->enumerate(enumerator, &id))
+ {
+ int written;
+
+ if (first_altName)
+ {
+ written = snprintf(pos, len, "%Y", id);
+ first_altName = FALSE;
+ }
+ else
+ {
+ written = snprintf(pos, len, ", %Y", id);
+ }
+ pos += written;
+ len -= written;
+ }
+ enumerator->destroy(enumerator);
+ if (!first_altName)
+ {
+ whack_log(RC_COMMENT, " altNames: %s", buf);
+ }
+
+ whack_log(RC_COMMENT, " subject: \"%Y\"",
+ certificate->get_subject(certificate));
+ whack_log(RC_COMMENT, " issuer: \"%Y\"",
+ certificate->get_issuer(certificate));
+ serial = x509->get_serial(x509);
+ whack_log(RC_COMMENT, " serial: %#B", &serial);
+
+ /* list validity */
+ certificate->get_validity(certificate, &now, &notBefore, &notAfter);
+ whack_log(RC_COMMENT, " validity: not before %T %s",
+ &notBefore, utc,
+ (notBefore < now)?"ok":"fatal (not valid yet)");
+ whack_log(RC_COMMENT, " not after %T %s",
+ &notAfter, utc,
+ check_expiry(notAfter, CA_CERT_WARNING_INTERVAL, TRUE));
+
+ key = certificate->get_public_key(certificate);
+ if (key)
+ {
+ whack_log(RC_COMMENT, " pubkey: %N %4d bits%s",
+ key_type_names, key->get_type(key),
+ key->get_keysize(key) * BITS_PER_BYTE,
+ cert->smartcard ? ", on smartcard" :
+ (has_private_key(cert)? ", has private key" : ""));
+
+ if (key->get_fingerprint(key, KEY_ID_PUBKEY_INFO_SHA1, &keyid))
+ {
+ whack_log(RC_COMMENT, " keyid: %#B", &keyid);
+ }
+ if (key->get_fingerprint(key, KEY_ID_PUBKEY_SHA1, &subjkey))
+ {
+ whack_log(RC_COMMENT, " subjkey: %#B", &subjkey);
+ }
+ key->destroy(key);
+ }
+
+ /* list optional authorityKeyIdentifier */
+ authkey = x509->get_authKeyIdentifier(x509);
+ if (authkey.ptr)
+ {
+ whack_log(RC_COMMENT, " authkey: %#B", &authkey);
+ }
+
+ /* list optional pathLenConstraint */
+ pathlen = x509->get_pathLenConstraint(x509);
+ if (pathlen != X509_NO_PATH_LEN_CONSTRAINT)
+ {
+ whack_log(RC_COMMENT, " pathlen: %d", pathlen);
+ }
+
+ }
+ cert = cert->next;
+ }
+}
+
diff --git a/debian/patches/snprintf-fix-4.4.0.patch b/debian/patches/snprintf-fix-4.4.0.patch
index 467bd2023..0cf97c0b0 100644
--- a/debian/patches/snprintf-fix-4.4.0.patch
+++ b/debian/patches/snprintf-fix-4.4.0.patch
@@ -9,20 +9,20 @@ Subject: [PATCH] snprintf() fixes, version 4.4.0
src/pluto/x509.c | 4 ++++
3 files changed, 27 insertions(+), 2 deletions(-)
-diff --git a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c
-index ff3ddeb..de5b85b 100644
---- a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c
-+++ b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c
-@@ -159,7 +159,7 @@ static char* get_string(private_ietf_attributes_t *this)
+Index: strongswan/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c
+===================================================================
+--- strongswan.orig/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c 2010-06-24 20:43:01.000000000 +0200
++++ strongswan/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c 2010-06-24 20:45:07.000000000 +0200
+@@ -159,7 +159,7 @@
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &attr))
{
- int written = 0;
+ int written;
-
+
if (first)
{
-@@ -168,8 +168,12 @@ static char* get_string(private_ietf_attributes_t *this)
+@@ -168,6 +168,10 @@
else
{
written = snprintf(pos, len, ", ");
@@ -31,12 +31,9 @@ index ff3ddeb..de5b85b 100644
+ break;
+ }
pos += written;
-- len -= written;
-+ len -= written;
+ len -= written;
}
-
- switch (attr->type)
-@@ -194,8 +198,13 @@ static char* get_string(private_ietf_attributes_t *this)
+@@ -194,8 +198,13 @@
break;
}
default:
@@ -50,11 +47,11 @@ index ff3ddeb..de5b85b 100644
pos += written;
len -= written;
}
-diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c
-index b0da340..cff24d7 100644
---- a/src/libstrongswan/utils/identification.c
-+++ b/src/libstrongswan/utils/identification.c
-@@ -297,18 +297,30 @@ static void dntoa(chunk_t dn, char *buf, size_t len)
+Index: strongswan/src/libstrongswan/utils/identification.c
+===================================================================
+--- strongswan.orig/src/libstrongswan/utils/identification.c 2010-06-24 20:43:01.000000000 +0200
++++ strongswan/src/libstrongswan/utils/identification.c 2010-06-24 20:44:09.348295306 +0200
+@@ -297,18 +297,30 @@
{
written = snprintf(buf, len,"%s=", oid_names[oid].name);
}
@@ -64,7 +61,7 @@ index b0da340..cff24d7 100644
+ }
buf += written;
len -= written;
-
+
chunk_printable(data, &printable, '?');
written = snprintf(buf, len, "%.*s", printable.len, printable.ptr);
chunk_free(&printable);
@@ -74,7 +71,7 @@ index b0da340..cff24d7 100644
+ }
buf += written;
len -= written;
-
+
if (data.ptr + data.len != dn.ptr + dn.len)
{
written = snprintf(buf, len, ", ");
@@ -85,11 +82,11 @@ index b0da340..cff24d7 100644
buf += written;
len -= written;
}
-diff --git a/src/pluto/x509.c b/src/pluto/x509.c
-index d8e8879..0dcc4fe 100644
---- a/src/pluto/x509.c
-+++ b/src/pluto/x509.c
-@@ -393,6 +393,10 @@ void list_x509cert_chain(const char *caption, cert_t* cert,
+Index: strongswan/src/pluto/x509.c
+===================================================================
+--- strongswan.orig/src/pluto/x509.c 2010-06-24 20:43:01.000000000 +0200
++++ strongswan/src/pluto/x509.c 2010-06-24 20:44:09.352296635 +0200
+@@ -393,6 +393,10 @@
{
written = snprintf(pos, len, ", %Y", id);
}
@@ -100,6 +97,3 @@ index d8e8879..0dcc4fe 100644
pos += written;
len -= written;
}
---
-1.7.0.4
-
diff --git a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c
index ff3ddeb6f..71dcd28f2 100644
--- a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c
+++ b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c
@@ -159,7 +159,7 @@ static char* get_string(private_ietf_attributes_t *this)
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &attr))
{
- int written = 0;
+ int written;
if (first)
{
@@ -168,6 +168,10 @@ static char* get_string(private_ietf_attributes_t *this)
else
{
written = snprintf(pos, len, ", ");
+ if (written < 0 || written >= len)
+ {
+ break;
+ }
pos += written;
len -= written;
}
@@ -194,8 +198,13 @@ static char* get_string(private_ietf_attributes_t *this)
break;
}
default:
+ written = 0;
break;
}
+ if (written < 0 || written >= len)
+ {
+ break;
+ }
pos += written;
len -= written;
}
diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c
index 6a3c3936c..6ccfa193d 100644
--- a/src/libstrongswan/utils/identification.c
+++ b/src/libstrongswan/utils/identification.c
@@ -297,18 +297,30 @@ static void dntoa(chunk_t dn, char *buf, size_t len)
{
written = snprintf(buf, len,"%s=", oid_names[oid].name);
}
+ if (written < 0 || written >= len)
+ {
+ break;
+ }
buf += written;
len -= written;
chunk_printable(data, &printable, '?');
written = snprintf(buf, len, "%.*s", printable.len, printable.ptr);
chunk_free(&printable);
+ if (written < 0 || written >= len)
+ {
+ break;
+ }
buf += written;
len -= written;
if (data.ptr + data.len != dn.ptr + dn.len)
{
written = snprintf(buf, len, ", ");
+ if (written < 0 || written >= len)
+ {
+ break;
+ }
buf += written;
len -= written;
}
diff --git a/src/pluto/x509.c b/src/pluto/x509.c
index 0a29830ea..0abebc6f0 100644
--- a/src/pluto/x509.c
+++ b/src/pluto/x509.c
@@ -393,6 +393,10 @@ void list_x509cert_chain(const char *caption, cert_t* cert,
{
written = snprintf(pos, len, ", %Y", id);
}
+ if (written < 0 || written >= len)
+ {
+ break;
+ }
pos += written;
len -= written;
}