Additional tests for identification_t added
authorTobias Brunner <tobias@strongswan.org>
Thu, 28 Mar 2013 15:53:07 +0000 (16:53 +0100)
committerTobias Brunner <tobias@strongswan.org>
Tue, 11 Jun 2013 09:03:13 +0000 (11:03 +0200)
src/libstrongswan/tests/test_identification.c

index fd6177f..d21d4c7 100644 (file)
 #include <utils/identification.h>
 
 /*******************************************************************************
+ * create (_from_encoding, _from_data, _from_string, _from_sockaddr)
+ */
+
+START_TEST(test_from_encoding)
+{
+       identification_t *a;
+       chunk_t expected, encoding;
+
+       /* only ID_ANY is handled differently, for all other types the following
+        * applies.  should we perhaps test that this is in fact the case? */
+       expected = chunk_from_str("moon@strongswan.org");
+       a = identification_create_from_encoding(ID_RFC822_ADDR, expected);
+       ck_assert(ID_RFC822_ADDR == a->get_type(a));
+       encoding = a->get_encoding(a);
+       ck_assert(expected.ptr != encoding.ptr);
+       ck_assert(chunk_equals(expected, encoding));
+       a->destroy(a);
+
+       a = identification_create_from_encoding(ID_ANY, expected);
+       ck_assert(ID_ANY == a->get_type(a));
+       encoding = a->get_encoding(a);
+       ck_assert(encoding.ptr == NULL);
+       ck_assert(encoding.len == 0);
+       a->destroy(a);
+}
+END_TEST
+
+START_TEST(test_from_data)
+{
+       identification_t *a;
+       chunk_t expected, encoding;
+
+       /* this uses the DN parser (C=CH) */
+       expected = chunk_from_chars(0x30, 0x0d, 0x31, 0x0b, 0x30, 0x09, 0x06,
+                                                               0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48);
+       a = identification_create_from_data(expected);
+       ck_assert(ID_DER_ASN1_DN == a->get_type(a));
+       encoding = a->get_encoding(a);
+       ck_assert(expected.ptr != encoding.ptr);
+       ck_assert(chunk_equals(expected, encoding));
+       a->destroy(a);
+
+       /* everything else is handled by the string parser */
+       expected = chunk_from_str("moon@strongswan.org");
+       a = identification_create_from_data(expected);
+       ck_assert(ID_RFC822_ADDR == a->get_type(a));
+       encoding = a->get_encoding(a);
+       ck_assert(expected.ptr != encoding.ptr);
+       ck_assert(chunk_equals(expected, encoding));
+       a->destroy(a);
+}
+END_TEST
+
+START_TEST(test_from_sockaddr)
+{
+       identification_t *a;
+       chunk_t expected, encoding;
+       struct sockaddr_in in = {
+               .sin_family = AF_INET,
+       };
+       struct sockaddr_in6 in6 = {
+               .sin6_family = AF_INET6,
+       };
+
+       expected = chunk_from_chars(0xc0, 0xa8, 0x01, 0x01);
+       memcpy(&in.sin_addr, expected.ptr, sizeof(in.sin_addr));
+       a = identification_create_from_sockaddr((sockaddr_t*)&in);
+       ck_assert(ID_IPV4_ADDR == a->get_type(a));
+       encoding = a->get_encoding(a);
+       ck_assert(chunk_equals(expected, encoding));
+       a->destroy(a);
+
+       expected = chunk_from_chars(0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01);
+       memcpy(&in6.sin6_addr, expected.ptr, sizeof(in6.sin6_addr));
+       a = identification_create_from_sockaddr((sockaddr_t*)&in6);
+       ck_assert(ID_IPV6_ADDR == a->get_type(a));
+       encoding = a->get_encoding(a);
+       ck_assert(chunk_equals(expected, encoding));
+       a->destroy(a);
+
+       in6.sin6_family = AF_UNSPEC;
+       a = identification_create_from_sockaddr((sockaddr_t*)&in6);
+       ck_assert(ID_ANY == a->get_type(a));
+       a->destroy(a);
+}
+END_TEST
+
+static struct {
+       char *id;
+       id_type_t type;
+       struct {
+               enum {
+                       ENC_CHUNK,
+                       ENC_STRING,
+                       ENC_SIMPLE,
+               } type;
+               union {
+                       chunk_t c;
+                       char *s;
+               } data;
+       } result;
+} string_data[] = {
+       {NULL,      ID_ANY,  { .type = ENC_CHUNK }},
+       {"",        ID_ANY,  { .type = ENC_CHUNK }},
+       {"%any",    ID_ANY,  { .type = ENC_CHUNK }},
+       {"%any6",   ID_ANY,  { .type = ENC_CHUNK }},
+       {"0.0.0.0", ID_ANY,  { .type = ENC_CHUNK }},
+       {"0::0",    ID_ANY,  { .type = ENC_CHUNK }},
+       {"::",      ID_ANY,  { .type = ENC_CHUNK }},
+       {"*",       ID_ANY,  { .type = ENC_CHUNK }},
+       {"any",     ID_FQDN, { .type = ENC_SIMPLE }},
+       {"any6",    ID_FQDN, { .type = ENC_SIMPLE }},
+       {"0",       ID_FQDN, { .type = ENC_SIMPLE }},
+       {"**",      ID_FQDN, { .type = ENC_SIMPLE }},
+       {"192.168.1.1", ID_IPV4_ADDR, { .type = ENC_CHUNK,
+                                                                       .data.c = chunk_from_chars(0xc0, 0xa8, 0x01, 0x01) }},
+       {"192.168.",ID_FQDN, { .type = ENC_SIMPLE }},
+       {".",       ID_FQDN, { .type = ENC_SIMPLE }},
+       {"fec0::1", ID_IPV6_ADDR, { .type = ENC_CHUNK,
+                                                               .data.c = chunk_from_chars(0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                                                                                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01) }},
+       {"fec0::",  ID_IPV6_ADDR, { .type = ENC_CHUNK,
+                                                               .data.c = chunk_from_chars(0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                                                                                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) }},
+       {"fec0:",   ID_KEY_ID,    { .type = ENC_SIMPLE }},
+       {":",       ID_KEY_ID,    { .type = ENC_SIMPLE }},
+       {"alice@strongswan.org", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
+       {"alice@strongswan", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
+       {"alice@",  ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
+       {"alice",   ID_FQDN, { .type = ENC_SIMPLE }},
+       {"@",       ID_FQDN, { .type = ENC_CHUNK }},
+       {" @",      ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
+       {"@strongswan.org",  ID_FQDN, { .type = ENC_STRING,
+                                                                       .data.s = "strongswan.org" }},
+       {"@#deadbeef", ID_KEY_ID, { .type = ENC_CHUNK,
+                                                               .data.c = chunk_from_chars(0xde, 0xad, 0xbe, 0xef) }},
+       {"@#deadbee",  ID_KEY_ID, { .type = ENC_CHUNK,
+                                                               .data.c = chunk_from_chars(0x0d, 0xea, 0xdb, 0xee) }},
+       {"foo=bar",    ID_KEY_ID, { .type = ENC_SIMPLE }},
+       {"foo=",           ID_KEY_ID, { .type = ENC_SIMPLE }},
+       {"=bar",           ID_KEY_ID, { .type = ENC_SIMPLE }},
+       {"C=",             ID_DER_ASN1_DN, { .type = ENC_CHUNK,
+                                                                        .data.c = chunk_from_chars(0x30, 0x0b, 0x31, 0x09, 0x30, 0x07, 0x06,
+                                                                                                                               0x03, 0x55, 0x04, 0x06, 0x13, 0x00)}},
+       {"C=CH",           ID_DER_ASN1_DN, { .type = ENC_CHUNK,
+                                                                        .data.c = chunk_from_chars(0x30, 0x0d, 0x31, 0x0b, 0x30, 0x09, 0x06,
+                                                                                                                               0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48)}},
+       {"C=CH,",          ID_DER_ASN1_DN, { .type = ENC_CHUNK,
+                                                                        .data.c = chunk_from_chars(0x30, 0x0d, 0x31, 0x0b, 0x30, 0x09, 0x06,
+                                                                                                                               0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48)}},
+       {"C=CH, ",         ID_DER_ASN1_DN, { .type = ENC_CHUNK,
+                                                                        .data.c = chunk_from_chars(0x30, 0x0d, 0x31, 0x0b, 0x30, 0x09, 0x06,
+                                                                                                                               0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48)}},
+       {"C=CH, O",        ID_KEY_ID, { .type = ENC_SIMPLE }},
+};
+
+START_TEST(test_from_string)
+{
+       identification_t *a;
+       chunk_t encoding, expected;
+       char *id;
+
+       id = string_data[_i].id;
+       a = identification_create_from_string(id);
+       fail_unless(a->get_type(a) == string_data[_i].type,
+                               "type of id '%s' is %N, %N expected", id,
+                               id_type_names, a->get_type(a),
+                               id_type_names, string_data[_i].type);
+
+       encoding = a->get_encoding(a);
+       switch (string_data[_i].result.type)
+       {
+               case ENC_SIMPLE:
+                       expected = chunk_from_str(string_data[_i].id);
+                       break;
+               case ENC_STRING:
+                       expected = chunk_from_str(string_data[_i].result.data.s);
+                       break;
+               case ENC_CHUNK:
+                       expected = string_data[_i].result.data.c;
+                       break;
+               default:
+                       fail("unexpected result type");
+       }
+
+       ck_assert(!id || (char*)encoding.ptr != id);
+       if (expected.ptr)
+       {
+               fail_unless(chunk_equals(encoding, expected),
+                                       "parsing '%s' failed\nencoding %B\nexpected %B\n",
+                                       id, &encoding, &expected);
+       }
+       else
+       {
+               ck_assert(encoding.ptr == NULL);
+               ck_assert(encoding.len == 0);
+       }
+       a->destroy(a);
+}
+END_TEST
+
+/*******************************************************************************
+ * printf_hook
+ */
+
+static void string_equals(char *a_str, char *b_str)
+{
+       identification_t *b;
+       char buf[128];
+
+       b = b_str ? identification_create_from_string(b_str) : NULL;
+       snprintf(buf, sizeof(buf), "%Y", b);
+       DESTROY_IF(b);
+       ck_assert_str_eq(a_str, buf);
+}
+
+static void string_equals_id(char *a_str, identification_t *b)
+{
+       char buf[128];
+
+       snprintf(buf, sizeof(buf), "%Y", b);
+       DESTROY_IF(b);
+       ck_assert_str_eq(a_str, buf);
+}
+
+START_TEST(test_printf_hook)
+{
+       string_equals("(null)", NULL);
+       string_equals("%any", "");
+       string_equals("%any", "%any");
+       string_equals("%any", "*");
+
+       string_equals("192.168.1.1", "192.168.1.1");
+       string_equals_id("(invalid ID_IPV4_ADDR)",
+                               identification_create_from_encoding(ID_IPV4_ADDR, chunk_empty));
+       string_equals("fec0::1", "fec0::1");
+       string_equals("fec0::1", "fec0:0:0::1");
+       string_equals_id("(invalid ID_IPV6_ADDR)",
+                               identification_create_from_encoding(ID_IPV6_ADDR, chunk_empty));
+
+       string_equals_id("(unknown ID type: 255)",
+                               identification_create_from_encoding(255, chunk_empty));
+
+       string_equals("moon@strongswan.org", "moon@strongswan.org");
+       string_equals("MOON@STRONGSWAN.ORG", "MOON@STRONGSWAN.ORG");
+       /* non-printable characters */
+       string_equals_id("????@strongswan.org", identification_create_from_encoding(ID_RFC822_ADDR,
+                       chunk_from_chars(0xfa, 0xfb, 0xfc, 0xfd, 0x40, 0x73, 0x74, 0x72,
+                                                        0x6f, 0x6e, 0x67, 0x73, 0x77, 0x61, 0x6e, 0x2e,
+                                                        0x6f, 0x72, 0x67)));
+
+       /* not a DN => ID_KEY_ID => no normalization */
+       string_equals("C=CH, AsdF=asdf", "C=CH, AsdF=asdf");
+       string_equals_id("moon@strongswan.org", identification_create_from_encoding(ID_KEY_ID,
+                       chunk_from_str("moon@strongswan.org")));
+       /* non-printable characters */
+       string_equals_id("de:ad:be:ef", identification_create_from_encoding(ID_KEY_ID,
+                       chunk_from_chars(0xde, 0xad, 0xbe, 0xef)));
+       /* printable characters */
+       string_equals_id("ABCDEFGHIJKLMNOPQRS",
+               identification_create_from_encoding(ID_KEY_ID,
+                       chunk_from_chars(0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+                                                        0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
+                                                        0x51, 0x52, 0x53)));
+       /* ABCDEFGHIJKLMNOPQRST is printable but has the length of a SHA1 hash */
+       string_equals_id("41:42:43:44:45:46:47:48:49:4a:4b:4c:4d:4e:4f:50:51:52:53:54",
+               identification_create_from_encoding(ID_KEY_ID,
+                       chunk_from_chars(0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+                                                        0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
+                                                        0x51, 0x52, 0x53, 0x54)));
+
+       string_equals_id("", identification_create_from_encoding(ID_DER_ASN1_DN, chunk_empty));
+       string_equals("C=", "C=");
+       string_equals("C=", "C=,");
+       string_equals("C=", "C=, ");
+       string_equals("C=", "C= , ");
+       string_equals("C=, O=strongSwan", "C=, O=strongSwan");
+       string_equals("C=CH, O=", "C=CH, O=");
+       string_equals("C=CH, O=strongSwan, CN=strongswan.org",
+                                 "C=CH, O=strongSwan, CN=strongswan.org");
+       string_equals("CN=strongswan.org, O=strongSwan, C=CH",
+                                 "cn=strongswan.org, o=strongSwan, c=CH");
+       string_equals("C=CH, O=strongSwan, CN=strongswan.org",
+                                 "C=CH,O=strongSwan,CN=strongswan.org");
+       string_equals("C=CH, O=strongSwan, CN=strongswan.org",
+                                 "/C=CH/O=strongSwan/CN=strongswan.org");
+       string_equals("CN=strongswan.org, O=strongSwan, C=CH",
+                                 "CN=strongswan.org,O=strongSwan,C=CH");
+
+       string_equals("C=CH, E=moon@strongswan.org, CN=moon",
+                                 "C=CH, email=moon@strongswan.org, CN=moon");
+       string_equals("C=CH, E=moon@strongswan.org, CN=moon",
+                                 "C=CH, emailAddress=moon@strongswan.org, CN=moon");
+
+       /* C=CH, pseudonym=ANO (pseudonym is currently not recognized) */
+       string_equals_id("C=CH, 55:04:41=ANO", identification_create_from_encoding(ID_DER_ASN1_DN,
+               chunk_from_chars(0x30, 0x19, 0x31, 0x17, 0x30, 0x09, 0x06, 0x03, 0x55,
+                                                0x04, 0x06, 0x13, 0x02, 0x43, 0x48, 0x30, 0x0a, 0x06,
+                                                0x03, 0x55, 0x04, 0x41, 0x13, 0x03, 0x41, 0x4e, 0x4f)));
+       /* C=CH, O=strongSwan (but instead of a 2nd OID -0x06- we got NULL -0x05) */
+       string_equals_id("C=CH, (invalid ID_DER_ASN1_DN)", identification_create_from_encoding(ID_DER_ASN1_DN,
+               chunk_from_chars(0x30, 0x20, 0x31, 0x1e, 0x30, 0x09, 0x06, 0x03, 0x55,
+                                                0x04, 0x06, 0x13, 0x02, 0x43, 0x48, 0x30, 0x11, 0x05,
+                                                0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x73, 0x74, 0x72,
+                                                0x6f, 0x6e, 0x67, 0x53, 0x77, 0x61, 0x6e)));
+       /* moon@strongswan.org as GN */
+       string_equals_id("(ASN.1 general name)", identification_create_from_encoding(ID_DER_ASN1_GN,
+               chunk_from_chars(0x81, 0x14, 0x6d, 0x6f, 0x6f, 0x6e, 0x40, 0x73, 0x74,
+                                                0x72, 0x6f, 0x6e, 0x67, 0x73, 0x77, 0x61, 0x6e, 0x2e,
+                                                0x6f, 0x72, 0x67)));
+}
+END_TEST
+
+START_TEST(test_printf_hook_width)
+{
+       identification_t *a;
+       char buf[128];
+
+       a = identification_create_from_string("moon@strongswan.org");
+       snprintf(buf, sizeof(buf), "%25Y", a);
+       ck_assert_str_eq("      moon@strongswan.org", buf);
+       snprintf(buf, sizeof(buf), "%-*Y", 25, a);
+       ck_assert_str_eq("moon@strongswan.org      ", buf);
+       snprintf(buf, sizeof(buf), "%5Y", a);
+       ck_assert_str_eq("moon@strongswan.org", buf);
+       DESTROY_IF(a);
+}
+END_TEST
+
+/*******************************************************************************
  * equals
  */
 
@@ -29,6 +360,7 @@ static bool id_equals(identification_t *a, char *b_str)
 
        b = identification_create_from_string(b_str);
        equals = a->equals(a, b);
+       equals = equals && b->equals(b, a);
        b->destroy(b);
        return equals;
 }
@@ -39,14 +371,23 @@ START_TEST(test_equals)
        chunk_t encoding, fuzzed;
        int i;
 
+       /* this test also tests identification_create_from_string with DNs */
        a = identification_create_from_string(
-                                                        "C=CH, E=martin@strongswan.org, CN=martin");
-
-       ck_assert(id_equals(a, "C=CH, E=martin@strongswan.org, CN=martin"));
-       ck_assert(id_equals(a, "C=ch, E=martin@STRONGSWAN.ORG, CN=Martin"));
-       ck_assert(!id_equals(a, "C=CN, E=martin@strongswan.org, CN=martin"));
-       ck_assert(!id_equals(a, "E=martin@strongswan.org, C=CH, CN=martin"));
-       ck_assert(!id_equals(a, "E=martin@strongswan.org, C=CH, CN=martin"));
+                                                        "C=CH, E=moon@strongswan.org, CN=moon");
+
+       ck_assert(id_equals(a, "C=CH, E=moon@strongswan.org, CN=moon"));
+       ck_assert(id_equals(a, "C==CH, E==moon@strongswan.org,,, CN==moon"));
+       ck_assert(id_equals(a, "  C=CH, E=moon@strongswan.org, CN=moon  "));
+       ck_assert(id_equals(a, "C=ch, E=moon@STRONGSWAN.ORG, CN=Moon"));
+       ck_assert(id_equals(a, "/C=CH/E=moon@strongswan.org/CN=moon"));
+       ck_assert(id_equals(a, "C=CH/E=moon@strongswan.org/CN=moon"));
+       ck_assert(id_equals(a, "C=CH/E=moon@strongswan.org,CN=moon"));
+       ck_assert(id_equals(a, "C=CH / E=moon@strongswan.org , CN=moon"));
+
+       ck_assert(!id_equals(a, "C=CH E=moon@strongswan.org CN=moon"));
+       ck_assert(!id_equals(a, "C=CN, E=moon@strongswan.org, CN=moon"));
+       ck_assert(!id_equals(a, "E=moon@strongswan.org, C=CH, CN=moon"));
+       ck_assert(!id_equals(a, "E=moon@strongswan.org, C=CH, CN=moon"));
 
        encoding = chunk_clone(a->get_encoding(a));
        a->destroy(a);
@@ -54,14 +395,18 @@ START_TEST(test_equals)
        /* simple fuzzing, increment each byte of encoding */
        for (i = 0; i < encoding.len; i++)
        {
-               if (i == 11 || i == 30 || i == 62)
+               if (i == 11 || i == 30 || i == 60)
                {       /* skip ASN.1 type fields, as equals() handles them graceful */
                        continue;
                }
                fuzzed = chunk_clone(encoding);
                fuzzed.ptr[i]++;
                a = identification_create_from_encoding(ID_DER_ASN1_DN, fuzzed);
-               ck_assert(!id_equals(a, "C=CH, E=martin@strongswan.org, CN=martin"));
+               if (id_equals(a, "C=CH, E=moon@strongswan.org, CN=moon"))
+               {
+                       printf("%d %B\n%B\n", i, &fuzzed, &encoding);
+               }
+               ck_assert(!id_equals(a, "C=CH, E=moon@strongswan.org, CN=moon"));
                a->destroy(a);
                free(fuzzed.ptr);
        }
@@ -69,14 +414,14 @@ START_TEST(test_equals)
        /* and decrement each byte of encoding */
        for (i = 0; i < encoding.len; i++)
        {
-               if (i == 11 || i == 30 || i == 62)
+               if (i == 11 || i == 30 || i == 60)
                {
                        continue;
                }
                fuzzed = chunk_clone(encoding);
                fuzzed.ptr[i]--;
                a = identification_create_from_encoding(ID_DER_ASN1_DN, fuzzed);
-               ck_assert(!id_equals(a, "C=CH, E=martin@strongswan.org, CN=martin"));
+               ck_assert(!id_equals(a, "C=CH, E=moon@strongswan.org, CN=moon"));
                a->destroy(a);
                free(fuzzed.ptr);
        }
@@ -84,6 +429,53 @@ START_TEST(test_equals)
 }
 END_TEST
 
+START_TEST(test_equals_any)
+{
+       identification_t *a, *b;
+
+       a = identification_create_from_string("%any");
+       b = identification_create_from_encoding(ID_ANY, chunk_empty);
+       ck_assert(a->equals(a, b));
+       ck_assert(b->equals(b, a));
+       b->destroy(b);
+
+       b = identification_create_from_string("C=CH, O=strongSwan, CN=strongswan.org");
+       ck_assert(!a->equals(a, b));
+       ck_assert(!b->equals(b, a));
+       a->destroy(a);
+       b->destroy(b);
+}
+END_TEST
+
+START_TEST(test_equals_binary)
+{
+       identification_t *a, *b;
+       chunk_t encoding;
+
+       encoding = chunk_from_str("foobar=");
+       /* strings containing = are parsed as KEY_ID if they aren't valid ASN.1 DNs */
+       a = identification_create_from_string("foobar=");
+       ck_assert(a->get_type(a) == ID_KEY_ID);
+       b = identification_create_from_encoding(ID_KEY_ID, encoding);
+       ck_assert(a->equals(a, b));
+       a->destroy(a);
+       b->destroy(b);
+}
+END_TEST
+
+START_TEST(test_equals_fqdn)
+{
+       identification_t *a;
+
+       a = identification_create_from_string("ipsec.strongswan.org");
+       ck_assert(id_equals(a, "IPSEC.strongswan.org"));
+       ck_assert(id_equals(a, "ipsec.strongSwan.org"));
+       ck_assert(id_equals(a, "ipsec.strongSwan.ORG"));
+       ck_assert(!id_equals(a, "strongswan.org"));
+       a->destroy(a);
+}
+END_TEST
+
 /*******************************************************************************
  * matches
  */
@@ -103,16 +495,84 @@ START_TEST(test_matches)
 {
        identification_t *a;
 
-       a = identification_create_from_string("C=CH, E=martin@strongswan.org, CN=martin");
+       a = identification_create_from_string("C=CH, E=moon@strongswan.org, CN=moon");
 
-       ck_assert(id_matches(a, "C=CH, E=martin@strongswan.org, CN=martin", ID_MATCH_PERFECT));
-       ck_assert(id_matches(a, "C=CH, E=*, CN=martin", ID_MATCH_ONE_WILDCARD));
+       ck_assert(id_matches(a, "C=CH, E=moon@strongswan.org, CN=moon", ID_MATCH_PERFECT));
+       ck_assert(id_matches(a, "C=CH, E=*, CN=moon", ID_MATCH_ONE_WILDCARD));
        ck_assert(id_matches(a, "C=CH, E=*, CN=*", ID_MATCH_ONE_WILDCARD - 1));
        ck_assert(id_matches(a, "C=*, E=*, CN=*", ID_MATCH_ONE_WILDCARD - 2));
        ck_assert(id_matches(a, "C=*, E=*, CN=*, O=BADInc", ID_MATCH_NONE));
        ck_assert(id_matches(a, "C=*, E=*", ID_MATCH_NONE));
        ck_assert(id_matches(a, "C=*, E=a@b.c, CN=*", ID_MATCH_NONE));
+       ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
+
+       a->destroy(a);
+}
+END_TEST
+
+START_TEST(test_matches_any)
+{
+       identification_t *a;
+
+       a = identification_create_from_string("%any");
 
+       ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
+       ck_assert(id_matches(a, "", ID_MATCH_ANY));
+       ck_assert(id_matches(a, "*", ID_MATCH_ANY));
+       ck_assert(id_matches(a, "moon@strongswan.org", ID_MATCH_NONE));
+       ck_assert(id_matches(a, "vpn.strongswan.org", ID_MATCH_NONE));
+       a->destroy(a);
+}
+END_TEST
+
+START_TEST(test_matches_binary)
+{
+       identification_t *a;
+
+       /* strings containing = are parsed as KEY_ID if they aren't valid ASN.1 DNs */
+       a = identification_create_from_string("foo=bar");
+       ck_assert(a->get_type(a) == ID_KEY_ID);
+       ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
+       ck_assert(id_matches(a, "foo=bar", ID_MATCH_PERFECT));
+       ck_assert(id_matches(a, "bar=foo", ID_MATCH_NONE));
+       ck_assert(id_matches(a, "*=bar", ID_MATCH_NONE));
+       ck_assert(id_matches(a, "foo=*", ID_MATCH_NONE));
+       ck_assert(id_matches(a, "foo@bar", ID_MATCH_NONE));
+       a->destroy(a);
+}
+END_TEST
+
+START_TEST(test_matches_string)
+{
+       identification_t *a;
+
+       a = identification_create_from_string("moon@strongswan.org");
+
+       ck_assert(id_matches(a, "moon@strongswan.org", ID_MATCH_PERFECT));
+       ck_assert(id_matches(a, "*@strongswan.org", ID_MATCH_ONE_WILDCARD));
+       ck_assert(id_matches(a, "*@*.org", ID_MATCH_NONE));
+       ck_assert(id_matches(a, "*@*", ID_MATCH_NONE));
+       /* the following two are parsed as ID_FQDN, so no match */
+       ck_assert(id_matches(a, "*strongswan.org", ID_MATCH_NONE));
+       ck_assert(id_matches(a, "*.org", ID_MATCH_NONE));
+       ck_assert(id_matches(a, "moon@*", ID_MATCH_NONE));
+       ck_assert(id_matches(a, "**", ID_MATCH_NONE));
+       ck_assert(id_matches(a, "*", ID_MATCH_ANY));
+       ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
+       a->destroy(a);
+
+       a = identification_create_from_string("vpn.strongswan.org");
+
+       ck_assert(id_matches(a, "vpn.strongswan.org", ID_MATCH_PERFECT));
+       ck_assert(id_matches(a, "*.strongswan.org", ID_MATCH_ONE_WILDCARD));
+       ck_assert(id_matches(a, "*strongswan.org", ID_MATCH_ONE_WILDCARD));
+       ck_assert(id_matches(a, "*.org", ID_MATCH_ONE_WILDCARD));
+       ck_assert(id_matches(a, "*.strongswan.*", ID_MATCH_NONE));
+       ck_assert(id_matches(a, "*vpn.strongswan.org", ID_MATCH_NONE));
+       ck_assert(id_matches(a, "vpn.strongswan.*", ID_MATCH_NONE));
+       ck_assert(id_matches(a, "**", ID_MATCH_NONE));
+       ck_assert(id_matches(a, "*", ID_MATCH_ANY));
+       ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
        a->destroy(a);
 }
 END_TEST
@@ -184,6 +644,28 @@ START_TEST(test_contains_wildcards)
 }
 END_TEST
 
+/*******************************************************************************
+ * clone
+ */
+
+START_TEST(test_clone)
+{
+       identification_t *a, *b;
+       chunk_t a_enc, b_enc;
+
+       a = identification_create_from_string("moon@strongswan.org");
+       a_enc = a->get_encoding(a);
+       b = a->clone(a);
+       ck_assert(b != NULL);
+       ck_assert(a != b);
+       b_enc = b->get_encoding(b);
+       ck_assert(a_enc.ptr != b_enc.ptr);
+       ck_assert(chunk_equals(a_enc, b_enc));
+       a->destroy(a);
+       b->destroy(b);
+}
+END_TEST
+
 Suite *identification_suite_create()
 {
        Suite *s;
@@ -191,12 +673,30 @@ Suite *identification_suite_create()
 
        s = suite_create("identification");
 
+       tc = tcase_create("create");
+       tcase_add_test(tc, test_from_encoding);
+       tcase_add_test(tc, test_from_data);
+       tcase_add_test(tc, test_from_sockaddr);
+       tcase_add_loop_test(tc, test_from_string, 0, countof(string_data));
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("printf_hook");
+       tcase_add_test(tc, test_printf_hook);
+       tcase_add_test(tc, test_printf_hook_width);
+       suite_add_tcase(s, tc);
+
        tc = tcase_create("equals");
        tcase_add_test(tc, test_equals);
+       tcase_add_test(tc, test_equals_any);
+       tcase_add_test(tc, test_equals_binary);
+       tcase_add_test(tc, test_equals_fqdn);
        suite_add_tcase(s, tc);
 
        tc = tcase_create("matches");
        tcase_add_test(tc, test_matches);
+       tcase_add_test(tc, test_matches_any);
+       tcase_add_test(tc, test_matches_binary);
+       tcase_add_test(tc, test_matches_string);
        suite_add_tcase(s, tc);
 
        tc = tcase_create("part enumeration");
@@ -207,5 +707,9 @@ Suite *identification_suite_create()
        tcase_add_test(tc, test_contains_wildcards);
        suite_add_tcase(s, tc);
 
+       tc = tcase_create("clone");
+       tcase_add_test(tc, test_clone);
+       suite_add_tcase(s, tc);
+
        return s;
 }