summaryrefslogtreecommitdiff
path: root/src/libstrongswan/tests/suites
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2014-03-11 20:48:48 +0100
committerYves-Alexis Perez <corsac@debian.org>2014-03-11 20:48:48 +0100
commit15fb7904f4431a6e7c305fd08732458f7f885e7e (patch)
treec93b60ee813af70509f00f34e29ebec311762427 /src/libstrongswan/tests/suites
parent5313d2d78ca150515f7f5eb39801c100690b6b29 (diff)
downloadvyos-strongswan-15fb7904f4431a6e7c305fd08732458f7f885e7e.tar.gz
vyos-strongswan-15fb7904f4431a6e7c305fd08732458f7f885e7e.zip
Imported Upstream version 5.1.2
Diffstat (limited to 'src/libstrongswan/tests/suites')
-rw-r--r--src/libstrongswan/tests/suites/test_array.c532
-rw-r--r--src/libstrongswan/tests/suites/test_asn1.c869
-rw-r--r--src/libstrongswan/tests/suites/test_asn1_parser.c291
-rw-r--r--src/libstrongswan/tests/suites/test_bio_reader.c450
-rw-r--r--src/libstrongswan/tests/suites/test_bio_writer.c392
-rw-r--r--src/libstrongswan/tests/suites/test_chunk.c1027
-rw-r--r--src/libstrongswan/tests/suites/test_crypter.c107
-rw-r--r--src/libstrongswan/tests/suites/test_ecdsa.c243
-rw-r--r--src/libstrongswan/tests/suites/test_enum.c248
-rw-r--r--src/libstrongswan/tests/suites/test_enumerator.c409
-rw-r--r--src/libstrongswan/tests/suites/test_fetch_http.c273
-rw-r--r--src/libstrongswan/tests/suites/test_hasher.c189
-rw-r--r--src/libstrongswan/tests/suites/test_hashtable.c346
-rw-r--r--src/libstrongswan/tests/suites/test_host.c651
-rw-r--r--src/libstrongswan/tests/suites/test_identification.c857
-rw-r--r--src/libstrongswan/tests/suites/test_linked_list.c390
-rw-r--r--src/libstrongswan/tests/suites/test_linked_list_enumerator.c361
-rw-r--r--src/libstrongswan/tests/suites/test_ntru.c1042
-rw-r--r--src/libstrongswan/tests/suites/test_pen.c87
-rw-r--r--src/libstrongswan/tests/suites/test_printf.c228
-rw-r--r--src/libstrongswan/tests/suites/test_rsa.c399
-rw-r--r--src/libstrongswan/tests/suites/test_settings.c920
-rw-r--r--src/libstrongswan/tests/suites/test_stream.c267
-rw-r--r--src/libstrongswan/tests/suites/test_test_rng.c56
-rw-r--r--src/libstrongswan/tests/suites/test_threading.c1466
-rw-r--r--src/libstrongswan/tests/suites/test_utils.c743
-rw-r--r--src/libstrongswan/tests/suites/test_vectors.c42
-rw-r--r--src/libstrongswan/tests/suites/test_watcher.c214
28 files changed, 13099 insertions, 0 deletions
diff --git a/src/libstrongswan/tests/suites/test_array.c b/src/libstrongswan/tests/suites/test_array.c
new file mode 100644
index 000000000..ba2aff460
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_array.c
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2014 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * 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 "test_suite.h"
+
+#include <collections/array.h>
+
+START_TEST(test_append_ptr)
+{
+ array_t *array;
+ uintptr_t x;
+ int i;
+
+ array = array_create(0, 0);
+
+ for (i = 0; i < 4; i++)
+ {
+ ck_assert_int_eq(array_count(array), 0);
+
+ array_insert(array, ARRAY_HEAD, (void*)(uintptr_t)3);
+ array_insert(array, ARRAY_TAIL, (void*)(uintptr_t)4);
+ ck_assert_int_eq(array_count(array), 2);
+
+ /* 3, 4 */
+
+ ck_assert(array_get(array, ARRAY_HEAD, &x));
+ ck_assert_int_eq(x, 3);
+ ck_assert(array_get(array, 1, &x));
+ ck_assert_int_eq(x, 4);
+ ck_assert(array_get(array, ARRAY_TAIL, &x));
+ ck_assert_int_eq(x, 4);
+ ck_assert(!array_get(array, 3, &x));
+
+ array_insert(array, ARRAY_HEAD, (void*)(uintptr_t)1);
+ array_insert(array, 1, (void*)(uintptr_t)2);
+ ck_assert_int_eq(array_count(array), 4);
+
+ /* 1, 2, 3, 4 */
+
+ array_insert(array, ARRAY_TAIL, (void*)(uintptr_t)5);
+ array_insert(array, ARRAY_HEAD, (void*)(uintptr_t)0);
+ ck_assert_int_eq(array_count(array), 6);
+
+ /* 0, 1, 2, 3, 4, 5 */
+
+ ck_assert(array_remove(array, ARRAY_TAIL, &x));
+ ck_assert_int_eq(x, 5);
+ ck_assert(array_remove(array, 4, &x));
+ ck_assert_int_eq(x, 4);
+
+ if (i < 3)
+ {
+ array_compress(array);
+ }
+
+ /* 0, 1, 2, 3 */
+
+ ck_assert(array_remove(array, 1, &x));
+ ck_assert_int_eq(x, 1);
+ ck_assert(array_remove(array, ARRAY_HEAD, &x));
+ ck_assert_int_eq(x, 0);
+
+ if (i < 2)
+ {
+ array_compress(array);
+ }
+
+ /* 2, 3 */
+
+ ck_assert(array_remove(array, ARRAY_TAIL, &x));
+ ck_assert_int_eq(x, 3);
+ ck_assert(array_remove(array, ARRAY_TAIL, &x));
+ ck_assert_int_eq(x, 2);
+
+ if (i < 1)
+ {
+ array_compress(array);
+ }
+
+ ck_assert_int_eq(array_count(array), 0);
+
+ ck_assert(array_remove(array, ARRAY_HEAD, NULL) == FALSE);
+ ck_assert(array_remove(array, ARRAY_TAIL, NULL) == FALSE);
+ }
+
+ array_destroy(array);
+}
+END_TEST
+
+START_TEST(test_append_obj)
+{
+ array_t *array;
+ int i, x, y[6] = {0, 1, 2, 3, 4, 5};
+
+ array = array_create(sizeof(y[0]), 0);
+
+ for (i = 0; i < 4; i++)
+ {
+ ck_assert_int_eq(array_count(array), 0);
+
+ array_insert(array, ARRAY_HEAD, &y[3]);
+ array_insert(array, ARRAY_TAIL, &y[4]);
+ ck_assert_int_eq(array_count(array), 2);;
+
+ /* 3, 4 */
+
+ ck_assert(array_get(array, ARRAY_HEAD, &x));
+ ck_assert_int_eq(x, 3);
+ ck_assert(array_get(array, 1, &x));
+ ck_assert_int_eq(x, 4);
+ ck_assert(array_get(array, ARRAY_TAIL, &x));
+ ck_assert_int_eq(x, 4);
+ ck_assert(!array_get(array, 3, &x));
+
+ array_insert(array, ARRAY_HEAD, &y[1]);
+ array_insert(array, 1, &y[2]);
+ ck_assert_int_eq(array_count(array), 4);
+
+ /* 1, 2, 3, 4 */
+
+ array_insert(array, ARRAY_TAIL, &y[5]);
+ array_insert(array, ARRAY_HEAD, &y[0]);
+ ck_assert_int_eq(array_count(array), 6);
+
+ /* 0, 1, 2, 3, 4, 5 */
+
+ ck_assert(array_remove(array, ARRAY_TAIL, &x));
+ ck_assert_int_eq(x, 5);
+ ck_assert(array_remove(array, 4, &x));
+ ck_assert_int_eq(x, 4);
+
+ if (i < 3)
+ {
+ array_compress(array);
+ }
+
+ /* 0, 1, 2, 3 */
+
+ ck_assert(array_remove(array, ARRAY_HEAD, &x));
+ ck_assert_int_eq(x, 0);
+ ck_assert(array_remove(array, ARRAY_HEAD, &x));
+ ck_assert_int_eq(x, 1);
+
+ if (i < 2)
+ {
+ array_compress(array);
+ }
+
+ /* 2, 3 */
+
+ ck_assert(array_remove(array, ARRAY_TAIL, &x));
+ ck_assert_int_eq(x, 3);
+ ck_assert(array_remove(array, ARRAY_HEAD, &x));
+ ck_assert_int_eq(x, 2);
+
+ if (i < 1)
+ {
+ array_compress(array);
+ }
+
+ ck_assert_int_eq(array_count(array), 0);
+
+ ck_assert(array_remove(array, ARRAY_HEAD, NULL) == FALSE);
+ ck_assert(array_remove(array, ARRAY_TAIL, NULL) == FALSE);
+ }
+
+ array_destroy(array);
+}
+END_TEST
+
+START_TEST(test_enumerate)
+{
+ array_t *array;
+ int i, *x, y[6] = {0, 1, 2, 3, 4, 5};
+ enumerator_t *enumerator;
+
+ array = array_create(sizeof(y[0]), 0);
+
+ array_insert(array, ARRAY_TAIL, &y[0]);
+ array_insert(array, ARRAY_TAIL, &y[1]);
+ array_insert(array, ARRAY_TAIL, &y[2]);
+ array_insert(array, ARRAY_TAIL, &y[3]);
+ array_insert(array, ARRAY_TAIL, &y[4]);
+ array_insert(array, ARRAY_TAIL, &y[5]);
+
+ ck_assert_int_eq(array_count(array), 6);
+
+ /* 0, 1, 2, 3, 4, 5 */
+
+ i = 0;
+ enumerator = array_create_enumerator(array);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ ck_assert_int_eq(*x, y[i]);
+ i++;
+ }
+ enumerator->destroy(enumerator);
+ ck_assert_int_eq(i, 6);
+
+ i = 0;
+ enumerator = array_create_enumerator(array);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ ck_assert_int_eq(*x, y[i]);
+ if (i == 0 || i == 3 || i == 5)
+ {
+ array_remove_at(array, enumerator);
+ }
+ i++;
+ }
+ enumerator->destroy(enumerator);
+ ck_assert_int_eq(i, 6);
+ ck_assert_int_eq(array_count(array), 3);
+
+ /* 1, 2, 4 */
+
+ i = 0;
+ enumerator = array_create_enumerator(array);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ switch (i++)
+ {
+ case 0:
+ ck_assert_int_eq(*x, y[1]);
+ break;
+ case 1:
+ ck_assert_int_eq(*x, y[2]);
+ break;
+ case 2:
+ ck_assert_int_eq(*x, y[4]);
+ break;
+ default:
+ ck_assert(0);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ array_compress(array);
+
+ i = 0;
+ enumerator = array_create_enumerator(array);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ switch (i++)
+ {
+ case 0:
+ ck_assert_int_eq(*x, y[1]);
+ break;
+ case 1:
+ ck_assert_int_eq(*x, y[2]);
+ break;
+ case 2:
+ ck_assert_int_eq(*x, y[4]);
+ break;
+ default:
+ ck_assert(0);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ array_destroy(array);
+}
+END_TEST
+
+static int comp_obj(const void *a, const void *b, void *arg)
+{
+ ck_assert_str_eq(arg, "arg");
+ return *(int*)a - *(int*)b;
+}
+
+START_TEST(test_sort_obj)
+{
+ array_t *array;
+ int x[][3] = {
+ {1, 2, 3},
+ {1, 3, 2},
+ {2, 1, 3},
+ {2, 3, 1},
+ {3, 1, 2},
+ {3, 2, 1},
+ };
+ char *arg = "arg";
+ int i, v;
+
+ for (i = 0; i < countof(x); i++)
+ {
+ array = array_create(sizeof(x[i][0]), 0);
+ array_insert(array, ARRAY_TAIL, &x[i][0]);
+ array_insert(array, ARRAY_TAIL, &x[i][1]);
+ array_insert(array, ARRAY_TAIL, &x[i][2]);
+
+ array_sort(array, comp_obj, arg);
+
+ ck_assert(array_get(array, 0, &v));
+ ck_assert_int_eq(v, 1);
+ ck_assert(array_get(array, 1, &v));
+ ck_assert_int_eq(v, 2);
+ ck_assert(array_get(array, 2, &v));
+ ck_assert_int_eq(v, 3);
+
+ array_destroy(array);
+ }
+}
+END_TEST
+
+static int comp_ptr(const void *a, const void *b, void *arg)
+{
+ ck_assert_str_eq(arg, "arg");
+ return strcmp(a, b);
+}
+
+START_TEST(test_sort_ptr)
+{
+ array_t *array;
+ char *x[][3] = {
+ {"a", "b", "c"},
+ {"a", "c", "b"},
+ {"b", "a", "c"},
+ {"b", "c", "a"},
+ {"c", "a", "b"},
+ {"c", "b", "a"},
+ };
+ char *v, *arg = "arg";
+ int i;
+
+ for (i = 0; i < countof(x); i++)
+ {
+ array = array_create(0, 0);
+ array_insert(array, ARRAY_TAIL, x[i][0]);
+ array_insert(array, ARRAY_TAIL, x[i][1]);
+ array_insert(array, ARRAY_TAIL, x[i][2]);
+
+ array_sort(array, comp_ptr, arg);
+
+ ck_assert(array_get(array, 0, &v));
+ ck_assert_str_eq(v, "a");
+ ck_assert(array_get(array, 1, &v));
+ ck_assert_str_eq(v, "b");
+ ck_assert(array_get(array, 2, &v));
+ ck_assert_str_eq(v, "c");
+
+ array_destroy(array);
+ }
+}
+END_TEST
+
+static int comp_search_obj(const void *a, const void *b)
+{
+ return *(int*)a - *(int*)b;
+}
+
+START_TEST(test_bsearch_obj)
+{
+ array_t *array;
+ int x[] = { 3, 2, 1 };
+ int k, v;
+
+ array = array_create(sizeof(x[0]), 0);
+ array_insert(array, ARRAY_TAIL, &x[0]);
+ array_insert(array, ARRAY_TAIL, &x[1]);
+ array_insert(array, ARRAY_TAIL, &x[2]);
+
+ array_sort(array, (void*)comp_search_obj, NULL);
+
+ k = 0;
+ ck_assert_int_eq(array_bsearch(array, &k, comp_search_obj, &v), -1);
+ for (k = 1; k < 4; k++)
+ {
+ ck_assert_int_eq(array_bsearch(array, &k, comp_search_obj, &v), k-1);
+ ck_assert_int_eq(v, k);
+ }
+ k = 4;
+ ck_assert_int_eq(array_bsearch(array, &k, comp_search_obj, &v), -1);
+ array_destroy(array);
+}
+END_TEST
+
+static int comp_search_ptr(const void *a, const void *b)
+{
+ return strcmp(a, b);
+}
+
+START_TEST(test_bsearch_ptr)
+{
+ array_t *array;
+ char *x[] = {"c", "b", "a"};
+ char *v;
+
+ array = array_create(0, 0);
+ array_insert(array, ARRAY_TAIL, x[0]);
+ array_insert(array, ARRAY_TAIL, x[1]);
+ array_insert(array, ARRAY_TAIL, x[2]);
+
+ array_sort(array, (void*)comp_search_ptr, NULL);
+
+ ck_assert_int_eq(array_bsearch(array, "abc", comp_search_ptr, &v), -1);
+ ck_assert_int_eq(array_bsearch(array, "a", comp_search_ptr, &v), 0);
+ ck_assert_str_eq(v, "a");
+ ck_assert_int_eq(array_bsearch(array, "b", comp_search_ptr, &v), 1);
+ ck_assert_str_eq(v, "b");
+ ck_assert_int_eq(array_bsearch(array, "c", comp_search_ptr, &v), 2);
+ ck_assert_str_eq(v, "c");
+
+ array_destroy(array);
+}
+END_TEST
+
+static void invoke(void *data, int idx, void *user)
+{
+ int *y = user, *x = data;
+
+ ck_assert(idx < 3);
+
+ ck_assert_int_eq(y[idx], *x);
+ y[idx] = 0;
+}
+
+START_TEST(test_invoke)
+{
+ array_t *array;
+ int y[] = {1, 2, 3};
+
+ array = array_create(sizeof(y[0]), 0);
+
+ array_insert(array, ARRAY_TAIL, &y[0]);
+ array_insert(array, ARRAY_TAIL, &y[1]);
+ array_insert(array, ARRAY_TAIL, &y[2]);
+
+ array_invoke(array, invoke, y);
+
+ ck_assert_int_eq(y[0], 0);
+ ck_assert_int_eq(y[0], 0);
+ ck_assert_int_eq(y[0], 0);
+
+ array_destroy(array);
+}
+END_TEST
+
+typedef struct obj_t obj_t;
+
+struct obj_t {
+ void (*fun)(obj_t *obj);
+ int x;
+ int *counter;
+};
+
+static void fun(obj_t *obj)
+{
+ ck_assert(obj->x == (*obj->counter)++);
+}
+
+START_TEST(test_invoke_offset)
+{
+ array_t *array;
+ obj_t objs[5];
+ int i, counter = 0;
+
+ array = array_create(0, 0);
+
+ for (i = 0; i < countof(objs); i++)
+ {
+ objs[i].x = i;
+ objs[i].counter = &counter;
+ objs[i].fun = fun;
+
+ array_insert(array, ARRAY_TAIL, &objs[i]);
+ }
+
+ ck_assert_int_eq(countof(objs), array_count(array));
+
+ array_invoke_offset(array, offsetof(obj_t, fun));
+
+ ck_assert_int_eq(counter, countof(objs));
+
+ array_destroy(array);
+}
+END_TEST
+
+Suite *array_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("array");
+
+ tc = tcase_create("add/get/remove ptr");
+ tcase_add_test(tc, test_append_ptr);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("add/get/remove obj");
+ tcase_add_test(tc, test_append_obj);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("enumerate");
+ tcase_add_test(tc, test_enumerate);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("sort");
+ tcase_add_test(tc, test_sort_obj);
+ tcase_add_test(tc, test_sort_ptr);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("bsearch");
+ tcase_add_test(tc, test_bsearch_obj);
+ tcase_add_test(tc, test_bsearch_ptr);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("invoke");
+ tcase_add_test(tc, test_invoke);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("invoke offset");
+ tcase_add_test(tc, test_invoke_offset);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_asn1.c b/src/libstrongswan/tests/suites/test_asn1.c
new file mode 100644
index 000000000..d0cd7e6e4
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_asn1.c
@@ -0,0 +1,869 @@
+/*
+ * Copyright (C) 2013 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 "test_suite.h"
+
+#include <asn1/asn1.h>
+#include <asn1/oid.h>
+#include <utils/chunk.h>
+
+/*******************************************************************************
+ * algorithm_identifier
+ */
+
+START_TEST(test_asn1_algorithmIdentifier)
+{
+ typedef struct {
+ int n;
+ chunk_t algid;
+ } testdata_t;
+
+ testdata_t test[] = {
+ { OID_ECDSA_WITH_SHA1, chunk_from_chars(0x30, 0x09, 0x06, 0x07,
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01) },
+ { OID_SHA1_WITH_RSA, chunk_from_chars(0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00) },
+ };
+
+ chunk_t algid;
+ int i;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ algid = asn1_algorithmIdentifier(test[i].n);
+ ck_assert(chunk_equals(algid, test[i].algid));
+ free(algid.ptr);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * parse_algorithm_identifier
+ */
+
+START_TEST(test_asn1_parse_algorithmIdentifier)
+{
+ typedef struct {
+ int alg;
+ bool empty;
+ chunk_t parameters;
+ } testdata_t;
+
+ testdata_t test[] = {
+ { OID_ECDSA_WITH_SHA1, TRUE, chunk_empty },
+ { OID_SHA1_WITH_RSA, TRUE, chunk_from_chars(0x05, 0x00) },
+ { OID_3DES_EDE_CBC, FALSE, chunk_from_chars(0x04, 0x01, 0xaa) },
+ { OID_PBKDF2, FALSE, chunk_from_chars(0x30, 0x01, 0xaa) }
+ };
+
+ chunk_t algid, parameters;
+ int i, alg;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ algid = asn1_wrap(ASN1_SEQUENCE, "mc",
+ asn1_build_known_oid(test[i].alg), test[i].parameters);
+ parameters = chunk_empty;
+ if (i == 2)
+ {
+ alg = asn1_parse_algorithmIdentifier(algid, 0, NULL);
+ }
+ else
+ {
+ alg = asn1_parse_algorithmIdentifier(algid, 0, &parameters);
+ if (test[i].empty)
+ {
+ ck_assert(parameters.len == 0 && parameters.ptr == NULL);
+ }
+ else
+ {
+ ck_assert(chunk_equals(parameters, test[i].parameters));
+ }
+ }
+ ck_assert(alg == test[i].alg);
+ chunk_free(&algid);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * known_oid
+ */
+
+START_TEST(test_asn1_known_oid)
+{
+ typedef struct {
+ int n;
+ chunk_t oid;
+ } testdata_t;
+
+ testdata_t test[] = {
+ { OID_UNKNOWN, chunk_empty },
+ { OID_UNKNOWN, chunk_from_chars(0x55, 0x04, 0x02) },
+ { OID_COUNTRY, chunk_from_chars(0x55, 0x04, 0x06) },
+ { OID_STRONGSWAN, chunk_from_chars(0x2b, 0x06, 0x01, 0x04, 0x01,
+ 0x82, 0xa0, 0x2a, 0x01) }
+ };
+
+ int i;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ ck_assert(asn1_known_oid(test[i].oid) == test[i].n);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * build_known_oid
+ */
+
+START_TEST(test_asn1_build_known_oid)
+{
+ typedef struct {
+ int n;
+ chunk_t oid;
+ } testdata_t;
+
+ testdata_t test[] = {
+ { OID_UNKNOWN, chunk_empty },
+ { OID_MAX, chunk_empty },
+ { OID_COUNTRY, chunk_from_chars(0x06, 0x03, 0x55, 0x04, 0x06) },
+ { OID_STRONGSWAN, chunk_from_chars(0x06, 0x09, 0x2b, 0x06, 0x01, 0x04,
+ 0x01, 0x82, 0xa0, 0x2a, 0x01) }
+ };
+
+ int i;
+ chunk_t oid = chunk_empty;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ oid = asn1_build_known_oid(test[i].n);
+ if (test[i].oid.len == 0)
+ {
+ ck_assert(oid.len == 0 && oid.ptr == NULL);
+ }
+ else
+ {
+ ck_assert(chunk_equals(oid, test[i].oid));
+ chunk_free(&oid);
+ }
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * oid_from_string
+ */
+
+START_TEST(test_asn1_oid_from_string)
+{
+ typedef struct {
+ char *string;
+ chunk_t oid;
+ } testdata_t;
+
+ testdata_t test[] = {
+ { "", chunk_empty },
+ { " ", chunk_empty },
+ { "0.2.262.1", chunk_from_chars(
+ 0x02, 0x82, 0x06, 0x01) },
+ { "1.2.840.10045.4.1", chunk_from_chars(
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01) },
+ { "1.3.6.1.4.1.36906.1", chunk_from_chars(
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa0, 0x2a, 0x01) },
+ { "2.16.840.1.101.3.4.2.1", chunk_from_chars(
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01) },
+ { "0.10.100.1000.10000.100000.1000000.10000000.100000000.268435455",
+ chunk_from_chars(0x0a,0x64, 0x87, 0x68, 0xce, 0x10, 0x86, 0x8d,
+ 0x20, 0xbd, 0x84, 0x40, 0x84, 0xe2, 0xad, 0x00,
+ 0xaf, 0xd7, 0xc2, 0x00, 0xff, 0xff, 0xff, 0x7f) },
+ { "0.1.2.3.4.5.6.7.8.9.10.128.129.130.131.132.133.134.135.136.137."
+ "256.257.258.259.260.261.262.263.264.265.384.385.386.387.388."
+ "2097153", chunk_from_chars(
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x81, 0x00, 0x81, 0x01, 0x81, 0x02, 0x81, 0x03, 0x81, 0x04,
+ 0x81, 0x05, 0x81, 0x06, 0x81, 0x07, 0x81, 0x08, 0x81, 0x09,
+ 0x82, 0x00, 0x82, 0x01, 0x82, 0x02, 0x82, 0x03, 0x82, 0x04,
+ 0x82, 0x05, 0x82, 0x06, 0x82, 0x07, 0x82, 0x08, 0x82, 0x09,
+ 0x83, 0x00, 0x83, 0x01, 0x83, 0x02, 0x83, 0x03, 0x83, 0x04,
+ 0x81, 0x80, 0x80, 0x01) },
+ { "0.1.2.3.4.5.6.7.8.9.10.128.129.130.131.132.133.134.135.136.137."
+ "256.257.258.259.260.261.262.263.264.265.384.385.386.387.388."
+ "1.2097153", chunk_empty },
+ { "1.a.2.b.3", chunk_empty }
+ };
+
+ int i;
+ chunk_t oid = chunk_empty;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ oid = asn1_oid_from_string(test[i].string);
+ if (test[i].oid.len == 0)
+ {
+ ck_assert(oid.len == 0 && oid.ptr == NULL);
+ }
+ else
+ {
+ ck_assert(chunk_equals(oid, test[i].oid));
+ chunk_free(&oid);
+ }
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * oid_to_string
+ */
+
+START_TEST(test_asn1_oid_to_string)
+{
+ typedef struct {
+ char *string;
+ chunk_t oid;
+ } testdata_t;
+
+ testdata_t test[] = {
+ { NULL, chunk_empty },
+ { "0.2.262.1", chunk_from_chars(
+ 0x02, 0x82, 0x06, 0x01) },
+ { "1.2.840.10045.4.1", chunk_from_chars(
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01) },
+ { "1.3.6.1.4.1.36906.1", chunk_from_chars(
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa0, 0x2a, 0x01) },
+ { "2.16.840.1.101.3.4.2.1", chunk_from_chars(
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01) },
+ { "0.10.100.1000.10000.100000.1000000.10000000.100000000.268435455",
+ chunk_from_chars( 0x0a, 0x64, 0x87, 0x68, 0xce, 0x10, 0x86, 0x8d,
+ 0x20, 0xbd, 0x84, 0x40, 0x84, 0xe2, 0xad, 0x00,
+ 0xaf, 0xd7, 0xc2, 0x00, 0xff, 0xff, 0xff, 0x7f) },
+ { NULL, chunk_from_chars(
+ 0x0a, 0x02, 0x64, 0x87, 0x68, 0xce, 0x10, 0x86, 0x8d, 0x20,
+ 0xbd, 0x84, 0x40, 0x84, 0xe2, 0xad, 0x00, 0xaf, 0xd7, 0xc2, 0x00,
+ 0xff, 0xff, 0xff, 0x7f) },
+ { NULL, chunk_from_chars(0x0a, 0x87) }
+ };
+
+ int i;
+ char *string = NULL;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ string = asn1_oid_to_string(test[i].oid);
+ if (test[i].string == NULL)
+ {
+ ck_assert(string == NULL);
+ }
+ else
+ {
+ ck_assert(streq(string, test[i].string));
+ free(string);
+ }
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * length
+ */
+
+START_TEST(test_asn1_length)
+{
+ chunk_t a;
+
+ a = chunk_empty;
+ ck_assert(asn1_length(&a) == ASN1_INVALID_LENGTH);
+
+ a = chunk_from_chars(0x04);
+ ck_assert(asn1_length(&a) == ASN1_INVALID_LENGTH);
+
+ a = chunk_from_chars(0x04, 0x00);
+ ck_assert(asn1_length(&a) == 0);
+
+ a = chunk_from_chars(0x04, 0x01);
+ ck_assert(asn1_length(&a) == ASN1_INVALID_LENGTH);
+
+ a = chunk_from_chars(0x04, 0x01, 0xaa);
+ ck_assert(asn1_length(&a) == 1);
+
+ a = chunk_from_chars(0x04, 0x7f, 0xaa);
+ a.len = 2 + 127;
+ ck_assert(asn1_length(&a) == 127);
+
+ a = chunk_from_chars(0x04, 0x80, 0xaa);
+ a.len = 2 + 128;
+ ck_assert(asn1_length(&a) == ASN1_INVALID_LENGTH);
+
+ a = chunk_from_chars(0x04, 0x81);
+ ck_assert(asn1_length(&a) == ASN1_INVALID_LENGTH);
+
+ a = chunk_from_chars(0x04, 0x81, 0x00);
+ ck_assert(asn1_length(&a) == 0);
+
+ a = chunk_from_chars(0x04, 0x81, 0x80, 0xaa);
+ ck_assert(asn1_length(&a) == ASN1_INVALID_LENGTH);
+
+ a = chunk_from_chars(0x04, 0x81, 0x80, 0xaa);
+ a.len = 3 + 128;
+ ck_assert(asn1_length(&a) == 128);
+
+ a = chunk_from_chars(0x04, 0x82, 0x01, 0x02, 0xaa);
+ a.len = 4 + 258;
+ ck_assert(asn1_length(&a) == 258);
+
+ a = chunk_from_chars(0x04, 0x83, 0x01, 0x02, 0x03, 0xaa);
+ a.len = 5 + 66051;
+ ck_assert(asn1_length(&a) == 66051);
+
+ a = chunk_from_chars(0x04, 0x84, 0x01, 0x02, 0x03, 0x04, 0xaa);
+ a.len = 6 + 16909060;
+ ck_assert(asn1_length(&a) == 16909060);
+
+ /* largest chunk on 32 bit system */
+ a = chunk_from_chars(0x04, 0x84, 0xff, 0xff, 0xff, 0xf9, 0xaa);
+ a.len = 4294967295;
+ ck_assert(asn1_length(&a) == 4294967289);
+
+}
+END_TEST
+
+/*******************************************************************************
+ * unwrap
+ */
+
+START_TEST(test_asn1_unwrap)
+{
+ chunk_t c0 = chunk_from_chars(0x30);
+ chunk_t c1 = chunk_from_chars(0x30, 0x01, 0xaa);
+ chunk_t c2 = chunk_from_chars(0x30, 0x80);
+ chunk_t c3 = chunk_from_chars(0x30, 0x81);
+ chunk_t c4 = chunk_from_chars(0x30, 0x81, 0x01, 0xaa);
+ chunk_t c5 = chunk_from_chars(0x30, 0x81, 0x02, 0xaa);
+
+ chunk_t inner;
+ chunk_t inner_ref = chunk_from_chars(0xaa);
+
+ ck_assert(asn1_unwrap(&c0, &inner) == ASN1_INVALID);
+
+ ck_assert(asn1_unwrap(&c1, &inner) == ASN1_SEQUENCE);
+
+ ck_assert(chunk_equals(inner, inner_ref));
+
+ ck_assert(asn1_unwrap(&c2, &inner) == ASN1_INVALID);
+
+ ck_assert(asn1_unwrap(&c3, &inner) == ASN1_INVALID);
+
+ ck_assert(asn1_unwrap(&c4, &inner) == ASN1_SEQUENCE);
+
+ ck_assert(chunk_equals(inner, inner_ref));
+
+ ck_assert(asn1_unwrap(&c5, &inner) == ASN1_INVALID);
+}
+END_TEST
+
+/*******************************************************************************
+ * is_asn1
+ */
+
+START_TEST(test_is_asn1)
+{
+ typedef struct {
+ bool asn1;
+ chunk_t chunk;
+ } testdata_t;
+
+ u_char buf[8];
+ chunk_t chunk_zero = { buf, 0 };
+ chunk_t chunk_mean = { 0, 1 };
+
+ testdata_t test[] = {
+ { FALSE, chunk_zero },
+ { FALSE, chunk_empty },
+ { FALSE, chunk_mean },
+ { TRUE, chunk_from_chars(0x30, 0x00) },
+ { TRUE, chunk_from_chars(0x31, 0x00) },
+ { TRUE, chunk_from_chars(0x04, 0x00) },
+ { FALSE, chunk_from_chars(0x02, 0x00) },
+ { FALSE, chunk_from_chars(0x30, 0x01) },
+ { FALSE, chunk_from_chars(0x30, 0x80) },
+ { TRUE, chunk_from_chars(0x30, 0x01, 0xa1) },
+ { FALSE, chunk_from_chars(0x30, 0x01, 0xa1, 0xa2) },
+ { TRUE, chunk_from_chars(0x30, 0x01, 0xa1, 0x0a) },
+ { FALSE, chunk_from_chars(0x30, 0x01, 0xa1, 0xa2, 0x0a) },
+ };
+
+ int i;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ ck_assert(is_asn1(test[i].chunk) == test[i].asn1);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * is_printablestring
+ */
+
+START_TEST(test_asn1_is_printablestring)
+{
+ typedef struct {
+ bool printable;
+ char *string;
+ } testdata_t;
+
+
+ testdata_t test[] = {
+ { TRUE, "" },
+ { TRUE, "Z" },
+ { FALSE, "Z#" },
+ { FALSE, "&Z" },
+ { FALSE, "Z@z" },
+ { FALSE, "!" }, { FALSE, "*" }, { FALSE, "$" }, { FALSE, "%" },
+ { FALSE, "[" }, { FALSE, "]" }, { FALSE, "{" }, { FALSE, "}" },
+ { FALSE, "|" }, { FALSE, "~" }, { FALSE, "^" }, { FALSE, "_" },
+ { FALSE, "\"" }, { FALSE, "\\" }, { FALSE, "ä" }, { FALSE, "à" },
+ { TRUE, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789 '()+,-./:=?" },
+ };
+
+ chunk_t chunk;
+ int i;
+
+ ck_assert(asn1_is_printablestring(chunk_empty));
+
+ for (i = 0; i < countof(test); i++)
+ {
+ chunk = chunk_from_str(test[i].string);
+ ck_assert(asn1_is_printablestring(chunk) == test[i].printable);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * to_time
+ */
+
+START_TEST(test_asn1_to_time)
+{
+ typedef struct {
+ time_t time;
+ u_int8_t type;
+ char *string;
+ } testdata_t;
+
+ testdata_t test[] = {
+ { 352980, 0x18, "197001050203Z" },
+ { 352984, 0x18, "19700105020304Z" },
+ { 352980, 0x17, "7001050203Z" },
+ { 347580, 0x17, "7001050203+0130" },
+ { 358380, 0x17, "7001050203-0130" },
+ { 352984, 0x17, "700105020304Z" },
+ { 347584, 0x17, "700105020304+0130" },
+ { 358384, 0x17, "700105020304-0130" },
+ { 0, 0x17, "700105020304+01" },
+ { 0, 0x17, "700105020304-01" },
+ { 0, 0x17, "700105020304" },
+ { 0, 0x17, "70010502Z" },
+ { 0, 0x17, "7001050203xxZ" },
+ { 0, 0x17, "7000050203Z" },
+ { 0, 0x17, "7013050203Z" },
+ { 0, 0x17, "7001004203Z" },
+ { 0, 0x17, "7001320203Z" },
+ { 0, 0x17, "700101-103Z" },
+ { 0, 0x17, "7001016003Z" },
+ { 0, 0x17, "70010102-1Z" },
+ { 0, 0x17, "7001010260Z" },
+ { 0, 0x17, "7001010203-1Z" },
+ { 0, 0x17, "700101020361Z" },
+ { -631152000, 0x17, "500101000000Z" }, /* UTCTime min */
+ { 59, 0x17, "691231235959-0001" },
+ { -1, 0x17, "691231235959Z" },
+ { 0, 0x17, "700101000000Z" },
+ { -60, 0x17, "700101000000+0001" },
+ { 2524607999UL, 0x17, "491231235959Z" }, /* UTCTime max */
+ { 5097600, 0x17, "7003010000Z" },
+ { 68256000, 0x17, "7203010000Z" },
+ { 951868800, 0x17, "0003010000Z" },
+ { 4107542400UL, 0x18, "210003010000Z" }
+ };
+
+ int i;
+ chunk_t chunk;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ if (sizeof(time_t) == 4 && test[i].time < 0)
+ {
+ continue;
+ }
+ chunk = chunk_from_str(test[i].string);
+ ck_assert(asn1_to_time(&chunk, test[i].type) == test[i].time);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * from_time
+ */
+
+START_TEST(test_asn1_from_time)
+{
+ typedef struct {
+ time_t time;
+ u_int8_t type;
+ chunk_t chunk;
+ } testdata_t;
+
+ testdata_t test[] = {
+ { 352984, 0x18, chunk_from_chars(
+ 0x18, 0x0f, 0x31, 0x39, 0x37, 0x30, 0x30, 0x31, 0x30, 0x35,
+ 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x5a) },
+ { 352984, 0x17, chunk_from_chars(
+ 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30, 0x35,
+ 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x5a) },
+ { 1078099200, 0x17, chunk_from_chars(
+ 0x17, 0x0d, 0x30, 0x34, 0x30, 0x33, 0x30, 0x31,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a) },
+ { 4107542400UL, 0x18, chunk_from_chars(
+ 0x18, 0x0f, 0x32, 0x31, 0x30, 0x30, 0x30, 0x33, 0x30, 0x31,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a) }
+ };
+
+ int i;
+ chunk_t chunk;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ if (sizeof(time_t) == 4 && test[i].time < 0)
+ {
+ continue;
+ }
+ chunk = asn1_from_time(&test[i].time, test[i].type);
+ ck_assert(chunk_equals(chunk, test[i].chunk));
+ free(chunk.ptr);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * parse_time
+ */
+
+START_TEST(test_asn1_parse_time)
+{
+ typedef struct {
+ time_t time;
+ chunk_t chunk;
+ } testdata_t;
+
+ testdata_t test[] = {
+ { 352984, chunk_from_chars(
+ 0x18, 0x0f, 0x31, 0x39, 0x37, 0x30, 0x30, 0x31, 0x30, 0x35,
+ 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x5a) },
+ { 352984, chunk_from_chars(
+ 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30, 0x35,
+ 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x5a) },
+ { 0, chunk_from_chars(0x05, 0x00) }
+ };
+
+ int i;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ ck_assert(asn1_parse_time(test[i].chunk, 0) == test[i].time);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * build_object
+ */
+
+START_TEST(test_asn1_build_object)
+{
+ typedef struct {
+ size_t len;
+ size_t size;
+ u_char *b;
+ } testdata_t;
+
+ u_char b0[] = { 0x05, 0x00 };
+ u_char b1[] = { 0x04, 0x7f };
+ u_char b2[] = { 0x04, 0x81, 0x80 };
+ u_char b3[] = { 0x04, 0x81, 0xff };
+ u_char b4[] = { 0x04, 0x82, 0x01, 0x00 };
+ u_char b5[] = { 0x04, 0x82, 0xff, 0xff };
+ u_char b6[] = { 0x04, 0x83, 0x01, 0x00, 0x00 };
+
+ testdata_t test[] = {
+ { 0, sizeof(b0), b0 },
+ { 127, sizeof(b1), b1 },
+ { 128, sizeof(b2), b2 },
+ { 255, sizeof(b3), b3 },
+ { 256, sizeof(b4), b4 },
+ { 65535, sizeof(b5), b5 },
+ { 65536, sizeof(b6), b6 }
+ };
+
+ chunk_t a = chunk_empty;
+ u_char *pos;
+ int i;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ pos = asn1_build_object(&a, test[i].b[0], test[i].len);
+ ck_assert(pos == (a.ptr + test[i].size));
+ ck_assert(a.len == test[i].size + test[i].len);
+ ck_assert(memeq(a.ptr, test[i].b, test[i].size));
+ chunk_free(&a);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * simple_object
+ */
+
+START_TEST(test_asn1_simple_object)
+{
+ chunk_t a = chunk_empty;
+ chunk_t b = chunk_from_chars(0x04, 0x05, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5);
+ chunk_t c = chunk_from_chars(0xa1, 0xa2, 0xa3, 0xa4, 0xa5);
+
+ a = asn1_simple_object(0x04, c);
+ ck_assert(chunk_equals(a, b));
+ chunk_free(&a);
+}
+END_TEST
+
+/*******************************************************************************
+ * parse_simple_object
+ */
+
+START_TEST(test_asn1_parse_simple_object)
+{
+ typedef struct {
+ bool res;
+ int type;
+ chunk_t chunk;
+ } testdata_t;
+
+ testdata_t test[] = {
+ { FALSE, 0x04, chunk_from_chars(0x04) },
+ { FALSE, 0x04, chunk_from_chars(0x02, 0x01, 0x55) },
+ { FALSE, 0x04, chunk_from_chars(0x04, 0x01) },
+ { TRUE, 0x04, chunk_from_chars(0x04, 0x01, 0x55) },
+ { TRUE, 0x06, chunk_from_chars(0x06, 0x02, 0x55, 0x03) },
+ { TRUE, 0x06, chunk_from_chars(0x06, 0x00) },
+ { TRUE, 0x13, chunk_from_chars(0x13, 0x01, 0x55), }
+ };
+
+ int i;
+ bool res;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ res = asn1_parse_simple_object(&test[i].chunk, test[i].type, 0, "test");
+ ck_assert(res == test[i].res);
+ if (res && test[i].chunk.len)
+ {
+ ck_assert(*test[i].chunk.ptr == 0x55);
+ }
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * bitstring
+ */
+
+START_TEST(test_asn1_bitstring)
+{
+ chunk_t a = chunk_empty;
+ chunk_t b = chunk_from_chars(0x03, 0x05, 0x00, 0xa1, 0xa2, 0xa3, 0xa4);
+ chunk_t c = chunk_from_chars(0xa1, 0xa2, 0xa3, 0xa4);
+ chunk_t d = chunk_clone(c);
+
+ a = asn1_bitstring("c", c);
+ ck_assert(chunk_equals(a, b));
+ chunk_free(&a);
+
+ a = asn1_bitstring("m", d);
+ ck_assert(chunk_equals(a, b));
+ chunk_free(&a);
+}
+END_TEST
+
+/*******************************************************************************
+ * integer
+ */
+
+START_TEST(test_asn1_integer)
+{
+ typedef struct {
+ chunk_t b;
+ chunk_t c;
+ } testdata_t;
+
+ chunk_t b0 = chunk_from_chars(0x02, 0x01, 0x00);
+ chunk_t b1 = chunk_from_chars(0x02, 0x01, 0x7f);
+ chunk_t b2 = chunk_from_chars(0x02, 0x02, 0x00, 0x80);
+
+ chunk_t c0 = chunk_empty;
+ chunk_t c1 = chunk_from_chars(0x7f);
+ chunk_t c2 = chunk_from_chars(0x80);
+ chunk_t c3 = chunk_from_chars(0x00, 0x80);
+
+ testdata_t test[] = {
+ { b0, c0 },
+ { b1, c1 },
+ { b2, c2 },
+ { b2, c3 }
+ };
+
+ chunk_t a = chunk_empty;
+ int i;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ a = asn1_integer("c", test[i].c);
+ ck_assert(chunk_equals(a, test[i].b));
+ chunk_free(&a);
+
+ a = asn1_integer("m", chunk_clone(test[i].c));
+ ck_assert(chunk_equals(a, test[i].b));
+ chunk_free(&a);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * parse_integer_uint64
+ */
+
+START_TEST(test_asn1_parse_integer_uint64)
+{
+ typedef struct {
+ u_int64_t n;
+ chunk_t chunk;
+ } testdata_t;
+
+
+ testdata_t test[] = {
+ { 67305985ULL, chunk_from_chars(
+ 0x04, 0x03, 0x02, 0x01) },
+ { 578437695752307201ULL, chunk_from_chars(
+ 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01) },
+ { 18446744073709551615ULL, chunk_from_chars(
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff) }
+ };
+
+ int i;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ ck_assert(asn1_parse_integer_uint64(test[i].chunk) == test[i].n);
+ }
+}
+END_TEST
+
+Suite *asn1_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("asn1");
+
+ tc = tcase_create("algorithmIdentifier");
+ tcase_add_test(tc, test_asn1_algorithmIdentifier);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("parse_algorithmIdentifier");
+ tcase_add_test(tc, test_asn1_parse_algorithmIdentifier);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("known_oid");
+ tcase_add_test(tc, test_asn1_known_oid);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("build_known_oid");
+ tcase_add_test(tc, test_asn1_build_known_oid);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("oid_from_string");
+ tcase_add_test(tc, test_asn1_oid_from_string);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("oid_to_string");
+ tcase_add_test(tc, test_asn1_oid_to_string);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("length");
+ tcase_add_test(tc, test_asn1_length);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("unwrap");
+ tcase_add_test(tc, test_asn1_unwrap);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("is_asn1");
+ tcase_add_test(tc, test_is_asn1);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("is_printablestring");
+ tcase_add_test(tc, test_asn1_is_printablestring);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("to_time");
+ tcase_add_test(tc, test_asn1_to_time);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("from_time");
+ tcase_add_test(tc, test_asn1_from_time);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("parse_time");
+ tcase_add_test(tc, test_asn1_parse_time);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("build_object");
+ tcase_add_test(tc, test_asn1_build_object);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("simple_object");
+ tcase_add_test(tc, test_asn1_simple_object);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("parse_simple_object");
+ tcase_add_test(tc, test_asn1_parse_simple_object);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("bitstring");
+ tcase_add_test(tc, test_asn1_bitstring);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("integer");
+ tcase_add_test(tc, test_asn1_integer);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("parse_integer_uint64");
+ tcase_add_test(tc, test_asn1_parse_integer_uint64);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_asn1_parser.c b/src/libstrongswan/tests/suites/test_asn1_parser.c
new file mode 100644
index 000000000..973562bff
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_asn1_parser.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2014 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 "test_suite.h"
+
+#include <asn1/asn1_parser.h>
+#include <utils/chunk.h>
+
+/*******************************************************************************
+ * utilities
+ */
+
+typedef struct {
+ bool success;
+ int count;
+ chunk_t blob;
+} asn1_test_t;
+
+static void run_parser_test(const asn1Object_t *objects, int id,
+ asn1_test_t *test)
+{
+ asn1_parser_t *parser;
+ chunk_t object;
+ int objectID, count = 0;
+ bool success;
+
+ parser = asn1_parser_create(objects, test->blob);
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ if (objectID == id)
+ {
+ count++;
+ }
+ }
+ success = parser->success(parser);
+ parser->destroy(parser);
+
+ ck_assert(success == test->success && count == test->count);
+}
+
+/*******************************************************************************
+ * length
+ */
+
+static const asn1Object_t octetStringObjects[] = {
+ { 0, "octetString", ASN1_OCTET_STRING, ASN1_BODY }, /* 0 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+
+asn1_test_t length_tests[] = {
+ { FALSE, 0, { NULL, 0 } },
+ { FALSE, 0, chunk_from_chars(0x04) },
+ { TRUE, 1, chunk_from_chars(0x04, 0x00) },
+ { TRUE, 1, chunk_from_chars(0x04, 0x01, 0xaa) },
+ { FALSE, 0, chunk_from_chars(0x04, 0x7f) },
+ { FALSE, 0, chunk_from_chars(0x04, 0x80) },
+ { FALSE, 0, chunk_from_chars(0x04, 0x81) },
+ { TRUE, 1, chunk_from_chars(0x04, 0x81, 0x00) },
+ { FALSE, 0, chunk_from_chars(0x04, 0x81, 0x01) },
+ { TRUE, 1, chunk_from_chars(0x04, 0x81, 0x01, 0xaa) },
+ { FALSE, 0, chunk_from_chars(0x04, 0x82, 0x00, 0x01) },
+ { TRUE, 1, chunk_from_chars(0x04, 0x82, 0x00, 0x01, 0xaa) },
+ { FALSE, 0, chunk_from_chars(0x04, 0x83, 0x00, 0x00, 0x01) },
+ { TRUE, 1, chunk_from_chars(0x04, 0x83, 0x00, 0x00, 0x01, 0xaa) },
+ { FALSE, 0, chunk_from_chars(0x04, 0x84, 0x00, 0x00, 0x00, 0x01) },
+ { TRUE, 1, chunk_from_chars(0x04, 0x84, 0x00, 0x00, 0x00, 0x01, 0xaa) },
+};
+
+START_TEST(test_asn1_parser_length)
+{
+ run_parser_test(octetStringObjects, 0, &length_tests[_i]);
+}
+END_TEST
+
+/*******************************************************************************
+ * loop
+ */
+
+static const asn1Object_t loopObjects[] = {
+ { 0, "loopObjects", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
+ { 1, "octetString", ASN1_OCTET_STRING, ASN1_BODY }, /* 1 */
+ { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+
+asn1_test_t loop_tests[] = {
+ { TRUE, 0, chunk_from_chars(0x30, 0x00) },
+ { FALSE, 0, chunk_from_chars(0x30, 0x02, 0x04, 0x01) },
+ { TRUE, 1, chunk_from_chars(0x30, 0x03, 0x04, 0x01, 0xaa) },
+ { TRUE, 2, chunk_from_chars(0x30, 0x05, 0x04, 0x01, 0xaa, 0x04, 0x00) },
+ { FALSE, 1, chunk_from_chars(0x30, 0x05, 0x04, 0x01, 0xaa, 0x05, 0x00) },
+ { TRUE, 3, chunk_from_chars(0x30, 0x09, 0x04, 0x01, 0xaa, 0x04, 0x00,
+ 0x04, 0x02, 0xbb, 0xcc) },
+};
+
+START_TEST(test_asn1_parser_loop)
+{
+ run_parser_test(loopObjects, 1, &loop_tests[_i]);
+}
+END_TEST
+
+/*******************************************************************************
+ * default
+ */
+
+typedef struct {
+ int i1, i2, i3;
+ chunk_t blob;
+} default_opt_test_t;
+
+static const asn1Object_t defaultObjects[] = {
+ { 0, "defaultObjects", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
+ { 1, "explicit int1", ASN1_CONTEXT_C_1, ASN1_DEF }, /* 1 */
+ { 2, "int1", ASN1_INTEGER, ASN1_BODY }, /* 2 */
+ { 1, "int2", ASN1_INTEGER, ASN1_DEF|ASN1_BODY }, /* 3 */
+ { 1, "implicit int3", ASN1_CONTEXT_S_3, ASN1_DEF|ASN1_BODY }, /* 4 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+
+default_opt_test_t default_tests[] = {
+ { -1, -2, -3, chunk_from_chars(0x30, 0x00) },
+ { 1, -2, -3, chunk_from_chars(0x30, 0x05, 0xa1, 0x03, 0x02, 0x01, 0x01) },
+ { -1, 2, -3, chunk_from_chars(0x30, 0x03, 0x02, 0x01, 0x02) },
+ { -1, -2, 3, chunk_from_chars(0x30, 0x03, 0x83, 0x01, 0x03) },
+ { 1, 2, -3, chunk_from_chars(0x30, 0x08, 0xa1, 0x03, 0x02, 0x01, 0x01,
+ 0x02, 0x01, 0x02) },
+ { 1, -2, 3, chunk_from_chars(0x30, 0x08, 0xa1, 0x03, 0x02, 0x01, 0x01,
+ 0x83, 0x01, 0x03) },
+ { -1, 2, 3, chunk_from_chars(0x30, 0x06, 0x02, 0x01, 0x02,
+ 0x83, 0x01, 0x03) },
+ { 1, 2, 3, chunk_from_chars(0x30, 0x0b, 0xa1, 0x03, 0x02, 0x01, 0x01,
+ 0x02, 0x01, 0x02,
+ 0x83, 0x01, 0x03) },
+ { 0, 0, 0, chunk_from_chars(0x30, 0x0b, 0xa1, 0x03, 0x04, 0x01, 0xaa,
+ 0x02, 0x01, 0x02,
+ 0x83, 0x01, 0x03) },
+ { 1, 0, 0, chunk_from_chars(0x30, 0x0b, 0xa1, 0x03, 0x02, 0x01, 0x01,
+ 0x02, 0x05, 0x02,
+ 0x83, 0x01, 0x03) },
+ { 1, 2, 0, chunk_from_chars(0x30, 0x0b, 0xa1, 0x03, 0x02, 0x01, 0x01,
+ 0x02, 0x01, 0x02,
+ 0x83, 0x02, 0x03) },
+};
+
+START_TEST(test_asn1_parser_default)
+{
+ asn1_parser_t *parser;
+ chunk_t object;
+ int objectID, i1 = 0, i2 = 0, i3 = 0;
+ bool success;
+
+ parser = asn1_parser_create(defaultObjects, default_tests[_i].blob);
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ switch (objectID)
+ {
+ case 2:
+ i1 = object.len ? *object.ptr : -1;
+ break;
+ case 3:
+ i2 = object.len ? *object.ptr : -2;
+ break;
+ case 4:
+ i3 = object.len ? *object.ptr : -3;
+ break;
+ default:
+ break;
+ }
+ }
+ success = parser->success(parser);
+ parser->destroy(parser);
+
+ ck_assert(success == (default_tests[_i].i1 &&
+ default_tests[_i].i2 &&
+ default_tests[_i].i3));
+
+ ck_assert(i1 == default_tests[_i].i1 &&
+ i2 == default_tests[_i].i2 &&
+ i3 == default_tests[_i].i3);
+}
+END_TEST
+
+/*******************************************************************************
+ * option
+ */
+
+static const asn1Object_t optionObjects[] = {
+ { 0, "optionalObjects", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
+ { 1, "sequence int1", ASN1_SEQUENCE, ASN1_OPT }, /* 1 */
+ { 2, "int1", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 2 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */
+ { 1, "int2", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 5 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */
+ { 1, "implicit int3", ASN1_CONTEXT_S_3, ASN1_OPT|ASN1_BODY }, /* 7 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 8 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+
+default_opt_test_t option_tests[] = {
+ { 0, 0, 0, chunk_from_chars(0x30, 0x00) },
+ { 1, 0, 0, chunk_from_chars(0x30, 0x05, 0x30, 0x03, 0x02, 0x01, 0x01) },
+ { 0, 2, 0, chunk_from_chars(0x30, 0x03, 0x02, 0x01, 0x02) },
+ { 0, 0, 3, chunk_from_chars(0x30, 0x03, 0x83, 0x01, 0x03) },
+ { 1, 2, 0, chunk_from_chars(0x30, 0x08, 0x30, 0x03, 0x02, 0x01, 0x01,
+ 0x02, 0x01, 0x02) },
+ { 1, 0, 3, chunk_from_chars(0x30, 0x08, 0x30, 0x03, 0x02, 0x01, 0x01,
+ 0x83, 0x01, 0x03) },
+ { 0, 2, 3, chunk_from_chars(0x30, 0x06, 0x02, 0x01, 0x02,
+ 0x83, 0x01, 0x03) },
+ { 1, 2, 3, chunk_from_chars(0x30, 0x0b, 0x30, 0x03, 0x02, 0x01, 0x01,
+ 0x02, 0x01, 0x02,
+ 0x83, 0x01, 0x03) },
+ { 0, 2, 3, chunk_from_chars(0x30, 0x08, 0x30, 0x00,
+ 0x02, 0x01, 0x02,
+ 0x83, 0x01, 0x03) },
+};
+
+START_TEST(test_asn1_parser_option)
+{
+ asn1_parser_t *parser;
+ chunk_t object;
+ int objectID, i1 = 0, i2 = 0, i3 = 0;
+ bool success;
+
+ parser = asn1_parser_create(optionObjects, option_tests[_i].blob);
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ switch (objectID)
+ {
+ case 2:
+ i1 = *object.ptr;
+ break;
+ case 5:
+ i2 = *object.ptr;
+ break;
+ case 7:
+ i3 = *object.ptr;
+ break;
+ default:
+ break;
+ }
+ }
+ success = parser->success(parser);
+ parser->destroy(parser);
+
+ ck_assert(success);
+
+ ck_assert(i1 == option_tests[_i].i1 &&
+ i2 == option_tests[_i].i2 &&
+ i3 == option_tests[_i].i3);
+}
+END_TEST
+
+Suite *asn1_parser_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("asn1_parser");
+
+ tc = tcase_create("length");
+ tcase_add_loop_test(tc, test_asn1_parser_length, 0, countof(length_tests));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("loop");
+ tcase_add_loop_test(tc, test_asn1_parser_loop, 0, countof(loop_tests));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("default");
+ tcase_add_loop_test(tc, test_asn1_parser_default, 0, countof(default_tests));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("option");
+ tcase_add_loop_test(tc, test_asn1_parser_option, 0, countof(option_tests));
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_bio_reader.c b/src/libstrongswan/tests/suites/test_bio_reader.c
new file mode 100644
index 000000000..6a9743d62
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_bio_reader.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * 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 "test_suite.h"
+
+#include <bio/bio_reader.h>
+
+/*******************************************************************************
+ * different integer reads
+ */
+
+#define assert_integer_read(data, bits, val) ({ \
+ bio_reader_t *reader = bio_reader_create(data); \
+ typeof(val) i; \
+ for (i = 0; reader->remaining(reader) >= (bits / 8); i++) \
+ { \
+ ck_assert(reader->read_uint##bits(reader, &val)); \
+ ck_assert_int_eq(i, val); \
+ } \
+ ck_assert_int_eq(i, data.len / (bits / 8)); \
+ ck_assert_int_eq(reader->remaining(reader), data.len % (bits / 8)); \
+ ck_assert(!reader->read_uint##bits(reader, &val)); \
+ reader->destroy(reader); \
+})
+
+#define assert_integer_read_uneven(data, bits, val) ({ \
+ int i; \
+ for (i = 0; i <= bits / 8; i++, data.len++) \
+ { \
+ assert_integer_read(data, bits, val); \
+ } \
+})
+
+#define assert_basic_read(bits, val) ({ \
+ chunk_t data; \
+ data = chunk_empty; \
+ assert_integer_read(data, bits, val); \
+ data = chunk_alloca(bits / 8); \
+ memset(data.ptr, 0, data.len); \
+ data.len = 0; \
+ assert_integer_read_uneven(data, bits, val); \
+})
+
+#define assert_extended_read(data, bits, val) ({ \
+ chunk_t extended = chunk_alloca(data.len + bits / 8); \
+ memset(extended.ptr, 0, extended.len); \
+ extended.ptr[extended.len - 1] = data.len / (bits / 8); \
+ memcpy(extended.ptr, data.ptr, data.len); \
+ extended.len = data.len; \
+ assert_integer_read_uneven(extended, bits, val); \
+})
+
+START_TEST(test_read_uint8)
+{
+ chunk_t data = chunk_from_chars(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07);
+ u_int8_t val;
+
+ assert_integer_read(data, 8, val);
+ assert_basic_read(8, val);
+ assert_extended_read(data, 8, val);
+}
+END_TEST
+
+START_TEST(test_read_uint16)
+{
+ chunk_t data = chunk_from_chars(0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03);
+ u_int16_t val;
+
+ assert_integer_read(data, 16, val);
+ assert_basic_read(16, val);
+ assert_extended_read(data, 16, val);
+}
+END_TEST
+
+START_TEST(test_read_uint24)
+{
+ chunk_t data = chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x03);
+ u_int32_t val;
+
+ assert_integer_read(data, 24, val);
+ assert_basic_read(24, val);
+ assert_extended_read(data, 24, val);
+}
+END_TEST
+
+START_TEST(test_read_uint32)
+{
+ chunk_t data = chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03);
+ u_int32_t val;
+
+ assert_integer_read(data, 32, val);
+ assert_basic_read(32, val);
+ assert_extended_read(data, 32, val);
+}
+END_TEST
+
+START_TEST(test_read_uint64)
+{
+ chunk_t data = chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03);
+ u_int64_t val;
+
+ assert_integer_read(data, 64, val);
+ assert_basic_read(64, val);
+ assert_extended_read(data, 64, val);
+}
+END_TEST
+
+/*******************************************************************************
+ * different integer reads from the end of a buffer
+ */
+
+#define assert_integer_read_end(data, bits, val) ({ \
+ bio_reader_t *reader = bio_reader_create(data); \
+ typeof(val) i; \
+ for (i = 0; reader->remaining(reader) >= (bits / 8); i++) \
+ { \
+ ck_assert(reader->read_uint##bits##_end(reader, &val)); \
+ ck_assert_int_eq(i, val); \
+ } \
+ ck_assert_int_eq(i, data.len / (bits / 8)); \
+ ck_assert_int_eq(reader->remaining(reader), data.len % (bits / 8)); \
+ ck_assert(!reader->read_uint##bits##_end(reader, &val)); \
+ reader->destroy(reader); \
+})
+
+#define assert_integer_read_end_uneven(data, bits, val) ({ \
+ int i; \
+ data.ptr += bits / 8; \
+ for (i = 0; i <= bits / 8; i++, data.ptr--, data.len++) \
+ { \
+ assert_integer_read_end(data, bits, val); \
+ } \
+})
+
+#define assert_basic_read_end(bits, val) ({ \
+ chunk_t data; \
+ data = chunk_empty; \
+ assert_integer_read_end(data, bits, val); \
+ data = chunk_alloca(bits / 8); \
+ memset(data.ptr, 0, data.len); \
+ data.len = 0; \
+ assert_integer_read_end_uneven(data, bits, val); \
+})
+
+#define assert_extended_read_end(data, bits, val) ({ \
+ chunk_t extended = chunk_alloca(data.len + bits / 8); \
+ memset(extended.ptr, 0, extended.len); \
+ extended.ptr[bits / 8 - 1] = data.len / (bits / 8); \
+ memcpy(extended.ptr + bits / 8, data.ptr, data.len); \
+ extended.len = data.len; \
+ assert_integer_read_end_uneven(extended, bits, val); \
+})
+
+START_TEST(test_read_uint8_end)
+{
+ chunk_t data = chunk_from_chars(0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00);
+ u_int8_t val;
+
+ assert_integer_read_end(data, 8, val);
+ assert_basic_read_end(8, val);
+ assert_extended_read_end(data, 8, val);
+}
+END_TEST
+
+START_TEST(test_read_uint16_end)
+{
+ chunk_t data = chunk_from_chars(0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00);
+ u_int16_t val;
+
+ assert_integer_read_end(data, 16, val);
+ assert_basic_read_end(16, val);
+ assert_extended_read_end(data, 16, val);
+}
+END_TEST
+
+START_TEST(test_read_uint24_end)
+{
+ chunk_t data = chunk_from_chars(0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00);
+ u_int32_t val;
+
+ assert_integer_read_end(data, 24, val);
+ assert_basic_read_end(24, val);
+ assert_extended_read_end(data, 24, val);
+}
+END_TEST
+
+START_TEST(test_read_uint32_end)
+{
+ chunk_t data = chunk_from_chars(0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00);
+ u_int32_t val;
+
+ assert_integer_read_end(data, 32, val);
+ assert_basic_read_end(32, val);
+ assert_extended_read_end(data, 32, val);
+}
+END_TEST
+
+START_TEST(test_read_uint64_end)
+{
+ chunk_t data = chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ u_int64_t val;
+
+ assert_integer_read_end(data, 64, val);
+ assert_basic_read_end(64, val);
+ assert_extended_read_end(data, 64, val);
+}
+END_TEST
+
+/*******************************************************************************
+ * read data
+ */
+
+static inline void assert_reader_after_read(bio_reader_t *reader, chunk_t data)
+{
+ chunk_t peek;
+
+ ck_assert_int_eq(reader->remaining(reader), data.len);
+ peek = reader->peek(reader);
+ ck_assert_int_eq(reader->remaining(reader), data.len);
+ ck_assert(peek.ptr == data.ptr);
+ data.ptr != NULL ? ck_assert(chunk_equals(peek, data))
+ : ck_assert(peek.ptr == NULL);
+}
+
+START_TEST(test_read_data)
+{
+ chunk_t read, data = chunk_from_chars(0x00, 0x00, 0x00, 0x00);
+ bio_reader_t *reader;
+
+ reader = bio_reader_create(chunk_empty);
+ ck_assert_int_eq(reader->remaining(reader), 0);
+ ck_assert(reader->read_data(reader, 0, &read));
+ ck_assert(!reader->read_data(reader, 1, &read));
+ reader->destroy(reader);
+
+ reader = bio_reader_create(data);
+ ck_assert(reader->read_data(reader, 0, &read));
+ ck_assert_int_eq(read.len, 0);
+ ck_assert(read.ptr == data.ptr);
+ assert_reader_after_read(reader, data);
+
+ ck_assert(reader->read_data(reader, 1, &read));
+ ck_assert_int_eq(read.len, 1);
+ ck_assert(read.ptr == data.ptr);
+ assert_reader_after_read(reader, chunk_skip(data, 1));
+
+ ck_assert(reader->read_data(reader, 2, &read));
+ ck_assert_int_eq(read.len, 2);
+ ck_assert(read.ptr == data.ptr + 1);
+ assert_reader_after_read(reader, chunk_skip(data, 3));
+
+ ck_assert(!reader->read_data(reader, 2, &read));
+ ck_assert(reader->read_data(reader, 1, &read));
+ ck_assert_int_eq(read.len, 1);
+ ck_assert(read.ptr == data.ptr + 3);
+ assert_reader_after_read(reader, chunk_skip(data, 4));
+
+ ck_assert_int_eq(reader->remaining(reader), 0);
+ ck_assert(reader->read_data(reader, 0, &read));
+ ck_assert(!reader->read_data(reader, 1, &read));
+ reader->destroy(reader);
+}
+END_TEST
+
+START_TEST(test_read_data_end)
+{
+ chunk_t read, data = chunk_from_chars(0x00, 0x00, 0x00, 0x00);
+ bio_reader_t *reader;
+
+ reader = bio_reader_create(chunk_empty);
+ ck_assert_int_eq(reader->remaining(reader), 0);
+ ck_assert(reader->read_data_end(reader, 0, &read));
+ ck_assert(!reader->read_data_end(reader, 1, &read));
+ reader->destroy(reader);
+
+ reader = bio_reader_create(data);
+ ck_assert(reader->read_data_end(reader, 0, &read));
+ ck_assert_int_eq(read.len, 0);
+ ck_assert(read.ptr == data.ptr + data.len);
+ assert_reader_after_read(reader, data);
+
+ ck_assert(reader->read_data_end(reader, 1, &read));
+ ck_assert_int_eq(read.len, 1);
+ data.len--;
+ ck_assert(read.ptr == data.ptr + data.len);
+ assert_reader_after_read(reader, data);
+
+ ck_assert(reader->read_data_end(reader, 2, &read));
+ ck_assert_int_eq(read.len, 2);
+ data.len -= 2;
+ ck_assert(read.ptr == data.ptr + data.len);
+ assert_reader_after_read(reader, data);
+
+ ck_assert(!reader->read_data(reader, 2, &read));
+ ck_assert(reader->read_data(reader, 1, &read));
+ ck_assert_int_eq(read.len, 1);
+ ck_assert(read.ptr == data.ptr);
+ assert_reader_after_read(reader, chunk_empty);
+
+ ck_assert_int_eq(reader->remaining(reader), 0);
+ ck_assert(reader->read_data(reader, 0, &read));
+ ck_assert(!reader->read_data(reader, 1, &read));
+ reader->destroy(reader);
+}
+END_TEST
+
+/*******************************************************************************
+ * read length followed by data
+ */
+
+#define assert_read_data_len(bits) ({ \
+ bio_reader_t *reader; \
+ chunk_t read, data; \
+ int i, len = bits / 8; \
+ data = chunk_empty; \
+ reader = bio_reader_create(data); \
+ ck_assert(!reader->read_data##bits(reader, &read)); \
+ reader->destroy(reader); \
+ data = chunk_alloca(len + 8); \
+ memset(data.ptr, 0, data.len); \
+ for (i = 0; i <= 8; i++) \
+ { \
+ data.ptr[len - 1] = i; \
+ data.len = len + i; \
+ reader = bio_reader_create(data); \
+ ck_assert(reader->read_data##bits(reader, &read)); \
+ ck_assert_int_eq(reader->remaining(reader), 0); \
+ ck_assert_int_eq(read.len, i); \
+ ck_assert((!read.ptr && !read.len) || (read.ptr == data.ptr + len)); \
+ reader->destroy(reader); \
+ } \
+ data.ptr[len - 1] = i; \
+ reader = bio_reader_create(data); \
+ ck_assert(!reader->read_data##bits(reader, &read)); \
+ reader->destroy(reader); \
+})
+
+START_TEST(test_read_data8)
+{
+ assert_read_data_len(8);
+}
+END_TEST
+
+START_TEST(test_read_data16)
+{
+ assert_read_data_len(16);
+}
+END_TEST
+
+START_TEST(test_read_data24)
+{
+ assert_read_data_len(24);
+}
+END_TEST
+
+START_TEST(test_read_data32)
+{
+ assert_read_data_len(32);
+}
+END_TEST
+
+/*******************************************************************************
+ * test constructors
+ */
+
+START_TEST(test_create)
+{
+ chunk_t data = chunk_from_str("foobar");
+ bio_reader_t *reader;
+
+ data = chunk_clone(data);
+ reader = bio_reader_create(data);
+ reader->destroy(reader);
+ chunk_free(&data);
+}
+END_TEST
+
+START_TEST(test_create_own)
+{
+ chunk_t data = chunk_from_str("foobar");
+ bio_reader_t *reader;
+
+ data = chunk_clone(data);
+ reader = bio_reader_create_own(data);
+ reader->destroy(reader);
+}
+END_TEST
+
+Suite *bio_reader_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("bio_reader");
+
+ tc = tcase_create("integer reads");
+ tcase_add_test(tc, test_read_uint8);
+ tcase_add_test(tc, test_read_uint16);
+ tcase_add_test(tc, test_read_uint24);
+ tcase_add_test(tc, test_read_uint32);
+ tcase_add_test(tc, test_read_uint64);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("integer reads from end");
+ tcase_add_test(tc, test_read_uint8_end);
+ tcase_add_test(tc, test_read_uint16_end);
+ tcase_add_test(tc, test_read_uint24_end);
+ tcase_add_test(tc, test_read_uint32_end);
+ tcase_add_test(tc, test_read_uint64_end);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("data reads and peek");
+ tcase_add_test(tc, test_read_data);
+ tcase_add_test(tc, test_read_data_end);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("data length reads");
+ tcase_add_test(tc, test_read_data8);
+ tcase_add_test(tc, test_read_data16);
+ tcase_add_test(tc, test_read_data24);
+ tcase_add_test(tc, test_read_data32);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("constructors");
+ tcase_add_test(tc, test_create);
+ tcase_add_test(tc, test_create_own);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_bio_writer.c b/src/libstrongswan/tests/suites/test_bio_writer.c
new file mode 100644
index 000000000..e74288eb7
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_bio_writer.c
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * 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 "test_suite.h"
+
+#include <bio/bio_writer.h>
+
+/*******************************************************************************
+ * different integer writes
+ */
+
+static inline void verify_int_buffer(chunk_t data, int bits, int val)
+{
+ size_t i;
+ int len = bits / 8;
+
+ ck_assert_int_eq(data.len, (val + 1) * len);
+ for (i = 0; i < data.len; i++)
+ {
+ if ((i + 1) % len)
+ {
+ ck_assert_int_eq(data.ptr[i], 0);
+ }
+ else
+ {
+ ck_assert_int_eq(data.ptr[i], i / len);
+ }
+ }
+}
+
+#define assert_integer_write(init, bits) ({ \
+ int i; \
+ bio_writer_t *writer = bio_writer_create(init); \
+ for (i = 0; i < 16; i++) \
+ { \
+ writer->write_uint##bits(writer, i); \
+ verify_int_buffer(writer->get_buf(writer), bits, i); \
+ } \
+ writer->destroy(writer); \
+})
+
+START_TEST(test_write_uint8)
+{
+ /* use default buffer (and increase) size */
+ assert_integer_write(0, 8);
+ /* force a resize by the given size */
+ assert_integer_write(1, 8);
+}
+END_TEST
+
+START_TEST(test_write_uint16)
+{
+ assert_integer_write(0, 16);
+ assert_integer_write(1, 16);
+}
+END_TEST
+
+START_TEST(test_write_uint24)
+{
+ assert_integer_write(0, 24);
+ assert_integer_write(1, 24);
+}
+END_TEST
+
+START_TEST(test_write_uint32)
+{
+ assert_integer_write(0, 32);
+ assert_integer_write(1, 32);
+}
+END_TEST
+
+START_TEST(test_write_uint64)
+{
+ assert_integer_write(0, 64);
+ assert_integer_write(1, 64);
+}
+END_TEST
+
+/*******************************************************************************
+ * write data / skip
+ */
+
+static inline void assert_writer_after_write(bio_writer_t *writer, int count)
+{
+ chunk_t buf;
+ size_t i;
+
+ buf = writer->get_buf(writer);
+ ck_assert_int_eq(buf.len, count * 3);
+ for (i = 0; i < buf.len; i++)
+ {
+ ck_assert(buf.ptr[i] == i % 3);
+ }
+}
+
+START_TEST(test_write_data)
+{
+ chunk_t buf, data = chunk_from_chars(0x00, 0x01, 0x02);
+ bio_writer_t *writer;
+
+ /* no allocation, but default buffer size */
+ writer = bio_writer_create(0);
+ buf = writer->get_buf(writer);
+ ck_assert_int_eq(buf.len, 0);
+ ck_assert(buf.ptr == NULL);
+
+ writer->write_data(writer, chunk_empty);
+ buf = writer->get_buf(writer);
+ ck_assert_int_eq(buf.len, 0);
+ ck_assert(buf.ptr == NULL);
+ writer->destroy(writer);
+
+ /* custom buffer size, initial buffer allocated */
+ writer = bio_writer_create(1);
+ buf = writer->get_buf(writer);
+ ck_assert_int_eq(buf.len, 0);
+ ck_assert(buf.ptr != NULL);
+
+ writer->write_data(writer, chunk_empty);
+ buf = writer->get_buf(writer);
+ ck_assert_int_eq(buf.len, 0);
+ ck_assert(buf.ptr != NULL);
+ writer->destroy(writer);
+
+ writer = bio_writer_create(0);
+
+ writer->write_data(writer, data);
+ assert_writer_after_write(writer, 1);
+
+ writer->write_data(writer, data);
+ assert_writer_after_write(writer, 2);
+
+ writer->write_data(writer, data);
+ assert_writer_after_write(writer, 3);
+
+ writer->destroy(writer);
+}
+END_TEST
+
+START_TEST(test_skip)
+{
+ chunk_t skipped, buf, data = chunk_from_chars(0x00, 0x01, 0x02);
+ bio_writer_t *writer;
+
+ writer = bio_writer_create(4);
+ skipped = writer->skip(writer, 3);
+ ck_assert_int_eq(skipped.len, 3);
+ buf = writer->get_buf(writer);
+ ck_assert(skipped.ptr == buf.ptr);
+ memset(skipped.ptr, 0, skipped.len);
+
+ writer->write_data(writer, data);
+ buf = writer->get_buf(writer);
+ ck_assert(chunk_equals(buf, chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x01, 0x02)));
+ writer->destroy(writer);
+
+ writer = bio_writer_create(1);
+ skipped = writer->skip(writer, 3);
+ memcpy(skipped.ptr, data.ptr, data.len);
+
+ writer->write_data(writer, data);
+ assert_writer_after_write(writer, 2);
+ writer->destroy(writer);
+}
+END_TEST
+
+/*******************************************************************************
+ * write length followed by data
+ */
+
+#define assert_write_data_len(init, bits) ({ \
+ bio_writer_t *writer; \
+ chunk_t buf, data; \
+ int i, len = bits / 8; \
+ writer = bio_writer_create(init); \
+ writer->write_data##bits(writer, chunk_empty); \
+ buf = writer->get_buf(writer); \
+ ck_assert_int_eq(buf.len, len); \
+ ck_assert_int_eq(buf.ptr[len - 1], 0); \
+ writer->destroy(writer); \
+ data = chunk_alloca(32); \
+ memset(data.ptr, 0, data.len); \
+ for (i = 0; i < 32; i++) \
+ { \
+ data.ptr[i] = i; \
+ data.len = i; \
+ writer = bio_writer_create(init); \
+ writer->write_data##bits(writer, data); \
+ buf = writer->get_buf(writer); \
+ ck_assert_int_eq(buf.len, len + i); \
+ ck_assert_int_eq(buf.ptr[len - 1], i); \
+ ck_assert(chunk_equals(chunk_create(buf.ptr + len, buf.len - len), data)); \
+ writer->destroy(writer); \
+ } \
+})
+
+START_TEST(test_write_data8)
+{
+ assert_write_data_len(0, 8);
+ assert_write_data_len(1, 8);
+}
+END_TEST
+
+START_TEST(test_write_data16)
+{
+ assert_write_data_len(0, 16);
+ assert_write_data_len(1, 16);
+}
+END_TEST
+
+START_TEST(test_write_data24)
+{
+ assert_write_data_len(0, 24);
+ assert_write_data_len(1, 24);
+}
+END_TEST
+
+START_TEST(test_write_data32)
+{
+ assert_write_data_len(0, 32);
+ assert_write_data_len(1, 32);
+}
+END_TEST
+
+
+/*******************************************************************************
+ * add length header before current data
+ */
+
+#define assert_wrap_data(init, bits) ({ \
+ bio_writer_t *writer; \
+ chunk_t buf, data; \
+ int i, len = bits / 8; \
+ writer = bio_writer_create(init); \
+ writer->wrap##bits(writer); \
+ buf = writer->get_buf(writer); \
+ ck_assert_int_eq(buf.len, len); \
+ ck_assert_int_eq(buf.ptr[len - 1], 0); \
+ writer->destroy(writer); \
+ data = chunk_alloca(32); \
+ memset(data.ptr, 0, data.len); \
+ for (i = 0; i < 32; i++) \
+ { \
+ data.ptr[i] = i; \
+ data.len = i; \
+ writer = bio_writer_create(init); \
+ writer->write_data(writer, data); \
+ writer->wrap##bits(writer); \
+ buf = writer->get_buf(writer); \
+ ck_assert_int_eq(buf.len, len + i); \
+ ck_assert_int_eq(buf.ptr[len - 1], i); \
+ ck_assert(chunk_equals(chunk_create(buf.ptr + len, buf.len - len), data)); \
+ writer->wrap##bits(writer); \
+ buf = writer->get_buf(writer); \
+ ck_assert_int_eq(buf.len, 2 * len + i); \
+ ck_assert_int_eq(buf.ptr[len - 1], len + i); \
+ ck_assert(chunk_equals(chunk_create(buf.ptr + 2 * len, buf.len - 2 * len), data)); \
+ writer->destroy(writer); \
+ } \
+})
+
+START_TEST(test_wrap8)
+{
+ assert_wrap_data(0, 8);
+ assert_wrap_data(1, 8);
+}
+END_TEST
+
+START_TEST(test_wrap16)
+{
+ assert_wrap_data(0, 16);
+ assert_wrap_data(1, 16);
+}
+END_TEST
+
+START_TEST(test_wrap24)
+{
+ assert_wrap_data(0, 24);
+ assert_wrap_data(1, 24);
+}
+END_TEST
+
+START_TEST(test_wrap32)
+{
+ assert_wrap_data(0, 32);
+ assert_wrap_data(1, 32);
+}
+END_TEST
+
+/*******************************************************************************
+ * test data extraction
+ */
+
+START_TEST(test_get_buf)
+{
+ bio_writer_t *writer;
+ chunk_t data1, data2;
+
+ writer = bio_writer_create(0);
+ writer->write_uint8(writer, 1);
+ data1 = writer->get_buf(writer);
+ ck_assert_int_eq(data1.len, 1);
+ ck_assert(data1.ptr[0] == 1);
+
+ data2 = writer->get_buf(writer);
+ ck_assert(chunk_equals(data1, data2));
+ ck_assert(data1.ptr == data2.ptr);
+ writer->destroy(writer);
+}
+END_TEST
+
+START_TEST(test_extract_buf)
+{
+ bio_writer_t *writer;
+ chunk_t data1, data2;
+
+ writer = bio_writer_create(0);
+ writer->write_uint8(writer, 1);
+ data1 = writer->extract_buf(writer);
+ ck_assert_int_eq(data1.len, 1);
+ ck_assert(data1.ptr[0] == 1);
+
+ data2 = writer->get_buf(writer);
+ ck_assert_int_eq(data2.len, 0);
+ ck_assert(data2.ptr == NULL);
+ data2 = writer->extract_buf(writer);
+ ck_assert_int_eq(data2.len, 0);
+ ck_assert(data2.ptr == NULL);
+
+ writer->write_uint8(writer, 1);
+ data2 = writer->get_buf(writer);
+ ck_assert(chunk_equals(data1, data2));
+ ck_assert(data1.ptr != data2.ptr);
+
+ writer->destroy(writer);
+ chunk_free(&data1);
+}
+END_TEST
+
+Suite *bio_writer_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("bio_writer");
+
+ tc = tcase_create("integer writes");
+ tcase_add_test(tc, test_write_uint8);
+ tcase_add_test(tc, test_write_uint16);
+ tcase_add_test(tc, test_write_uint24);
+ tcase_add_test(tc, test_write_uint32);
+ tcase_add_test(tc, test_write_uint64);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("data writes/skip");
+ tcase_add_test(tc, test_write_data);
+ tcase_add_test(tc, test_skip);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("data length writes");
+ tcase_add_test(tc, test_write_data8);
+ tcase_add_test(tc, test_write_data16);
+ tcase_add_test(tc, test_write_data24);
+ tcase_add_test(tc, test_write_data32);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("wrap writes");
+ tcase_add_test(tc, test_wrap8);
+ tcase_add_test(tc, test_wrap16);
+ tcase_add_test(tc, test_wrap24);
+ tcase_add_test(tc, test_wrap32);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("get/extract");
+ tcase_add_test(tc, test_get_buf);
+ tcase_add_test(tc, test_extract_buf);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_chunk.c b/src/libstrongswan/tests/suites/test_chunk.c
new file mode 100644
index 000000000..e373fbdb6
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_chunk.c
@@ -0,0 +1,1027 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * Copyright (C) 2008 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 "test_suite.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <utils/chunk.h>
+#include <threading/thread.h>
+
+/*******************************************************************************
+ * utilities
+ */
+
+static void assert_chunk_empty(chunk_t chunk)
+{
+ ck_assert(chunk.len == 0 && chunk.ptr == NULL);
+}
+
+/*******************************************************************************
+ * equals
+ */
+
+START_TEST(test_chunk_equals)
+{
+ chunk_t chunk = chunk_from_str("chunk");
+ chunk_t chunk_a, chunk_b;
+
+ chunk_a = chunk_empty;
+ chunk_b = chunk_empty;
+ ck_assert(!chunk_equals(chunk_a, chunk_b));
+
+ chunk_a = chunk;
+ ck_assert(!chunk_equals(chunk_a, chunk_b));
+ chunk_b = chunk;
+ ck_assert(chunk_equals(chunk_a, chunk_b));
+
+ chunk_b = chunk_from_str("asdf");
+ ck_assert(!chunk_equals(chunk_a, chunk_b));
+
+ chunk_b = chunk_from_str("chunk");
+ ck_assert(chunk_equals(chunk_a, chunk_b));
+}
+END_TEST
+
+/*******************************************************************************
+ * chunk_compare test
+ */
+
+static struct {
+ int result;
+ chunk_t a;
+ chunk_t b;
+} compare_data[] = {
+ { 0, { NULL, 0 }, { NULL, 0 }},
+ { 0, chunk_from_chars(0x00), chunk_from_chars(0x00)},
+ {-1, chunk_from_chars(0x00), chunk_from_chars(0x01)},
+ { 1, chunk_from_chars(0x01), chunk_from_chars(0x00)},
+ { 0, chunk_from_chars(0x00, 0x00), chunk_from_chars(0x00, 0x00)},
+ {-1, chunk_from_chars(0x00, 0x00), chunk_from_chars(0x00, 0x01)},
+ { 1, chunk_from_chars(0x00, 0x01), chunk_from_chars(0x00, 0x00)},
+ {-1, chunk_from_chars(0x00, 0x00), chunk_from_chars(0x01, 0x00)},
+ { 1, chunk_from_chars(0x01, 0x00), chunk_from_chars(0x00, 0x00)},
+ {-1, chunk_from_chars(0xff), chunk_from_chars(0x00, 0x00)},
+ { 1, chunk_from_chars(0x00, 0x00), chunk_from_chars(0xff)},
+};
+
+START_TEST(test_compare)
+{
+ int result, expected;
+
+ result = chunk_compare(compare_data[_i].a, compare_data[_i].b);
+ expected = compare_data[_i].result;
+ ck_assert((result == 0 && expected == 0) ||
+ (result < 0 && expected < 0) ||
+ (result > 0 && expected > 0));
+}
+END_TEST
+
+/*******************************************************************************
+ * clear
+ */
+
+START_TEST(test_chunk_clear)
+{
+ chunk_t chunk;
+ u_char *ptr;
+ int i;
+ bool cleared = TRUE;
+
+ chunk = chunk_empty;
+ chunk_clear(&chunk);
+ chunk_free(&chunk);
+
+ chunk = chunk_alloc(64);
+ ptr = chunk.ptr;
+ for (i = 0; i < 64; i++)
+ {
+ chunk.ptr[i] = i;
+ }
+ chunk_clear(&chunk);
+ /* check memory area of freed chunk. We can't use ck_assert() for this
+ * test directly, as it might allocate data at the freed area. */
+ for (i = 0; i < 64; i++)
+ {
+ if (ptr[i] != 0 && ptr[i] == i)
+ {
+ cleared = FALSE;
+ break;
+ }
+ }
+ assert_chunk_empty(chunk);
+ ck_assert(cleared);
+}
+END_TEST
+
+/*******************************************************************************
+ * chunk_length
+ */
+
+START_TEST(test_chunk_length)
+{
+ chunk_t a, b, c;
+ size_t len;
+
+ a = chunk_empty;
+ b = chunk_empty;
+ c = chunk_empty;
+ len = chunk_length("ccc", a, b, c);
+ ck_assert_int_eq(len, 0);
+
+ a = chunk_from_str("foo");
+ b = chunk_from_str("bar");
+ len = chunk_length("ccc", a, b, c);
+ ck_assert_int_eq(len, 6);
+
+ len = chunk_length("zcc", a, b, c);
+ ck_assert_int_eq(len, 0);
+
+ len = chunk_length("czc", a, b, c);
+ ck_assert_int_eq(len, 3);
+
+ a = chunk_from_str("foo");
+ b = chunk_from_str("bar");
+ c = chunk_from_str("baz");
+ len = chunk_length("ccc", a, b, c);
+ ck_assert_int_eq(len, 9);
+}
+END_TEST
+
+/*******************************************************************************
+ * chunk_create_cat
+ */
+
+START_TEST(test_chunk_create_cat)
+{
+ chunk_t foo, bar;
+ chunk_t a, b, c;
+ u_char *ptra, *ptrb;
+
+ foo = chunk_from_str("foo");
+ bar = chunk_from_str("bar");
+
+ /* to simplify things we use the chunk_cata macro */
+
+ a = chunk_empty;
+ b = chunk_empty;
+ c = chunk_cata("cc", a, b);
+ ck_assert_int_eq(c.len, 0);
+ ck_assert(c.ptr != NULL);
+
+ a = foo;
+ b = bar;
+ c = chunk_cata("cc", a, b);
+ ck_assert_int_eq(c.len, 6);
+ ck_assert(chunk_equals(c, chunk_from_str("foobar")));
+
+ a = chunk_clone(foo);
+ b = chunk_clone(bar);
+ c = chunk_cata("mm", a, b);
+ ck_assert_int_eq(c.len, 6);
+ ck_assert(chunk_equals(c, chunk_from_str("foobar")));
+
+ a = chunk_clone(foo);
+ b = chunk_clone(bar);
+ ptra = a.ptr;
+ ptrb = b.ptr;
+ c = chunk_cata("ss", a, b);
+ ck_assert_int_eq(c.len, 6);
+ ck_assert(chunk_equals(c, chunk_from_str("foobar")));
+ /* check memory area of cleared chunk */
+ ck_assert(!chunk_equals(foo, chunk_create(ptra, 3)));
+ ck_assert(!chunk_equals(bar, chunk_create(ptrb, 3)));
+}
+END_TEST
+
+/*******************************************************************************
+ * chunk_split
+ */
+
+static bool mem_in_chunk(u_char *ptr, chunk_t chunk)
+{
+ return ptr >= chunk.ptr && ptr < (chunk.ptr + chunk.len);
+}
+
+START_TEST(test_chunk_split)
+{
+ chunk_t foo, bar, foobar;
+ chunk_t a, b, c;
+ u_char *ptra, *ptrb;
+
+ foo = chunk_from_str("foo");
+ bar = chunk_from_str("bar");
+ foobar = chunk_from_str("foobar");
+
+ chunk_split(foobar, "aa", 3, &a, 3, &b);
+ ck_assert(chunk_equals(a, foo));
+ ck_assert(chunk_equals(b, bar));
+ ck_assert(!mem_in_chunk(a.ptr, foobar));
+ ck_assert(!mem_in_chunk(b.ptr, foobar));
+ chunk_free(&a);
+ chunk_free(&b);
+
+ chunk_split(foobar, "mm", 3, &a, 3, &b);
+ ck_assert(chunk_equals(a, foo));
+ ck_assert(chunk_equals(b, bar));
+ ck_assert(mem_in_chunk(a.ptr, foobar));
+ ck_assert(mem_in_chunk(b.ptr, foobar));
+
+ chunk_split(foobar, "am", 3, &a, 3, &b);
+ ck_assert(chunk_equals(a, foo));
+ ck_assert(chunk_equals(b, bar));
+ ck_assert(!mem_in_chunk(a.ptr, foobar));
+ ck_assert(mem_in_chunk(b.ptr, foobar));
+ chunk_free(&a);
+
+ a = chunk_alloca(3);
+ ptra = a.ptr;
+ b = chunk_alloca(3);
+ ptrb = b.ptr;
+ chunk_split(foobar, "cc", 3, &a, 3, &b);
+ ck_assert(chunk_equals(a, foo));
+ ck_assert(chunk_equals(b, bar));
+ ck_assert(a.ptr == ptra);
+ ck_assert(b.ptr == ptrb);
+
+ chunk_split(foobar, "mm", 1, NULL, 2, &a, 2, NULL, 1, &b);
+ ck_assert(chunk_equals(a, chunk_from_str("oo")));
+ ck_assert(chunk_equals(b, chunk_from_str("r")));
+
+ chunk_split(foobar, "mm", 6, &a, 6, &b);
+ ck_assert(chunk_equals(a, foobar));
+ assert_chunk_empty(b);
+
+ chunk_split(foobar, "mac", 12, &a, 12, &b, 12, &c);
+ ck_assert(chunk_equals(a, foobar));
+ assert_chunk_empty(b);
+ assert_chunk_empty(c);
+}
+END_TEST
+
+/*******************************************************************************
+ * chunk_skip[_zero]
+ */
+
+START_TEST(test_chunk_skip)
+{
+ chunk_t foobar, a;
+
+ foobar = chunk_from_str("foobar");
+ a = foobar;
+ a = chunk_skip(a, 0);
+ ck_assert(chunk_equals(a, foobar));
+ a = chunk_skip(a, 1);
+ ck_assert(chunk_equals(a, chunk_from_str("oobar")));
+ a = chunk_skip(a, 2);
+ ck_assert(chunk_equals(a, chunk_from_str("bar")));
+ a = chunk_skip(a, 3);
+ assert_chunk_empty(a);
+
+ a = foobar;
+ a = chunk_skip(a, 6);
+ assert_chunk_empty(a);
+
+ a = foobar;
+ a = chunk_skip(a, 10);
+ assert_chunk_empty(a);
+}
+END_TEST
+
+START_TEST(test_chunk_skip_zero)
+{
+ chunk_t foobar, a;
+
+ a = chunk_empty;
+ a = chunk_skip_zero(a);
+ assert_chunk_empty(a);
+
+ foobar = chunk_from_str("foobar");
+ a = foobar;
+ a = chunk_skip_zero(a);
+ ck_assert(chunk_equals(a, foobar));
+
+ a = chunk_from_chars(0x00, 0xaa, 0xbb, 0xcc);
+ a = chunk_skip_zero(a);
+ ck_assert(chunk_equals(a, chunk_from_chars(0xaa, 0xbb, 0xcc)));
+ a = chunk_skip_zero(a);
+ ck_assert(chunk_equals(a, chunk_from_chars(0xaa, 0xbb, 0xcc)));
+}
+END_TEST
+
+/*******************************************************************************
+ * BASE16 encoding test
+ */
+
+START_TEST(test_base16)
+{
+ /* test vectors from RFC 4648:
+ *
+ * BASE16("") = ""
+ * BASE16("f") = "66"
+ * BASE16("fo") = "666F"
+ * BASE16("foo") = "666F6F"
+ * BASE16("foob") = "666F6F62"
+ * BASE16("fooba") = "666F6F6261"
+ * BASE16("foobar") = "666F6F626172"
+ */
+ typedef struct {
+ bool upper;
+ char *in;
+ char *out;
+ } testdata_t;
+
+ testdata_t test[] = {
+ {TRUE, "", ""},
+ {TRUE, "f", "66"},
+ {TRUE, "fo", "666F"},
+ {TRUE, "foo", "666F6F"},
+ {TRUE, "foob", "666F6F62"},
+ {TRUE, "fooba", "666F6F6261"},
+ {TRUE, "foobar", "666F6F626172"},
+ {FALSE, "", ""},
+ {FALSE, "f", "66"},
+ {FALSE, "fo", "666f"},
+ {FALSE, "foo", "666f6f"},
+ {FALSE, "foob", "666f6f62"},
+ {FALSE, "fooba", "666f6f6261"},
+ {FALSE, "foobar", "666f6f626172"},
+ };
+ testdata_t test_colon[] = {
+ {TRUE, "", ""},
+ {TRUE, "f", "66"},
+ {TRUE, "fo", "66:6F"},
+ {TRUE, "foo", "66:6F:6F"},
+ {FALSE, "foob", "66:6f:6f:62"},
+ {FALSE, "fooba", "66:6f:6f:62:61"},
+ {FALSE, "foobar", "66:6f:6f:62:61:72"},
+ {FALSE, "foobar", "66:6f6f:6261:72"},
+ };
+ int i;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ chunk_t out;
+
+ out = chunk_to_hex(chunk_create(test[i].in, strlen(test[i].in)), NULL,
+ test[i].upper);
+ ck_assert_str_eq(out.ptr, test[i].out);
+ free(out.ptr);
+ }
+
+ for (i = 0; i < countof(test); i++)
+ {
+ chunk_t out;
+
+ out = chunk_from_hex(chunk_create(test[i].out, strlen(test[i].out)), NULL);
+ fail_unless(strneq(out.ptr, test[i].in, out.len),
+ "base16 conversion error - should '%s', is %#B",
+ test[i].in, &out);
+ free(out.ptr);
+ }
+
+ for (i = 0; i < countof(test_colon); i++)
+ {
+ chunk_t out;
+
+ out = chunk_from_hex(chunk_create(test_colon[i].out, strlen(test_colon[i].out)), NULL);
+ fail_unless(strneq(out.ptr, test_colon[i].in, out.len),
+ "base16 conversion error - should '%s', is %#B",
+ test_colon[i].in, &out);
+ free(out.ptr);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * BASE64 encoding test
+ */
+
+START_TEST(test_base64)
+{
+ /* test vectors from RFC 4648:
+ *
+ * BASE64("") = ""
+ * BASE64("f") = "Zg=="
+ * BASE64("fo") = "Zm8="
+ * BASE64("foo") = "Zm9v"
+ * BASE64("foob") = "Zm9vYg=="
+ * BASE64("fooba") = "Zm9vYmE="
+ * BASE64("foobar") = "Zm9vYmFy"
+ */
+ typedef struct {
+ char *in;
+ char *out;
+ } testdata_t;
+
+ testdata_t test[] = {
+ {"", ""},
+ {"f", "Zg=="},
+ {"fo", "Zm8="},
+ {"foo", "Zm9v"},
+ {"foob", "Zm9vYg=="},
+ {"fooba", "Zm9vYmE="},
+ {"foobar", "Zm9vYmFy"},
+ };
+ int i;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ chunk_t out;
+
+ out = chunk_to_base64(chunk_create(test[i].in, strlen(test[i].in)), NULL);
+ ck_assert_str_eq(out.ptr, test[i].out);
+ free(out.ptr);
+ }
+
+ for (i = 0; i < countof(test); i++)
+ {
+ chunk_t out;
+
+ out = chunk_from_base64(chunk_create(test[i].out, strlen(test[i].out)), NULL);
+ fail_unless(strneq(out.ptr, test[i].in, out.len),
+ "base64 conversion error - should '%s', is %#B",
+ test[i].in, &out);
+ free(out.ptr);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * BASE32 encoding test
+ */
+
+START_TEST(test_base32)
+{
+ /* test vectors from RFC 4648:
+ *
+ * BASE32("") = ""
+ * BASE32("f") = "MY======"
+ * BASE32("fo") = "MZXQ===="
+ * BASE32("foo") = "MZXW6==="
+ * BASE32("foob") = "MZXW6YQ="
+ * BASE32("fooba") = "MZXW6YTB"
+ * BASE32("foobar") = "MZXW6YTBOI======"
+ */
+ typedef struct {
+ char *in;
+ char *out;
+ } testdata_t;
+
+ testdata_t test[] = {
+ {"", ""},
+ {"f", "MY======"},
+ {"fo", "MZXQ===="},
+ {"foo", "MZXW6==="},
+ {"foob", "MZXW6YQ="},
+ {"fooba", "MZXW6YTB"},
+ {"foobar", "MZXW6YTBOI======"},
+ };
+ int i;
+
+ for (i = 0; i < countof(test); i++)
+ {
+ chunk_t out;
+
+ out = chunk_to_base32(chunk_create(test[i].in, strlen(test[i].in)), NULL);
+ ck_assert_str_eq(out.ptr, test[i].out);
+ free(out.ptr);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * chunk_increment test
+ */
+
+static struct {
+ bool overflow;
+ chunk_t in;
+ chunk_t out;
+} increment_data[] = {
+ {TRUE, { NULL, 0 }, { NULL, 0 }},
+ {FALSE, chunk_from_chars(0x00), chunk_from_chars(0x01)},
+ {FALSE, chunk_from_chars(0xfe), chunk_from_chars(0xff)},
+ {TRUE, chunk_from_chars(0xff), chunk_from_chars(0x00)},
+ {FALSE, chunk_from_chars(0x00, 0x00), chunk_from_chars(0x00, 0x01)},
+ {FALSE, chunk_from_chars(0x00, 0xff), chunk_from_chars(0x01, 0x00)},
+ {FALSE, chunk_from_chars(0xfe, 0xff), chunk_from_chars(0xff, 0x00)},
+ {TRUE, chunk_from_chars(0xff, 0xff), chunk_from_chars(0x00, 0x00)},
+};
+
+START_TEST(test_increment)
+{
+ chunk_t chunk;
+ bool overflow;
+
+ chunk = chunk_clonea(increment_data[_i].in);
+ overflow = chunk_increment(chunk);
+ ck_assert(overflow == increment_data[_i].overflow);
+ ck_assert(!increment_data[_i].out.ptr ||
+ chunk_equals(chunk, increment_data[_i].out));
+}
+END_TEST
+
+/*******************************************************************************
+ * chunk_printable tests
+ */
+
+static struct {
+ bool printable;
+ chunk_t in;
+ char *out;
+} printable_data[] = {
+ {TRUE, chunk_from_chars(0x31), "1"},
+ {FALSE, chunk_from_chars(0x00), "?"},
+ {FALSE, chunk_from_chars(0x31, 0x00), "1?"},
+ {FALSE, chunk_from_chars(0x00, 0x31), "?1"},
+ {TRUE, chunk_from_chars(0x3f, 0x31), "?1"},
+ {FALSE, chunk_from_chars(0x00, 0x31, 0x00), "?1?"},
+ {FALSE, chunk_from_chars(0x00, 0x31, 0x00, 0x32), "?1?2"},
+};
+
+START_TEST(test_printable)
+{
+ bool printable;
+
+ printable = chunk_printable(printable_data[_i].in, NULL, ' ');
+ ck_assert(printable == printable_data[_i].printable);
+}
+END_TEST
+
+START_TEST(test_printable_sanitize)
+{
+ chunk_t sane, expected;
+ bool printable;
+
+ printable = chunk_printable(printable_data[_i].in, &sane, '?');
+ ck_assert(printable == printable_data[_i].printable);
+ expected = chunk_from_str(printable_data[_i].out);
+ ck_assert(chunk_equals(sane, expected));
+ chunk_free(&sane);
+}
+END_TEST
+
+START_TEST(test_printable_empty)
+{
+ chunk_t sane;
+ bool printable;
+
+ printable = chunk_printable(chunk_empty, NULL, ' ');
+ ck_assert(printable);
+
+ sane.ptr = (void*)1;
+ sane.len = 1;
+ printable = chunk_printable(chunk_empty, &sane, ' ');
+ ck_assert(printable);
+ assert_chunk_empty(sane);
+}
+END_TEST
+
+/*******************************************************************************
+ * test for chunk_mac(), i.e. SipHash-2-4
+ */
+
+/**
+ * SipHash-2-4 output with
+ * k = 00 01 02 ...
+ * and
+ * in = (empty string)
+ * in = 00 (1 byte)
+ * in = 00 01 (2 bytes)
+ * in = 00 01 02 (3 bytes)
+ * ...
+ * in = 00 01 02 ... 3e (63 bytes)
+ */
+static const u_char sip_vectors[64][8] =
+{
+ { 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, },
+ { 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, },
+ { 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, },
+ { 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, },
+ { 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, },
+ { 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, },
+ { 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, },
+ { 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, },
+ { 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, },
+ { 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, },
+ { 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, },
+ { 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, },
+ { 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, },
+ { 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, },
+ { 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, },
+ { 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, },
+ { 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, },
+ { 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, },
+ { 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, },
+ { 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, },
+ { 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, },
+ { 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, },
+ { 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, },
+ { 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, },
+ { 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, },
+ { 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, },
+ { 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, },
+ { 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, },
+ { 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, },
+ { 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, },
+ { 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, },
+ { 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, },
+ { 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, },
+ { 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, },
+ { 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, },
+ { 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, },
+ { 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, },
+ { 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, },
+ { 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, },
+ { 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, },
+ { 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, },
+ { 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, },
+ { 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, },
+ { 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, },
+ { 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, },
+ { 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, },
+ { 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, },
+ { 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, },
+ { 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, },
+ { 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, },
+ { 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, },
+ { 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, },
+ { 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, },
+ { 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, },
+ { 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, },
+ { 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, },
+ { 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, },
+ { 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, },
+ { 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, },
+ { 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, },
+ { 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, },
+ { 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, },
+ { 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, },
+ { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, }
+};
+
+/**
+ * Our SipHash-2-4 implementation returns the result in host order, which
+ * doesn't matter for practical purposes and even avoids a byte swap. But
+ * because the test vectors are in little-endian we have to account for this
+ * with this custom comparison function.
+ */
+static inline bool sipeq(const void *a, const void *b, size_t n)
+{
+ u_char *ap = (u_char*)a, *bp = (u_char*)b;
+ int i;
+
+ for (i = 0; i < n; i++)
+ {
+#ifdef WORDS_BIGENDIAN
+ if (ap[i] != bp[n - i - 1])
+#else
+ if (ap[i] != bp[i])
+#endif
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+START_TEST(test_chunk_mac)
+{
+ chunk_t in;
+ u_char key[16];
+ u_int64_t out;
+ int i, count;
+
+ count = countof(sip_vectors);
+ in = chunk_alloca(count);
+
+ for (i = 0; i < 16; ++i)
+ {
+ key[i] = i;
+ }
+
+ for (i = 0; i < count; ++i)
+ {
+ in.ptr[i] = i;
+ in.len = i;
+ out = chunk_mac(in, key);
+ fail_unless(sipeq(&out, sip_vectors[i], 8),
+ "test vector failed for %d bytes", i);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * test for chunk_hash[_inc]()
+ */
+
+START_TEST(test_chunk_hash)
+{
+ chunk_t chunk;
+ u_int32_t hash_a, hash_b, hash_c;
+
+ chunk = chunk_from_str("asdf");
+
+ /* output is randomized, so there are no test-vectors we could use */
+ hash_a = chunk_hash(chunk);
+ hash_b = chunk_hash(chunk);
+ ck_assert(hash_a == hash_b);
+ hash_b = chunk_hash_inc(chunk, hash_a);
+ ck_assert(hash_a != hash_b);
+ hash_c = chunk_hash_inc(chunk, hash_a);
+ ck_assert(hash_b == hash_c);
+}
+END_TEST
+
+/*******************************************************************************
+ * test for chunk_hash_static[_inc]()
+ */
+
+START_TEST(test_chunk_hash_static)
+{
+ chunk_t in;
+ u_int32_t out, hash_a, hash_b, hash_inc = 0x7b891a95;
+ int i, count;
+
+ count = countof(sip_vectors);
+ in = chunk_alloca(count);
+
+ for (i = 0; i < count; ++i)
+ {
+ in.ptr[i] = i;
+ in.len = i;
+ /* compared to chunk_mac() we only get half the value back */
+ out = chunk_hash_static(in);
+ fail_unless(sipeq(&out, sip_vectors[i], 4),
+ "test vector failed for %d bytes", i);
+ }
+ hash_a = chunk_hash_static_inc(in, out);
+ ck_assert_int_eq(hash_a, hash_inc);
+ hash_b = chunk_hash_static_inc(in, out);
+ ck_assert_int_eq(hash_a, hash_b);
+}
+END_TEST
+
+/*******************************************************************************
+ * test for chunk_map and friends
+ */
+
+START_TEST(test_chunk_map)
+{
+ chunk_t *map, contents = chunk_from_chars(0x01,0x02,0x03,0x04,0x05);
+ char *path = "/tmp/strongswan-chunk-map-test";
+
+ ck_assert(chunk_write(contents, path, 022, TRUE));
+
+ /* read */
+ map = chunk_map(path, FALSE);
+ ck_assert(map != NULL);
+ ck_assert_msg(chunk_equals(*map, contents), "%B", map);
+ /* altering mapped chunk should not hurt */
+ *map = chunk_empty;
+ ck_assert(chunk_unmap(map));
+
+ /* write */
+ map = chunk_map(path, TRUE);
+ ck_assert(map != NULL);
+ ck_assert_msg(chunk_equals(*map, contents), "%B", map);
+ map->ptr[0] = 0x06;
+ ck_assert(chunk_unmap(map));
+
+ /* verify write */
+ contents.ptr[0] = 0x06;
+ map = chunk_map(path, FALSE);
+ ck_assert(map != NULL);
+ ck_assert_msg(chunk_equals(*map, contents), "%B", map);
+ ck_assert(chunk_unmap(map));
+
+ unlink(path);
+}
+END_TEST
+
+/*******************************************************************************
+ * test for chunk_from_fd
+ */
+
+START_TEST(test_chunk_from_fd_file)
+{
+ chunk_t in, contents = chunk_from_chars(0x01,0x02,0x03,0x04,0x05);
+ char *path = "/tmp/strongswan-chunk-fd-test";
+ int fd;
+
+ ck_assert(chunk_write(contents, path, 022, TRUE));
+
+ fd = open(path, O_RDONLY);
+ ck_assert(fd != -1);
+
+ ck_assert(chunk_from_fd(fd, &in));
+ close(fd);
+ ck_assert_msg(chunk_equals(in, contents), "%B", &in);
+ unlink(path);
+ free(in.ptr);
+}
+END_TEST
+
+START_TEST(test_chunk_from_fd_skt)
+{
+ chunk_t in, contents = chunk_from_chars(0x01,0x02,0x03,0x04,0x05);
+ int s[2];
+
+ ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0);
+ ck_assert(write(s[1], contents.ptr, contents.len) == contents.len);
+ close(s[1]);
+ ck_assert_msg(chunk_from_fd(s[0], &in), "%s", strerror(errno));
+ close(s[0]);
+ ck_assert_msg(chunk_equals(in, contents), "%B", &in);
+ free(in.ptr);
+}
+END_TEST
+
+#define FROM_FD_COUNT 8192
+
+void *chunk_from_fd_run(void *data)
+{
+ int i, fd = (uintptr_t)data;
+
+ for (i = 0; i < FROM_FD_COUNT; i++)
+ {
+ ck_assert(write(fd, &i, sizeof(i)) == sizeof(i));
+ }
+ close(fd);
+ return NULL;
+}
+
+START_TEST(test_chunk_from_fd_huge)
+{
+ thread_t *thread;
+ chunk_t in;
+ int s[2], i;
+
+ ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0);
+
+ thread = thread_create(chunk_from_fd_run, (void*)(uintptr_t)s[1]);
+ ck_assert_msg(chunk_from_fd(s[0], &in), "%s", strerror(errno));
+ ck_assert_int_eq(in.len, FROM_FD_COUNT * sizeof(i));
+ for (i = 0; i < FROM_FD_COUNT; i++)
+ {
+ ck_assert_int_eq(((int*)in.ptr)[i], i);
+ }
+ thread->join(thread);
+ close(s[0]);
+ free(in.ptr);
+}
+END_TEST
+
+/*******************************************************************************
+ * printf_hook tests
+ */
+
+static struct {
+ chunk_t in;
+ char *out;
+ char *out_plus;
+} printf_hook_data[] = {
+ {chunk_from_chars(), "", ""},
+ {chunk_from_chars(0x00), "00", "00"},
+ {chunk_from_chars(0x00, 0x01), "00:01", "0001"},
+ {chunk_from_chars(0x00, 0x01, 0x02), "00:01:02", "000102"},
+};
+
+START_TEST(test_printf_hook_hash)
+{
+ char buf[16];
+ int len;
+
+ len = snprintf(buf, sizeof(buf), "%#B", &printf_hook_data[_i].in);
+ ck_assert(len >= 0 && len < sizeof(buf));
+ ck_assert_str_eq(buf, printf_hook_data[_i].out);
+}
+END_TEST
+
+START_TEST(test_printf_hook_plus)
+{
+ char buf[16];
+ int len;
+
+ len = snprintf(buf, sizeof(buf), "%+B", &printf_hook_data[_i].in);
+ ck_assert(len >= 0 && len < sizeof(buf));
+ ck_assert_str_eq(buf, printf_hook_data[_i].out_plus);
+}
+END_TEST
+
+START_TEST(test_printf_hook)
+{
+ char buf[128], mem[128];
+ int len;
+
+ /* %B should be the same as %b, which is what we check, comparing the
+ * acutal result could be tricky as %b prints the chunk's memory address */
+ len = snprintf(buf, sizeof(buf), "%B", &printf_hook_data[_i].in);
+ ck_assert(len >= 0 && len < sizeof(buf));
+ len = snprintf(mem, sizeof(mem), "%b", printf_hook_data[_i].in.ptr,
+ (u_int)printf_hook_data[_i].in.len);
+ ck_assert(len >= 0 && len < sizeof(mem));
+ ck_assert_str_eq(buf, mem);
+}
+END_TEST
+
+Suite *chunk_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("chunk");
+
+ tc = tcase_create("equals");
+ tcase_add_test(tc, test_chunk_equals);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("chunk_compare");
+ tcase_add_loop_test(tc, test_compare, 0, countof(compare_data));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("clear");
+ tcase_add_test(tc, test_chunk_clear);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("chunk_length");
+ tcase_add_test(tc, test_chunk_length);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("chunk_create_cat");
+ tcase_add_test(tc, test_chunk_create_cat);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("chunk_split");
+ tcase_add_test(tc, test_chunk_split);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("chunk_skip");
+ tcase_add_test(tc, test_chunk_skip);
+ tcase_add_test(tc, test_chunk_skip_zero);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("chunk_increment");
+ tcase_add_loop_test(tc, test_increment, 0, countof(increment_data));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("chunk_printable");
+ tcase_add_loop_test(tc, test_printable, 0, countof(printable_data));
+ tcase_add_loop_test(tc, test_printable_sanitize, 0, countof(printable_data));
+ tcase_add_test(tc, test_printable_empty);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("baseXX");
+ tcase_add_test(tc, test_base64);
+ tcase_add_test(tc, test_base32);
+ tcase_add_test(tc, test_base16);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("chunk_mac");
+ tcase_add_test(tc, test_chunk_mac);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("chunk_hash");
+ tcase_add_test(tc, test_chunk_hash);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("chunk_hash_static");
+ tcase_add_test(tc, test_chunk_hash_static);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("chunk_map");
+ tcase_add_test(tc, test_chunk_map);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("chunk_from_fd");
+ tcase_add_test(tc, test_chunk_from_fd_file);
+ tcase_add_test(tc, test_chunk_from_fd_skt);
+ tcase_add_test(tc, test_chunk_from_fd_huge);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("printf_hook");
+ tcase_add_loop_test(tc, test_printf_hook_hash, 0, countof(printf_hook_data));
+ tcase_add_loop_test(tc, test_printf_hook_plus, 0, countof(printf_hook_data));
+ tcase_add_loop_test(tc, test_printf_hook, 0, countof(printf_hook_data));
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_crypter.c b/src/libstrongswan/tests/suites/test_crypter.c
new file mode 100644
index 000000000..4e7550aee
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_crypter.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2013 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 "test_suite.h"
+
+#include <crypto/crypters/crypter.h>
+#include <asn1/oid.h>
+#include <utils/test.h>
+
+typedef struct {
+ int oid;
+ encryption_algorithm_t alg;
+ size_t key_size;
+}crypter_oid_t;
+
+static crypter_oid_t oids[] = {
+ { OID_UNKNOWN, ENCR_AES_CBC, 0 },
+ { OID_UNKNOWN, ENCR_CAMELLIA_CBC, 0 },
+ { OID_UNKNOWN, ENCR_UNDEFINED, 0 },
+ { OID_DES_CBC, ENCR_DES, 0 },
+ { OID_3DES_EDE_CBC, ENCR_3DES, 0 },
+ { OID_AES128_CBC, ENCR_AES_CBC, 128 },
+ { OID_AES192_CBC, ENCR_AES_CBC, 192 },
+ { OID_AES256_CBC, ENCR_AES_CBC, 256 },
+ { OID_CAMELLIA128_CBC, ENCR_CAMELLIA_CBC, 128 },
+ { OID_CAMELLIA192_CBC, ENCR_CAMELLIA_CBC, 192 },
+ { OID_CAMELLIA256_CBC, ENCR_CAMELLIA_CBC, 256 }
+};
+
+START_TEST(test_crypter_from_oid)
+{
+ size_t key_size;
+
+ ck_assert(encryption_algorithm_from_oid(oids[_i].oid, NULL) ==
+ oids[_i].alg);
+ ck_assert(encryption_algorithm_from_oid(oids[_i].oid, &key_size) ==
+ oids[_i].alg);
+ ck_assert(key_size == oids[_i].key_size);
+}
+END_TEST
+
+START_TEST(test_crypter_to_oid)
+{
+ ck_assert(encryption_algorithm_to_oid(oids[_i].alg,
+ oids[_i].key_size) == oids[_i].oid);
+}
+END_TEST
+
+typedef struct {
+ encryption_algorithm_t alg;
+ bool is_aead;
+}crypter_aead_t;
+
+static crypter_aead_t aead[] = {
+ { ENCR_AES_CCM_ICV8, TRUE },
+ { ENCR_AES_CCM_ICV12, TRUE },
+ { ENCR_AES_CCM_ICV16, TRUE },
+ { ENCR_AES_GCM_ICV8, TRUE },
+ { ENCR_AES_GCM_ICV12, TRUE },
+ { ENCR_AES_GCM_ICV16, TRUE },
+ { ENCR_NULL_AUTH_AES_GMAC, TRUE },
+ { ENCR_CAMELLIA_CCM_ICV8, TRUE },
+ { ENCR_CAMELLIA_CCM_ICV12, TRUE },
+ { ENCR_CAMELLIA_CCM_ICV16, TRUE },
+ { ENCR_AES_CBC, FALSE },
+ { ENCR_CAMELLIA_CBC, FALSE }
+};
+
+START_TEST(test_crypter_is_aead)
+{
+ ck_assert(encryption_algorithm_is_aead(aead[_i].alg) == aead[_i].is_aead);
+}
+END_TEST
+
+Suite *crypter_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("crypter");
+
+ tc = tcase_create("from_oid");
+ tcase_add_loop_test(tc, test_crypter_from_oid, 2, countof(oids));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("to_oid");
+ tcase_add_loop_test(tc, test_crypter_to_oid, 0, countof(oids));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("is_aead");
+ tcase_add_loop_test(tc, test_crypter_is_aead, 0, countof(aead));
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_ecdsa.c b/src/libstrongswan/tests/suites/test_ecdsa.c
new file mode 100644
index 000000000..3c842996d
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_ecdsa.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * 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 "test_suite.h"
+
+#include <plugins/plugin_feature.h>
+
+/**
+ * Signature schemes to test
+ */
+static struct {
+ /* key size for scheme, 0 for any */
+ int key_size;
+ signature_scheme_t scheme;
+} schemes[] = {
+ { 0, SIGN_ECDSA_WITH_SHA1_DER },
+ { 0, SIGN_ECDSA_WITH_SHA256_DER },
+ { 0, SIGN_ECDSA_WITH_SHA384_DER },
+ { 0, SIGN_ECDSA_WITH_SHA512_DER },
+ { 0, SIGN_ECDSA_WITH_NULL },
+ { 256, SIGN_ECDSA_256 },
+ { 384, SIGN_ECDSA_384 },
+ { 521, SIGN_ECDSA_521 },
+};
+
+/**
+ * Perform a signature verification "good" test having a keypair
+ */
+static void test_good_sig(private_key_t *privkey, public_key_t *pubkey)
+{
+ chunk_t sig, data = chunk_from_chars(0x01,0x02,0x03,0xFD,0xFE,0xFF);
+ int i;
+
+ for (i = 0; i < countof(schemes); i++)
+ {
+ if (!lib->plugins->has_feature(lib->plugins,
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, schemes[i].scheme)) ||
+ !lib->plugins->has_feature(lib->plugins,
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, schemes[i].scheme)))
+ {
+ continue;
+ }
+ if (schemes[i].key_size != 0 &&
+ schemes[i].scheme != privkey->get_keysize(privkey))
+ {
+ continue;
+ }
+ fail_unless(privkey->sign(privkey, schemes[i].scheme, data, &sig),
+ "sign %N", signature_scheme_names, schemes[i].scheme);
+ fail_unless(pubkey->verify(pubkey, schemes[i].scheme, data, sig),
+ "verify %N", signature_scheme_names, schemes[i].scheme);
+ free(sig.ptr);
+ }
+}
+
+/**
+ * Some special signatures that should never validate successfully
+ */
+static chunk_t invalid_sigs[] = {
+ chunk_from_chars(),
+ chunk_from_chars(0x00),
+ chunk_from_chars(0x00,0x00),
+ chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
+ chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
+ chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
+ chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
+ chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
+ chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
+};
+
+/**
+ * Check public key that it properly fails against some crafted sigs
+ */
+static void test_bad_sigs(public_key_t *pubkey)
+{
+ chunk_t data = chunk_from_chars(0x01,0x02,0x03,0xFD,0xFE,0xFF);
+ int s, i;
+
+ for (s = 0; s < countof(schemes); s++)
+ {
+ if (schemes[s].key_size != 0 &&
+ schemes[s].scheme != pubkey->get_keysize(pubkey))
+ {
+ continue;
+ }
+ if (!lib->plugins->has_feature(lib->plugins,
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, schemes[s].scheme)))
+ {
+ continue;
+ }
+ for (i = 0; i < countof(invalid_sigs); i++)
+ {
+ fail_if(
+ pubkey->verify(pubkey, schemes[s].scheme, data, invalid_sigs[i]),
+ "bad %N sig accepted %B",
+ signature_scheme_names, schemes[s].scheme,
+ &invalid_sigs[i]);
+ }
+ }
+}
+
+/**
+ * ECDSA key sizes to test
+ */
+static int key_sizes[] = {
+ 256, 384, 521,
+};
+
+START_TEST(test_gen)
+{
+ private_key_t *privkey;
+ public_key_t *pubkey;
+
+ privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ECDSA,
+ BUILD_KEY_SIZE, key_sizes[_i], BUILD_END);
+ ck_assert(privkey != NULL);
+ pubkey = privkey->get_public_key(privkey);
+ ck_assert(pubkey != NULL);
+
+ test_good_sig(privkey, pubkey);
+
+ test_bad_sigs(pubkey);
+
+ pubkey->destroy(pubkey);
+ privkey->destroy(privkey);
+}
+END_TEST
+
+/**
+ * Private keys to load
+ */
+static chunk_t keys[] = {
+ chunk_from_chars( /* ECDSA-256 */
+ 0x30,0x77,0x02,0x01,0x01,0x04,0x20,0x42,0xc6,0x8c,0xff,0x2b,0x8b,0x87,0xa1,0xfb,
+ 0x50,0xf6,0xfe,0xd6,0x88,0xb3,0x0a,0x48,0xb2,0xc5,0x8f,0x50,0xe0,0xcf,0x40,0xfa,
+ 0x57,0xd1,0xc6,0x6c,0x20,0x64,0xc5,0xa0,0x0a,0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,
+ 0x03,0x01,0x07,0xa1,0x44,0x03,0x42,0x00,0x04,0x9c,0xb2,0x52,0xcb,0xc0,0x5c,0xcf,
+ 0x97,0xdd,0xd6,0xe7,0x49,0x32,0x47,0x0c,0x8e,0xdb,0x6d,0xbf,0xc8,0x1a,0x0a,0x01,
+ 0xe8,0x5e,0x3f,0x8e,0x64,0x33,0xb4,0x15,0xbb,0x1b,0xa5,0xed,0xf9,0x4b,0xa7,0xe8,
+ 0x5e,0x6f,0x49,0x24,0xf7,0x32,0xf4,0x9b,0x4c,0x47,0xdc,0xf1,0x28,0x44,0x1c,0x37,
+ 0xdb,0xee,0xfb,0xd8,0xbd,0x4e,0x5c,0xeb,0x07),
+ chunk_from_chars( /* ECDSA-384 */
+ 0x30,0x81,0xa4,0x02,0x01,0x01,0x04,0x30,0x4b,0xbf,0x6c,0xf5,0x24,0x78,0x53,0x4b,
+ 0x1a,0x91,0x23,0xae,0x30,0xc8,0xb3,0xc9,0xc2,0x9b,0x23,0x07,0x10,0x6f,0x1b,0x47,
+ 0x7c,0xa0,0xd4,0x79,0x3c,0xc4,0x83,0x10,0xd1,0x44,0x07,0xc2,0x1b,0x66,0xff,0xae,
+ 0x76,0x57,0x72,0x90,0x53,0xc2,0xf5,0x29,0xa0,0x07,0x06,0x05,0x2b,0x81,0x04,0x00,
+ 0x22,0xa1,0x64,0x03,0x62,0x00,0x04,0x1e,0xcf,0x1c,0x85,0x9d,0x06,0xa0,0x54,0xa2,
+ 0x24,0x2f,0xd8,0x63,0x56,0x7b,0x70,0x0b,0x7f,0x81,0x96,0xce,0xb9,0x2e,0x35,0x03,
+ 0x9c,0xf9,0x0a,0x5d,0x3b,0x10,0xf7,0x13,0x7a,0x0d,0xca,0x56,0xda,0x1d,0x44,0x84,
+ 0x07,0x6f,0x58,0xdc,0x34,0x7b,0x1d,0x4c,0xdd,0x28,0x10,0xc0,0xe2,0xae,0xf4,0xd6,
+ 0xda,0xea,0xaf,0xfc,0x7a,0xaf,0x59,0x5f,0xbc,0x91,0x65,0xd3,0x21,0x19,0x61,0xbb,
+ 0xfe,0x3c,0xdb,0x47,0xcb,0x7a,0xe7,0x5d,0xbd,0x28,0xde,0x25,0x64,0x9e,0x3a,0xa9,
+ 0x18,0xed,0x24,0xe1,0x1f,0x73,0xcc),
+ chunk_from_chars( /* ECDSA-521 */
+ 0x30,0x81,0xdc,0x02,0x01,0x01,0x04,0x42,0x01,0xcf,0x38,0xaa,0xa7,0x7a,0x79,0x48,
+ 0xa9,0x60,0x55,0x24,0xa8,0x7e,0xe1,0xbc,0x45,0x35,0x16,0xff,0x18,0xce,0x44,0xa2,
+ 0x0b,0x72,0x6b,0xca,0x0a,0x40,0xb4,0x97,0x13,0x17,0x90,0x50,0x15,0xb9,0xba,0xfc,
+ 0x08,0x0e,0xdb,0xf8,0xfc,0x06,0x35,0x37,0xbf,0xfb,0x25,0x74,0xfe,0x0f,0xe1,0x3c,
+ 0x3a,0xf0,0x0d,0xe0,0x52,0x15,0xa8,0x07,0x6f,0x3e,0xa0,0x07,0x06,0x05,0x2b,0x81,
+ 0x04,0x00,0x23,0xa1,0x81,0x89,0x03,0x81,0x86,0x00,0x04,0x00,0x56,0x81,0x28,0xd6,
+ 0xac,0xe9,0xc8,0x82,0x2c,0xac,0x61,0x6d,0xdd,0x88,0x79,0x00,0xe3,0x7a,0x4d,0x25,
+ 0xc4,0xea,0x05,0x80,0x75,0x48,0xbc,0x75,0x73,0xc4,0xe9,0x76,0x68,0xba,0x51,0xc3,
+ 0x29,0xce,0x7d,0x1b,0xb0,0x8b,0xac,0xc1,0xcc,0x23,0xa7,0x2d,0xa7,0x2c,0x95,0xf6,
+ 0x01,0x40,0x26,0x01,0x1c,0x1c,0x9c,0xe7,0xa7,0xb4,0x0f,0x8e,0xba,0x01,0x07,0xb3,
+ 0xf7,0xbe,0x45,0x20,0xa9,0x9e,0x70,0xf0,0xcf,0x9b,0xa0,0x91,0xe3,0x88,0x8f,0x04,
+ 0x69,0x3d,0x0f,0x2b,0xf3,0xb4,0x03,0x19,0x89,0xcf,0xfa,0x77,0x04,0x15,0xaf,0xdd,
+ 0xf7,0x32,0x76,0x25,0x25,0x05,0x8d,0xfd,0x18,0x8a,0xda,0xd6,0xbc,0x71,0xb8,0x9f,
+ 0x39,0xb0,0xaf,0xcc,0x54,0xb0,0x9c,0x4d,0x54,0xfb,0x46,0x53,0x5f,0xf8,0x45),
+};
+
+START_TEST(test_load)
+{
+ private_key_t *privkey;
+ public_key_t *pubkey;
+
+ privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ECDSA,
+ BUILD_BLOB_ASN1_DER, keys[_i], BUILD_END);
+ ck_assert(privkey != NULL);
+ pubkey = privkey->get_public_key(privkey);
+ ck_assert(pubkey != NULL);
+
+ test_good_sig(privkey, pubkey);
+
+ test_bad_sigs(pubkey);
+
+ pubkey->destroy(pubkey);
+ privkey->destroy(privkey);
+}
+END_TEST
+
+Suite *ecdsa_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+ int gen_count = countof(key_sizes);
+
+ s = suite_create("ecdsa");
+
+ if (getenv("TESTS_REDUCED_KEYLENGTHS") != NULL)
+ {
+ gen_count = min(1, gen_count);
+ }
+
+ tc = tcase_create("generate");
+ tcase_add_loop_test(tc, test_gen, 0, gen_count);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("load");
+ tcase_add_loop_test(tc, test_load, 0, countof(keys));
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_enum.c b/src/libstrongswan/tests/suites/test_enum.c
new file mode 100644
index 000000000..990d9cfad
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_enum.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * 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 "test_suite.h"
+
+#include <utils/enum.h>
+#include <utils/utils.h>
+
+/*******************************************************************************
+ * continuous enum
+ */
+enum {
+ CONT1,
+ CONT2,
+ CONT3,
+ CONT4,
+ CONT5,
+} test_enum_cont;
+
+/* can't be static */
+enum_name_t *test_enum_cont_names;
+
+ENUM_BEGIN(test_enum_cont_names, CONT1, CONT5,
+ "CONT1", "CONT2", "CONT3", "CONT4", "CONT5");
+ENUM_END(test_enum_cont_names, CONT5);
+
+/*******************************************************************************
+ * split enum
+ */
+enum {
+ SPLIT1 = 1,
+ SPLIT2,
+ SPLIT3 = 5,
+ SPLIT4,
+ SPLIT5 = 255,
+} test_enum_split;
+
+/* can't be static */
+enum_name_t *test_enum_split_names;
+
+ENUM_BEGIN(test_enum_split_names, SPLIT1, SPLIT2,
+ "SPLIT1", "SPLIT2");
+ENUM_NEXT(test_enum_split_names, SPLIT3, SPLIT4, SPLIT2,
+ "SPLIT3", "SPLIT4");
+ENUM_NEXT(test_enum_split_names, SPLIT5, SPLIT5, SPLIT4,
+ "SPLIT5");
+ENUM_END(test_enum_split_names, SPLIT5);
+
+/*******************************************************************************
+ * enum_to_name
+ */
+
+static struct {
+ int val;
+ char *str;
+} name_tests_cont[] = {
+ {-1, NULL},
+ {CONT1, "CONT1"},
+ {CONT2, "CONT2"},
+ {CONT3, "CONT3"},
+ {CONT4, "CONT4"},
+ {CONT5, "CONT5"},
+ {5, NULL},
+}, name_tests_split[] = {
+ {-1, NULL},
+ {0, NULL},
+ {SPLIT1, "SPLIT1"},
+ {SPLIT2, "SPLIT2"},
+ {3, NULL},
+ {4, NULL},
+ {SPLIT3, "SPLIT3"},
+ {SPLIT4, "SPLIT4"},
+ {7, NULL},
+ {254, NULL},
+ {SPLIT5, "SPLIT5"},
+ {256, NULL},
+};
+
+START_TEST(test_enum_to_name_cont)
+{
+ char *str = enum_to_name(test_enum_cont_names, name_tests_cont[_i].val);
+ if (str)
+ {
+ ck_assert_str_eq(str, name_tests_cont[_i].str);
+ }
+ else
+ {
+ ck_assert(str == name_tests_cont[_i].str);
+ }
+}
+END_TEST
+
+START_TEST(test_enum_to_name_split)
+{
+ char *str = enum_to_name(test_enum_split_names, name_tests_split[_i].val);
+ if (str)
+ {
+ ck_assert_str_eq(str, name_tests_split[_i].str);
+ }
+ else
+ {
+ ck_assert(str == name_tests_split[_i].str);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * enum_from_name
+ */
+
+static struct {
+ int val;
+ char *str;
+} enum_tests_cont[] = {
+ {CONT1, "CONT1"},
+ {CONT2, "CONT2"},
+ {CONT2, "CoNt2"},
+ {CONT3, "CONT3"},
+ {CONT4, "CONT4"},
+ {CONT5, "CONT5"},
+ {-1, "asdf"},
+ {-1, ""},
+ {-1, NULL},
+}, enum_tests_split[] = {
+ {SPLIT1, "SPLIT1"},
+ {SPLIT1, "split1"},
+ {SPLIT2, "SPLIT2"},
+ {SPLIT2, "SpLiT2"},
+ {SPLIT3, "SPLIT3"},
+ {SPLIT4, "SPLIT4"},
+ {SPLIT5, "SPLIT5"},
+ {-1, "asdf"},
+ {-1, ""},
+ {-1, NULL},
+};
+
+START_TEST(test_enum_from_name_cont)
+{
+ int val = enum_from_name(test_enum_cont_names, enum_tests_cont[_i].str);
+ ck_assert_int_eq(val, enum_tests_cont[_i].val);
+}
+END_TEST
+
+START_TEST(test_enum_from_name_split)
+{
+ int val = enum_from_name(test_enum_split_names, enum_tests_split[_i].str);
+ ck_assert_int_eq(val, enum_tests_split[_i].val);
+}
+END_TEST
+
+/*******************************************************************************
+ * enum_printf_hook
+ */
+
+static struct {
+ int val;
+ char *str;
+} printf_tests_cont[] = {
+ {-1, "(-1)"},
+ {CONT1, "CONT1"},
+ {CONT2, "CONT2"},
+ {CONT3, "CONT3"},
+ {CONT4, "CONT4"},
+ {CONT5, "CONT5"},
+ {5, "(5)"},
+}, printf_tests_split[] = {
+ {-1, "(-1)"},
+ {0, "(0)"},
+ {SPLIT1, "SPLIT1"},
+ {SPLIT2, "SPLIT2"},
+ {3, "(3)"},
+ {4, "(4)"},
+ {SPLIT3, "SPLIT3"},
+ {SPLIT4, "SPLIT4"},
+ {7, "(7)"},
+ {254, "(254)"},
+ {SPLIT5, "SPLIT5"},
+ {256, "(256)"},
+};
+
+START_TEST(test_enum_printf_hook_cont)
+{
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "%N", test_enum_cont_names, printf_tests_cont[_i].val);
+ ck_assert_str_eq(printf_tests_cont[_i].str, buf);
+}
+END_TEST
+
+START_TEST(test_enum_printf_hook_split)
+{
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "%N", test_enum_split_names, printf_tests_split[_i].val);
+ ck_assert_str_eq(printf_tests_split[_i].str, buf);
+}
+END_TEST
+
+START_TEST(test_enum_printf_hook_width)
+{
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "%10N", test_enum_cont_names, CONT1);
+ ck_assert_str_eq(" CONT1", buf);
+ snprintf(buf, sizeof(buf), "%-*N", 10, test_enum_cont_names, CONT2);
+ ck_assert_str_eq("CONT2 ", buf);
+ snprintf(buf, sizeof(buf), "%3N", test_enum_cont_names, CONT3);
+ ck_assert_str_eq("CONT3", buf);
+}
+END_TEST
+
+Suite *enum_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("enum");
+
+ tc = tcase_create("enum_to_name");
+ tcase_add_loop_test(tc, test_enum_to_name_cont, 0, countof(name_tests_cont));
+ tcase_add_loop_test(tc, test_enum_to_name_split, 0, countof(name_tests_split));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("enum_from_name");
+ tcase_add_loop_test(tc, test_enum_from_name_cont, 0, countof(enum_tests_cont));
+ tcase_add_loop_test(tc, test_enum_from_name_split, 0, countof(enum_tests_split));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("enum_printf_hook");
+ tcase_add_loop_test(tc, test_enum_printf_hook_cont, 0, countof(printf_tests_cont));
+ tcase_add_loop_test(tc, test_enum_printf_hook_split, 0, countof(printf_tests_split));
+ tcase_add_test(tc, test_enum_printf_hook_width);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_enumerator.c b/src/libstrongswan/tests/suites/test_enumerator.c
new file mode 100644
index 000000000..b5dde4650
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_enumerator.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * Copyright (C) 2007 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 "test_suite.h"
+
+#include <collections/enumerator.h>
+#include <collections/linked_list.h>
+
+/*******************************************************************************
+ * token test
+ */
+
+static const char *token_results1[] = { "abc", "cde", "efg" };
+static const char *token_results2[] = { "a", "b", "c" };
+
+static struct {
+ char *string;
+ char *sep;
+ char *trim;
+ const char **results;
+} token_tests[] = {
+ {"abc, cde, efg", ",", " ", token_results1},
+ {" abc 1:2 cde;3 4efg5. ", ":;.,", " 12345", token_results1},
+ {"abc.cde,efg", ",.", "", token_results1},
+ {" abc cde efg ", " ", " ", token_results1},
+ {"a'abc' c 'cde' cefg", " ", " abcd", token_results1},
+ {"'abc' abc 'cde'd 'efg'", " ", " abcd", token_results1},
+
+ {"a, b, c", ",", " ", token_results2},
+ {"a,b,c", ",", " ", token_results2},
+ {" a 1:2 b;3 4c5. ", ":;.,", " 12345", token_results2},
+ {"a.b,c", ",.", "", token_results2},
+ {" a b c ", " ", " ", token_results2},
+};
+
+START_TEST(test_token)
+{
+ enumerator_t *enumerator;
+ const char **results;
+ char *token;
+ int tok = 0;
+
+ enumerator = enumerator_create_token(token_tests[_i].string,
+ token_tests[_i].sep, token_tests[_i].trim);
+ results = token_tests[_i].results;
+ while (enumerator->enumerate(enumerator, &token))
+ {
+ switch (tok)
+ {
+ case 0:
+ case 1:
+ case 2:
+ ck_assert_str_eq(token, results[tok]);
+ break;
+ default:
+ fail("unexpected token '%s'", token);
+ }
+ tok++;
+ }
+ fail_if(tok != 3, "not enough tokens (%d) extracted from '%s'",
+ tok, token_tests[_i].string);
+ enumerator->destroy(enumerator);
+}
+END_TEST
+
+/*******************************************************************************
+ * utilities for filtered, nested and cleaner tests
+ */
+
+static int destroy_data_called;
+
+START_SETUP(setup_destroy_data)
+{
+ destroy_data_called = 0;
+}
+END_SETUP
+
+START_TEARDOWN(teardown_destroy_data)
+{
+ ck_assert_int_eq(destroy_data_called, 1);
+}
+END_TEARDOWN
+
+static void destroy_data(void *data)
+{
+ fail_if(data != (void*)101, "data does not match '101' in destructor");
+ destroy_data_called++;
+}
+
+/*******************************************************************************
+ * filtered test
+ */
+
+static bool filter(void *data, int *v, int *vo, int *w, int *wo,
+ int *x, int *xo, int *y, int *yo, int *z, int *zo)
+{
+ int val = *v;
+
+ *vo = val++;
+ *wo = val++;
+ *xo = val++;
+ *yo = val++;
+ *zo = val++;
+ fail_if(data != (void*)101, "data does not match '101' in filter function");
+ return TRUE;
+}
+
+static bool filter_odd(void *data, int *item, int *out)
+{
+ fail_if(data != (void*)101, "data does not match '101' in filter function");
+ *out = *item;
+ return *item % 2 == 0;
+}
+
+START_TEST(test_filtered)
+{
+ int round, v, w, x, y, z;
+ linked_list_t *list;
+ enumerator_t *enumerator;
+
+ list = linked_list_create_with_items((void*)1, (void*)2, (void*)3, (void*)4,
+ (void*)5, NULL);
+
+ round = 1;
+ enumerator = enumerator_create_filter(list->create_enumerator(list),
+ (void*)filter, (void*)101, destroy_data);
+ while (enumerator->enumerate(enumerator, &v, &w, &x, &y, &z))
+ {
+ ck_assert_int_eq(v, round);
+ ck_assert_int_eq(w, round + 1);
+ ck_assert_int_eq(x, round + 2);
+ ck_assert_int_eq(y, round + 3);
+ ck_assert_int_eq(z, round + 4);
+ round++;
+ }
+ enumerator->destroy(enumerator);
+ ck_assert_int_eq(round, 6);
+
+ list->destroy(list);
+}
+END_TEST
+
+START_TEST(test_filtered_filter)
+{
+ int count, x;
+ linked_list_t *list;
+ enumerator_t *enumerator;
+
+ list = linked_list_create_with_items((void*)1, (void*)2, (void*)3, (void*)4,
+ (void*)5, NULL);
+
+ count = 0;
+ /* should also work without destructor, so set this manually */
+ destroy_data_called = 1;
+ enumerator = enumerator_create_filter(list->create_enumerator(list),
+ (void*)filter_odd, (void*)101, NULL);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ ck_assert(x % 2 == 0);
+ count++;
+ }
+ enumerator->destroy(enumerator);
+ ck_assert_int_eq(count, 2);
+
+ list->destroy(list);
+}
+END_TEST
+
+/*******************************************************************************
+ * nested test
+ */
+
+static enumerator_t* create_inner(linked_list_t *outer, void *data)
+{
+ fail_if(data != (void*)101, "data does not match '101' in nested constr.");
+ return outer->create_enumerator(outer);
+}
+
+static enumerator_t* create_inner_null(void *outer, void *data)
+{
+ ck_assert(outer == (void*)1);
+ fail_if(data != (void*)101, "data does not match '101' in nested constr.");
+ return NULL;
+}
+
+START_TEST(test_nested)
+{
+ linked_list_t *list, *l1, *l2, *l3;
+ enumerator_t *enumerator;
+ intptr_t x;
+ int round;
+
+ l1 = linked_list_create_with_items((void*)1, (void*)2, NULL);
+ l2 = linked_list_create();
+ l3 = linked_list_create_with_items((void*)3, (void*)4, (void*)5, NULL);
+ list = linked_list_create_with_items(l1, l2, l3, NULL);
+
+ round = 1;
+ enumerator = enumerator_create_nested(list->create_enumerator(list),
+ (void*)create_inner, (void*)101, destroy_data);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ ck_assert_int_eq(round, x);
+ round++;
+ }
+ enumerator->destroy(enumerator);
+ ck_assert_int_eq(round, 6);
+
+ list->destroy(list);
+ l1->destroy(l1);
+ l2->destroy(l2);
+ l3->destroy(l3);
+}
+END_TEST
+
+START_TEST(test_nested_reset)
+{
+ linked_list_t *list, *l1, *l2, *l3;
+ enumerator_t *outer, *enumerator;
+ intptr_t x;
+ int count = 0;
+
+ l1 = linked_list_create_with_items((void*)1, (void*)2, NULL);
+ l2 = linked_list_create();
+ l3 = linked_list_create_with_items((void*)3, (void*)4, (void*)5, NULL);
+ list = linked_list_create_with_items(l1, l2, l3, NULL);
+
+ outer = list->create_enumerator(list);
+ enumerator = enumerator_create_nested(outer, (void*)create_inner,
+ (void*)101, destroy_data);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ count++;
+ }
+ ck_assert_int_eq(count, 5);
+
+ list->reset_enumerator(list, outer);
+ ck_assert(enumerator->enumerate(enumerator, &x));
+ ck_assert_int_eq(x, 1);
+ enumerator->destroy(enumerator);
+
+ list->destroy(list);
+ l1->destroy(l1);
+ l2->destroy(l2);
+ l3->destroy(l3);
+}
+END_TEST
+
+START_TEST(test_nested_empty)
+{
+ linked_list_t *list;
+ enumerator_t *enumerator;
+ intptr_t x;
+ int count;
+
+ list = linked_list_create();
+ count = 0;
+ enumerator = enumerator_create_nested(list->create_enumerator(list),
+ (void*)create_inner, (void*)101, destroy_data);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ count++;
+ }
+ enumerator->destroy(enumerator);
+ ck_assert_int_eq(count, 0);
+
+ list->destroy(list);
+}
+END_TEST
+
+START_TEST(test_nested_null)
+{
+ linked_list_t *list;
+ enumerator_t *enumerator;
+ intptr_t x;
+ int count;
+
+ list = linked_list_create_with_items((void*)1, NULL);
+
+ count = 0;
+ /* should also work without destructor, so set this manually */
+ destroy_data_called = 1;
+ enumerator = enumerator_create_nested(list->create_enumerator(list),
+ (void*)create_inner_null, (void*)101, NULL);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ count++;
+ }
+ enumerator->destroy(enumerator);
+ ck_assert_int_eq(count, 0);
+
+ list->destroy(list);
+}
+END_TEST
+
+/*******************************************************************************
+ * cleaner test
+ */
+
+START_TEST(test_cleaner)
+{
+ enumerator_t *enumerator;
+ linked_list_t *list;
+ intptr_t x;
+ int round;
+
+ list = linked_list_create_with_items((void*)1, (void*)2, NULL);
+
+ round = 1;
+ enumerator = enumerator_create_cleaner(list->create_enumerator(list),
+ destroy_data, (void*)101);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ ck_assert_int_eq(round, x);
+ round++;
+ }
+ ck_assert_int_eq(round, 3);
+ enumerator->destroy(enumerator);
+ list->destroy(list);
+}
+END_TEST
+
+/*******************************************************************************
+ * single test
+ */
+
+static void single_cleanup(void *data)
+{
+ ck_assert_int_eq((intptr_t)data, 1);
+}
+
+static void do_test_single(enumerator_t *enumerator)
+{
+ intptr_t x;
+
+ ck_assert(enumerator->enumerate(enumerator, &x));
+ ck_assert_int_eq(x, 1);
+ ck_assert(!enumerator->enumerate(enumerator, &x));
+ enumerator->destroy(enumerator);
+}
+
+START_TEST(test_single)
+{
+ enumerator_t *enumerator;
+
+ enumerator = enumerator_create_single((void*)1, NULL);
+ do_test_single(enumerator);
+}
+END_TEST
+
+START_TEST(test_single_cleanup)
+{
+ enumerator_t *enumerator;
+
+ enumerator = enumerator_create_single((void*)1, single_cleanup);
+ do_test_single(enumerator);
+}
+END_TEST
+
+Suite *enumerator_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("enumerator");
+
+ tc = tcase_create("tokens");
+ tcase_add_loop_test(tc, test_token, 0, countof(token_tests));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("filtered");
+ tcase_add_checked_fixture(tc, setup_destroy_data, teardown_destroy_data);
+ tcase_add_test(tc, test_filtered);
+ tcase_add_test(tc, test_filtered_filter);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("nested");
+ tcase_add_checked_fixture(tc, setup_destroy_data, teardown_destroy_data);
+ tcase_add_test(tc, test_nested);
+ tcase_add_test(tc, test_nested_reset);
+ tcase_add_test(tc, test_nested_empty);
+ tcase_add_test(tc, test_nested_null);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("cleaner");
+ tcase_add_checked_fixture(tc, setup_destroy_data, teardown_destroy_data);
+ tcase_add_test(tc, test_cleaner);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("single");
+ tcase_add_test(tc, test_single);
+ tcase_add_test(tc, test_single_cleanup);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_fetch_http.c b/src/libstrongswan/tests/suites/test_fetch_http.c
new file mode 100644
index 000000000..8749ff375
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_fetch_http.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * 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 "test_suite.h"
+
+#include <unistd.h>
+#include <time.h>
+
+/**
+ * HTTP test definition
+ */
+typedef struct {
+ /* HTTP Method */
+ char *meth;
+ /* HTTP 1.x minor version */
+ int minor;
+ /* host to connect to */
+ char *host;
+ /* HTTP service port */
+ int port;
+ /* path on host to fetch from */
+ char *path;
+ /* request Content-Type, if any */
+ char *type;
+ /* request data, if any */
+ void *req;
+ /* length of request data */
+ int req_len;
+ /* response data, if any */
+ void *res;
+ /* length of response data */
+ int res_len;
+} test_service_t;
+
+static char large[] = {
+ 0x88,0x3e,0xa3,0xe3,0x95,0x67,0x53,0x93,0xc8,0xce,0x5c,0xcd,0x8c,0x03,0x0c,0xa8,
+ 0x94,0xaf,0x49,0xf6,0xc6,0x50,0xad,0xb8,0xea,0xb8,0x85,0x8a,0xde,0x92,0xe1,0xbc,
+ 0xf3,0x15,0xbb,0x5b,0xb8,0x35,0xd8,0x17,0xad,0xcf,0x6b,0x07,0x63,0x61,0x2e,0x2f,
+ 0xa5,0xc9,0x1d,0xa7,0xac,0xaa,0x4d,0xde,0x71,0x65,0x95,0x87,0x66,0x50,0xa2,0xa6,
+ 0x28,0xef,0x49,0x5c,0x53,0xa3,0x87,0xad,0x42,0xc3,0x41,0xd8,0xfa,0x92,0xd8,0x32,
+ 0xce,0x7c,0xf2,0x72,0x2f,0x51,0x27,0x71,0xe3,0x78,0x59,0xf9,0x46,0x23,0xf3,0xa7,
+ 0x38,0x12,0x05,0xbb,0x1a,0xb0,0xe0,0x12,0xae,0x97,0xa1,0x0f,0xd4,0x34,0xe0,0x15,
+ 0xb4,0xa3,0x15,0x08,0xbe,0xff,0x4d,0x31,0x81,0x39,0x62,0x29,0xf0,0x90,0x79,0x02,
+ 0x4d,0x0c,0xf4,0x9e,0xe5,0xd4,0xdc,0xca,0xea,0xb8,0x85,0x8a,0xde,0x92,0xe1,0xbc,
+ 0xf3,0x15,0xbb,0x5b,0xb8,0x35,0xd8,0x17,0xad,0xcf,0x6b,0x07,0x63,0x61,0x2e,0x2f,
+ 0xa5,0xc9,0x1d,0xa7,0xac,0xaa,0x4d,0xde,0x71,0x65,0x95,0x87,0x66,0x50,0xa2,0xa6,
+ 0x28,0xef,0x49,0x5c,0x53,0xa3,0x87,0xad,0x42,0xc3,0x41,0xd8,0xfa,0x92,0xd8,0x32,
+ 0xce,0x7c,0xf2,0x72,0x2f,0x51,0x27,0x71,0xe3,0x78,0x59,0xf9,0x46,0x23,0xf3,0xa7,
+ 0x38,0x12,0x05,0xbb,0x1a,0xb0,0xe0,0x12,0xae,0x97,0xa1,0x0f,0xd4,0x34,0xe0,0x15,
+ 0xf3,0x15,0xbb,0x5b,0xb8,0x35,0xd8,0x17,0xad,0xcf,0x6b,0x07,0x63,0x61,0x2e,0x2f,
+ 0xa5,0xc9,0x1d,0xa7,0xac,0xaa,0x4d,0xde,0x71,0x65,0x95,0x87,0x66,0x50,0xa2,0xa6,
+ 0x28,0xef,0x49,0x5c,0x53,0xa3,0x87,0xad,0x42,0xc3,0x41,0xd8,0xfa,0x92,0xd8,0x32,
+ 0xce,0x7c,0xf2,0x72,0x2f,0x51,0x27,0x71,0xe3,0x78,0x59,0xf9,0x46,0x23,0xf3,0xa7,
+ 0x38,0x12,0x05,0xbb,0x1a,0xb0,0xe0,0x12,0xae,0x97,0xa1,0x0f,0xd4,0x34,0xe0,0x15,
+ 0xb4,0xa3,0x15,0x08,0xbe,0xff,0x4d,0x31,0x81,0x39,0x62,0x29,0xf0,0x90,0x79,0x02,
+ 0x4d,0x0c,0xf4,0x9e,0xe5,0xd4,0xdc,0xca,0xea,0xb8,0x85,0x8a,0xde,0x92,0xe1,0xbc,
+ 0xf3,0x15,0xbb,0x5b,0xb8,0x35,0xd8,0x17,0xad,0xcf,0x6b,0x07,0x63,0x61,0x2e,0x2f,
+ 0xa5,0xc9,0x1d,0xa7,0xac,0xaa,0x4d,0xde,0x71,0x65,0x95,0x87,0x66,0x50,0xa2,0xa6,
+ 0x28,0xef,0x49,0x5c,0x53,0xa3,0x87,0xad,0x42,0xc3,0x41,0xd8,0xfa,0x92,0xd8,0x32,
+ 0xce,0x7c,0xf2,0x72,0x2f,0x51,0x27,0x71,0xe3,0x78,0x59,0xf9,0x46,0x23,0xf3,0xa7,
+ 0x38,0x12,0x05,0xbb,0x1a,0xb0,0xe0,0x12,0xae,0x97,0xa1,0x0f,0xd4,0x34,0xe0,0x15,
+ 0xb4,0xa3,0x15,0x08,0xbe,0xff,0x4d,0x31,0x81,0x39,0x62,0x29,0xf0,0x90,0x79,0x02,
+ 0x4d,0x0c,0xf4,0x9e,0xe5,0xd4,0xdc,0xca,0xea,0xb8,0x85,0x8a,0xde,0x92,0xe1,0xbc,
+};
+
+static bool servicing(void *data, stream_t *stream)
+{
+ test_service_t *test = (test_service_t*)data;
+ char buf[1024], hdr[256], *start, *end = NULL, *body = NULL, *type = NULL;
+ struct tm tm;
+ time_t t;
+ ssize_t len, tot = 0;
+ int nr = 0;
+
+ start = buf;
+
+ /* parse method and headers */
+ while (end != start)
+ {
+ len = stream->read(stream, buf + tot, sizeof(buf) - tot, TRUE);
+ ck_assert(len > 0);
+ tot += len;
+
+ while (TRUE)
+ {
+ end = memchr(start, '\n', tot);
+ if (!end)
+ {
+ break;
+ }
+ *end = '\0';
+ ck_assert(end > buf);
+ ck_assert(*(--end) == '\r');
+ *end = '\0';
+ if (end == start)
+ {
+ body = end + strlen("\r\n");
+ break;
+ }
+ switch (nr++)
+ {
+ case 0:
+ snprintf(hdr, sizeof(hdr), "%s %s HTTP/1.%u",
+ test->meth, test->path, test->minor);
+ ck_assert_str_eq(hdr, start);
+ break;
+ default:
+ if (strcasepfx(start, "Content-Length: "))
+ {
+ ck_assert_int_eq(
+ atoi(start + strlen("Content-Length: ")),
+ test->req_len);
+ }
+ if (strcasepfx(start, "Content-Type: "))
+ {
+ type = start + strlen("Content-Type: ");
+ }
+ break;
+ }
+ start = end + strlen("\r\n");
+ }
+ }
+
+ if (test->type)
+ {
+ ck_assert(type);
+ ck_assert_str_eq(type, test->type);
+ }
+
+ /* request body */
+ if (test->req_len)
+ {
+ ck_assert(stream->read_all(stream, buf + tot,
+ test->req_len - (tot - (body - buf))));
+ ck_assert(memeq(body, test->req, test->req_len));
+ }
+
+ /* response headers */
+ snprintf(buf, sizeof(buf), "HTTP/1.%u 200 OK\r\n", test->minor);
+ ck_assert(stream->write_all(stream, buf, strlen(buf)));
+ t = time(NULL);
+ gmtime_r(&t, &tm);
+ strftime(buf, sizeof(buf), "%a, %d %b %Y %T %z", &tm);
+ ck_assert(stream->write_all(stream, buf, strlen(buf)));
+ snprintf(buf, sizeof(buf), "Server: strongSwan unit test\r\n");
+ ck_assert(stream->write_all(stream, buf, strlen(buf)));
+
+ /* rest of response headers */
+ snprintf(buf, sizeof(buf), "Content-Type: text/plain\r\n");
+ ck_assert(stream->write_all(stream, buf, strlen(buf)));
+ snprintf(buf, sizeof(buf), "Content-Length: %u\r\n", test->res_len);
+ ck_assert(stream->write_all(stream, buf, strlen(buf)));
+ snprintf(buf, sizeof(buf), "Connection: close\r\n");
+ ck_assert(stream->write_all(stream, buf, strlen(buf)));
+ snprintf(buf, sizeof(buf), "\r\n");
+ ck_assert(stream->write_all(stream, buf, strlen(buf)));
+
+ /* response body */
+ ck_assert(stream->write_all(stream, test->res, test->res_len));
+ return FALSE;
+}
+
+static test_service_t gtests[] = {
+ { "GET", 1, "127.0.0.1", 6543, "/a/test/?b=c", NULL,
+ NULL, 0, "\x12\x34", 2 },
+ { "GET", 0, "localhost", 6543, "/", NULL,
+ NULL, 0, NULL, 0 },
+ { "GET", 0, "127.0.0.1", 6543, "/largefile", NULL,
+ NULL, 0, large, sizeof(large) },
+ { "GET", 1, "[::1]", 6543, "/ipv6-url", NULL,
+ NULL, 0, "\x00\r\n\r\x00testdatablabla", 20 },
+};
+
+START_TEST(test_get)
+{
+ stream_service_t *service;
+ status_t status;
+ chunk_t data, expected;
+ char uri[256];
+
+ lib->processor->set_threads(lib->processor, 8);
+
+ snprintf(uri, sizeof(uri), "tcp://%s:%u", gtests[_i].host, gtests[_i].port);
+ service = lib->streams->create_service(lib->streams, uri, 1);
+ ck_assert(service != NULL);
+ service->on_accept(service, servicing, &gtests[_i], JOB_PRIO_HIGH, 0);
+
+ snprintf(uri, sizeof(uri), "http://%s:%u%s",
+ gtests[_i].host, gtests[_i].port, gtests[_i].path);
+ status = lib->fetcher->fetch(lib->fetcher, uri, &data,
+ !gtests[_i].minor ? FETCH_HTTP_VERSION_1_0 : FETCH_END,
+ FETCH_END);
+ ck_assert_int_eq(status, SUCCESS);
+ expected = chunk_create(gtests[_i].res, gtests[_i].res_len);
+ ck_assert_msg(chunk_compare(expected, data) == 0,
+ "exp %B\ngot %B\n", &expected, &data);
+ free(data.ptr);
+
+ service->destroy(service);
+}
+END_TEST
+
+
+static test_service_t ptests[] = {
+ { "POST", 1, "127.0.0.1", 6543, "/a/test/?b=c", "application/binary",
+ "\x23\x45", 2, "\x12\x34", 2 },
+ { "POST", 0, "localhost", 6543, "/largefile", "application/x-large",
+ large, sizeof(large), large, sizeof(large) },
+ { "POST", 1, "[::1]", 6543, "/ipv6-url", "text/plain",
+ "\x00\r\n\r\x00testdatablabla", 20, "\x00\r\n\r\x00testdatablabla", 20 },
+};
+
+START_TEST(test_post)
+{
+ stream_service_t *service;
+ status_t status;
+ chunk_t data, expected;
+ char uri[256];
+
+ lib->processor->set_threads(lib->processor, 8);
+
+ snprintf(uri, sizeof(uri), "tcp://%s:%u", ptests[_i].host, ptests[_i].port);
+ service = lib->streams->create_service(lib->streams, uri, 1);
+ ck_assert(service != NULL);
+ service->on_accept(service, servicing, &ptests[_i], JOB_PRIO_HIGH, 0);
+
+ snprintf(uri, sizeof(uri), "http://%s:%u%s",
+ ptests[_i].host, ptests[_i].port, ptests[_i].path);
+ status = lib->fetcher->fetch(lib->fetcher, uri, &data,
+ FETCH_REQUEST_TYPE, ptests[_i].type,
+ FETCH_REQUEST_DATA,
+ chunk_create(ptests[_i].req, ptests[_i].req_len),
+ !ptests[_i].minor ? FETCH_HTTP_VERSION_1_0 : FETCH_END,
+ FETCH_END);
+ ck_assert_int_eq(status, SUCCESS);
+ expected = chunk_create(ptests[_i].res, ptests[_i].res_len);
+ ck_assert_msg(chunk_compare(expected, data) == 0,
+ "exp %B\ngot %B\n", &expected, &data);
+ free(data.ptr);
+
+ service->destroy(service);
+}
+END_TEST
+
+Suite *fetch_http_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("http fetcher");
+
+ tc = tcase_create("GET");
+ tcase_add_loop_test(tc, test_get, 0, countof(gtests));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("POST");
+ tcase_add_loop_test(tc, test_post, 0, countof(ptests));
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_hasher.c b/src/libstrongswan/tests/suites/test_hasher.c
new file mode 100644
index 000000000..41a9d64ef
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_hasher.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2013 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 "test_suite.h"
+
+#include <crypto/hashers/hasher.h>
+#include <crypto/prfs/prf.h>
+#include <crypto/signers/signer.h>
+#include <asn1/oid.h>
+#include <utils/test.h>
+
+typedef struct {
+ int oid;
+ hash_algorithm_t alg;
+ key_type_t key;
+}hasher_oid_t;
+
+static hasher_oid_t oids[] = {
+ { OID_MD2, HASH_MD2, KEY_ANY },
+ { OID_MD5, HASH_MD5, KEY_ANY },
+ { OID_SHA1, HASH_SHA1, KEY_ANY },
+ { OID_SHA224, HASH_SHA224, KEY_ANY },
+ { OID_SHA256, HASH_SHA256, KEY_ANY },
+ { OID_SHA384, HASH_SHA384, KEY_ANY },
+ { OID_SHA512, HASH_SHA512, KEY_ANY },
+ { OID_UNKNOWN, HASH_UNKNOWN, KEY_ANY },
+ { OID_MD2_WITH_RSA, HASH_MD2, KEY_RSA },
+ { OID_MD5_WITH_RSA, HASH_MD5, KEY_RSA },
+ { OID_SHA1_WITH_RSA, HASH_SHA1, KEY_RSA },
+ { OID_SHA224_WITH_RSA, HASH_SHA224, KEY_RSA },
+ { OID_SHA256_WITH_RSA, HASH_SHA256, KEY_RSA },
+ { OID_SHA384_WITH_RSA, HASH_SHA384, KEY_RSA },
+ { OID_SHA512_WITH_RSA, HASH_SHA512, KEY_RSA },
+ { OID_UNKNOWN, HASH_UNKNOWN, KEY_RSA },
+ { OID_ECDSA_WITH_SHA1, HASH_SHA1, KEY_ECDSA },
+ { OID_ECDSA_WITH_SHA256, HASH_SHA256, KEY_ECDSA },
+ { OID_ECDSA_WITH_SHA384, HASH_SHA384, KEY_ECDSA },
+ { OID_ECDSA_WITH_SHA512, HASH_SHA512, KEY_ECDSA },
+ { OID_UNKNOWN, HASH_UNKNOWN, KEY_ECDSA }
+};
+
+START_TEST(test_hasher_from_oid)
+{
+ ck_assert(hasher_algorithm_from_oid(oids[_i].oid) == oids[_i].alg);
+}
+END_TEST
+
+START_TEST(test_hasher_to_oid)
+{
+ ck_assert(hasher_algorithm_to_oid(oids[_i].alg) == oids[_i].oid);
+}
+END_TEST
+
+START_TEST(test_hasher_sig_to_oid)
+{
+ ck_assert(hasher_signature_algorithm_to_oid(oids[_i].alg,
+ oids[_i].key) == oids[_i].oid);
+}
+END_TEST
+
+typedef struct {
+ pseudo_random_function_t prf;
+ hash_algorithm_t alg;
+}hasher_prf_t;
+
+static hasher_prf_t prfs[] = {
+ { PRF_HMAC_MD5, HASH_MD5 },
+ { PRF_HMAC_SHA1, HASH_SHA1 },
+ { PRF_FIPS_SHA1_160, HASH_SHA1 },
+ { PRF_KEYED_SHA1, HASH_SHA1 },
+ { PRF_HMAC_SHA2_256, HASH_SHA256 },
+ { PRF_HMAC_SHA2_384, HASH_SHA384 },
+ { PRF_HMAC_SHA2_512, HASH_SHA512 },
+ { PRF_HMAC_TIGER, HASH_UNKNOWN },
+ { PRF_AES128_XCBC, HASH_UNKNOWN },
+ { PRF_AES128_CMAC, HASH_UNKNOWN },
+ { PRF_FIPS_DES, HASH_UNKNOWN },
+ { PRF_CAMELLIA128_XCBC, HASH_UNKNOWN },
+ { PRF_UNDEFINED, HASH_UNKNOWN },
+ { 0, HASH_UNKNOWN }
+};
+
+START_TEST(test_hasher_from_prf)
+{
+ ck_assert(hasher_algorithm_from_prf(prfs[_i].prf) == prfs[_i].alg);
+}
+END_TEST
+
+typedef struct {
+ integrity_algorithm_t auth;
+ hash_algorithm_t alg;
+ size_t length;
+}hasher_auth_t;
+
+static hasher_auth_t auths[] = {
+ { AUTH_UNDEFINED, HASH_MD2, 0 },
+ { AUTH_UNDEFINED, HASH_MD4, 0 },
+ { AUTH_UNDEFINED, HASH_SHA224, 0 },
+ { AUTH_UNDEFINED, 9, 0 },
+ { AUTH_UNDEFINED, HASH_UNKNOWN, 0 },
+ { AUTH_HMAC_MD5_96, HASH_MD5, 12 },
+ { AUTH_HMAC_SHA1_96, HASH_SHA1, 12 },
+ { AUTH_HMAC_SHA2_256_96, HASH_SHA256, 12 },
+ { AUTH_HMAC_MD5_128, HASH_MD5, 16 },
+ { AUTH_HMAC_SHA1_128, HASH_SHA1, 16 },
+ { AUTH_HMAC_SHA2_256_128, HASH_SHA256, 16 },
+ { AUTH_HMAC_SHA1_160, HASH_SHA1, 20 },
+ { AUTH_HMAC_SHA2_384_192, HASH_SHA384, 24 },
+ { AUTH_HMAC_SHA2_256_256, HASH_SHA256, 32 },
+ { AUTH_HMAC_SHA2_512_256, HASH_SHA512, 32 },
+ { AUTH_HMAC_SHA2_384_384, HASH_SHA384, 48 },
+ { AUTH_HMAC_SHA2_512_512, HASH_SHA512, 64 },
+ { AUTH_AES_CMAC_96, HASH_UNKNOWN, 0 },
+ { AUTH_AES_128_GMAC, HASH_UNKNOWN, 0 },
+ { AUTH_AES_192_GMAC, HASH_UNKNOWN, 0 },
+ { AUTH_AES_256_GMAC, HASH_UNKNOWN, 0 },
+ { AUTH_AES_XCBC_96, HASH_UNKNOWN, 0 },
+ { AUTH_DES_MAC, HASH_UNKNOWN, 0 },
+ { AUTH_CAMELLIA_XCBC_96, HASH_UNKNOWN, 0 },
+ { 0, HASH_UNKNOWN, 0 }
+};
+
+START_TEST(test_hasher_from_integrity)
+{
+ size_t length;
+
+ length = 0;
+ ck_assert(hasher_algorithm_from_integrity(auths[_i].auth, NULL) ==
+ auths[_i].alg);
+ ck_assert(hasher_algorithm_from_integrity(auths[_i].auth, &length) ==
+ auths[_i].alg);
+ ck_assert(length == auths[_i].length);
+}
+END_TEST
+
+START_TEST(test_hasher_to_integrity)
+{
+ ck_assert(hasher_algorithm_to_integrity(
+ auths[_i].alg, auths[_i].length) == auths[_i].auth);
+ ck_assert(hasher_algorithm_to_integrity(
+ auths[_i].alg, 0) == AUTH_UNDEFINED);
+}
+END_TEST
+
+Suite *hasher_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("hasher");
+
+ tc = tcase_create("from_oid");
+ tcase_add_loop_test(tc, test_hasher_from_oid, 0, 15);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("to_oid");
+ tcase_add_loop_test(tc, test_hasher_to_oid, 0, 8);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("sig_to_oid");
+ tcase_add_loop_test(tc, test_hasher_sig_to_oid, 7, countof(oids));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("from_prf");
+ tcase_add_loop_test(tc, test_hasher_from_prf, 0, countof(prfs));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("from_integrity");
+ tcase_add_loop_test(tc, test_hasher_from_integrity, 4, countof(auths));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("to_integrity");
+ tcase_add_loop_test(tc, test_hasher_to_integrity, 0, 17);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_hashtable.c b/src/libstrongswan/tests/suites/test_hashtable.c
new file mode 100644
index 000000000..8cc7bfe42
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_hashtable.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2010-2013 Tobias Brunner
+ * 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 "test_suite.h"
+
+#include <collections/hashtable.h>
+#include <utils/chunk.h>
+
+/*******************************************************************************
+ * string hash table functions
+ */
+
+static u_int hash(char *key)
+{
+ return chunk_hash(chunk_from_str(key));
+}
+
+static bool equals(char *key1, char *key2)
+{
+ return streq(key1, key2);
+}
+
+/*******************************************************************************
+ * test fixture
+ */
+
+static hashtable_t *ht;
+
+START_SETUP(setup_ht)
+{
+ ht = hashtable_create((hashtable_hash_t)hash,
+ (hashtable_equals_t)equals, 0);
+ ck_assert_int_eq(ht->get_count(ht), 0);
+}
+END_SETUP
+
+START_TEARDOWN(teardown_ht)
+{
+ ht->destroy(ht);
+}
+END_TEARDOWN
+
+/*******************************************************************************
+ * put/get
+ */
+
+START_TEST(test_put_get)
+{
+ char *k1 = "key1", *k2 = "key2", *k3 = "key3";
+ char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value;
+
+ value = ht->put(ht, k1, v1);
+ ck_assert_int_eq(ht->get_count(ht), 1);
+ ck_assert(streq(ht->get(ht, k1), v1));
+ ck_assert(ht->get(ht, k2) == NULL);
+ ck_assert(ht->get(ht, k3) == NULL);
+ ck_assert(value == NULL);
+
+ ht->put(ht, k2, v2);
+ ht->put(ht, k3, v3);
+ ck_assert_int_eq(ht->get_count(ht), 3);
+ ck_assert(streq(ht->get(ht, k1), v1));
+ ck_assert(streq(ht->get(ht, k2), v2));
+ ck_assert(streq(ht->get(ht, k3), v3));
+
+ value = ht->put(ht, k2, v1);
+ ck_assert_int_eq(ht->get_count(ht), 3);
+ ck_assert(streq(value, v2));
+ ck_assert(streq(ht->get(ht, k2), v1));
+}
+END_TEST
+
+/*******************************************************************************
+ * get_match
+ */
+
+static u_int hash_match(char *key)
+{
+ return chunk_hash(chunk_create(key, 4));
+}
+
+static bool equal_match(char *key1, char *key2)
+{
+ if (!strneq(key1, key2, 4))
+ {
+ return FALSE;
+ }
+ /* look for an item with a key < than what we look for */
+ return strcmp(key1, key2) >= 0;
+}
+
+START_TEST(test_get_match)
+{
+ char *k1 = "key1_a", *k2 = "key2", *k3 = "key1_b", *k4 = "key1_c";
+ char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value;
+
+ ht = hashtable_create((hashtable_hash_t)hash_match,
+ (hashtable_equals_t)equals, 0);
+
+ ht->put(ht, k1, v1);
+ ht->put(ht, k2, v2);
+ value = ht->put(ht, k3, v3);
+ ck_assert_int_eq(ht->get_count(ht), 3);
+ ck_assert(streq(ht->get(ht, k1), v1));
+ ck_assert(streq(ht->get(ht, k2), v2));
+ ck_assert(streq(ht->get(ht, k3), v3));
+ ck_assert(value == NULL);
+
+ value = ht->get_match(ht, k1, (hashtable_equals_t)equal_match);
+ ck_assert(value != NULL);
+ ck_assert(streq(value, v1));
+ value = ht->get_match(ht, k2, (hashtable_equals_t)equal_match);
+ ck_assert(value != NULL);
+ ck_assert(streq(value, v2));
+ value = ht->get_match(ht, k3, (hashtable_equals_t)equal_match);
+ ck_assert(value != NULL);
+ ck_assert(streq(value, v1));
+ value = ht->get_match(ht, k4, (hashtable_equals_t)equal_match);
+ ck_assert(value != NULL);
+ ck_assert(streq(value, v1));
+
+ ht->destroy(ht);
+}
+END_TEST
+
+/*******************************************************************************
+ * remove
+ */
+
+static void do_remove(char *k1, char *k2, char *k3)
+{
+ char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value;
+
+ ht->put(ht, k1, v1);
+ ht->put(ht, k2, v2);
+ ht->put(ht, k3, v3);
+
+ value = ht->remove(ht, k2);
+ ck_assert_int_eq(ht->get_count(ht), 2);
+ ck_assert(streq(ht->get(ht, k1), v1));
+ ck_assert(streq(ht->get(ht, k3), v3));
+ ck_assert(streq(value, v2));
+ ck_assert(ht->get(ht, k2) == NULL);
+
+ value = ht->remove(ht, k2);
+ ck_assert_int_eq(ht->get_count(ht), 2);
+ ck_assert(value == NULL);
+
+ value = ht->remove(ht, k1);
+ value = ht->remove(ht, k3);
+ ck_assert_int_eq(ht->get_count(ht), 0);
+ ck_assert(ht->get(ht, k1) == NULL);
+ ck_assert(ht->get(ht, k2) == NULL);
+ ck_assert(ht->get(ht, k3) == NULL);
+}
+
+START_TEST(test_remove)
+{
+ char *k1 = "key1", *k2 = "key2", *k3 = "key3";
+
+ do_remove(k1, k2, k3);
+}
+END_TEST
+
+START_TEST(test_remove_one_bucket)
+{
+ char *k1 = "key1_a", *k2 = "key1_b", *k3 = "key1_c";
+
+ ht->destroy(ht);
+ /* set a capacity to avoid rehashing, which would change the items' order */
+ ht = hashtable_create((hashtable_hash_t)hash_match,
+ (hashtable_equals_t)equals, 8);
+
+ do_remove(k1, k2, k3);
+}
+END_TEST
+
+/*******************************************************************************
+ * enumerator
+ */
+
+START_TEST(test_enumerator)
+{
+ char *k1 = "key1", *k2 = "key2", *k3 = "key3", *key;
+ char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value;
+ enumerator_t *enumerator;
+ int count;
+
+ ht->put(ht, k1, v1);
+ ht->put(ht, k2, v2);
+ ht->put(ht, k3, v3);
+
+ count = 0;
+ enumerator = ht->create_enumerator(ht);
+ while (enumerator->enumerate(enumerator, &key, &value))
+ {
+ ck_assert(streq(key, k1) || streq(key, k2) || streq(key, k3));
+ ck_assert(streq(value, v1) || streq(value, v2) || streq(value, v3));
+ ck_assert(!streq(key, k1) || streq(value, v1));
+ ck_assert(!streq(key, k2) || streq(value, v2));
+ ck_assert(!streq(key, k3) || streq(value, v3));
+ count++;
+ }
+ enumerator->destroy(enumerator);
+ ck_assert_int_eq(count, 3);
+
+ count = 0;
+ enumerator = ht->create_enumerator(ht);
+ while (enumerator->enumerate(enumerator, NULL, NULL))
+ {
+ count++;
+ }
+ enumerator->destroy(enumerator);
+ ck_assert_int_eq(count, 3);
+
+ value = ht->remove(ht, k1);
+ value = ht->remove(ht, k2);
+ value = ht->remove(ht, k3);
+
+ count = 0;
+ enumerator = ht->create_enumerator(ht);
+ while (enumerator->enumerate(enumerator, &key, &value))
+ {
+ count++;
+ }
+ enumerator->destroy(enumerator);
+ ck_assert_int_eq(count, 0);
+}
+END_TEST
+
+/*******************************************************************************
+ * remove_at
+ */
+
+static void do_remove_at(char *k1, char *k2, char *k3)
+{
+ char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value, *key;
+ enumerator_t *enumerator;
+
+ ht->put(ht, k1, v1);
+ ht->put(ht, k2, v2);
+ ht->put(ht, k3, v3);
+
+ enumerator = ht->create_enumerator(ht);
+ ht->remove_at(ht, enumerator);
+ while (enumerator->enumerate(enumerator, &key, &value))
+ {
+ if (streq(key, k2))
+ {
+ ht->remove_at(ht, enumerator);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ ck_assert_int_eq(ht->get_count(ht), 2);
+ ck_assert(ht->get(ht, k1) != NULL);
+ ck_assert(ht->get(ht, k3) != NULL);
+ ck_assert(ht->get(ht, k2) == NULL);
+
+ ht->put(ht, k2, v2);
+
+ ck_assert_int_eq(ht->get_count(ht), 3);
+ ck_assert(ht->get(ht, k1) != NULL);
+ ck_assert(ht->get(ht, k2) != NULL);
+ ck_assert(ht->get(ht, k3) != NULL);
+
+ enumerator = ht->create_enumerator(ht);
+ while (enumerator->enumerate(enumerator, &key, &value))
+ {
+ ht->remove_at(ht, enumerator);
+ }
+ enumerator->destroy(enumerator);
+
+ ck_assert_int_eq(ht->get_count(ht), 0);
+ ck_assert(ht->get(ht, k1) == NULL);
+ ck_assert(ht->get(ht, k2) == NULL);
+ ck_assert(ht->get(ht, k3) == NULL);
+}
+
+START_TEST(test_remove_at)
+{
+ char *k1 = "key1", *k2 = "key2", *k3 = "key3";
+
+ do_remove_at(k1, k2, k3);
+}
+END_TEST
+
+START_TEST(test_remove_at_one_bucket)
+{
+ char *k1 = "key1_a", *k2 = "key1_b", *k3 = "key1_c";
+
+ ht->destroy(ht);
+ /* set a capacity to avoid rehashing, which would change the items' order */
+ ht = hashtable_create((hashtable_hash_t)hash_match,
+ (hashtable_equals_t)equals, 8);
+ do_remove_at(k1, k2, k3);
+}
+END_TEST
+
+Suite *hashtable_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("hashtable");
+
+ tc = tcase_create("put/get");
+ tcase_add_checked_fixture(tc, setup_ht, teardown_ht);
+ tcase_add_test(tc, test_put_get);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("get_match");
+ tcase_add_test(tc, test_get_match);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("remove");
+ tcase_add_checked_fixture(tc, setup_ht, teardown_ht);
+ tcase_add_test(tc, test_remove);
+ tcase_add_test(tc, test_remove_one_bucket);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("enumerator");
+ tcase_add_checked_fixture(tc, setup_ht, teardown_ht);
+ tcase_add_test(tc, test_enumerator);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("remove_at");
+ tcase_add_checked_fixture(tc, setup_ht, teardown_ht);
+ tcase_add_test(tc, test_remove_at);
+ tcase_add_test(tc, test_remove_at_one_bucket);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_host.c b/src/libstrongswan/tests/suites/test_host.c
new file mode 100644
index 000000000..30b9eb940
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_host.c
@@ -0,0 +1,651 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * 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 "test_suite.h"
+
+#include <networking/host.h>
+
+/**
+ * Verify a netmask (a number of set bits starting at byte 0)
+ * Can also be used to check for %any (mask == 0)
+ */
+static void verify_netmask(chunk_t addr, int mask)
+{
+ int byte, bit;
+
+ for (byte = 0; byte < addr.len; byte++)
+ {
+ for (bit = 7; bit >= 0; bit--)
+ {
+ int val = (addr.ptr[byte] >> bit) & 0x01;
+ if (mask-- > 0)
+ {
+ ck_assert_int_eq(val, 1);
+ }
+ else
+ {
+ ck_assert_int_eq(val, 0);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ * host_create_any
+ */
+
+static void verify_any(host_t *host, int family, u_int16_t port)
+{
+ verify_netmask(host->get_address(host), 0);
+ ck_assert(host->is_anyaddr(host));
+ ck_assert_int_eq(host->get_port(host), port);
+ ck_assert_int_eq(host->get_family(host), family);
+}
+
+static void test_create_any(int family)
+{
+ host_t *host;
+
+ host = host_create_any(family);
+ verify_any(host, family, 0);
+ host->destroy(host);
+}
+
+START_TEST(test_create_any_v4)
+{
+ test_create_any(AF_INET);
+}
+END_TEST
+
+START_TEST(test_create_any_v6)
+{
+ test_create_any(AF_INET6);
+}
+END_TEST
+
+START_TEST(test_create_any_other)
+{
+ host_t *host;
+
+ host = host_create_any(AF_UNSPEC);
+ ck_assert(host == NULL);
+}
+END_TEST
+
+/*******************************************************************************
+ * host_create_from_string
+ */
+
+static void verify_address(host_t *host, chunk_t addr, int family, u_int16_t port)
+{
+ ck_assert(chunk_equals(host->get_address(host), addr));
+ ck_assert(!host->is_anyaddr(host));
+ ck_assert_int_eq(host->get_port(host), port);
+ ck_assert_int_eq(host->get_family(host), family);
+}
+
+static const chunk_t addr_v4 = chunk_from_chars(0xc0, 0xa8, 0x00, 0x01);
+static const chunk_t addr_v6 = chunk_from_chars(0xfe, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01);
+
+START_TEST(test_create_from_string_v4)
+{
+ host_t *host;
+
+ host = host_create_from_string("%any", 500);
+ verify_any(host, AF_INET, 500);
+ host->destroy(host);
+
+ host = host_create_from_string("%any4", 500);
+ verify_any(host, AF_INET, 500);
+ host->destroy(host);
+
+ host = host_create_from_string("0.0.0.0", 500);
+ verify_any(host, AF_INET, 500);
+ host->destroy(host);
+
+ host = host_create_from_string("192.168.0.1", 500);
+ verify_address(host, addr_v4, AF_INET, 500);
+ host->destroy(host);
+
+ host = host_create_from_string("192.168.0.1::500", 500);
+ ck_assert(host == NULL);
+ host = host_create_from_string("123.456.789.012", 500);
+ ck_assert(host == NULL);
+ host = host_create_from_string("1.1.1.1.1.1.1.1", 500);
+ ck_assert(host == NULL);
+ host = host_create_from_string("foo.b.a.r", 500);
+ ck_assert(host == NULL);
+}
+END_TEST
+
+START_TEST(test_create_from_string_any_v6)
+{
+ host_t *host;
+
+ host = host_create_from_string("%any6", 500);
+ verify_any(host, AF_INET6, 500);
+ host->destroy(host);
+
+ host = host_create_from_string("::", 500);
+ verify_any(host, AF_INET6, 500);
+ host->destroy(host);
+
+ host = host_create_from_string("fec1::1", 500);
+ verify_address(host, addr_v6, AF_INET6, 500);
+ host->destroy(host);
+
+ host = host_create_from_string("fec1::1.500", 500);
+ ck_assert(host == NULL);
+ host = host_create_from_string("f::e::c::1::1", 500);
+ ck_assert(host == NULL);
+ host = host_create_from_string("foo::bar", 500);
+ ck_assert(host == NULL);
+}
+END_TEST
+
+/*******************************************************************************
+ * host_create_from_string_and_family
+ */
+
+static void test_create_from_string_and_family_any(char *string, int family,
+ int expected)
+{
+ host_t *host;
+
+ host = host_create_from_string_and_family(string, family, 500);
+ if (expected == AF_UNSPEC)
+ {
+ ck_assert(host == NULL);
+ }
+ else
+ {
+ verify_any(host, expected, 500);
+ host->destroy(host);
+ }
+}
+
+static void test_create_from_string_and_family_addr(char *string, chunk_t addr,
+ int family, int expected)
+{
+ host_t *host;
+
+ host = host_create_from_string_and_family(string, family, 500);
+ if (expected == AF_UNSPEC)
+ {
+ ck_assert(host == NULL);
+ }
+ else
+ {
+ verify_address(host, addr, expected, 500);
+ host->destroy(host);
+ }
+}
+
+START_TEST(test_create_from_string_and_family_v4)
+{
+ test_create_from_string_and_family_any("%any", AF_INET, AF_INET);
+ test_create_from_string_and_family_any("%any4", AF_INET, AF_INET);
+ test_create_from_string_and_family_any("0.0.0.0", AF_INET, AF_INET);
+
+ test_create_from_string_and_family_any("%any4", AF_INET6, AF_UNSPEC);
+ test_create_from_string_and_family_any("0.0.0.0", AF_INET6, AF_UNSPEC);
+
+ test_create_from_string_and_family_addr("192.168.0.1", addr_v4, AF_INET, AF_INET);
+ test_create_from_string_and_family_addr("192.168.0.1", addr_v4, AF_INET6, AF_UNSPEC);
+}
+END_TEST
+
+START_TEST(test_create_from_string_and_family_v6)
+{
+ test_create_from_string_and_family_any("%any", AF_INET6, AF_INET6);
+ test_create_from_string_and_family_any("%any6", AF_INET6, AF_INET6);
+ test_create_from_string_and_family_any("::", AF_INET6, AF_INET6);
+
+ test_create_from_string_and_family_any("%any6", AF_INET, AF_UNSPEC);
+ test_create_from_string_and_family_any("::", AF_INET, AF_UNSPEC);
+
+ test_create_from_string_and_family_addr("fec1::1", addr_v6, AF_INET6, AF_INET6);
+ test_create_from_string_and_family_addr("fec1::1", addr_v6, AF_INET, AF_UNSPEC);
+}
+END_TEST
+
+START_TEST(test_create_from_string_and_family_other)
+{
+ test_create_from_string_and_family_any("%any", AF_UNSPEC, AF_INET);
+ test_create_from_string_and_family_any("%any4", AF_UNSPEC, AF_INET);
+ test_create_from_string_and_family_any("0.0.0.0", AF_UNSPEC, AF_INET);
+
+ test_create_from_string_and_family_any("%any6", AF_UNSPEC, AF_INET6);
+ test_create_from_string_and_family_any("::", AF_UNSPEC, AF_INET6);
+
+ test_create_from_string_and_family_addr("192.168.0.1", addr_v4, AF_UNSPEC, AF_INET);
+ test_create_from_string_and_family_addr("fec1::1", addr_v6, AF_UNSPEC, AF_INET6);
+}
+END_TEST
+
+/*******************************************************************************
+ * host_create_from_sockaddr
+ */
+
+START_TEST(test_create_from_sockaddr_v4)
+{
+ struct sockaddr_in addr = {
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ .sin_len = sizeof(struct sockaddr_in),
+#endif
+ .sin_family = AF_INET,
+ .sin_port = htons(500),
+ }, *val;
+ socklen_t *socklen;
+ host_t *host;
+
+ host = host_create_from_sockaddr((sockaddr_t*)&addr);
+ verify_any(host, AF_INET, 500);
+ val = (struct sockaddr_in*)host->get_sockaddr(host);
+ ck_assert(memeq(&addr, val, sizeof(addr)));
+ socklen = host->get_sockaddr_len(host);
+ ck_assert(*socklen == sizeof(addr));
+ host->destroy(host);
+}
+END_TEST
+
+START_TEST(test_create_from_sockaddr_v6)
+{
+ struct sockaddr_in6 addr = {
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ .sin6_len = sizeof(struct sockaddr_in6),
+#endif
+ .sin6_family = AF_INET6,
+ .sin6_port = htons(500),
+ }, *val;
+ socklen_t *socklen;
+ host_t *host;
+
+ host = host_create_from_sockaddr((sockaddr_t*)&addr);
+ verify_any(host, AF_INET6, 500);
+ val = (struct sockaddr_in6*)host->get_sockaddr(host);
+ ck_assert(memeq(&addr, val, sizeof(addr)));
+ socklen = host->get_sockaddr_len(host);
+ ck_assert(*socklen == sizeof(addr));
+ host->destroy(host);
+}
+END_TEST
+
+START_TEST(test_create_from_sockaddr_other)
+{
+ struct sockaddr_un addr = {
+ .sun_family = AF_UNIX,
+ };
+ host_t *host;
+
+ host = host_create_from_sockaddr((sockaddr_t*)&addr);
+ ck_assert(host == NULL);
+}
+END_TEST
+
+/*******************************************************************************
+ * host_create_from_chunk
+ */
+
+START_TEST(test_create_from_chunk_v4)
+{
+ host_t *host;
+
+ host = host_create_from_chunk(AF_INET, addr_v4, 500);
+ verify_address(host, addr_v4, AF_INET, 500);
+ host->destroy(host);
+
+ host = host_create_from_chunk(AF_UNSPEC, addr_v4, 500);
+ verify_address(host, addr_v4, AF_INET, 500);
+ host->destroy(host);
+
+ host = host_create_from_chunk(AF_INET, chunk_empty, 500);
+ ck_assert(host == NULL);
+ host = host_create_from_chunk(AF_UNSPEC, chunk_empty, 500);
+ ck_assert(host == NULL);
+}
+END_TEST
+
+START_TEST(test_create_from_chunk_v6)
+{
+ host_t *host;
+
+ host = host_create_from_chunk(AF_INET6, addr_v6, 500);
+ verify_address(host, addr_v6, AF_INET6, 500);
+ host->destroy(host);
+
+ host = host_create_from_chunk(AF_UNSPEC, addr_v6, 500);
+ verify_address(host, addr_v6, AF_INET6, 500);
+ host->destroy(host);
+
+ host = host_create_from_chunk(AF_INET6, chunk_empty, 500);
+ ck_assert(host == NULL);
+}
+END_TEST
+
+START_TEST(test_create_from_chunk_other)
+{
+ host_t *host;
+
+ host = host_create_from_chunk(AF_UNIX, addr_v6, 500);
+ ck_assert(host == NULL);
+}
+END_TEST
+
+/*******************************************************************************
+ * host_create_from_subnet
+ */
+
+START_TEST(test_create_from_subnet_v4)
+{
+ host_t *host;
+ int bits = -1;
+
+ host = host_create_from_subnet("0.0.0.0/0", &bits);
+ verify_any(host, AF_INET, 0);
+ ck_assert_int_eq(bits, 0);
+ host->destroy(host);
+
+ host = host_create_from_subnet("192.168.0.1", &bits);
+ verify_address(host, addr_v4, AF_INET, 0);
+ ck_assert_int_eq(bits, 32);
+ host->destroy(host);
+
+ host = host_create_from_subnet("192.168.0.1/24", &bits);
+ verify_address(host, addr_v4, AF_INET, 0);
+ ck_assert_int_eq(bits, 24);
+ host->destroy(host);
+
+ host = host_create_from_subnet("foo.b.a.r", &bits);
+ ck_assert(host == NULL);
+}
+END_TEST
+
+START_TEST(test_create_from_subnet_v6)
+{
+ host_t *host;
+ int bits = -1;
+
+ host = host_create_from_subnet("::/0", &bits);
+ verify_any(host, AF_INET6, 0);
+ ck_assert_int_eq(bits, 0);
+ host->destroy(host);
+
+ host = host_create_from_subnet("fec1::1", &bits);
+ verify_address(host, addr_v6, AF_INET6, 0);
+ ck_assert_int_eq(bits, 128);
+ host->destroy(host);
+
+ host = host_create_from_subnet("fec1::1/64", &bits);
+ verify_address(host, addr_v6, AF_INET6, 0);
+ ck_assert_int_eq(bits, 64);
+ host->destroy(host);
+
+ host = host_create_from_subnet("foo::bar", &bits);
+ ck_assert(host == NULL);
+}
+END_TEST
+
+/*******************************************************************************
+ * host_create_netmask
+ */
+
+static void test_create_netmask(int family)
+{
+ host_t *netmask;
+ int i, len = (family == AF_INET) ? 32 : 128;
+
+ netmask = host_create_netmask(family, -1);
+ ck_assert(netmask == NULL);
+ for (i = 0; i <= len; i++)
+ {
+ netmask = host_create_netmask(family, i);
+ verify_netmask(netmask->get_address(netmask), i);
+ netmask->destroy(netmask);
+ }
+ netmask = host_create_netmask(family, len + 1);
+ ck_assert(netmask == NULL);
+}
+
+START_TEST(test_create_netmask_v4)
+{
+ test_create_netmask(AF_INET);
+}
+END_TEST
+
+START_TEST(test_create_netmask_v6)
+{
+ test_create_netmask(AF_INET6);
+}
+END_TEST
+
+START_TEST(test_create_netmask_other)
+{
+ host_t *netmask;
+
+ netmask = host_create_netmask(AF_UNSPEC, 0);
+ ck_assert(netmask == NULL);
+}
+END_TEST
+
+/*******************************************************************************
+ * equals, ip_equals
+ */
+
+START_TEST(test_equals)
+{
+ host_t *a, *b;
+
+ a = host_create_from_string("192.168.0.1", 500);
+ b = host_create_from_string("192.168.0.1", 0);
+ ck_assert(!a->equals(a, b));
+ ck_assert(!b->equals(b, a));
+ ck_assert(a->ip_equals(a, b));
+ ck_assert(b->ip_equals(b, a));
+ b->set_port(b, 500);
+ ck_assert(a->equals(a, b));
+ ck_assert(b->equals(b, a));
+ ck_assert(a->ip_equals(a, b));
+ ck_assert(b->ip_equals(b, a));
+ b->destroy(b);
+ b = host_create_from_string("192.168.0.2", 500);
+ ck_assert(!a->ip_equals(a, b));
+ ck_assert(!a->equals(a, b));
+ b->destroy(b);
+
+ b = host_create_from_string("fec1::1", 500);
+ ck_assert(!a->ip_equals(a, b));
+ ck_assert(!a->equals(a, b));
+ a->destroy(a);
+ a = host_create_from_string("fec1::1", 500);
+ ck_assert(a->equals(a, b));
+ ck_assert(a->ip_equals(a, b));
+ a->destroy(a);
+ b->destroy(b);
+}
+END_TEST
+
+START_TEST(test_equals_any)
+{
+ host_t *a, *b;
+
+ a = host_create_from_string("%any", 500);
+ b = host_create_from_string("%any", 0);
+ ck_assert(!a->equals(a, b));
+ ck_assert(a->ip_equals(a, b));
+ b->set_port(b, 500);
+ ck_assert(a->equals(a, b));
+ ck_assert(a->ip_equals(a, b));
+ b->destroy(b);
+ b = host_create_from_string("%any6", 0);
+ ck_assert(a->ip_equals(a, b));
+ ck_assert(!a->equals(a, b));
+ b->set_port(b, 500);
+ ck_assert(a->ip_equals(a, b));
+ ck_assert(a->equals(a, b));
+ a->destroy(a);
+ b->destroy(b);
+}
+END_TEST
+
+/*******************************************************************************
+ * clone
+ */
+
+START_TEST(test_clone)
+{
+ host_t *a, *b;
+
+ a = host_create_from_string("192.168.0.1", 500);
+ b = a->clone(a);
+ ck_assert(a != b);
+ ck_assert(a->equals(a, b));
+ a->destroy(a);
+ b->destroy(b);
+}
+END_TEST
+
+/*******************************************************************************
+ * printf hook
+ */
+
+static struct {
+ char *addr;
+ u_int16_t port;
+ /* results for %H, %+H, %#H (falls back to [0]) */
+ char *result[3];
+} printf_data[] = {
+ {NULL, 0, { "(null)" }},
+ {NULL, 500, { "(null)" }},
+ {"%any", 0, { "%any", "0.0.0.0", "0.0.0.0[0]" }},
+ {"%any", 500, { "%any", "0.0.0.0", "0.0.0.0[500]" }},
+ {"%any6", 0, { "%any6", "::", "::[0]" }},
+ {"%any6", 500, { "%any6", "::", "::[500]" }},
+ {"192.168.0.1", 0, { "192.168.0.1", "192.168.0.1", "192.168.0.1[0]" }},
+ {"192.168.0.1", 500, { "192.168.0.1", "192.168.0.1", "192.168.0.1[500]" }},
+ {"fec1::1", 0, { "fec1::1", "fec1::1", "fec1::1[0]" }},
+ {"fec1::1", 500, { "fec1::1", "fec1::1", "fec1::1[500]" }},
+};
+
+static void verify_printf(host_t *host, const char *format, char *expected)
+{
+ char buf[64];
+
+ snprintf(buf, sizeof(buf), format, host);
+ ck_assert_str_eq(expected, buf);
+}
+
+START_TEST(test_printf_hook)
+{
+ static const char *formats[] = { "%H", "%+H", "%#H" };
+ host_t *host = NULL;
+ char *expected;
+ int i;
+
+ if (printf_data[_i].addr)
+ {
+ host = host_create_from_string(printf_data[_i].addr,
+ printf_data[_i].port);
+ }
+ for (i = 0; i < countof(formats); i++)
+ {
+ expected = printf_data[_i].result[i];
+ expected = expected ?: printf_data[_i].result[0];
+ verify_printf(host, formats[i], expected);
+ }
+ DESTROY_IF(host);
+}
+END_TEST
+
+START_TEST(test_printf_hook_align)
+{
+ host_t *host;
+
+ verify_printf(NULL, "%14H", " (null)");
+ verify_printf(NULL, "%-14H", "(null) ");
+
+ host = host_create_from_string("192.168.0.1", 0);
+ verify_printf(host, "%14H", " 192.168.0.1");
+ verify_printf(host, "%-14H", "192.168.0.1 ");
+ verify_printf(host, "%4H", "192.168.0.1");
+ verify_printf(host, "%-4H", "192.168.0.1");
+ host->destroy(host);
+}
+END_TEST
+
+Suite *host_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("host");
+
+ tc = tcase_create("host_create_any");
+ tcase_add_test(tc, test_create_any_v4);
+ tcase_add_test(tc, test_create_any_v6);
+ tcase_add_test(tc, test_create_any_other);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("host_create_from_string");
+ tcase_add_test(tc, test_create_from_string_v4);
+ tcase_add_test(tc, test_create_from_string_any_v6);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("host_create_from_string_and_family");
+ tcase_add_test(tc, test_create_from_string_and_family_v4);
+ tcase_add_test(tc, test_create_from_string_and_family_v6);
+ tcase_add_test(tc, test_create_from_string_and_family_other);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("host_create_from_sockaddr");
+ tcase_add_test(tc, test_create_from_sockaddr_v4);
+ tcase_add_test(tc, test_create_from_sockaddr_v6);
+ tcase_add_test(tc, test_create_from_sockaddr_other);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("host_create_from_chunk");
+ tcase_add_test(tc, test_create_from_chunk_v4);
+ tcase_add_test(tc, test_create_from_chunk_v6);
+ tcase_add_test(tc, test_create_from_chunk_other);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("host_create_from_subnet");
+ tcase_add_test(tc, test_create_from_subnet_v4);
+ tcase_add_test(tc, test_create_from_subnet_v6);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("host_create_netmask");
+ tcase_add_test(tc, test_create_netmask_v4);
+ tcase_add_test(tc, test_create_netmask_v6);
+ tcase_add_test(tc, test_create_netmask_other);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("equals, ip_equals");
+ tcase_add_test(tc, test_equals);
+ tcase_add_test(tc, test_equals_any);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("clone");
+ tcase_add_test(tc, test_clone);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("printf hook");
+ tcase_add_loop_test(tc, test_printf_hook, 0, countof(printf_data));
+ tcase_add_test(tc, test_printf_hook_align);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_identification.c b/src/libstrongswan/tests/suites/test_identification.c
new file mode 100644
index 000000000..edf53f0fd
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_identification.c
@@ -0,0 +1,857 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * Copyright (C) 2009 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 "test_suite.h"
+
+#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 = chunk_empty;
+ 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
+ */
+
+static bool id_equals(identification_t *a, char *b_str)
+{
+ identification_t *b;
+ bool equals;
+
+ b = identification_create_from_string(b_str);
+ equals = a->equals(a, b);
+ ck_assert_int_eq(equals, b->equals(b, a));
+ b->destroy(b);
+ return equals;
+}
+
+START_TEST(test_equals)
+{
+ identification_t *a;
+ chunk_t encoding, fuzzed;
+ int i;
+
+ /* this test also tests identification_create_from_string with DNs */
+ a = identification_create_from_string(
+ "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);
+
+ /* simple fuzzing, increment each byte of encoding */
+ for (i = 0; i < encoding.len; i++)
+ {
+ 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);
+ 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);
+ }
+
+ /* and decrement each byte of encoding */
+ for (i = 0; i < encoding.len; i++)
+ {
+ 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=moon@strongswan.org, CN=moon"));
+ a->destroy(a);
+ free(fuzzed.ptr);
+ }
+ free(encoding.ptr);
+}
+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
+
+START_TEST(test_equals_empty)
+{
+ identification_t *a;
+
+ a = identification_create_from_encoding(_i, chunk_empty);
+
+ switch (_i)
+ {
+ case ID_ANY:
+ ck_assert(id_equals(a, "%any"));
+ break;
+ case ID_IPV4_ADDR:
+ ck_assert(!id_equals(a, "192.168.1.1"));
+ break;
+ case ID_FQDN:
+ ck_assert(!id_equals(a, "moon.strongswan.org"));
+ break;
+ case ID_USER_FQDN:
+ ck_assert(!id_equals(a, "moon@strongswan.org"));
+ break;
+ case ID_IPV6_ADDR:
+ ck_assert(!id_equals(a, "fec0::1"));
+ break;
+ case ID_DER_ASN1_DN:
+ ck_assert(!id_equals(a, "C=CH, E=moon@strongswan.org, CN=moon"));
+ break;
+ case ID_KEY_ID:
+ ck_assert(!id_equals(a, "@#12345678"));
+ break;
+ case ID_DER_ASN1_GN:
+ case ID_IPV4_ADDR_SUBNET:
+ case ID_IPV6_ADDR_SUBNET:
+ case ID_IPV4_ADDR_RANGE:
+ case ID_IPV6_ADDR_RANGE:
+ /* currently not tested */
+ break;
+ }
+
+ a->destroy(a);
+}
+END_TEST
+
+/*******************************************************************************
+ * matches
+ */
+
+static bool id_matches(identification_t *a, char *b_str, id_match_t expected)
+{
+ identification_t *b;
+ id_match_t match;
+
+ b = identification_create_from_string(b_str);
+ match = a->matches(a, b);
+ b->destroy(b);
+ return match == expected;
+}
+
+START_TEST(test_matches)
+{
+ identification_t *a;
+
+ a = identification_create_from_string("C=CH, E=moon@strongswan.org, CN=moon");
+
+ 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
+
+START_TEST(test_matches_empty)
+{
+ identification_t *a;
+
+ a = identification_create_from_encoding(_i, chunk_empty);
+
+ switch (_i)
+ {
+ case ID_ANY:
+ ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
+ break;
+ case ID_IPV4_ADDR:
+ ck_assert(id_matches(a, "192.168.1.1", ID_MATCH_NONE));
+ break;
+ case ID_FQDN:
+ ck_assert(id_matches(a, "moon.strongswan.org", ID_MATCH_NONE));
+ break;
+ case ID_USER_FQDN:
+ ck_assert(id_matches(a, "moon@strongswan.org", ID_MATCH_NONE));
+ break;
+ case ID_IPV6_ADDR:
+ ck_assert(id_matches(a, "fec0::1", ID_MATCH_NONE));
+ break;
+ case ID_DER_ASN1_DN:
+ ck_assert(id_matches(a, "C=CH, E=moon@strongswan.org, CN=moon",
+ ID_MATCH_NONE));
+ break;
+ case ID_KEY_ID:
+ ck_assert(id_matches(a, "@#12345678", ID_MATCH_NONE));
+ break;
+ case ID_DER_ASN1_GN:
+ case ID_IPV4_ADDR_SUBNET:
+ case ID_IPV6_ADDR_SUBNET:
+ case ID_IPV4_ADDR_RANGE:
+ case ID_IPV6_ADDR_RANGE:
+ /* currently not tested */
+ break;
+ }
+
+ a->destroy(a);
+}
+END_TEST
+
+static bool id_matches_rev(identification_t *a, char *b_str, id_match_t expected)
+{
+ identification_t *b;
+ id_match_t match;
+
+ b = identification_create_from_string(b_str);
+ match = b->matches(b, a);
+ b->destroy(b);
+ return match == expected;
+}
+
+START_TEST(test_matches_empty_reverse)
+{
+ identification_t *a;
+
+ a = identification_create_from_encoding(_i, chunk_empty);
+
+ switch (_i)
+ {
+ case ID_ANY:
+ ck_assert(id_matches_rev(a, "%any", ID_MATCH_ANY));
+ break;
+ case ID_IPV4_ADDR:
+ ck_assert(id_matches_rev(a, "192.168.1.1", ID_MATCH_NONE));
+ break;
+ case ID_FQDN:
+ ck_assert(id_matches_rev(a, "moon.strongswan.org", ID_MATCH_NONE));
+ break;
+ case ID_USER_FQDN:
+ ck_assert(id_matches_rev(a, "moon@strongswan.org", ID_MATCH_NONE));
+ break;
+ case ID_IPV6_ADDR:
+ ck_assert(id_matches_rev(a, "fec0::1", ID_MATCH_NONE));
+ break;
+ case ID_DER_ASN1_DN:
+ ck_assert(id_matches_rev(a, "C=CH, E=moon@strongswan.org, CN=moon",
+ ID_MATCH_NONE));
+ break;
+ case ID_KEY_ID:
+ ck_assert(id_matches_rev(a, "@#12345678", ID_MATCH_NONE));
+ break;
+ case ID_DER_ASN1_GN:
+ case ID_IPV4_ADDR_SUBNET:
+ case ID_IPV6_ADDR_SUBNET:
+ case ID_IPV4_ADDR_RANGE:
+ case ID_IPV6_ADDR_RANGE:
+ /* currently not tested */
+ break;
+ }
+
+ a->destroy(a);
+}
+END_TEST
+
+/*******************************************************************************
+ * identification part enumeration
+ */
+
+START_TEST(test_parts)
+{
+ identification_t *id;
+ enumerator_t *enumerator;
+ id_part_t part;
+ chunk_t data;
+ int i = 0;
+
+ id = identification_create_from_string("C=CH, O=strongSwan, CN=tester");
+
+ enumerator = id->create_part_enumerator(id);
+ while (enumerator->enumerate(enumerator, &part, &data))
+ {
+ switch (i++)
+ {
+ case 0:
+ ck_assert(part == ID_PART_RDN_C &&
+ chunk_equals(data, chunk_create("CH", 2)));
+ break;
+ case 1:
+ ck_assert(part == ID_PART_RDN_O &&
+ chunk_equals(data, chunk_from_str("strongSwan")));
+ break;
+ case 2:
+ ck_assert(part == ID_PART_RDN_CN &&
+ chunk_equals(data, chunk_from_str("tester")));
+ break;
+ default:
+ fail("unexpected identification part %d", part);
+ }
+ }
+ ck_assert_int_eq(i, 3);
+ enumerator->destroy(enumerator);
+ id->destroy(id);
+}
+END_TEST
+
+/*******************************************************************************
+ * wildcards
+ */
+
+static bool id_contains_wildcards(char *string)
+{
+ identification_t *id;
+ bool contains;
+
+ id = identification_create_from_string(string);
+ contains = id->contains_wildcards(id);
+ id->destroy(id);
+ return contains;
+}
+
+START_TEST(test_contains_wildcards)
+{
+ ck_assert(id_contains_wildcards("%any"));
+ ck_assert(id_contains_wildcards("C=*, O=strongSwan, CN=gw"));
+ ck_assert(id_contains_wildcards("C=CH, O=strongSwan, CN=*"));
+ ck_assert(id_contains_wildcards("*@strongswan.org"));
+ ck_assert(id_contains_wildcards("*.strongswan.org"));
+ ck_assert(!id_contains_wildcards("C=**, O=a*, CN=*a"));
+}
+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;
+ TCase *tc;
+
+ 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);
+ tcase_add_loop_test(tc, test_equals_empty, ID_ANY, ID_KEY_ID + 1);
+ 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);
+ tcase_add_loop_test(tc, test_matches_empty, ID_ANY, ID_KEY_ID + 1);
+ tcase_add_loop_test(tc, test_matches_empty_reverse, ID_ANY, ID_KEY_ID + 1);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("part enumeration");
+ tcase_add_test(tc, test_parts);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("wildcards");
+ 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;
+}
diff --git a/src/libstrongswan/tests/suites/test_linked_list.c b/src/libstrongswan/tests/suites/test_linked_list.c
new file mode 100644
index 000000000..922f954e3
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_linked_list.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * 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 "test_suite.h"
+
+#include <collections/linked_list.h>
+
+/*******************************************************************************
+ * test fixture
+ */
+
+static linked_list_t *list;
+
+START_SETUP(setup_list)
+{
+ void *x = NULL;
+
+ list = linked_list_create();
+ ck_assert_int_eq(list->get_count(list), 0);
+ ck_assert(list->get_first(list, &x) == NOT_FOUND);
+ ck_assert(list->get_last(list, &x) == NOT_FOUND);
+}
+END_SETUP
+
+START_TEARDOWN(teardown_list)
+{
+ list->destroy(list);
+}
+END_TEARDOWN
+
+/*******************************************************************************
+ * insert first/last
+ */
+
+START_TEST(test_insert_first)
+{
+ void *a = (void*)1, *b = (void*)2, *x = NULL;
+
+ list->insert_first(list, a);
+ ck_assert_int_eq(list->get_count(list), 1);
+ ck_assert(list->get_first(list, &x) == SUCCESS);
+ ck_assert(x == a);
+ ck_assert(list->get_last(list, &x) == SUCCESS);
+ ck_assert(x == a);
+
+ list->insert_first(list, b);
+ ck_assert_int_eq(list->get_count(list), 2);
+ ck_assert(list->get_first(list, &x) == SUCCESS);
+ ck_assert(x == b);
+ ck_assert(list->get_last(list, &x) == SUCCESS);
+ ck_assert(x == a);
+}
+END_TEST
+
+START_TEST(test_insert_last)
+{
+ void *a = (void*)1, *b = (void*)2, *x = NULL;
+
+ list->insert_last(list, a);
+ ck_assert_int_eq(list->get_count(list), 1);
+ ck_assert(list->get_first(list, &x) == SUCCESS);
+ ck_assert(x == a);
+ ck_assert(list->get_last(list, &x) == SUCCESS);
+ ck_assert(x == a);
+
+ list->insert_last(list, b);
+ ck_assert_int_eq(list->get_count(list), 2);
+ ck_assert(list->get_first(list, &x) == SUCCESS);
+ ck_assert(x == a);
+ ck_assert(list->get_last(list, &x) == SUCCESS);
+ ck_assert(x == b);
+}
+END_TEST
+
+/*******************************************************************************
+ * remove first/last
+ */
+
+START_TEST(test_remove_first)
+{
+ void *a = (void*)1, *b = (void*)2, *x = NULL;
+
+ list->insert_first(list, a);
+ list->insert_first(list, b);
+ ck_assert(list->remove_first(list, &x) == SUCCESS);
+ ck_assert_int_eq(list->get_count(list), 1);
+ ck_assert(x == b);
+ ck_assert(list->remove_first(list, &x) == SUCCESS);
+ ck_assert_int_eq(list->get_count(list), 0);
+ ck_assert(x == a);
+ ck_assert(list->remove_first(list, &x) == NOT_FOUND);
+ ck_assert(list->remove_last(list, &x) == NOT_FOUND);
+}
+END_TEST
+
+START_TEST(test_remove_last)
+{
+ void *a = (void*)1, *b = (void*)2, *x = NULL;
+
+ list->insert_first(list, a);
+ list->insert_first(list, b);
+ ck_assert(list->remove_last(list, &x) == SUCCESS);
+ ck_assert_int_eq(list->get_count(list), 1);
+ ck_assert(x == a);
+ ck_assert(list->remove_last(list, &x) == SUCCESS);
+ ck_assert_int_eq(list->get_count(list), 0);
+ ck_assert(x == b);
+ ck_assert(list->remove_first(list, &x) == NOT_FOUND);
+ ck_assert(list->remove_last(list, &x) == NOT_FOUND);
+}
+END_TEST
+
+/*******************************************************************************
+ * helper function for remove and find tests
+ */
+
+static bool match_a(void *item, void *a)
+{
+ ck_assert(a == (void*)1);
+ return item == a;
+}
+
+static bool match_b(void *item, void *b)
+{
+ ck_assert(b == (void*)2);
+ return item == b;
+}
+
+/*******************************************************************************
+ * remove
+ */
+
+START_TEST(test_remove)
+{
+ void *a = (void*)1, *b = (void*)2;
+
+ list->insert_first(list, a);
+ ck_assert(list->remove(list, a, NULL) == 1);
+ ck_assert_int_eq(list->get_count(list), 0);
+
+ list->insert_last(list, a);
+ list->insert_last(list, a);
+ list->insert_last(list, a);
+ list->insert_last(list, b);
+ ck_assert(list->remove(list, a, NULL) == 3);
+ ck_assert(list->remove(list, a, NULL) == 0);
+ ck_assert_int_eq(list->get_count(list), 1);
+ ck_assert(list->remove(list, b, NULL) == 1);
+ ck_assert(list->remove(list, b, NULL) == 0);
+}
+END_TEST
+
+START_TEST(test_remove_callback)
+{
+ void *a = (void*)1, *b = (void*)2;
+
+ list->insert_last(list, a);
+ list->insert_last(list, b);
+ list->insert_last(list, a);
+ list->insert_last(list, b);
+ ck_assert(list->remove(list, a, match_a) == 2);
+ ck_assert(list->remove(list, a, match_a) == 0);
+ ck_assert_int_eq(list->get_count(list), 2);
+ ck_assert(list->remove(list, b, match_b) == 2);
+ ck_assert(list->remove(list, b, match_b) == 0);
+ ck_assert_int_eq(list->get_count(list), 0);
+}
+END_TEST
+
+/*******************************************************************************
+ * find
+ */
+
+static bool match_a_b(void *item, void *a, void *b)
+{
+ ck_assert(a == (void*)1);
+ ck_assert(b == (void*)2);
+ return item == a || item == b;
+}
+
+START_TEST(test_find)
+{
+ void *a = (void*)1, *b = (void*)2;
+
+ ck_assert(list->find_first(list, NULL, &a) == NOT_FOUND);
+ list->insert_last(list, a);
+ ck_assert(list->find_first(list, NULL, &a) == SUCCESS);
+ ck_assert(list->find_first(list, NULL, &b) == NOT_FOUND);
+ list->insert_last(list, b);
+ ck_assert(list->find_first(list, NULL, &a) == SUCCESS);
+ ck_assert(list->find_first(list, NULL, &b) == SUCCESS);
+
+ ck_assert(list->find_first(list, NULL, NULL) == NOT_FOUND);
+}
+END_TEST
+
+START_TEST(test_find_callback)
+{
+ void *a = (void*)1, *b = (void*)2, *x = NULL;
+
+ ck_assert(list->find_first(list, (linked_list_match_t)match_a_b, &x, a, b) == NOT_FOUND);
+ list->insert_last(list, a);
+ ck_assert(list->find_first(list, (linked_list_match_t)match_a, NULL, a) == SUCCESS);
+ x = NULL;
+ ck_assert(list->find_first(list, (linked_list_match_t)match_a, &x, a) == SUCCESS);
+ ck_assert(a == x);
+ ck_assert(list->find_first(list, (linked_list_match_t)match_b, &x, b) == NOT_FOUND);
+ ck_assert(a == x);
+ x = NULL;
+ ck_assert(list->find_first(list, (linked_list_match_t)match_a_b, &x, a, b) == SUCCESS);
+ ck_assert(a == x);
+
+ list->insert_last(list, b);
+ ck_assert(list->find_first(list, (linked_list_match_t)match_a, &x, a) == SUCCESS);
+ ck_assert(a == x);
+ ck_assert(list->find_first(list, (linked_list_match_t)match_b, &x, b) == SUCCESS);
+ ck_assert(b == x);
+ x = NULL;
+ ck_assert(list->find_first(list, (linked_list_match_t)match_a_b, &x, a, b) == SUCCESS);
+ ck_assert(a == x);
+}
+END_TEST
+
+/*******************************************************************************
+ * invoke
+ */
+
+typedef struct invoke_t invoke_t;
+
+struct invoke_t {
+ int val;
+ void (*invoke)(invoke_t *item, void *a, void *b, void *c, void *d, int *sum);
+};
+
+static void invoke(intptr_t item, void *a, void *b, void *c, void *d, int *sum)
+{
+ ck_assert_int_eq((uintptr_t)a, 1);
+ ck_assert_int_eq((uintptr_t)b, 2);
+ ck_assert_int_eq((uintptr_t)c, 3);
+ ck_assert_int_eq((uintptr_t)d, 4);
+ *sum += item;
+}
+
+static void invoke_offset(invoke_t *item, void *a, void *b, void *c, void *d, int *sum)
+{
+ invoke(item->val, a, b, c, d, sum);
+}
+
+START_TEST(test_invoke_function)
+{
+ int sum = 0;
+
+ list->insert_last(list, (void*)1);
+ list->insert_last(list, (void*)2);
+ list->insert_last(list, (void*)3);
+ list->insert_last(list, (void*)4);
+ list->insert_last(list, (void*)5);
+ list->invoke_function(list, (linked_list_invoke_t)invoke,
+ (uintptr_t)1, (uintptr_t)2,
+ (uintptr_t)3, (uintptr_t)4, &sum);
+ ck_assert_int_eq(sum, 15);
+}
+END_TEST
+
+START_TEST(test_invoke_offset)
+{
+ invoke_t items[] = {
+ { .val = 1, .invoke = invoke_offset, },
+ { .val = 2, .invoke = invoke_offset, },
+ { .val = 3, .invoke = invoke_offset, },
+ { .val = 4, .invoke = invoke_offset, },
+ { .val = 5, .invoke = invoke_offset, },
+ };
+ int i, sum = 0;
+
+ for (i = 0; i < countof(items); i++)
+ {
+ list->insert_last(list, &items[i]);
+ }
+ list->invoke_offset(list, offsetof(invoke_t, invoke),
+ (uintptr_t)1, (uintptr_t)2,
+ (uintptr_t)3, (uintptr_t)4, &sum);
+ ck_assert_int_eq(sum, 15);
+}
+END_TEST
+
+/*******************************************************************************
+ * clone
+ */
+
+typedef struct clone_t clone_t;
+
+struct clone_t {
+ void *val;
+ void *(*clone)(clone_t *item);
+};
+
+static void *clonefn(clone_t *item)
+{
+ return item->val;
+}
+
+static void test_clone(linked_list_t *list)
+{
+ intptr_t x;
+ int round = 1;
+
+ ck_assert_int_eq(list->get_count(list), 5);
+ while (list->remove_first(list, (void*)&x) == SUCCESS)
+ {
+ ck_assert_int_eq(round, x);
+ round++;
+ }
+ ck_assert_int_eq(round, 6);
+}
+
+START_TEST(test_clone_offset)
+{
+ linked_list_t *other;
+ clone_t items[] = {
+ { .val = (void*)1, .clone = clonefn, },
+ { .val = (void*)2, .clone = clonefn, },
+ { .val = (void*)3, .clone = clonefn, },
+ { .val = (void*)4, .clone = clonefn, },
+ { .val = (void*)5, .clone = clonefn, },
+ };
+ int i;
+
+ for (i = 0; i < countof(items); i++)
+ {
+ list->insert_last(list, &items[i]);
+ }
+ other = list->clone_offset(list, offsetof(clone_t, clone));
+ test_clone(other);
+ other->destroy(other);
+}
+END_TEST
+
+Suite *linked_list_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("linked list");
+
+ tc = tcase_create("insert/get");
+ tcase_add_checked_fixture(tc, setup_list, teardown_list);
+ tcase_add_test(tc, test_insert_first);
+ tcase_add_test(tc, test_insert_last);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("remove");
+ tcase_add_checked_fixture(tc, setup_list, teardown_list);
+ tcase_add_test(tc, test_remove_first);
+ tcase_add_test(tc, test_remove_last);
+ tcase_add_test(tc, test_remove);
+ tcase_add_test(tc, test_remove_callback);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("find");
+ tcase_add_checked_fixture(tc, setup_list, teardown_list);
+ tcase_add_test(tc, test_find);
+ tcase_add_test(tc, test_find_callback);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("invoke");
+ tcase_add_checked_fixture(tc, setup_list, teardown_list);
+ tcase_add_test(tc, test_invoke_function);
+ tcase_add_test(tc, test_invoke_offset);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("clone");
+ tcase_add_checked_fixture(tc, setup_list, teardown_list);
+ tcase_add_test(tc, test_clone_offset);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_linked_list_enumerator.c b/src/libstrongswan/tests/suites/test_linked_list_enumerator.c
new file mode 100644
index 000000000..48d6f40e6
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_linked_list_enumerator.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * 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 "test_suite.h"
+
+#include <collections/linked_list.h>
+
+/*******************************************************************************
+ * test fixture
+ */
+
+static linked_list_t *list;
+
+START_SETUP(setup_list)
+{
+ list = linked_list_create_with_items((void*)1, (void*)2, (void*)3, (void*)4,
+ (void*)5, NULL);
+ ck_assert_int_eq(list->get_count(list), 5);
+}
+END_SETUP
+
+START_TEARDOWN(teardown_list)
+{
+ list->destroy(list);
+}
+END_TEARDOWN
+
+/*******************************************************************************
+ * enumeration
+ */
+
+START_TEST(test_enumerate)
+{
+ enumerator_t *enumerator;
+ intptr_t x;
+ int round;
+
+ round = 1;
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ ck_assert_int_eq(round, x);
+ round++;
+ }
+ ck_assert_int_eq(round, 6);
+ enumerator->destroy(enumerator);
+}
+END_TEST
+
+START_TEST(test_enumerate_null)
+{
+ enumerator_t *enumerator;
+ int round;
+
+ round = 1;
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, NULL))
+ {
+ round++;
+ }
+ ck_assert_int_eq(round, 6);
+ enumerator->destroy(enumerator);
+}
+END_TEST
+
+START_TEST(test_reset_enumerator)
+{
+ enumerator_t *enumerator;
+ intptr_t x;
+ int round;
+
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ }
+ list->reset_enumerator(list, enumerator);
+ round = 1;
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ ck_assert_int_eq(round, x);
+ round++;
+ }
+ ck_assert_int_eq(round, 6);
+ enumerator->destroy(enumerator);
+}
+END_TEST
+
+/*******************************************************************************
+ * insert before
+ */
+
+START_TEST(test_insert_before)
+{
+ enumerator_t *enumerator;
+ intptr_t x;
+ int round;
+
+ round = 1;
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ ck_assert_int_eq(round, x);
+ round++;
+ if (x == _i)
+ {
+ list->insert_before(list, enumerator, (void*)6);
+ }
+ }
+ ck_assert_int_eq(list->get_count(list), 6);
+ list->reset_enumerator(list, enumerator);
+ round = 1;
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ if (round == _i && x != _i)
+ {
+ ck_assert_int_eq(6, x);
+ }
+ else
+ {
+ ck_assert_int_eq(round, x);
+ round++;
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+END_TEST
+
+START_TEST(test_insert_before_ends)
+{
+ enumerator_t *enumerator;
+ intptr_t x;
+ int round;
+
+ enumerator = list->create_enumerator(list);
+ list->insert_before(list, enumerator, (void*)0);
+ ck_assert_int_eq(list->get_count(list), 6);
+ ck_assert(list->get_first(list, (void*)&x) == SUCCESS);
+ ck_assert_int_eq(x, 0);
+ round = 0;
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ ck_assert_int_eq(round, x);
+ round++;
+ }
+ list->insert_before(list, enumerator, (void*)6);
+ ck_assert_int_eq(list->get_count(list), 7);
+ ck_assert(list->get_last(list, (void*)&x) == SUCCESS);
+ ck_assert_int_eq(x, 6);
+ ck_assert(!enumerator->enumerate(enumerator, &x));
+ enumerator->destroy(enumerator);
+}
+END_TEST
+
+START_TEST(test_insert_before_empty)
+{
+ enumerator_t *enumerator;
+ intptr_t x;
+
+ list->destroy(list);
+ list = linked_list_create();
+ enumerator = list->create_enumerator(list);
+ list->insert_before(list, enumerator, (void*)1);
+ ck_assert_int_eq(list->get_count(list), 1);
+ ck_assert(list->get_first(list, (void*)&x) == SUCCESS);
+ ck_assert_int_eq(x, 1);
+ ck_assert(list->get_last(list, (void*)&x) == SUCCESS);
+ ck_assert_int_eq(x, 1);
+ ck_assert(enumerator->enumerate(enumerator, &x));
+ ck_assert_int_eq(x, 1);
+ ck_assert(!enumerator->enumerate(enumerator, NULL));
+ enumerator->destroy(enumerator);
+}
+END_TEST
+
+/*******************************************************************************
+ * remove_at
+ */
+
+START_TEST(test_remove_at)
+{
+ enumerator_t *enumerator;
+ intptr_t x;
+ int round;
+
+ round = 1;
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ ck_assert_int_eq(round, x);
+ if (round == 2)
+ {
+ list->remove_at(list, enumerator);
+ }
+ round++;
+ }
+ ck_assert_int_eq(list->get_count(list), 4);
+ list->reset_enumerator(list, enumerator);
+ round = 1;
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ if (round == 2)
+ { /* skip removed item */
+ round++;
+ }
+ ck_assert_int_eq(round, x);
+ round++;
+ }
+ enumerator->destroy(enumerator);
+}
+END_TEST
+
+START_TEST(test_remove_at_ends)
+{
+ enumerator_t *enumerator;
+ intptr_t x;
+
+ enumerator = list->create_enumerator(list);
+ list->remove_at(list, enumerator);
+ ck_assert_int_eq(list->get_count(list), 5);
+ ck_assert(list->get_first(list, (void*)&x) == SUCCESS);
+ ck_assert_int_eq(x, 1);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ }
+ list->remove_at(list, enumerator);
+ ck_assert_int_eq(list->get_count(list), 5);
+ ck_assert(list->get_last(list, (void*)&x) == SUCCESS);
+ ck_assert_int_eq(x, 5);
+ enumerator->destroy(enumerator);
+}
+END_TEST
+
+START_TEST(test_insert_before_remove_at)
+{
+ enumerator_t *enumerator;
+ intptr_t x;
+ int round;
+
+ round = 1;
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ ck_assert_int_eq(round, x);
+ if (round == 2)
+ { /* this replaces the current item, as insert_before does not change
+ * the enumerator position */
+ list->insert_before(list, enumerator, (void*)42);
+ list->remove_at(list, enumerator);
+ }
+ else if (round == 4)
+ { /* this does not replace the item, as remove_at moves the enumerator
+ * position to the previous item */
+ list->remove_at(list, enumerator);
+ list->insert_before(list, enumerator, (void*)21);
+ }
+ round++;
+ }
+ ck_assert_int_eq(list->get_count(list), 5);
+ list->reset_enumerator(list, enumerator);
+ round = 1;
+ while (enumerator->enumerate(enumerator, &x))
+ {
+ if (round == 2)
+ { /* check replaced item */
+ ck_assert_int_eq(42, x);
+ }
+ else if (round == 3)
+ { /* check misplaced item */
+ ck_assert_int_eq(21, x);
+ }
+ else if (round == 4)
+ { /* check misplaced item */
+ ck_assert_int_eq(3, x);
+ }
+ else
+ {
+ ck_assert_int_eq(round, x);
+ }
+ round++;
+ }
+ enumerator->destroy(enumerator);
+}
+END_TEST
+
+/*******************************************************************************
+ * create list from enumerator
+ */
+
+START_TEST(test_create_from_enumerator)
+{
+ enumerator_t *enumerator, *enumerator_other;
+ linked_list_t *other;
+ intptr_t x, y;
+ int count = 0;
+
+ enumerator = list->create_enumerator(list);
+ other = linked_list_create_from_enumerator(enumerator);
+ ck_assert_int_eq(other->get_count(list), 5);
+
+ enumerator = list->create_enumerator(list);
+ enumerator_other = other->create_enumerator(other);
+ while (enumerator->enumerate(enumerator, &x) &&
+ enumerator_other->enumerate(enumerator_other, &y))
+ {
+ ck_assert_int_eq(x, y);
+ count++;
+ }
+ ck_assert_int_eq(count, 5);
+ enumerator_other->destroy(enumerator_other);
+ enumerator->destroy(enumerator);
+ other->destroy(other);
+}
+END_TEST
+
+Suite *linked_list_enumerator_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("linked list and enumerators");
+
+ tc = tcase_create("enumerate");
+ tcase_add_checked_fixture(tc, setup_list, teardown_list);
+ tcase_add_test(tc, test_enumerate);
+ tcase_add_test(tc, test_enumerate_null);
+ tcase_add_test(tc, test_reset_enumerator);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("insert_before()");
+ tcase_add_checked_fixture(tc, setup_list, teardown_list);
+ tcase_add_loop_test(tc, test_insert_before, 1, 5);
+ tcase_add_test(tc, test_insert_before_ends);
+ tcase_add_test(tc, test_insert_before_empty);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("modify");
+ tcase_add_checked_fixture(tc, setup_list, teardown_list);
+ tcase_add_test(tc, test_remove_at);
+ tcase_add_test(tc, test_remove_at_ends);
+ tcase_add_test(tc, test_insert_before_remove_at);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("create_from_enumerator");
+ tcase_add_checked_fixture(tc, setup_list, teardown_list);
+ tcase_add_test(tc, test_create_from_enumerator);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_ntru.c b/src/libstrongswan/tests/suites/test_ntru.c
new file mode 100644
index 000000000..a46f5742c
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_ntru.c
@@ -0,0 +1,1042 @@
+/*
+ * Copyright (C) 2013-2014 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 "test_suite.h"
+
+#include <tests/utils/test_rng.h>
+#include <plugins/ntru/ntru_drbg.h>
+#include <plugins/ntru/ntru_mgf1.h>
+#include <plugins/ntru/ntru_trits.h>
+#include <plugins/ntru/ntru_poly.h>
+#include <utils/test.h>
+
+IMPORT_FUNCTION_FOR_TESTS(ntru, ntru_drbg_create, ntru_drbg_t*,
+ u_int32_t strength, chunk_t pers_str, rng_t *entropy)
+
+IMPORT_FUNCTION_FOR_TESTS(ntru, ntru_mgf1_create, ntru_mgf1_t*,
+ hash_algorithm_t alg, chunk_t seed, bool hash_seed)
+
+IMPORT_FUNCTION_FOR_TESTS(ntru, ntru_trits_create, ntru_trits_t*,
+ size_t len, hash_algorithm_t alg, chunk_t seed)
+
+IMPORT_FUNCTION_FOR_TESTS(ntru, ntru_poly_create_from_seed, ntru_poly_t*,
+ hash_algorithm_t alg, chunk_t seed, uint8_t c_bits,
+ uint16_t N, uint16_t q, uint32_t indices_len_p,
+ uint32_t indices_len_m, bool is_product_form)
+
+IMPORT_FUNCTION_FOR_TESTS(ntru, ntru_poly_create_from_data, ntru_poly_t*,
+ u_int16_t *data, uint16_t N, uint16_t q,
+ uint32_t indices_len_p, uint32_t indices_len_m,
+ bool is_product_form)
+
+/**
+ * NTRU parameter sets to test
+ */
+static struct {
+ diffie_hellman_group_t group;
+ char *group_name;
+} params[] = {
+ { NTRU_112_BIT, "NTRU_112" },
+ { NTRU_128_BIT, "NTRU_128" },
+ { NTRU_192_BIT, "NTRU_192" },
+ { NTRU_256_BIT, "NTRU_256" }
+};
+
+/**
+ * NTRU parameter set selection
+ */
+char *parameter_sets[] = {
+ "x9_98_speed", "x9_98_bandwidth", "x9_98_balance", "optimum"
+};
+
+typedef struct {
+ u_int32_t requested;
+ u_int32_t standard;
+}strength_t;
+
+strength_t strengths[] = {
+ { 80, 112 },
+ { 112, 112 },
+ { 120, 128 },
+ { 128, 128 },
+ { 150, 192 },
+ { 192, 192 },
+ { 200, 256 },
+ { 256, 256 },
+ { 512, 0 }
+};
+
+START_TEST(test_ntru_drbg_strength)
+{
+ ntru_drbg_t *drbg;
+ rng_t *entropy;
+
+ entropy = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
+ ck_assert(entropy != NULL);
+
+ drbg = ntru_drbg_create(strengths[_i].requested, chunk_empty, entropy);
+ if (strengths[_i].standard)
+ {
+ ck_assert(drbg != NULL);
+ ck_assert(drbg->get_strength(drbg) == strengths[_i].standard);
+ drbg->destroy(drbg);
+ }
+ else
+ {
+ ck_assert(drbg == NULL);
+ }
+ entropy->destroy(entropy);
+}
+END_TEST
+
+typedef struct {
+ chunk_t pers_str;
+ chunk_t entropy;
+ chunk_t out;
+} drbg_test_t;
+
+/**
+ * NIST SP 800-90A Deterministic Random Generator Validation System (DRBGVS)
+ */
+drbg_test_t drbg_tests[] = {
+ /* SHA-256 test case 1 - count 0 */
+ { { NULL, 0 },
+ chunk_from_chars(0x06, 0x03, 0x2c, 0xd5, 0xee, 0xd3, 0x3f, 0x39,
+ 0x26, 0x5f, 0x49, 0xec, 0xb1, 0x42, 0xc5, 0x11,
+ 0xda, 0x9a, 0xff, 0x2a, 0xf7, 0x12, 0x03, 0xbf,
+ 0xfa, 0xf3, 0x4a, 0x9c, 0xa5, 0xbd, 0x9c, 0x0d,
+ 0x0e, 0x66, 0xf7, 0x1e, 0xdc, 0x43, 0xe4, 0x2a,
+ 0x45, 0xad, 0x3c, 0x6f, 0xc6, 0xcd, 0xc4, 0xdf,
+ 0x01, 0x92, 0x0a, 0x4e, 0x66, 0x9e, 0xd3, 0xa8,
+ 0x5a, 0xe8, 0xa3, 0x3b, 0x35, 0xa7, 0x4a, 0xd7,
+ 0xfb, 0x2a, 0x6b, 0xb4, 0xcf, 0x39, 0x5c, 0xe0,
+ 0x03, 0x34, 0xa9, 0xc9, 0xa5, 0xa5, 0xd5, 0x52),
+ chunk_from_chars(0x76, 0xfc, 0x79, 0xfe, 0x9b, 0x50, 0xbe, 0xcc,
+ 0xc9, 0x91, 0xa1, 0x1b, 0x56, 0x35, 0x78, 0x3a,
+ 0x83, 0x53, 0x6a, 0xdd, 0x03, 0xc1, 0x57, 0xfb,
+ 0x30, 0x64, 0x5e, 0x61, 0x1c, 0x28, 0x98, 0xbb,
+ 0x2b, 0x1b, 0xc2, 0x15, 0x00, 0x02, 0x09, 0x20,
+ 0x8c, 0xd5, 0x06, 0xcb, 0x28, 0xda, 0x2a, 0x51,
+ 0xbd, 0xb0, 0x38, 0x26, 0xaa, 0xf2, 0xbd, 0x23,
+ 0x35, 0xd5, 0x76, 0xd5, 0x19, 0x16, 0x08, 0x42,
+ 0xe7, 0x15, 0x8a, 0xd0, 0x94, 0x9d, 0x1a, 0x9e,
+ 0xc3, 0xe6, 0x6e, 0xa1, 0xb1, 0xa0, 0x64, 0xb0,
+ 0x05, 0xde, 0x91, 0x4e, 0xac, 0x2e, 0x9d, 0x4f,
+ 0x2d, 0x72, 0xa8, 0x61, 0x6a, 0x80, 0x22, 0x54,
+ 0x22, 0x91, 0x82, 0x50, 0xff, 0x66, 0xa4, 0x1b,
+ 0xd2, 0xf8, 0x64, 0xa6, 0xa3, 0x8c, 0xc5, 0xb6,
+ 0x49, 0x9d, 0xc4, 0x3f, 0x7f, 0x2b, 0xd0, 0x9e,
+ 0x1e, 0x0f, 0x8f, 0x58, 0x85, 0x93, 0x51, 0x24)
+ },
+ /* SHA-256 test case 3 - count 0 */
+ { chunk_from_chars(0xf2, 0xe5, 0x8f, 0xe6, 0x0a, 0x3a, 0xfc, 0x59,
+ 0xda, 0xd3, 0x75, 0x95, 0x41, 0x5f, 0xfd, 0x31,
+ 0x8c, 0xcf, 0x69, 0xd6, 0x77, 0x80, 0xf6, 0xfa,
+ 0x07, 0x97, 0xdc, 0x9a, 0xa4, 0x3e, 0x14, 0x4c),
+ chunk_from_chars(0xfa, 0x0e, 0xe1, 0xfe, 0x39, 0xc7, 0xc3, 0x90,
+ 0xaa, 0x94, 0x15, 0x9d, 0x0d, 0xe9, 0x75, 0x64,
+ 0x34, 0x2b, 0x59, 0x17, 0x77, 0xf3, 0xe5, 0xf6,
+ 0xa4, 0xba, 0x2a, 0xea, 0x34, 0x2e, 0xc8, 0x40,
+ 0xdd, 0x08, 0x20, 0x65, 0x5c, 0xb2, 0xff, 0xdb,
+ 0x0d, 0xa9, 0xe9, 0x31, 0x0a, 0x67, 0xc9, 0xe5,
+ 0xe0, 0x62, 0x9b, 0x6d, 0x79, 0x75, 0xdd, 0xfa,
+ 0x96, 0xa3, 0x99, 0x64, 0x87, 0x40, 0xe6, 0x0f,
+ 0x1f, 0x95, 0x57, 0xdc, 0x58, 0xb3, 0xd7, 0x41,
+ 0x5f, 0x9b, 0xa9, 0xd4, 0xdb, 0xb5, 0x01, 0xf6),
+ chunk_from_chars(0xf9, 0x2d, 0x4c, 0xf9, 0x9a, 0x53, 0x5b, 0x20,
+ 0x22, 0x2a, 0x52, 0xa6, 0x8d, 0xb0, 0x4c, 0x5a,
+ 0xf6, 0xf5, 0xff, 0xc7, 0xb6, 0x6a, 0x47, 0x3a,
+ 0x37, 0xa2, 0x56, 0xbd, 0x8d, 0x29, 0x8f, 0x9b,
+ 0x4a, 0xa4, 0xaf, 0x7e, 0x8d, 0x18, 0x1e, 0x02,
+ 0x36, 0x79, 0x03, 0xf9, 0x3b, 0xdb, 0x74, 0x4c,
+ 0x6c, 0x2f, 0x3f, 0x34, 0x72, 0x62, 0x6b, 0x40,
+ 0xce, 0x9b, 0xd6, 0xa7, 0x0e, 0x7b, 0x8f, 0x93,
+ 0x99, 0x2a, 0x16, 0xa7, 0x6f, 0xab, 0x6b, 0x5f,
+ 0x16, 0x25, 0x68, 0xe0, 0x8e, 0xe6, 0xc3, 0xe8,
+ 0x04, 0xae, 0xfd, 0x95, 0x2d, 0xdd, 0x3a, 0xcb,
+ 0x79, 0x1c, 0x50, 0xf2, 0xad, 0x69, 0xe9, 0xa0,
+ 0x40, 0x28, 0xa0, 0x6a, 0x9c, 0x01, 0xd3, 0xa6,
+ 0x2a, 0xca, 0x2a, 0xaf, 0x6e, 0xfe, 0x69, 0xed,
+ 0x97, 0xa0, 0x16, 0x21, 0x3a, 0x2d, 0xd6, 0x42,
+ 0xb4, 0x88, 0x67, 0x64, 0x07, 0x2d, 0x9c, 0xbe)
+ },
+ /* SHA-256 test case 5 - count 0 */
+ { { NULL, 0 },
+ chunk_from_chars(0xff, 0x0c, 0xdd, 0x55, 0x5c, 0x60, 0x46, 0x47,
+ 0x60, 0xb2, 0x89, 0xb7, 0xbc, 0x1f, 0x81, 0x1a,
+ 0x41, 0xff, 0xf7, 0x2d, 0xe5, 0x90, 0x83, 0x85,
+ 0x8c, 0x02, 0x0a, 0x10, 0x53, 0xbd, 0xc7, 0x4a,
+ 0x7b, 0xc0, 0x99, 0x28, 0x5a, 0xd5, 0x62, 0x19,
+ 0x93, 0xb6, 0x39, 0xc4, 0xa9, 0x4c, 0x37, 0x6b,
+ 0x14, 0xfc, 0x6c, 0x9b, 0x17, 0x8d, 0xb6, 0x44,
+ 0xa8, 0xcd, 0x71, 0x30, 0xa4, 0xcf, 0x05, 0x16,
+ 0x78, 0xc8, 0xf4, 0xfa, 0x8f, 0x24, 0xc2, 0x7b,
+ 0x0a, 0x53, 0x13, 0x38, 0xa5, 0xce, 0x85, 0x89),
+ chunk_from_chars(0x2f, 0x26, 0x20, 0x34, 0x7b, 0xdd, 0xca, 0xa2,
+ 0x94, 0x36, 0x85, 0x34, 0x6b, 0xbf, 0x31, 0xc4,
+ 0x40, 0x81, 0xf8, 0x66, 0x5f, 0x3d, 0xdb, 0x2b,
+ 0x42, 0xae, 0x14, 0x16, 0xa7, 0x4c, 0x4b, 0x77,
+ 0xfa, 0xb3, 0xfa, 0x19, 0xae, 0xec, 0xc5, 0x47,
+ 0xe7, 0x6c, 0x8c, 0xbe, 0x6a, 0xd1, 0xf1, 0x00,
+ 0xa3, 0xfc, 0x8b, 0x2c, 0xe2, 0xa1, 0xea, 0x3a,
+ 0x3d, 0xd7, 0xcf, 0xad, 0x46, 0xc1, 0xb2, 0x78,
+ 0x30, 0xb9, 0x40, 0xba, 0x18, 0xd0, 0x9e, 0x9b,
+ 0x7f, 0xa9, 0x02, 0xbb, 0x76, 0x06, 0x69, 0xb1,
+ 0x73, 0x5c, 0xc7, 0xb7, 0xbd, 0x39, 0x05, 0x2d,
+ 0xa7, 0xf2, 0x62, 0x6f, 0xa8, 0x70, 0x00, 0xcf,
+ 0xfa, 0xda, 0x41, 0x00, 0x19, 0xd0, 0x53, 0x38,
+ 0x6a, 0xd8, 0x08, 0xbd, 0x3c, 0x0c, 0xfc, 0xf5,
+ 0x6b, 0x91, 0x87, 0x9e, 0xb8, 0xd3, 0xf9, 0x32,
+ 0xee, 0x2d, 0x18, 0x5e, 0x54, 0xf3, 0x1b, 0x74)
+ },
+ /* SHA-256 test case 7 - count 0 */
+ { chunk_from_chars(0x40, 0x93, 0x3f, 0xdc, 0xce, 0x41, 0x59, 0xb0,
+ 0x95, 0x51, 0x11, 0xf8, 0x44, 0x47, 0x1b, 0x0d,
+ 0xb8, 0x5b, 0x73, 0xbd, 0xd2, 0xb7, 0x8c, 0x46,
+ 0x8d, 0xd3, 0x9e, 0x2a, 0x9b, 0x29, 0xae, 0xf2),
+ chunk_from_chars(0x28, 0xba, 0x1a, 0x66, 0x16, 0x32, 0xef, 0xc8,
+ 0xec, 0xce, 0xd5, 0xf5, 0x1b, 0x79, 0x13, 0x00,
+ 0xfb, 0x3b, 0x55, 0xb0, 0x5d, 0x04, 0x17, 0x08,
+ 0x63, 0x8d, 0xe4, 0xbe, 0xb7, 0x57, 0xa9, 0xe5,
+ 0x76, 0x82, 0x87, 0x96, 0xaf, 0xf0, 0x7f, 0x55,
+ 0x79, 0x5c, 0xb5, 0x47, 0x13, 0xc7, 0x7e, 0xd4,
+ 0xa5, 0xf5, 0x42, 0xb0, 0x4a, 0xaa, 0x5d, 0xbc,
+ 0x93, 0x1e, 0x47, 0x01, 0x9f, 0xeb, 0x38, 0x96,
+ 0x26, 0x16, 0xc5, 0x7a, 0xf0, 0x9b, 0x7c, 0x1d,
+ 0xf8, 0x3f, 0x2b, 0x86, 0x0f, 0xf7, 0x65, 0x86),
+ chunk_from_chars(0x65, 0xe5, 0xaa, 0x47, 0xb3, 0x85, 0xf1, 0xea,
+ 0x42, 0xb2, 0x31, 0xb9, 0xfe, 0x74, 0x42, 0x53,
+ 0xb8, 0x59, 0x88, 0x59, 0xd7, 0x01, 0x1e, 0x52,
+ 0x5f, 0x5a, 0x2a, 0x1a, 0xd3, 0x2a, 0x97, 0x2a,
+ 0x85, 0x08, 0x02, 0xc6, 0x0a, 0x2b, 0xe1, 0x9b,
+ 0xe2, 0x70, 0x06, 0x3a, 0x3c, 0xfb, 0xea, 0xae,
+ 0x95, 0x4f, 0x10, 0xb1, 0x22, 0x35, 0x2d, 0xe6,
+ 0xa0, 0x8a, 0xc4, 0x10, 0xe0, 0x99, 0x16, 0x53,
+ 0xaa, 0xb2, 0x71, 0xb3, 0x60, 0xfe, 0x91, 0x91,
+ 0xcf, 0x5a, 0xdd, 0xcc, 0xcc, 0xed, 0x8c, 0x4a,
+ 0xcf, 0xb6, 0x14, 0x57, 0x04, 0x99, 0x92, 0x98,
+ 0x8f, 0xd7, 0xa9, 0xac, 0xca, 0x1f, 0x1b, 0xca,
+ 0x35, 0xf1, 0x47, 0x58, 0x13, 0x69, 0x4a, 0x39,
+ 0x98, 0x8e, 0x5f, 0xac, 0x9f, 0x4a, 0xc0, 0x57,
+ 0x22, 0x86, 0xbc, 0x46, 0x25, 0x82, 0xad, 0x0a,
+ 0xf7, 0x8a, 0xb3, 0xb8, 0x5e, 0xc1, 0x7a, 0x25)
+ }
+};
+
+START_TEST(test_ntru_drbg)
+{
+ ntru_drbg_t *drbg;
+ rng_t *entropy;
+ chunk_t out;
+
+ out = chunk_alloc(128);
+ entropy = test_rng_create(drbg_tests[_i].entropy);
+ drbg = ntru_drbg_create(256, drbg_tests[_i].pers_str, entropy);
+ ck_assert(drbg != NULL);
+ ck_assert(drbg->reseed(drbg));
+ ck_assert(drbg->generate(drbg, 256, 128, out.ptr));
+ ck_assert(drbg->generate(drbg, 256, 128, out.ptr));
+ ck_assert(chunk_equals(out, drbg_tests[_i].out));
+ drbg->destroy(drbg);
+ entropy->destroy(entropy);
+ chunk_free(&out);
+}
+END_TEST
+
+START_TEST(test_ntru_drbg_reseed)
+{
+ ntru_drbg_t *drbg;
+ rng_t *entropy;
+ chunk_t out;
+
+ lib->settings->set_int(lib->settings,
+ "libstrongswan.plugins.ntru.max_drbg_requests", 2);
+ out = chunk_alloc(128);
+ entropy = test_rng_create(drbg_tests[0].entropy);
+ drbg = ntru_drbg_create(256, chunk_empty, entropy);
+
+ /* bad output parameters */
+ ck_assert(!drbg->generate(drbg, 256, 0, out.ptr));
+ ck_assert(!drbg->generate(drbg, 256, 128, NULL));
+
+ /* no reseeding occurs */
+ ck_assert(drbg->generate(drbg, 256, 128, out.ptr));
+ ck_assert(drbg->generate(drbg, 256, 128, out.ptr));
+
+ /* consuming remaining entropy */
+ ck_assert(entropy->get_bytes(entropy, 32, out.ptr));
+
+ /* no entropy available for automatic reseeding */
+ ck_assert(!drbg->generate(drbg, 256, 128, out.ptr));
+ drbg->destroy(drbg);
+
+ /* no entropy available for DRBG instantiation */
+ drbg = ntru_drbg_create(256, chunk_empty, entropy);
+ ck_assert(drbg == NULL);
+ entropy->destroy(entropy);
+
+ /* one automatic reseeding occurs */
+ entropy = test_rng_create(drbg_tests[0].entropy);
+ drbg = ntru_drbg_create(256, chunk_empty, entropy);
+ ck_assert(drbg->generate(drbg, 256, 128, out.ptr));
+ ck_assert(drbg->generate(drbg, 256, 128, out.ptr));
+ ck_assert(drbg->generate(drbg, 256, 128, out.ptr));
+
+ /* no entropy left */
+ ck_assert(!entropy->get_bytes(entropy, 32, out.ptr));
+
+ drbg->destroy(drbg);
+ entropy->destroy(entropy);
+ chunk_free(&out);
+ lib->settings->set_int(lib->settings,
+ "libstrongswan.plugins.ntru.max_drbg_requests", 2000);
+}
+END_TEST
+
+typedef struct {
+ uint8_t c_bits;
+ uint16_t N;
+ uint16_t q;
+ bool is_product_form;
+ uint32_t indices_len;
+ uint32_t indices_size;
+ uint16_t *indices;
+} poly_test_t;
+
+typedef struct {
+ hash_algorithm_t alg;
+ size_t hash_size;
+ size_t ml1, ml2, ml3, seed_len;
+ chunk_t seed;
+ chunk_t hashed_seed;
+ chunk_t mask;
+ chunk_t trits;
+ poly_test_t poly_test[2];
+} mgf1_test_t;
+
+uint16_t indices_ees439ep1[] = {
+ 367, 413, 16, 214, 114, 128, 42, 268, 346, 329, 119, 303, 208, 287, 150,
+ 3, 45, 321, 110, 109, 272, 430, 80, 305, 51, 381, 322, 140, 207, 315,
+ 206, 186, 56, 5, 273, 177, 44, 100, 205, 210, 98, 191, 8, 336
+};
+
+uint16_t indices_ees613ep1[] = {
+ 245, 391, 251, 428, 301, 2, 176, 296, 461, 224, 590, 215, 250, 91, 395,
+ 363, 58, 537, 278, 291, 247, 33, 140, 447, 172, 514, 424, 412, 95, 94,
+ 281, 159, 196, 302, 277, 63, 404, 150, 608, 315, 195, 334, 207, 376, 398,
+ 0, 309, 486, 516, 86, 267, 139, 130, 38, 141, 258, 21, 341, 526, 388,
+ 194, 116, 138, 524, 547, 383, 542, 406, 270, 438, 240, 445, 527, 168, 320,
+ 186, 327, 212, 543, 82, 606, 131, 294, 392, 477, 430, 583, 142, 253, 434,
+ 134, 458, 559, 414, 162, 407, 580, 577, 191, 109, 554, 523, 32, 62, 297,
+ 283, 268, 54, 539, 5
+};
+
+uint16_t indices_ees743ep1[] = {
+ 285, 62, 136, 655, 460, 35, 450, 208, 340, 212, 61, 234, 454, 52, 520,
+ 399, 315, 616, 496, 88, 280, 543, 508, 237, 553, 39, 214, 253, 720, 291,
+ 586, 615, 635, 596, 62, 499, 301, 176, 271, 659, 372, 185, 621, 350, 683,
+ 180, 717, 509, 641, 738, 666, 171, 639, 606, 353, 706, 237, 358, 410, 423,
+ 197, 501, 261, 654, 658, 701, 377, 182, 548, 287, 700, 403, 248, 137
+};
+
+uint16_t indices_ees1171ep1[] = {
+ 514, 702, 760, 505, 262, 486, 695, 783, 533, 74, 403, 847, 170,1019, 568,
+ 676,1057, 277,1021, 238, 203, 884, 124, 87, 65, 93, 131, 881,1102, 133,
+ 459, 462, 92, 40, 5,1152,1158, 297, 599, 299, 7, 458, 347, 343, 173,
+ 1044, 264, 871, 819, 679, 328, 438, 990, 982, 308,1135, 423, 470, 254, 295,
+ 1029, 892, 759, 789, 123, 939, 749, 353,1062, 145, 562, 337, 550, 102, 549,
+ 821,1098, 823, 96, 365, 135,1110, 334, 391, 638, 963, 962,1002,1069, 993,
+ 983, 649,1056, 399, 385, 715, 582, 799, 161, 512, 629, 979, 250, 37, 213,
+ 929, 413, 566, 336, 727, 160, 616,1170, 748, 282,1115, 325, 994, 189, 500,
+ 913, 332,1118, 753, 946, 775, 59, 809, 782, 612, 909,1090, 223, 777, 940,
+ 866,1032, 471, 298, 969, 192, 411, 721, 476, 910,1045,1027, 812, 352, 487,
+ 215, 625, 808, 230, 602, 457, 900, 416, 985, 850, 908, 155, 670, 669,1054,
+ 400,1126, 733, 647, 786, 195, 148, 362,1094, 389,1086,1166, 231, 436, 210,
+ 333, 824, 785, 826, 658, 472, 639,1046,1028, 519, 422, 80, 924,1089, 547,
+ 1157, 579, 2, 508,1040, 998, 902,1058, 600, 220, 805, 945, 140,1117, 179,
+ 536, 191
+};
+
+/**
+ * MGF1 Mask Generation Function Test Vectors
+ */
+mgf1_test_t mgf1_tests[] = {
+ { HASH_SHA1, 20, 60, 20, 15, 24,
+ chunk_from_chars(
+ 0xED, 0xA5, 0xC3, 0xBC, 0xAF, 0xB3, 0x20, 0x7D,
+ 0x14, 0xA1, 0x54, 0xF7, 0x8B, 0x37, 0xF2, 0x8D,
+ 0x8C, 0x9B, 0xD5, 0x63, 0x57, 0x38, 0x11, 0xC2,
+ 0xB5, 0xCA, 0xBF, 0x06, 0x43, 0x45, 0x19, 0xD5,
+ 0xE7, 0x36, 0xD0, 0x29, 0x21, 0xDA, 0x02, 0x20,
+ 0x45, 0xF6, 0x5F, 0x0F, 0x10, 0x04, 0x2A, 0xE3,
+ 0x6A, 0x1D, 0xD5, 0x9F, 0x1D, 0x66, 0x44, 0x8F,
+ 0xFA, 0xC6, 0xCA, 0xA4, 0x6E, 0x3B, 0x00, 0x66,
+ 0xA6, 0xC9, 0x80, 0x5C, 0xF5, 0x2D, 0xD7, 0x72,
+ 0xC6, 0xD4, 0x4F, 0x30, 0x72, 0xA2, 0xAD, 0xE0,
+ 0x33, 0xE8, 0x55, 0xD5, 0xE6, 0xD6, 0x00, 0x1D,
+ 0xA8, 0x68, 0xFF, 0x97, 0x36, 0x8A, 0xF4, 0xD6,
+ 0xF1, 0xB6, 0x7E, 0x1F, 0x06, 0xCB, 0x57, 0xCB,
+ 0x35, 0x38, 0xF2, 0x2D, 0xF6, 0x20),
+ chunk_from_chars(
+ 0xF3, 0x9B, 0x0B, 0xB4, 0x97, 0x50, 0xB5, 0xA7,
+ 0xE6, 0xBD, 0xDA, 0xD0, 0x9A, 0x52, 0xBE, 0xA0,
+ 0x21, 0xC4, 0x90, 0xB6),
+ chunk_from_chars(
+ 0x10, 0x43, 0x76, 0x72, 0x6C, 0xDE, 0xA0, 0x0E,
+ 0x77, 0x51, 0xFB, 0x58, 0x39, 0x8A, 0x36, 0xE1,
+ 0x63, 0x2B, 0xC9, 0x17, 0x56, 0x0C, 0x4B, 0x46,
+ 0xA4, 0x07, 0xA4, 0x3B, 0x8E, 0x33, 0x4D, 0xD1,
+ 0x65, 0xF1, 0xAC, 0xC8, 0x59, 0x21, 0x32, 0x16,
+ 0x44, 0x2B, 0x7F, 0xB2, 0xA8, 0xA7, 0x26, 0x5D,
+ 0xE8, 0x02, 0xBE, 0x8E, 0xDC, 0x34, 0xEB, 0x10,
+ 0x76, 0x16, 0x8C, 0xDD, 0x90, 0x92, 0x3D, 0x29,
+ 0x90, 0x98, 0x46, 0x11, 0x73, 0x53, 0x47, 0xB1,
+ 0x2C, 0xD4, 0x83, 0x78, 0x9B, 0x93, 0x2F, 0x5B,
+ 0xFC, 0x26, 0xFF, 0x42, 0x08, 0x1F, 0x70, 0x66,
+ 0x40, 0x4B, 0xE7, 0x22, 0x3A, 0x56, 0x10, 0x6D,
+ 0x4D, 0x29, 0x0B, 0xCE, 0xA6, 0x21, 0xB5, 0x5C,
+ 0x71, 0x66, 0x2F, 0x70, 0x35, 0xD8, 0x8A, 0x92,
+ 0x33, 0xF0, 0x16, 0xD4, 0x0E, 0x43, 0x8A, 0x14),
+ chunk_from_chars(
+ 1, 2, 1, 0, 0, 1, 1, 1, 2, 0, 1, 0, 1, 1, 1, 0, 2, 0, 1, 1,
+ 0, 0, 0, 1, 1, 0, 2, 0, 2, 2, 1, 2, 2, 2, 1, 2, 1, 1, 0, 0,
+ 2, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 2, 0, 0, 1, 0, 1, 0, 2, 0,
+ 0, 1, 0, 2, 1, 0, 0, 0, 2, 0, 0, 0, 1, 2, 2, 0, 0, 2, 0, 1,
+ 1, 2, 1, 1, 0, 0, 1, 1, 1, 2, 2, 1, 2, 0, 0, 2, 1, 0, 0, 1,
+ 0, 1, 1, 0, 0, 0, 1, 2, 2, 0, 1, 2, 1, 2, 0, 2, 0, 0, 0, 2,
+ 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 1, 0, 2, 0, 1, 2, 0, 2, 1,
+ 0, 2, 2, 1, 0, 2, 1, 2, 2, 0, 2, 0, 2, 1, 2, 2, 0, 2, 0, 1,
+ 1, 2, 2, 2, 2, 1, 0, 1, 0, 2, 2, 0, 1, 1, 2, 2, 2, 0, 0, 1,
+ 0, 2, 0, 1, 0, 2, 1, 2, 1, 0, 1, 1, 2, 0, 0, 2, 1, 1, 2, 0,
+ 1, 2, 1, 1, 0, 1, 0, 2, 1, 1, 1, 2, 1, 0, 2, 0, 2, 0, 0, 2,
+ 2, 1, 0, 0, 2, 2, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 2, 1, 2, 2,
+ 2, 0, 0, 0, 0, 1, 0, 0, 1, 2, 1, 2, 0, 2, 1, 1, 1, 0, 2, 2,
+ 1, 2, 2, 1, 0, 1, 0, 2, 2, 2, 1, 2, 1, 0, 0, 1, 0, 1, 1, 1,
+ 1, 1, 2, 0, 0, 2, 1, 0, 2, 1, 2, 1, 0, 2, 2, 0, 0, 1, 2, 1,
+ 2, 0, 1, 2, 1, 1, 2, 0, 2, 0, 2, 1, 1, 1, 0, 0, 0, 1, 2, 1,
+ 2, 2, 1, 2, 1, 1, 2, 1, 2, 0, 2, 2, 1, 0, 0, 1, 2, 0, 1, 1,
+ 2, 0, 0, 0, 1, 2, 2, 1, 2, 0, 0, 2, 1, 0, 2, 2, 2, 1, 1, 0,
+ 2, 1, 2, 1, 2, 2, 1, 2, 1, 1, 0, 1, 1, 1, 1, 2, 0, 2, 2, 1,
+ 0, 1, 1, 2, 1, 2, 0, 2, 1, 0, 1, 0, 1, 0, 1, 2, 0, 1, 1, 0,
+ 0, 1, 1, 2, 0, 2, 2, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1,
+ 0, 1, 2, 0, 1, 1, 0, 1, 2, 0, 0, 1, 2, 2, 0, 0, 2, 1, 2),
+ {
+ { 9, 439, 2048, TRUE, 9 + (8 << 8) + (5 << 16),
+ countof(indices_ees439ep1), indices_ees439ep1
+ },
+ { 11, 613, 2048, FALSE, 55,
+ countof(indices_ees613ep1), indices_ees613ep1
+ }
+ }
+ },
+ { HASH_SHA256, 32, 64, 32, 33, 40,
+ chunk_from_chars(
+ 0x52, 0xC5, 0xDD, 0x1E, 0xEF, 0x76, 0x1B, 0x53,
+ 0x08, 0xE4, 0x86, 0x3F, 0x91, 0x12, 0x98, 0x69,
+ 0xC5, 0x9D, 0xDE, 0xF6, 0xFC, 0xFA, 0x93, 0xCE,
+ 0x32, 0x52, 0x66, 0xF9, 0xC9, 0x97, 0xF6, 0x42,
+ 0x00, 0x2C, 0x64, 0xED, 0x1A, 0x6B, 0x14, 0x0A,
+ 0x4B, 0x04, 0xCF, 0x6D, 0x2D, 0x82, 0x0A, 0x07,
+ 0xA2, 0x3B, 0xDE, 0xCE, 0x19, 0x8A, 0x39, 0x43,
+ 0x16, 0x61, 0x29, 0x98, 0x68, 0xEA, 0xE5, 0xCC,
+ 0x0A, 0xF8, 0xE9, 0x71, 0x26, 0xF1, 0x07, 0x36,
+ 0x2C, 0x07, 0x1E, 0xEB, 0xE4, 0x28, 0xA2, 0xF4,
+ 0xA8, 0x12, 0xC0, 0xC8, 0x20, 0x37, 0xF8, 0xF2,
+ 0x6C, 0xAF, 0xDC, 0x6F, 0x2E, 0xD0, 0x62, 0x58,
+ 0xD2, 0x37, 0x03, 0x6D, 0xFA, 0x6E, 0x1A, 0xAC,
+ 0x9F, 0xCA, 0x56, 0xC6, 0xA4, 0x52, 0x41, 0xE8,
+ 0x0F, 0x1B, 0x0C, 0xB9, 0xE6, 0xBA, 0xDE, 0xE1,
+ 0x03, 0x5E, 0xC2, 0xE5, 0xF8, 0xF4, 0xF3, 0x46,
+ 0x3A, 0x12, 0xC0, 0x1F, 0x3A, 0x00, 0xD0, 0x91,
+ 0x18, 0xDD, 0x53, 0xE4, 0x22, 0xF5, 0x26, 0xA4,
+ 0x54, 0xEE, 0x20, 0xF0, 0x80),
+ chunk_from_chars(
+ 0x76, 0x89, 0x8B, 0x1B, 0x60, 0xEC, 0x10, 0x9D,
+ 0x8F, 0x13, 0xF2, 0xFE, 0xD9, 0x85, 0xC1, 0xAB,
+ 0x7E, 0xEE, 0xB1, 0x31, 0xDD, 0xF7, 0x7F, 0x0C,
+ 0x7D, 0xF9, 0x6B, 0x7B, 0x19, 0x80, 0xBD, 0x28),
+ chunk_from_chars(
+ 0xF1, 0x19, 0x02, 0x4F, 0xDA, 0x58, 0x05, 0x9A,
+ 0x07, 0xDF, 0x61, 0x81, 0x22, 0x0E, 0x15, 0x46,
+ 0xCB, 0x35, 0x3C, 0xDC, 0xAD, 0x20, 0xD9, 0x3F,
+ 0x0D, 0xD1, 0xAA, 0x64, 0x66, 0x5C, 0xFA, 0x4A,
+ 0xFE, 0xD6, 0x8F, 0x55, 0x57, 0x15, 0xB2, 0xA6,
+ 0xA0, 0xE6, 0xA8, 0xC6, 0xBD, 0x28, 0xB4, 0xD5,
+ 0x6E, 0x5B, 0x4B, 0xB0, 0x97, 0x09, 0xF5, 0xAC,
+ 0x57, 0x65, 0x13, 0x97, 0x71, 0x2C, 0x45, 0x13,
+ 0x3D, 0xEE, 0xFB, 0xBF, 0xFE, 0xAF, 0xBB, 0x4B,
+ 0x0D, 0x5C, 0x45, 0xD4, 0x2F, 0x17, 0x92, 0x07,
+ 0x66, 0x11, 0xF5, 0x46, 0xF8, 0x0C, 0x03, 0x92,
+ 0xF5, 0xF5, 0xFF, 0xA4, 0xF3, 0x52, 0xF4, 0x08,
+ 0x2C, 0x49, 0x32, 0x1A, 0x93, 0x51, 0x98, 0xB6,
+ 0x94, 0x83, 0x39, 0xCF, 0x6B, 0x1F, 0x2F, 0xFC,
+ 0x2B, 0xFF, 0x10, 0x71, 0x7D, 0x35, 0x6C, 0xEA,
+ 0xC5, 0x66, 0xC7, 0x26, 0x7D, 0x9E, 0xAC, 0xDD,
+ 0x35, 0xD7, 0x06, 0x3F, 0x40, 0x82, 0xDA, 0xC3,
+ 0x2B, 0x3C, 0x91, 0x3A, 0x32, 0xF8, 0xB2, 0xC6,
+ 0x44, 0x4D, 0xCD, 0xB6, 0x54, 0x5F, 0x81, 0x95,
+ 0x59, 0xA1, 0xE5, 0x4E, 0xA5, 0x0A, 0x4A, 0x42),
+ chunk_from_chars(
+ 1, 2, 2, 2, 2, 1, 2, 2, 0, 0, 2, 0, 0, 0, 0, 1, 2, 2, 2, 0,
+ 2, 0, 0, 2, 2, 1, 2, 0, 0, 1, 2, 1, 0, 0, 0, 1, 0, 2, 2, 1,
+ 1, 2, 0, 0, 0, 1, 2, 0, 2, 2, 1, 2, 1, 0, 1, 0, 1, 2, 1, 1,
+ 1, 2, 0, 1, 0, 2, 1, 1, 0, 0, 0, 1, 2, 0, 0, 1, 2, 1, 2, 0,
+ 2, 1, 1, 1, 2, 2, 2, 2, 1, 0, 0, 2, 0, 2, 0, 1, 1, 0, 2, 2,
+ 2, 0, 1, 0, 2, 2, 1, 0, 1, 0, 1, 0, 0, 2, 2, 0, 0, 1, 2, 0,
+ 1, 1, 1, 0, 0, 2, 0, 2, 1, 2, 2, 2, 0, 0, 2, 1, 0, 2, 0, 1,
+ 0, 1, 2, 0, 1, 2, 0, 1, 0, 1, 2, 0, 2, 2, 0, 1, 2, 2, 1, 2,
+ 2, 2, 0, 2, 1, 1, 1, 0, 0, 1, 0, 2, 0, 0, 1, 0, 1, 2, 0, 0,
+ 1, 2, 1, 0, 2, 1, 1, 0, 0, 2, 1, 2, 2, 2, 1, 2, 1, 1, 2, 2,
+ 0, 2, 0, 0, 2, 0, 0, 1, 1, 2, 0, 0, 0, 1, 2, 1, 1, 1, 1, 0,
+ 0, 0, 2, 0, 2, 0, 2, 2, 1, 2, 2, 0, 0, 1, 1, 1, 0, 1, 0, 1,
+ 0, 1, 2, 2, 0, 2, 1, 1, 0, 2, 1, 2, 1, 2, 1, 0, 0, 1, 0, 0,
+ 1, 0, 1, 0, 2, 0, 2, 0, 0, 1, 2, 0, 2, 0, 1, 1, 0, 2, 0, 0,
+ 1, 2, 1, 2, 1, 2, 1, 0, 1, 1, 2, 2, 1, 1, 0, 0, 2, 1, 2, 0,
+ 1, 0, 2, 0, 0, 1, 2, 0, 2, 0, 1, 1, 2, 2, 2, 2, 0, 0, 1, 2,
+ 1, 1, 1, 0, 2, 1, 2, 2, 0, 2, 0, 1, 2, 2, 0, 1, 1, 1, 0, 0,
+ 2, 0, 1, 0, 1, 0, 2, 1, 2, 0, 2, 1, 2, 1, 2, 2, 0, 2, 1, 0,
+ 2, 1, 2, 0, 0, 2, 0, 1, 2, 1, 1, 2, 0, 0, 0, 0, 1, 2, 0, 1,
+ 2, 2, 1, 0, 0, 1, 2, 1, 2, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0,
+ 2, 0, 1, 2, 1, 2, 0, 0, 0, 2, 1, 0, 0, 0, 1, 2, 2, 0, 0, 0,
+ 2, 2, 1, 1, 0, 1, 0, 2, 2, 0, 2, 1, 2, 1, 0, 2, 2, 2, 0, 0,
+ 0, 1, 1, 2, 1, 0, 0, 0, 0, 1, 2, 2, 1, 2, 1, 2, 0, 2, 0, 2,
+ 1, 1, 1, 2, 1, 2, 1, 2, 1, 1, 0, 1, 0, 2, 0, 0, 0, 2, 1, 2,
+ 2, 2, 2, 0, 1, 1, 1, 0, 1, 0, 2, 0, 2, 1, 0, 1, 2, 1, 1, 0,
+ 1, 2, 1, 0, 0, 2, 1, 0, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 0,
+ 0, 0, 0, 1, 1, 0, 0, 2, 2, 2, 2, 2, 0, 1, 2, 0, 1, 2, 0, 1,
+ 1, 0, 1, 1, 2, 2, 0, 1, 1, 0, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1,
+ 1, 0, 1, 0, 2, 2, 1, 0, 2, 2, 2, 2, 2, 1, 0, 2, 2, 2, 1, 2,
+ 0, 2, 0, 0, 0, 0, 0, 1, 2, 0, 1, 0, 1),
+ {
+ { 13, 743, 2048, TRUE, 11 + (11 << 8) + (15 << 16),
+ countof(indices_ees743ep1), indices_ees743ep1
+ },
+ { 12, 1171, 2048, FALSE, 106,
+ countof(indices_ees1171ep1), indices_ees1171ep1
+ }
+ }
+ }
+};
+
+START_TEST(test_ntru_mgf1)
+{
+ ntru_mgf1_t *mgf1;
+ chunk_t mask, mask1, mask2, mask3;
+
+ mask1 = mgf1_tests[_i].mask;
+ mask2 = chunk_skip(mask1, mgf1_tests[_i].ml1);
+ mask3 = chunk_skip(mask2, mgf1_tests[_i].ml2);
+ mask1.len = mgf1_tests[_i].ml1;
+ mask2.len = mgf1_tests[_i].ml2;
+ mask3.len = mgf1_tests[_i].ml3;
+
+ mgf1 = ntru_mgf1_create(HASH_UNKNOWN, mgf1_tests[_i].seed, TRUE);
+ ck_assert(mgf1 == NULL);
+
+ mgf1 = ntru_mgf1_create(mgf1_tests[_i].alg, chunk_empty, TRUE);
+ ck_assert(mgf1 == NULL);
+
+ /* return mask in allocated chunk */
+ mgf1 = ntru_mgf1_create(mgf1_tests[_i].alg, mgf1_tests[_i].seed, TRUE);
+ ck_assert(mgf1);
+
+ /* check hash size */
+ ck_assert(mgf1->get_hash_size(mgf1) == mgf1_tests[_i].hash_size);
+
+ /* get zero number of octets */
+ ck_assert(mgf1->allocate_mask(mgf1, 0, &mask));
+ ck_assert(mask.len == 0 && mask.ptr == NULL);
+
+ /* get non-zero number of octets */
+ ck_assert(mgf1->allocate_mask(mgf1, mgf1_tests[_i].mask.len, &mask));
+ ck_assert(chunk_equals(mask, mgf1_tests[_i].mask));
+ mgf1->destroy(mgf1);
+
+ /* copy mask to pre-allocated buffer */
+ mgf1 = ntru_mgf1_create(mgf1_tests[_i].alg, mgf1_tests[_i].seed, TRUE);
+ ck_assert(mgf1);
+ ck_assert(mgf1->get_mask(mgf1, mgf1_tests[_i].mask.len, mask.ptr));
+ ck_assert(chunk_equals(mask, mgf1_tests[_i].mask));
+ mgf1->destroy(mgf1);
+
+ /* get mask in batches without hashing the seed */
+ mgf1 = ntru_mgf1_create(mgf1_tests[_i].alg, mgf1_tests[_i].hashed_seed, FALSE);
+ ck_assert(mgf1);
+
+ /* first batch */
+ ck_assert(mgf1->get_mask(mgf1, mask1.len, mask.ptr));
+ mask.len = mask1.len;
+ ck_assert(chunk_equals(mask, mask1));
+
+ /* second batch */
+ ck_assert(mgf1->get_mask(mgf1, mask2.len, mask.ptr));
+ mask.len = mask2.len;
+ ck_assert(chunk_equals(mask, mask2));
+
+ /* third batch */
+ ck_assert(mgf1->get_mask(mgf1, mask3.len, mask.ptr));
+ mask.len = mask3.len;
+ ck_assert(chunk_equals(mask, mask3));
+
+ mgf1->destroy(mgf1);
+ chunk_free(&mask);
+}
+END_TEST
+
+START_TEST(test_ntru_trits)
+{
+ ntru_trits_t *mask;
+ chunk_t trits;
+
+ mask = ntru_trits_create(mgf1_tests[_i].trits.len, HASH_UNKNOWN,
+ mgf1_tests[_i].seed);
+ ck_assert(mask == NULL);
+
+ mask = ntru_trits_create(mgf1_tests[_i].trits.len, mgf1_tests[_i].alg,
+ chunk_empty);
+ ck_assert(mask == NULL);
+
+ mask = ntru_trits_create(mgf1_tests[_i].trits.len, mgf1_tests[_i].alg,
+ mgf1_tests[_i].seed);
+ ck_assert(mask);
+
+ trits = chunk_create(mask->get_trits(mask), mask->get_size(mask));
+ ck_assert(chunk_equals(trits, mgf1_tests[_i].trits));
+ mask->destroy(mask);
+
+ /* generate a multiple of 5 trits */
+ mask = ntru_trits_create(10, mgf1_tests[_i].alg, mgf1_tests[_i].seed);
+ ck_assert(mask);
+
+ trits = chunk_create(mask->get_trits(mask), mask->get_size(mask));
+ ck_assert(chunk_equals(trits, chunk_create(mgf1_tests[_i].trits.ptr, 10)));
+ mask->destroy(mask);
+}
+END_TEST
+
+START_TEST(test_ntru_poly)
+{
+ ntru_poly_t *poly;
+ uint16_t *indices;
+ chunk_t seed;
+ poly_test_t *p;
+ int j, n;
+
+ seed = mgf1_tests[_i].seed;
+ seed.len = mgf1_tests[_i].seed_len;
+
+ p = &mgf1_tests[_i].poly_test[0];
+ poly = ntru_poly_create_from_seed(HASH_UNKNOWN, seed, p->c_bits, p->N, p->q,
+ p->indices_len, p->indices_len,
+ p->is_product_form);
+ ck_assert(poly == NULL);
+
+ for (n = 0; n < 2; n++)
+ {
+ p = &mgf1_tests[_i].poly_test[n];
+ poly = ntru_poly_create_from_seed(mgf1_tests[_i].alg, seed, p->c_bits,
+ p->N, p->q, p->indices_len,
+ p->indices_len, p->is_product_form);
+ ck_assert(poly != NULL && poly->get_size(poly) == p->indices_size);
+
+ indices = poly->get_indices(poly);
+ for (j = 0; j < p->indices_size; j++)
+ {
+ ck_assert(indices[j] == p->indices[j]);
+ }
+ poly->destroy(poly);
+ }
+}
+END_TEST
+
+typedef struct {
+ uint16_t N;
+ uint16_t q;
+ bool is_product_form;
+ uint32_t indices_len_p;
+ uint32_t indices_len_m;
+ uint16_t *indices;
+ uint16_t *a;
+ uint16_t *c;
+} ring_mult_test_t;
+
+uint16_t t1_indices[] = { 1, 6, 5, 3 };
+
+uint16_t t1_a[] = { 1, 0, 0, 0, 0, 0, 0 };
+uint16_t t1_c[] = { 0, 1, 0, 7, 0, 7, 1 };
+
+uint16_t t2_a[] = { 5, 0, 0, 0, 0, 0, 0 };
+uint16_t t2_c[] = { 0, 5, 0, 3, 0, 3, 5 };
+
+uint16_t t3_a[] = { 4, 0, 0, 0, 0, 0, 0 };
+uint16_t t3_c[] = { 0, 4, 0, 4, 0, 4, 4 };
+
+uint16_t t4_a[] = { 0, 6, 0, 0, 0, 0, 0 };
+uint16_t t4_c[] = { 6, 0, 6, 0, 2, 0, 2 };
+
+uint16_t t5_a[] = { 4, 6, 0, 0, 0, 0, 0 };
+uint16_t t5_c[] = { 6, 4, 6, 4, 2, 4, 6 };
+
+uint16_t t6_a[] = { 0, 0, 3, 0, 0, 0, 0 };
+uint16_t t6_c[] = { 5, 3, 0, 3, 0, 5, 0 };
+
+uint16_t t7_a[] = { 4, 6, 3, 0, 0, 0, 0 };
+uint16_t t7_c[] = { 3, 7, 6, 7, 2, 1, 6 };
+
+uint16_t t8_a[] = { 0, 0, 0, 7, 0, 0, 0 };
+uint16_t t8_c[] = { 0, 1, 7, 0, 7, 0, 1 };
+
+uint16_t t9_a[] = { 4, 6, 3, 7, 0, 0, 0 };
+uint16_t t9_c[] = { 3, 0, 5, 7, 1, 1, 7 };
+
+uint16_t t10_a[] = { 0, 0, 0, 0, 0, 1, 0 };
+uint16_t t10_c[] = { 0, 7, 0, 7, 1, 0, 1 };
+
+uint16_t t11_a[] = { 4, 6, 3, 7, 0, 1, 0 };
+uint16_t t11_c[] = { 3, 7, 5, 6, 2, 1, 0 };
+
+uint16_t t2_indices[] = { 1, 6, 5, 2, 3 };
+
+uint16_t t12_c[] = { 0, 1, 7, 7, 0, 1, 1 };
+uint16_t t13_c[] = { 0, 1, 7, 7, 0, 7, 1 };
+uint16_t t14_c[] = { 0, 1, 0, 31, 0, 31, 1 };
+uint16_t t15_c[] = { 0, 5, 0, 2043, 0, 2043, 5 };
+uint16_t t16_c[] = { 0, 5, 0, 32763, 0, 32763, 5 };
+
+uint16_t t3_indices[] = { 7, 2, 3, 5, 0, 2, 3, 10, 7, 0, 8, 2 };
+
+uint16_t t17_a[] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+uint16_t t17_c[] = { 7, 1, 0, 1, 1, 7, 0, 7, 7, 7, 2 };
+
+ring_mult_test_t ring_mult_tests[] = {
+ { 7, 8, FALSE, 2, 2, t1_indices, t1_a, t1_c },
+ { 7, 8, FALSE, 2, 2, t1_indices, t2_a, t2_c },
+ { 7, 8, FALSE, 2, 2, t1_indices, t3_a, t3_c },
+ { 7, 8, FALSE, 2, 2, t1_indices, t4_a, t4_c },
+ { 7, 8, FALSE, 2, 2, t1_indices, t5_a, t5_c },
+ { 7, 8, FALSE, 2, 2, t1_indices, t6_a, t6_c },
+ { 7, 8, FALSE, 2, 2, t1_indices, t7_a, t7_c },
+ { 7, 8, FALSE, 2, 2, t1_indices, t8_a, t8_c },
+ { 7, 8, FALSE, 2, 2, t1_indices, t9_a, t9_c },
+ { 7, 8, FALSE, 2, 2, t1_indices, t10_a, t10_c },
+ { 7, 8, FALSE, 2, 2, t1_indices, t11_a, t11_c },
+ { 7, 8, FALSE, 3, 2, t2_indices, t1_a, t12_c },
+ { 7, 8, FALSE, 2, 3, t2_indices, t1_a, t13_c },
+ { 7, 32, FALSE, 2, 2, t1_indices, t1_a, t14_c },
+ { 7, 2048, FALSE, 2, 2, t1_indices, t2_a, t15_c },
+ { 7, 32768, FALSE, 2, 2, t1_indices, t2_a, t16_c },
+ { 11, 8, TRUE, 197121, 197121, t3_indices, t17_a, t17_c },
+};
+
+START_TEST(test_ntru_ring_mult)
+{
+ ntru_poly_t *poly;
+ ring_mult_test_t *t;
+ uint16_t *c;
+ int i;
+
+ t = &ring_mult_tests[_i];
+ poly = ntru_poly_create_from_data(t->indices, t->N, t->q, t->indices_len_p,
+ t->indices_len_m, t->is_product_form);
+ ck_assert(poly != NULL);
+
+ c = malloc(t->N * sizeof(uint16_t));
+ poly->ring_mult(poly, t->a, c);
+
+ for (i = 0; i < t->N; i++)
+ {
+ ck_assert(c[i] == t->c[i]);
+ }
+
+ free(c);
+ poly->destroy(poly);
+}
+END_TEST
+
+int array_tests[] = { 0, 11, 12, 16 };
+
+START_TEST(test_ntru_array)
+{
+ ntru_poly_t *poly;
+ ring_mult_test_t *t;
+ uint16_t *c;
+ int i;
+
+ t = &ring_mult_tests[array_tests[_i]];
+
+ poly = ntru_poly_create_from_data(t->indices, t->N, t->q, t->indices_len_p,
+ t->indices_len_m, t->is_product_form);
+ ck_assert(poly != NULL);
+
+ c = malloc(t->N * sizeof(uint16_t));
+ poly->get_array(poly, c);
+
+ for (i = 0; i < t->N; i++)
+ {
+ ck_assert(c[i] == t->c[i]);
+ }
+
+ free(c);
+ poly->destroy(poly);
+}
+END_TEST
+
+START_TEST(test_ntru_ke)
+{
+ chunk_t pub_key, cipher_text, i_shared_secret, r_shared_secret;
+ diffie_hellman_t *i_ntru, *r_ntru;
+ char buf[10];
+ int n, len;
+ status_t status;
+
+ len = snprintf(buf, sizeof(buf), "%N", diffie_hellman_group_names,
+ params[_i].group);
+ ck_assert(len == 8);
+ ck_assert(streq(buf, params[_i].group_name));
+
+ for (n = 0; n < countof(parameter_sets); n++)
+ {
+ lib->settings->set_str(lib->settings,
+ "libstrongswan.plugins.ntru.parameter_set",
+ parameter_sets[n]);
+
+ i_ntru = lib->crypto->create_dh(lib->crypto, params[_i].group);
+ ck_assert(i_ntru != NULL);
+ ck_assert(i_ntru->get_dh_group(i_ntru) == params[_i].group);
+
+ i_ntru->get_my_public_value(i_ntru, &pub_key);
+ ck_assert(pub_key.len > 0);
+
+ r_ntru = lib->crypto->create_dh(lib->crypto, params[_i].group);
+ ck_assert(r_ntru != NULL);
+
+ r_ntru->set_other_public_value(r_ntru, pub_key);
+ r_ntru->get_my_public_value(r_ntru, &cipher_text);
+ ck_assert(cipher_text.len > 0);
+
+ status = r_ntru->get_shared_secret(r_ntru, &r_shared_secret);
+ ck_assert(status == SUCCESS);
+ ck_assert(r_shared_secret.len > 0);
+
+ i_ntru->set_other_public_value(i_ntru, cipher_text);
+ status = i_ntru->get_shared_secret(i_ntru, &i_shared_secret);
+
+ if (status == SUCCESS)
+ {
+ ck_assert(chunk_equals(i_shared_secret, r_shared_secret));
+ }
+ else
+ {
+ ck_assert(i_shared_secret.len == 0);
+ }
+
+ chunk_clear(&i_shared_secret);
+ chunk_clear(&r_shared_secret);
+ chunk_free(&pub_key);
+ chunk_free(&cipher_text);
+ i_ntru->destroy(i_ntru);
+ r_ntru->destroy(r_ntru);
+ }
+}
+END_TEST
+
+START_TEST(test_ntru_retransmission)
+{
+ diffie_hellman_t *i_ntru;
+ chunk_t pub_key1, pub_key2;
+
+ i_ntru = lib->crypto->create_dh(lib->crypto, NTRU_256_BIT);
+ i_ntru->get_my_public_value(i_ntru, &pub_key1);
+ i_ntru->get_my_public_value(i_ntru, &pub_key2);
+ ck_assert(chunk_equals(pub_key1, pub_key2));
+
+ chunk_free(&pub_key1);
+ chunk_free(&pub_key2);
+ i_ntru->destroy(i_ntru);
+}
+END_TEST
+
+chunk_t oid_tests[] = {
+ { NULL, 0 },
+ chunk_from_chars(0x00),
+ chunk_from_chars(0x01),
+ chunk_from_chars(0x02),
+ chunk_from_chars(0x02, 0x03, 0x00, 0x03, 0x10),
+ chunk_from_chars(0x01, 0x04, 0x00, 0x03, 0x10),
+ chunk_from_chars(0x01, 0x03, 0x00, 0x03, 0x10),
+ chunk_from_chars(0x01, 0x03, 0xff, 0x03, 0x10),
+};
+
+START_TEST(test_ntru_pubkey_oid)
+{
+ diffie_hellman_t *r_ntru;
+ chunk_t cipher_text;
+
+ r_ntru = lib->crypto->create_dh(lib->crypto, NTRU_128_BIT);
+ r_ntru->set_other_public_value(r_ntru, oid_tests[_i]);
+ r_ntru->get_my_public_value(r_ntru, &cipher_text);
+ ck_assert(cipher_text.len == 0);
+ r_ntru->destroy(r_ntru);
+}
+END_TEST
+
+START_TEST(test_ntru_wrong_set)
+{
+ diffie_hellman_t *i_ntru, *r_ntru;
+ chunk_t pub_key, cipher_text;
+
+ lib->settings->set_str(lib->settings,
+ "libstrongswan.plugins.ntru.parameter_set",
+ "x9_98_bandwidth");
+ i_ntru = lib->crypto->create_dh(lib->crypto, NTRU_112_BIT);
+ i_ntru->get_my_public_value(i_ntru, &pub_key);
+
+ lib->settings->set_str(lib->settings,
+ "libstrongswan.plugins.ntru.parameter_set",
+ "optimum");
+ r_ntru = lib->crypto->create_dh(lib->crypto, NTRU_112_BIT);
+ r_ntru->set_other_public_value(r_ntru, pub_key);
+ r_ntru->get_my_public_value(r_ntru, &cipher_text);
+ ck_assert(cipher_text.len == 0);
+
+ chunk_free(&pub_key);
+ chunk_free(&cipher_text);
+ i_ntru->destroy(i_ntru);
+ r_ntru->destroy(r_ntru);
+}
+END_TEST
+
+START_TEST(test_ntru_ciphertext)
+{
+ char buf_00[604], buf_ff[604];
+
+ chunk_t test[] = {
+ chunk_empty,
+ chunk_from_chars(0x00),
+ chunk_create(buf_00, sizeof(buf_00)),
+ chunk_create(buf_ff, sizeof(buf_ff)),
+ };
+
+ diffie_hellman_t *i_ntru;
+ chunk_t pub_key, shared_secret;
+ int i;
+
+ memset(buf_00, 0x00, sizeof(buf_00));
+ memset(buf_ff, 0xff, sizeof(buf_ff));
+
+ for (i = 0; i < countof(test); i++)
+ {
+ i_ntru = lib->crypto->create_dh(lib->crypto, NTRU_128_BIT);
+ i_ntru->get_my_public_value(i_ntru, &pub_key);
+ i_ntru->set_other_public_value(i_ntru, test[i]);
+ ck_assert(i_ntru->get_shared_secret(i_ntru, &shared_secret) != SUCCESS);
+ ck_assert(shared_secret.len == 0);
+
+ chunk_free(&pub_key);
+ i_ntru->destroy(i_ntru);
+ }
+}
+END_TEST
+
+START_TEST(test_ntru_wrong_ciphertext)
+{
+ diffie_hellman_t *i_ntru, *r_ntru, *m_ntru;
+ chunk_t pub_key_i, pub_key_m, cipher_text, shared_secret;
+
+ i_ntru = lib->crypto->create_dh(lib->crypto, NTRU_128_BIT);
+ r_ntru = lib->crypto->create_dh(lib->crypto, NTRU_128_BIT);
+ m_ntru = lib->crypto->create_dh(lib->crypto, NTRU_128_BIT);
+
+ i_ntru->get_my_public_value(i_ntru, &pub_key_i);
+ m_ntru->get_my_public_value(m_ntru, &pub_key_m);
+ r_ntru->set_other_public_value(r_ntru, pub_key_m);
+ r_ntru->get_my_public_value(r_ntru, &cipher_text);
+ i_ntru->set_other_public_value(i_ntru, cipher_text);
+ ck_assert(i_ntru->get_shared_secret(i_ntru, &shared_secret) != SUCCESS);
+ ck_assert(shared_secret.len == 0);
+
+ chunk_free(&pub_key_i);
+ chunk_free(&pub_key_m);
+ chunk_free(&cipher_text);
+ i_ntru->destroy(i_ntru);
+ m_ntru->destroy(m_ntru);
+ r_ntru->destroy(r_ntru);
+}
+END_TEST
+
+Suite *ntru_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("ntru");
+
+ tc = tcase_create("drbg_strength");
+ tcase_add_loop_test(tc, test_ntru_drbg_strength, 0, countof(strengths));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("drbg");
+ tcase_add_loop_test(tc, test_ntru_drbg, 0, countof(drbg_tests));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("drgb_reseed");
+ tcase_add_test(tc, test_ntru_drbg_reseed);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("mgf1");
+ tcase_add_loop_test(tc, test_ntru_mgf1, 0, countof(mgf1_tests));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("trits");
+ tcase_add_loop_test(tc, test_ntru_trits, 0, countof(mgf1_tests));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("poly");
+ tcase_add_loop_test(tc, test_ntru_poly, 0, countof(mgf1_tests));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("ring_mult");
+ tcase_add_loop_test(tc, test_ntru_ring_mult, 0, countof(ring_mult_tests));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("array");
+ tcase_add_loop_test(tc, test_ntru_array, 0, countof(array_tests));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("ke");
+ tcase_add_loop_test(tc, test_ntru_ke, 0, countof(params));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("retransmission");
+ tcase_add_test(tc, test_ntru_retransmission);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("pubkey_oid");
+ tcase_add_loop_test(tc, test_ntru_pubkey_oid, 0, countof(oid_tests));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("wrong_set");
+ tcase_add_test(tc, test_ntru_wrong_set);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("ciphertext");
+ tcase_add_test(tc, test_ntru_ciphertext);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("wrong_ciphertext");
+ tcase_add_test(tc, test_ntru_wrong_ciphertext);
+ suite_add_tcase(s, tc);
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_pen.c b/src/libstrongswan/tests/suites/test_pen.c
new file mode 100644
index 000000000..a6cbc9aa1
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_pen.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2013 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 "test_suite.h"
+
+#include <pen/pen.h>
+
+/*******************************************************************************
+ * create
+ */
+
+START_TEST(test_pen_type_create)
+{
+ pen_type_t ita_1 = pen_type_create(PEN_ITA, 100);
+
+ ck_assert(ita_1.vendor_id == PEN_ITA);
+ ck_assert(ita_1.type == 100);
+}
+END_TEST
+
+/*******************************************************************************
+ * equals
+ */
+
+START_TEST(test_pen_type_equals)
+{
+ pen_type_t ita_1 = pen_type_create(PEN_ITA, 100);
+ pen_type_t ita_2 = pen_type_create(PEN_ITA, 200);
+ pen_type_t fhh_1 = pen_type_create(PEN_FHH, 100);
+ pen_type_t fhh_2 = pen_type_create(PEN_FHH, 200);
+
+ ck_assert( pen_type_equals(ita_1, ita_1));
+ ck_assert(!pen_type_equals(ita_1, ita_2));
+ ck_assert(!pen_type_equals(ita_1, fhh_1));
+ ck_assert(!pen_type_equals(ita_1, fhh_2));
+}
+END_TEST
+
+/*******************************************************************************
+ * is
+ */
+
+START_TEST(test_pen_type_is)
+{
+ pen_type_t ita_1 = pen_type_create(PEN_ITA, 100);
+
+ ck_assert( pen_type_is(ita_1, PEN_ITA, 100));
+ ck_assert(!pen_type_is(ita_1, PEN_ITA, 200));
+ ck_assert(!pen_type_is(ita_1, PEN_FHH, 100));
+ ck_assert(!pen_type_is(ita_1, PEN_FHH, 200));
+}
+END_TEST
+
+Suite *pen_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("pen");
+
+ tc = tcase_create("create");
+ tcase_add_test(tc, test_pen_type_create);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("equals");
+ tcase_add_test(tc, test_pen_type_equals);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("is");
+ tcase_add_test(tc, test_pen_type_is);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_printf.c b/src/libstrongswan/tests/suites/test_printf.c
new file mode 100644
index 000000000..9e40d1fc0
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_printf.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * 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 "test_suite.h"
+
+#include <errno.h>
+#include <math.h>
+#include <inttypes.h>
+
+static void verify(char *expected, char *format, ...)
+{
+ char buf[128];
+ va_list args;
+
+ va_start(args, format);
+ vsnprintf(buf, sizeof(buf), format, args);
+ ck_assert_str_eq(expected, buf);
+ va_end(args);
+
+#ifdef HAVE_FMEMOPEN
+ {
+ FILE *mem;
+
+ mem = fmemopen(buf, sizeof(buf), "w");
+ va_start(args, format);
+ vfprintf(mem, format, args);
+ va_end(args);
+ fclose(mem);
+ ck_assert_str_eq(expected, buf);
+ }
+#endif /* HAVE_FMEMOPEN */
+}
+
+START_TEST(test_printf_null)
+{
+ char buf[16];
+
+ /* on FreeBSD "(null)" gets printed even when a precision of 0 is used.
+ * because printing of "(null)" for NULL is not standardized we don't verify
+ * the output and just make sure there is no crash */
+ snprintf(buf, sizeof(buf), "%s", NULL);
+}
+END_TEST
+
+START_TEST(test_printf_strings)
+{
+ verify("a bc def", "%s %s %s", "a", "bc", "def");
+ verify("", "%.0s", "asdfg");
+ verify("asd", "%.3s", "asdfg");
+ verify("asdf", "%.*s", (int)4, "asdfg");
+ verify(" asdf", "%6s", "asdf");
+ verify(" asdf", "%+6s", "asdf");
+ verify("asdf ", "%-6s", "asdf");
+}
+END_TEST
+
+START_TEST(test_printf_err)
+{
+ errno = EINVAL;
+ verify((char*)strerror(errno), "%m");
+}
+END_TEST
+
+START_TEST(test_printf_unsigned)
+{
+ verify("1 23 456", "%u %lu %llu", 1, (u_long)23, (u_int64_t)456);
+ verify("65535 255", "%hu %hhu", 0x1ffff, 0x1ff);
+ verify("123456789", "%zu", (size_t)123456789);
+ verify(" 12", "%5u", 12);
+ verify("12 ", "%-5u", 12);
+ verify("0012", "%04u", 12);
+ verify("0012", "%.4u", 12);
+}
+END_TEST
+
+START_TEST(test_printf_signed)
+{
+ verify("-1 -23 -456", "%d %ld %lld", -1, (long)-23, (int64_t)-456);
+ verify("-1 -1", "%hd %hhd", 0x1ffff, 0x1ff);
+ verify("123456789", "%zd", (ssize_t)123456789);
+ verify(" -12", "%5d", -12);
+ verify("-12 ", "%-5d", -12);
+ verify("-012", "%04d", -12);
+ verify("-0012", "%.4d", -12);
+}
+END_TEST
+
+START_TEST(test_printf_hex)
+{
+ verify("1 23 456", "%x %lx %llx", 1, (u_long)0x23, (u_int64_t)0x456);
+ verify("12abcdef 12ABCDEF", "%x %X", 0x12ABCDEF, 0x12ABCDEF);
+ verify("ffff ff", "%hx %hhx", 0x1ffff, 0x1ff);
+ verify("23456789", "%zx", (size_t)0x23456789);
+ verify(" ab", "%5x", 0xab);
+ verify("ab ", "%-5x", 0xab);
+ verify("00ab", "%04x", 0xab);
+ verify("00ab", "%.4x", 0xab);
+}
+END_TEST
+
+START_TEST(test_printf_float)
+{
+ verify("0.000000", "%f", 0.0);
+ verify("1.000000", "%f", 1.0);
+ verify("12345.1", "%.1f", 12345.123);
+ verify("1", "%.0f", 1.0);
+ verify("1.3", "%.1f", 1.346789);
+ verify("1.23", "%.2f", 1.23456789);
+ verify("1.123", "%.3f", 1.123456789);
+ verify("1.0123", "%.4f", 1.0123456789);
+
+ verify("-1.000000", "%f", -1.0);
+ verify("-12345.1", "%.1f", -12345.123);
+ verify("-1", "%.0f", -1.0);
+ verify("-1.3", "%.1f", -1.3456789);
+ verify("-1.23", "%.2f", -1.23456789);
+ verify("-1.123", "%.3f", -1.123456789);
+ verify("-1.0123", "%.4f", -1.0123456789);
+
+ verify(" 1.2", "%5.1f", 1.234);
+ verify("001.2", "%05.1f", 1.234);
+ verify("1.2 ", "%-5.1f", 1.234);
+
+ verify("12346", "%.0f", 12345.6789);
+ verify("2", "%.0f", 1.5);
+ verify("1", "%.0f", 1.49);
+ verify("1.2", "%.1f", 1.151);
+ verify("1.1", "%.1f", 1.149);
+ verify("1.13", "%.2f", 1.1251);
+ verify("1.12", "%.2f", 1.1249);
+ verify("1.124", "%.3f", 1.12351);
+ verify("1.123", "%.3f", 1.12349);
+
+ verify("-12346", "%.0f", -12345.6789);
+ verify("-2", "%.0f", -1.51);
+ verify("-1", "%.0f", -1.49);
+ verify("-1.2", "%.1f", -1.151);
+ verify("-1.1", "%.1f", -1.149);
+ verify("-1.13", "%.2f", -1.1251);
+ verify("-1.12", "%.2f", -1.1249);
+ verify("-1.124", "%.3f", -1.12351);
+ verify("-1.123", "%.3f", -1.12349);
+
+#ifdef NAN
+ verify("nan", "%.3f", NAN);
+ verify(" nan", "%5.3f", NAN);
+ verify("NAN", "%.3F", NAN);
+ verify("NAN ", "%-5.3F", NAN);
+#endif
+#ifdef INFINITY
+ verify("inf", "%.3f", INFINITY);
+ verify("-inf", "%.4f", -INFINITY);
+ verify("INF", "%.3F", INFINITY);
+ verify("-INF", "%.4F", -INFINITY);
+#endif
+}
+END_TEST
+
+START_TEST(test_printf_pri)
+{
+ verify("255", "%" PRIu8, (u_int8_t)0xFF);
+ verify("65535", "%" PRIu16, (u_int16_t)0xFFFF);
+ verify("4294967295", "%" PRIu32, (u_int32_t)0x1FFFFFFFFll);
+ verify("18446744073709551615", "%" PRIu64, (u_int64_t)0xFFFFFFFFFFFFFFFFll);
+
+ verify("-1", "%" PRId8, (int8_t)-1);
+ verify("-1", "%" PRId16, (int16_t)-1);
+ verify("-1", "%" PRId32, (int32_t)-1);
+ verify("-1", "%" PRId64, (int64_t)-1);
+
+ verify("1", "%" PRIuMAX, (uintmax_t)1);
+ verify("1", "%" PRIuPTR, (uintptr_t)1);
+
+ verify("-1", "%" PRIdMAX, (intmax_t)-1);
+ verify("-1", "%" PRIdPTR, (intptr_t)-1);
+}
+END_TEST
+
+Suite *printf_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("printf");
+
+ tc = tcase_create("strings");
+ tcase_add_test(tc, test_printf_null);
+ tcase_add_test(tc, test_printf_strings);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("err");
+ tcase_add_test(tc, test_printf_err);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("unsiged");
+ tcase_add_test(tc, test_printf_unsigned);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("siged");
+ tcase_add_test(tc, test_printf_signed);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("hex");
+ tcase_add_test(tc, test_printf_hex);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("float");
+ tcase_add_test(tc, test_printf_float);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("PRI*");
+ tcase_add_test(tc, test_printf_pri);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_rsa.c b/src/libstrongswan/tests/suites/test_rsa.c
new file mode 100644
index 000000000..2c1c6fb8d
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_rsa.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * 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 "test_suite.h"
+
+#include <plugins/plugin_feature.h>
+
+/**
+ * Signature schemes to test
+ */
+static signature_scheme_t schemes[] = {
+ SIGN_RSA_EMSA_PKCS1_NULL,
+ SIGN_RSA_EMSA_PKCS1_MD5,
+ SIGN_RSA_EMSA_PKCS1_SHA1,
+ SIGN_RSA_EMSA_PKCS1_SHA224,
+ SIGN_RSA_EMSA_PKCS1_SHA256,
+ SIGN_RSA_EMSA_PKCS1_SHA384,
+ SIGN_RSA_EMSA_PKCS1_SHA512,
+};
+
+/**
+ * Perform a signature verification "good" test having a keypair
+ */
+static void test_good_sig(private_key_t *privkey, public_key_t *pubkey)
+{
+ chunk_t sig, data = chunk_from_chars(0x01,0x02,0x03,0xFD,0xFE,0xFF);
+ int i;
+
+ for (i = 0; i < countof(schemes); i++)
+ {
+ if (!lib->plugins->has_feature(lib->plugins,
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, schemes[i])) ||
+ !lib->plugins->has_feature(lib->plugins,
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, schemes[i])))
+ {
+ continue;
+ }
+ fail_unless(privkey->sign(privkey, schemes[i], data, &sig),
+ "sign %N", signature_scheme_names, schemes[i]);
+ fail_unless(pubkey->verify(pubkey, schemes[i], data, sig),
+ "verify %N", signature_scheme_names, schemes[i]);
+ free(sig.ptr);
+ }
+}
+
+/**
+ * Some special signatures that should never validate successfully
+ */
+static chunk_t invalid_sigs[] = {
+ chunk_from_chars(),
+ chunk_from_chars(0x00),
+ chunk_from_chars(0x00,0x00),
+ chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
+ chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
+ chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
+ chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
+ chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
+ chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
+};
+
+/**
+ * Check public key that it properly fails against some crafted sigs
+ */
+static void test_bad_sigs(public_key_t *pubkey)
+{
+ chunk_t data = chunk_from_chars(0x01,0x02,0x03,0xFD,0xFE,0xFF);
+ int s, i;
+
+ for (s = 0; s < countof(schemes); s++)
+ {
+ if (!lib->plugins->has_feature(lib->plugins,
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, schemes[s])))
+ {
+ continue;
+ }
+ for (i = 0; i < countof(invalid_sigs); i++)
+ {
+ fail_if(
+ pubkey->verify(pubkey, schemes[s], data, invalid_sigs[i]),
+ "bad %N sig accepted %B", signature_scheme_names, schemes[s],
+ &invalid_sigs[i]);
+ }
+ }
+}
+
+/**
+ * RSA key sizes to test
+ */
+static int key_sizes[] = {
+ 768, 1024, 1536, 2048, 3072, 4096,
+};
+
+START_TEST(test_gen)
+{
+ private_key_t *privkey;
+ public_key_t *pubkey;
+
+ privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
+ BUILD_KEY_SIZE, key_sizes[_i], BUILD_END);
+ ck_assert(privkey != NULL);
+ pubkey = privkey->get_public_key(privkey);
+ ck_assert(pubkey != NULL);
+
+ test_good_sig(privkey, pubkey);
+
+ test_bad_sigs(pubkey);
+
+ pubkey->destroy(pubkey);
+ privkey->destroy(privkey);
+}
+END_TEST
+
+/**
+ * Private keys to load
+ */
+static chunk_t keys[] = {
+ chunk_from_chars( /* RSA-768 */
+ 0x30,0x82,0x01,0xcb,0x02,0x01,0x00,0x02,0x61,0x00,0xd1,0x5d,0x98,0x97,0x95,0x98,
+ 0x19,0x87,0x20,0x3f,0x10,0xb0,0x05,0x36,0x1e,0x1b,0xcd,0xc8,0x93,0x66,0xd7,0x43,
+ 0xed,0x84,0xb0,0x3e,0x96,0xd3,0xe7,0x27,0x0e,0xc0,0xba,0xdf,0x7e,0x32,0x05,0xd3,
+ 0x08,0xd6,0x44,0xd5,0x01,0x2b,0x3e,0x5d,0xc0,0x37,0xae,0x4f,0xe0,0xea,0x8d,0x2c,
+ 0x42,0x4c,0xa9,0xa2,0x42,0xbe,0xdd,0xdb,0xf7,0xd3,0x28,0x07,0x10,0x88,0x53,0x15,
+ 0xb2,0x4f,0xb5,0x9d,0x47,0x9b,0xd6,0xc8,0xfe,0x5b,0xa2,0xd7,0xe1,0x13,0xca,0x0b,
+ 0xce,0x7a,0xed,0xa2,0x3e,0xd5,0x9b,0xb8,0x8b,0x4f,0x02,0x03,0x01,0x00,0x01,0x02,
+ 0x60,0x2d,0x83,0x82,0x53,0x99,0xb2,0xaa,0x02,0x05,0x11,0x90,0xa8,0x23,0x49,0xe3,
+ 0x7b,0xb9,0xdd,0x9b,0xa5,0xa4,0xb0,0x60,0xa7,0x12,0xc5,0x58,0x76,0x92,0x6e,0x9c,
+ 0x37,0x6b,0xa8,0x80,0x3f,0x91,0xa2,0x91,0xee,0x3a,0xa2,0x6f,0x91,0x9e,0x0a,0x35,
+ 0x69,0xc0,0xa7,0xdc,0xd8,0x46,0xe4,0x29,0x1c,0x3d,0x34,0x30,0xa2,0xb9,0x0d,0x34,
+ 0x94,0xa1,0x12,0xa7,0x85,0xd3,0x2c,0x47,0x1b,0xf0,0x78,0xd5,0x22,0xfc,0xa5,0xe0,
+ 0x75,0xac,0x71,0x21,0xe8,0xe8,0x19,0x9f,0xbb,0x98,0x5c,0xa6,0x9d,0x42,0xd7,0x9c,
+ 0x89,0x02,0x31,0x00,0xee,0xaa,0x9e,0x82,0xe1,0xb2,0xdd,0x05,0xbc,0x2e,0x53,0xe9,
+ 0x64,0x4b,0x48,0x06,0x3a,0xfd,0x9e,0x91,0xce,0x1b,0x7f,0x66,0xbc,0xd2,0xc4,0xab,
+ 0xbf,0xc5,0x5d,0x1a,0xbd,0xd6,0xb5,0x9c,0x5c,0x18,0x01,0xe6,0x79,0x19,0xf2,0xc3,
+ 0x1d,0x66,0x88,0x2d,0x02,0x31,0x00,0xe0,0x92,0x34,0x1e,0x09,0xf2,0x1b,0xf9,0xbf,
+ 0x11,0x65,0x3f,0xc8,0x85,0x5a,0xe6,0xc0,0xcf,0x93,0x44,0xb0,0x50,0xe4,0x8b,0x6f,
+ 0x30,0xde,0x42,0x0c,0x8a,0x77,0x0d,0x98,0x7f,0x52,0x59,0x9e,0x87,0xb8,0x6e,0xdc,
+ 0xed,0x15,0x80,0xbd,0xbb,0xf2,0xeb,0x02,0x31,0x00,0xb0,0x6b,0x36,0x98,0x90,0xb5,
+ 0x62,0x63,0xa6,0xe2,0xa7,0xec,0x51,0xd2,0xc3,0xfe,0xb7,0x04,0x5a,0x7e,0x74,0xd8,
+ 0x26,0xa8,0x8e,0xd3,0x4d,0xc5,0x97,0x10,0x10,0xee,0x7f,0x7d,0x82,0xe9,0x7d,0xb9,
+ 0xd1,0x4d,0xc8,0x1e,0xc2,0x30,0x30,0x3f,0x66,0x51,0x02,0x31,0x00,0xaa,0x75,0x2f,
+ 0x4c,0x11,0xbe,0x8d,0x0f,0x8f,0xc1,0x13,0x7a,0x4b,0xa9,0x35,0x6b,0x6b,0xb4,0xe3,
+ 0x92,0xc2,0xc6,0x54,0x03,0xa6,0x5d,0x90,0x86,0xcf,0xe0,0x16,0x27,0xe2,0xb5,0xd9,
+ 0xfb,0x1e,0x82,0xe4,0x32,0x7a,0x4d,0x17,0x02,0x46,0x82,0x30,0x0b,0x02,0x30,0x09,
+ 0xf3,0xce,0x9b,0x02,0xc5,0x53,0xe9,0xa2,0x89,0xe2,0x3b,0x8c,0x8b,0xe9,0xc2,0xba,
+ 0x94,0x76,0x60,0x27,0x2b,0xe9,0x92,0xc1,0x5e,0x3c,0xc3,0x77,0x9b,0xc7,0xce,0xc6,
+ 0x67,0xd5,0x20,0x2c,0x54,0xa1,0x5d,0x2a,0x17,0x16,0x66,0xdf,0x5a,0xe9,0x87,
+ ),
+ chunk_from_chars( /* RSA-1024 */
+ 0x30,0x82,0x02,0x5c,0x02,0x01,0x00,0x02,0x81,0x81,0x00,0xc0,0xbd,0x48,0x83,0xbc,
+ 0xea,0x0b,0x32,0x06,0x4b,0xf5,0x10,0x54,0x1b,0xba,0x88,0xc4,0x10,0x7e,0x47,0xec,
+ 0x0e,0xf9,0xb4,0xcf,0x9a,0x02,0xc6,0xb3,0xaf,0x35,0xc8,0xaf,0x78,0x1a,0xbc,0x37,
+ 0x1a,0x25,0x7a,0x37,0x24,0x73,0x53,0x9a,0xf0,0x44,0x64,0x5b,0x6b,0x64,0x4c,0xfa,
+ 0x83,0x3a,0x0f,0x77,0x5d,0x7b,0x21,0xa2,0x25,0x00,0x11,0xae,0x72,0x36,0x35,0xd9,
+ 0x0d,0xef,0x5a,0xdd,0x98,0x35,0x49,0xaf,0x44,0xa0,0x33,0x29,0xc0,0xca,0xf5,0x6f,
+ 0xfe,0xc1,0x06,0x4c,0x80,0x9a,0x54,0xbe,0x46,0x1a,0x96,0xb1,0xf3,0x29,0xb8,0x9d,
+ 0x07,0x84,0x03,0x68,0x6b,0x9f,0xbf,0xe5,0xd8,0x14,0x2a,0xe0,0xef,0xbd,0x1a,0x61,
+ 0x0d,0x3a,0xc8,0x67,0xcd,0x99,0x90,0xe3,0xe6,0x52,0x83,0x02,0x03,0x01,0x00,0x01,
+ 0x02,0x81,0x80,0x13,0xd2,0xa3,0xe5,0xa0,0xb0,0x0a,0xe2,0x0f,0x3c,0x65,0x57,0xa8,
+ 0xe9,0x87,0xd5,0x79,0xcc,0xc9,0xca,0xc8,0x8a,0xd5,0xc0,0x74,0x90,0x3e,0x1e,0xda,
+ 0x40,0xcd,0x42,0xf7,0x01,0x09,0x9c,0x37,0xfd,0x41,0x6e,0x2b,0x6e,0x5d,0x4a,0x1e,
+ 0x52,0x53,0x1b,0xbb,0x3c,0x9f,0xfe,0x91,0x79,0x48,0xfc,0x69,0x90,0xbc,0xbc,0x3d,
+ 0xcf,0xee,0x62,0x0a,0xbd,0x57,0x6b,0xa9,0x51,0x3e,0xc2,0x7f,0x26,0xb1,0xaa,0x38,
+ 0xeb,0x40,0x91,0x3a,0x3c,0x80,0x1e,0x4e,0xe2,0xff,0xa2,0x8e,0x56,0xbb,0xb3,0xeb,
+ 0x24,0x81,0x4c,0x19,0x2c,0x8f,0x51,0x4c,0x04,0x81,0xaf,0x5e,0xc2,0xa6,0xf9,0xd3,
+ 0x48,0xee,0xe9,0x6d,0x9b,0xe1,0xe5,0x17,0x4f,0x07,0x18,0xea,0x96,0xd3,0x2c,0xce,
+ 0x44,0x71,0x51,0x02,0x41,0x00,0xe9,0xe9,0x46,0x7e,0xe1,0xc2,0x86,0x94,0x65,0x77,
+ 0x9c,0xc7,0x76,0x5d,0xa0,0xd3,0xcc,0x1f,0xa3,0xc7,0xfe,0xbb,0x4e,0x27,0xd6,0x43,
+ 0x6b,0xbd,0x0d,0x05,0x7a,0x10,0xe8,0x48,0x97,0x30,0xaa,0x53,0x61,0x57,0x1f,0x8a,
+ 0xf7,0x39,0x5e,0xa6,0xfe,0xe9,0x2c,0x19,0x5e,0x53,0xea,0xc2,0xb2,0xc2,0x11,0x3c,
+ 0x18,0xab,0xcf,0xc4,0x91,0x1b,0x02,0x41,0x00,0xd2,0xf0,0xb1,0x49,0xa1,0x6f,0xf1,
+ 0x83,0xa3,0xd2,0xa1,0x0e,0xb3,0xb3,0x33,0x01,0xed,0xd0,0x28,0xc1,0x2f,0x88,0x80,
+ 0x9f,0x43,0x7c,0x7e,0x5d,0x4c,0x15,0x05,0x86,0xff,0x75,0x9b,0xf1,0x64,0xde,0x06,
+ 0xbf,0xdd,0x98,0x50,0xd9,0x4a,0x3a,0xd6,0x25,0x1c,0xdd,0xc8,0x56,0x12,0x11,0xb9,
+ 0x02,0x42,0xc7,0x1d,0x86,0xeb,0xd9,0xc2,0xb9,0x02,0x41,0x00,0x80,0x25,0x8c,0xb9,
+ 0x76,0x75,0x5b,0xc5,0x70,0xd1,0x56,0xd2,0xef,0xc5,0xdb,0x96,0x2c,0xfe,0x28,0x7c,
+ 0x28,0xd1,0xf4,0xbf,0x5e,0x63,0x11,0x63,0x40,0xfe,0xff,0x20,0xc4,0x21,0x00,0xb3,
+ 0x68,0x9c,0xc5,0x77,0x35,0x90,0xac,0x60,0x81,0xba,0x7b,0x6c,0xc2,0xfc,0x22,0xf1,
+ 0x56,0x6b,0xd4,0x02,0xfd,0xee,0x2e,0x95,0xf1,0xfd,0x7e,0x81,0x02,0x40,0x47,0xaf,
+ 0x84,0x90,0x81,0x4c,0x89,0xc7,0x32,0xe5,0x61,0xd6,0x9d,0x3b,0x49,0x1a,0x5e,0xb7,
+ 0x5f,0x22,0x48,0x05,0x1b,0xb1,0x04,0x3e,0x4a,0xb3,0x6a,0x27,0xba,0xb9,0x26,0x17,
+ 0xd1,0xe7,0x37,0x60,0x3c,0xea,0xf7,0x63,0xcc,0x16,0x0c,0x23,0xf2,0xa2,0xaa,0x2c,
+ 0xb4,0xe8,0x8b,0x3b,0x7a,0xa4,0x4a,0x0d,0x60,0xfb,0x79,0x2b,0x88,0x01,0x02,0x40,
+ 0x42,0xee,0x12,0x91,0xf9,0x80,0x1e,0x60,0x0b,0xaa,0xbe,0xfd,0x09,0x84,0x93,0x0d,
+ 0x09,0xd3,0x1e,0x37,0x52,0xb0,0xe8,0x51,0x4f,0xd3,0x9e,0xda,0x32,0x38,0x22,0x35,
+ 0xdb,0x25,0x8b,0x9f,0x1a,0xb5,0xf1,0x75,0xfa,0x4d,0x09,0x42,0x01,0x64,0xe6,0xc4,
+ 0x6e,0xba,0x2d,0x88,0x92,0xbe,0xa9,0x1f,0x85,0x38,0x10,0xa3,0x0e,0x1a,0x92,0x54,
+ ),
+ chunk_from_chars( /* RSA-1536 */
+ 0x30,0x82,0x03,0x7d,0x02,0x01,0x00,0x02,0x81,0xc1,0x00,0xba,0xe3,0x37,0x93,0x7e,
+ 0x42,0x13,0x3c,0xba,0x41,0xc1,0x7b,0xf0,0xcc,0x7a,0x44,0xc6,0x54,0xc8,0x77,0x01,
+ 0x70,0x2f,0x6e,0x4a,0xcf,0x2d,0x07,0xab,0x01,0xc0,0x43,0xab,0x8d,0x33,0xb3,0xd4,
+ 0xeb,0xe3,0x90,0xf6,0x01,0x03,0x75,0x03,0x1d,0xe8,0x06,0x40,0x15,0xfa,0x96,0x0b,
+ 0xd5,0x26,0x64,0xea,0x55,0x82,0x16,0x7b,0xd5,0x1e,0xaa,0x08,0xc7,0x30,0x1a,0x59,
+ 0xf8,0xd9,0xe3,0x9e,0x89,0xd9,0x92,0x2c,0x32,0x79,0x0e,0xb3,0x25,0xbc,0x1d,0x7c,
+ 0x59,0xde,0x05,0x47,0x8f,0x61,0x77,0xf5,0x4f,0xed,0x82,0x2c,0xf8,0x2a,0x3e,0x02,
+ 0xf3,0xc0,0x15,0x51,0xde,0x05,0xc4,0xfc,0x80,0x91,0xae,0x06,0x1b,0xd7,0x39,0x8e,
+ 0x9a,0x6d,0xb3,0x2f,0xb0,0xd0,0xc8,0x96,0xa6,0x88,0xb3,0x17,0xca,0x58,0xbe,0x38,
+ 0x2c,0x64,0x35,0x5a,0x29,0xb7,0xf8,0x74,0x3d,0xbb,0xec,0x90,0x01,0x04,0x64,0x3d,
+ 0x38,0x0f,0x87,0xce,0xd7,0xfc,0xd2,0x96,0x93,0x31,0x85,0x0d,0x2d,0xa5,0x91,0xe2,
+ 0xfc,0x7b,0xea,0xb0,0x89,0x24,0xaa,0x00,0x29,0x8c,0x26,0x7c,0x94,0x54,0x74,0xe4,
+ 0x11,0xa8,0x04,0x6f,0x40,0xeb,0xaf,0xed,0xac,0x75,0x33,0x02,0x03,0x01,0x00,0x01,
+ 0x02,0x81,0xc0,0x0a,0x96,0xec,0x63,0xc1,0xa0,0x39,0xd9,0xd3,0x8d,0xfd,0x4a,0x2a,
+ 0x13,0x54,0x0c,0x48,0x96,0xae,0x43,0x3c,0x04,0x20,0xd3,0xe5,0x8e,0x46,0xb5,0x6c,
+ 0x05,0xad,0xe0,0xc7,0xbc,0x39,0x05,0x44,0x17,0xd7,0xad,0xb3,0x9a,0xcc,0x18,0xd9,
+ 0xc3,0xdc,0x8d,0x5a,0x1d,0x44,0xb5,0x32,0xd7,0x71,0x94,0xff,0x48,0x38,0x16,0x51,
+ 0x0e,0xfa,0xed,0x54,0x91,0x00,0xd3,0x45,0x6c,0xd9,0xdf,0xd1,0x70,0x6b,0x31,0x22,
+ 0xaa,0xfb,0x7c,0x0f,0x3f,0xa0,0xa0,0xa5,0x16,0xac,0x83,0x6d,0x12,0x1d,0x4a,0x40,
+ 0x4e,0xb6,0x9c,0xf4,0x67,0xaa,0xa9,0xb0,0xc8,0xb4,0x0a,0xd5,0x3b,0x5c,0x19,0xed,
+ 0x86,0x83,0x5a,0x75,0xbc,0xeb,0x17,0xc8,0x16,0xa0,0x60,0x2e,0xb6,0x25,0xc5,0x4d,
+ 0x59,0xba,0x62,0xcb,0x3d,0x91,0x7c,0x79,0x6a,0x4b,0x4a,0x54,0xbd,0xb7,0xa3,0x89,
+ 0x7f,0xbf,0x0e,0x77,0xe1,0x54,0x29,0x0d,0x45,0x6d,0xa8,0x15,0xa5,0x17,0x8c,0xcf,
+ 0x27,0x9e,0x47,0x4e,0x2a,0x91,0x7e,0x4e,0x14,0x59,0x8c,0x62,0x91,0xa3,0x40,0xa5,
+ 0x9e,0x67,0xbb,0x02,0x97,0xb4,0xe7,0x06,0x04,0xbc,0x16,0x24,0x3d,0x49,0xb1,0xf0,
+ 0xae,0xfc,0x1d,0x02,0x61,0x00,0xde,0x86,0x5d,0x49,0x88,0xeb,0x5c,0xd3,0xe5,0x11,
+ 0x48,0x0b,0x1e,0x52,0x95,0xa9,0x65,0x99,0x89,0xcf,0x51,0xb0,0x08,0xdd,0xb5,0x5b,
+ 0x64,0x1a,0x34,0xd2,0xee,0x4b,0x2d,0x8b,0xc1,0xd5,0xd6,0x1d,0x6c,0x0c,0x7e,0xa5,
+ 0x66,0x12,0xec,0xaf,0x5d,0xe9,0x33,0xd4,0xba,0x18,0x71,0x84,0x97,0xbe,0xc0,0x75,
+ 0x63,0x19,0xae,0xc6,0xc7,0x65,0xf3,0xf6,0xda,0x3f,0x91,0xfa,0x5e,0x87,0xf3,0xbc,
+ 0xd2,0x64,0x8d,0xcf,0xfb,0xdd,0x7f,0x9b,0x6c,0x81,0xba,0x9b,0x4e,0x94,0x5e,0x83,
+ 0xd1,0xcb,0xb9,0xf4,0x39,0x7f,0x02,0x61,0x00,0xd7,0x00,0x6d,0x8e,0x1b,0xa1,0x44,
+ 0xd9,0xff,0xe6,0x42,0x72,0x18,0x55,0x26,0x3e,0x87,0x40,0x71,0xb2,0x67,0x37,0x16,
+ 0xe9,0xbd,0x51,0x7f,0x0e,0x79,0x0e,0x75,0xa9,0x1f,0x0f,0x6b,0xa5,0x7c,0x5f,0xc8,
+ 0xdc,0x17,0xde,0x53,0x88,0x97,0x90,0x88,0xf2,0x4d,0x66,0x5e,0x0e,0x11,0x16,0x92,
+ 0x1e,0x61,0x56,0xe6,0xf0,0x74,0x81,0x58,0x95,0x05,0x29,0x71,0x9b,0xa0,0x69,0xed,
+ 0x14,0x23,0xf6,0x36,0x9b,0x8f,0x06,0x3a,0x76,0xab,0xeb,0xce,0xe8,0xdc,0x79,0xc1,
+ 0x29,0xb9,0xfc,0x49,0x7a,0x26,0x59,0xd6,0x4d,0x02,0x61,0x00,0xaf,0x3c,0xac,0xd6,
+ 0x2d,0xe6,0xfb,0x91,0x3a,0xc1,0x23,0x34,0xee,0x4a,0x26,0xe5,0xe1,0xc6,0xc9,0xc9,
+ 0xe4,0x10,0x76,0xca,0xf1,0xf8,0xe8,0x99,0xe2,0xa3,0x81,0x58,0xde,0xa3,0x42,0xa0,
+ 0x3d,0x1f,0xaa,0x69,0x24,0x8a,0xe8,0x19,0x5b,0x1e,0xb7,0x1b,0xe0,0xdf,0x53,0x35,
+ 0xd0,0x9f,0x94,0x48,0x79,0x93,0x77,0xd9,0x4f,0xd3,0xe6,0x4f,0x19,0x92,0x7a,0x48,
+ 0xb9,0x92,0xab,0x42,0xf0,0xe4,0xef,0xe2,0x93,0xf3,0x07,0xeb,0x64,0x84,0x67,0x2c,
+ 0xba,0x61,0x77,0xbe,0x4b,0xb8,0x0f,0x4d,0x1a,0x41,0x83,0xcd,0x02,0x60,0x56,0xec,
+ 0x55,0x5e,0x9e,0xcd,0x14,0x89,0x0e,0x6c,0x89,0x70,0x97,0x65,0xd5,0x90,0x72,0x1e,
+ 0x1b,0xd9,0x84,0xe1,0x40,0xe2,0x3f,0x28,0x33,0xb6,0x26,0x3b,0x32,0x56,0xad,0xb8,
+ 0x0e,0x4d,0x59,0x7b,0x60,0x39,0x9b,0x6c,0xc7,0x58,0xf1,0xed,0xfd,0x6f,0xf8,0xda,
+ 0xea,0x2b,0xc5,0xbc,0xda,0x56,0x6e,0x04,0x34,0x5a,0x02,0xc0,0x48,0x8f,0xf7,0x06,
+ 0x4a,0x68,0x20,0xf2,0xb2,0x66,0xf2,0x23,0x18,0xf0,0xcb,0x62,0x39,0x40,0xc1,0x41,
+ 0x14,0xe6,0x10,0x3d,0x29,0x5b,0x35,0x56,0x4a,0x5e,0x98,0x22,0xba,0x01,0x02,0x61,
+ 0x00,0xcc,0x80,0xb7,0xb9,0xb9,0x4a,0xaf,0x47,0x00,0x3e,0x21,0x0f,0xb8,0x4e,0x7c,
+ 0xb1,0xe4,0x25,0xd6,0x19,0x26,0x54,0xc6,0x8c,0x30,0x88,0x54,0x70,0xcf,0x1f,0x62,
+ 0x75,0xcb,0x18,0x58,0x6c,0x14,0xb0,0x9b,0x13,0x90,0xa2,0x1a,0x5a,0x79,0xa3,0x82,
+ 0xf0,0x9b,0xba,0xf0,0x90,0xaf,0xa1,0xe8,0xa8,0x70,0xef,0x60,0x6a,0x68,0xed,0x5a,
+ 0x21,0x77,0x69,0x7a,0xf2,0xee,0x3e,0xe5,0x90,0xd2,0x33,0x71,0x3b,0x82,0x88,0x75,
+ 0xdd,0x8e,0x6e,0xbc,0x17,0x83,0xef,0x37,0x82,0x4e,0x83,0x30,0xcb,0x8a,0xbc,0x6c,
+ 0x41,
+ ),
+ chunk_from_chars( /* RSA-2048 */
+ 0x30,0x82,0x04,0xa2,0x02,0x01,0x00,0x02,0x82,0x01,0x01,0x00,0xba,0xbf,0x27,0x0b,
+ 0x22,0x59,0xd8,0x6f,0xff,0x26,0x5d,0x41,0x3d,0xb0,0x94,0x58,0x5d,0xc0,0x46,0xb6,
+ 0x77,0xa9,0x78,0x10,0x6d,0xe9,0xbf,0xca,0x6f,0x04,0xe1,0xda,0x85,0x12,0x1e,0xe0,
+ 0xa6,0xc7,0xa2,0x71,0x04,0x8b,0x6e,0x84,0xf9,0x86,0x2b,0xeb,0x72,0x01,0x72,0xc8,
+ 0x0a,0x83,0xa6,0xf7,0xc0,0xd6,0x76,0x1d,0x28,0x38,0xb5,0x7e,0x6c,0x8c,0x6a,0x13,
+ 0xf4,0xf1,0x7f,0xf2,0x79,0xae,0x73,0xba,0x1a,0x3f,0x30,0x65,0xb6,0x23,0xa7,0x94,
+ 0x34,0x29,0x87,0xce,0x06,0x99,0xee,0x85,0x10,0xce,0x08,0xe2,0x8d,0xd5,0x47,0xf3,
+ 0xc8,0xf0,0x18,0x41,0xc0,0x59,0x66,0x06,0xda,0xb6,0x18,0xd2,0xa3,0xa0,0xbd,0x3a,
+ 0x90,0x7f,0x37,0x39,0xdf,0x98,0x55,0xa2,0x19,0x5e,0x37,0xbc,0x86,0xf3,0x02,0xf8,
+ 0x68,0x49,0x53,0xf2,0x4b,0x3d,0x7a,0xe3,0x1d,0xa4,0x15,0x10,0xa6,0xce,0x8c,0xb8,
+ 0xfd,0x95,0x54,0xa2,0x50,0xa2,0xd9,0x35,0x12,0x56,0xae,0xbc,0x51,0x33,0x6d,0xb8,
+ 0x63,0x7c,0x26,0xab,0x19,0x01,0xa5,0xda,0xfa,0x4b,0xb6,0x57,0xd3,0x4b,0xdd,0xc0,
+ 0x62,0xc5,0x05,0xb7,0xc3,0x2e,0x1f,0x17,0xc8,0x09,0x87,0x12,0x37,0x21,0xd7,0x7a,
+ 0x53,0xb0,0x47,0x60,0xa2,0xb5,0x23,0x3b,0x99,0xdf,0xea,0x8b,0x94,0xea,0x9d,0x53,
+ 0x5d,0x02,0x52,0xf7,0x29,0xfb,0x63,0xb0,0xff,0x27,0x5e,0xde,0x54,0x7d,0x95,0xd6,
+ 0x4e,0x58,0x12,0x06,0x60,0x22,0x33,0xf2,0x19,0x67,0x65,0xdd,0xf3,0x42,0xb5,0x00,
+ 0x51,0x35,0xe5,0x62,0x4d,0x90,0x44,0xfb,0x7f,0x5b,0xb5,0xe5,0x02,0x03,0x01,0x00,
+ 0x01,0x02,0x82,0x01,0x00,0x1c,0xf5,0x66,0xf5,0xce,0x4c,0x1d,0xe8,0xd2,0x29,0x6e,
+ 0x15,0x1f,0x9e,0x9a,0x06,0x70,0xf5,0x4f,0xd1,0xdc,0x51,0x02,0x8e,0x13,0xa9,0x47,
+ 0x85,0x39,0xfd,0x89,0x13,0x74,0x86,0xb8,0x94,0x90,0x30,0x4d,0x73,0x96,0xa7,0x93,
+ 0x8a,0x19,0xd2,0x91,0x4d,0x77,0xb6,0x9b,0x48,0xc3,0x7e,0xa2,0x5d,0xf1,0x80,0xa0,
+ 0x3c,0xc9,0xbf,0xaf,0x7f,0x4d,0x10,0x62,0x23,0xb9,0x9c,0x58,0x81,0xae,0x96,0x5b,
+ 0x9a,0x4c,0x97,0x27,0x67,0x62,0x5c,0xf9,0x8f,0xdd,0x1d,0xe2,0x92,0x13,0x8a,0x7b,
+ 0xc7,0x15,0x31,0xca,0x05,0x6d,0xc6,0x98,0xdb,0x88,0x39,0x99,0x1d,0x5b,0x19,0x51,
+ 0xdd,0xb6,0xbd,0x3d,0xb0,0xae,0x50,0x8e,0xff,0x7d,0xa8,0x48,0x95,0x58,0x23,0xbc,
+ 0x85,0xc0,0x46,0xd0,0xc0,0x0e,0xda,0xdd,0xa4,0x8e,0x8d,0x31,0x8b,0x89,0x0f,0x8b,
+ 0x76,0x9a,0xb5,0x99,0x56,0x5e,0xd3,0x0c,0x88,0x0b,0x03,0xf1,0xc9,0xe3,0x05,0x05,
+ 0x08,0x75,0xce,0x35,0x52,0xa0,0xc0,0xf2,0xf4,0xb9,0x87,0x22,0x21,0x3f,0x61,0xd6,
+ 0x99,0xae,0x0e,0x76,0x5d,0x9c,0x16,0xa3,0xe9,0xde,0x2d,0x2a,0x46,0xf7,0x89,0xbf,
+ 0x0d,0xb1,0x60,0xad,0xbc,0x24,0xe2,0xe5,0xb1,0xc1,0x1c,0x00,0x40,0x1c,0xbd,0xfa,
+ 0x6e,0xc7,0x0d,0xc1,0xda,0x4d,0x54,0x45,0x96,0xac,0xf7,0xfe,0x1b,0xf2,0x47,0x1e,
+ 0xf7,0x8b,0xcf,0x27,0xcc,0xe7,0x08,0xd6,0x43,0x60,0xea,0xda,0x19,0xd7,0x98,0x17,
+ 0x7c,0xab,0x0c,0x90,0x60,0x75,0x9f,0x8b,0xaa,0x13,0x63,0x98,0x9e,0xc6,0x41,0x9f,
+ 0xd4,0x85,0xa3,0xb2,0xb9,0x02,0x81,0x81,0x00,0xe1,0x20,0xf6,0xac,0xa9,0x01,0xbd,
+ 0x31,0xe6,0xb2,0x4e,0xcf,0x66,0xc3,0x11,0x0e,0x5b,0xfe,0x58,0x6b,0xc6,0x2d,0x7a,
+ 0x05,0x30,0x9a,0x6f,0xcc,0xcc,0xdf,0xd2,0x2c,0xe1,0x47,0x39,0x9e,0xf3,0x0c,0x81,
+ 0xd9,0x76,0x00,0xe2,0xb1,0x08,0x91,0xfb,0x12,0x04,0xf6,0x1f,0xea,0xff,0x82,0xe5,
+ 0x64,0x64,0x6f,0x14,0xbe,0x33,0x5f,0x41,0x5f,0x73,0x1f,0xa2,0x32,0xec,0x75,0xb3,
+ 0x98,0x4b,0x88,0x4d,0x1e,0xec,0x78,0xda,0x4c,0x2d,0xf8,0xbb,0xcf,0x0e,0x8f,0x2f,
+ 0x23,0xae,0xcd,0xe0,0x4c,0x13,0x1c,0x1c,0x16,0x8e,0xb9,0x9f,0x02,0x12,0x12,0xa5,
+ 0xf4,0x21,0xfe,0x57,0x08,0x7a,0xe8,0xbe,0x15,0xe9,0xdd,0x2a,0xd1,0x7b,0x39,0xd6,
+ 0x4f,0x70,0x74,0x7d,0xfd,0x39,0x97,0x80,0x8d,0x02,0x81,0x81,0x00,0xd4,0x5a,0xce,
+ 0x05,0x93,0x51,0x15,0x44,0xdd,0x4d,0x79,0x92,0x04,0xe6,0x64,0x7e,0x6c,0xb5,0x61,
+ 0x6b,0xc3,0xb3,0xae,0x4f,0x0a,0x75,0xbf,0x6c,0xec,0x47,0xf2,0xbc,0xea,0x76,0xc4,
+ 0xc2,0xe7,0xd2,0x50,0xc4,0xe0,0xaf,0x56,0x05,0x72,0x3c,0x34,0x8c,0x5b,0xae,0xb8,
+ 0x0e,0xfb,0x83,0x27,0xcf,0x61,0x05,0x44,0x97,0x3f,0x66,0x6d,0x26,0x7d,0xed,0xcd,
+ 0x5a,0x87,0x04,0xbc,0xb3,0x70,0x75,0x15,0x51,0xe9,0x18,0x85,0xf7,0x2a,0x45,0xd5,
+ 0xc7,0x93,0x32,0x07,0x2e,0x26,0x34,0x2d,0x18,0x63,0x45,0x06,0x6f,0xa9,0x75,0x5d,
+ 0x20,0x6b,0x0b,0x13,0x45,0x81,0x7e,0x5c,0xc5,0x48,0x16,0x4b,0x82,0x7c,0xad,0xbe,
+ 0xfd,0xa5,0x0a,0xd6,0xc2,0x21,0xfc,0xa5,0x84,0xaf,0xf3,0x10,0xb9,0x02,0x81,0x80,
+ 0x29,0x20,0x20,0x6f,0xc2,0x1f,0xf3,0x33,0xde,0x74,0xcc,0x38,0xcf,0x08,0xeb,0x60,
+ 0xb8,0x25,0x6a,0x79,0xa5,0xa6,0x41,0x18,0x19,0x9c,0xdc,0xb7,0x88,0xe5,0x8a,0x3b,
+ 0x70,0x9b,0xd6,0x46,0xd7,0x17,0x7d,0xd0,0xff,0xe1,0x81,0x87,0xdd,0x8c,0xed,0x54,
+ 0x89,0x5b,0x7c,0xd1,0x2d,0x03,0xf8,0x6b,0xb2,0x7d,0x28,0x48,0xe6,0x91,0x8c,0x1b,
+ 0xa7,0xa8,0x2b,0xb5,0x29,0xc5,0x06,0x9d,0xd7,0x8e,0x7a,0xa8,0x1f,0x82,0xa4,0x3e,
+ 0x2e,0x57,0xb5,0xd7,0x49,0x4d,0x96,0xca,0xe9,0xef,0xe9,0xfd,0x7b,0xb0,0x32,0xe1,
+ 0x5c,0x09,0x44,0xa6,0xd8,0x2e,0x57,0xea,0x95,0x1b,0x25,0x43,0x03,0x50,0xe9,0x08,
+ 0x8f,0xc4,0x3b,0x42,0x31,0x44,0x8b,0x85,0xcf,0x81,0x38,0x52,0xbd,0xe6,0x93,0x31,
+ 0x02,0x81,0x80,0x18,0x3d,0x79,0x51,0x07,0x9c,0xf4,0xd9,0x94,0x8d,0x78,0x78,0x23,
+ 0x99,0x0d,0x15,0xa5,0x61,0x1b,0x0a,0xcb,0x1f,0x22,0xa1,0xa1,0x27,0x09,0xbf,0xec,
+ 0x44,0xd6,0x3f,0x9c,0x60,0x0c,0x5b,0xd7,0x4c,0x99,0xad,0xaf,0x9c,0x34,0x2c,0x90,
+ 0xfa,0xb0,0x60,0xe9,0x42,0x4b,0x7e,0x62,0x55,0x79,0x60,0xe1,0xc9,0x51,0x28,0x16,
+ 0xb3,0xa1,0x78,0x08,0x5d,0xf1,0xd8,0x08,0x9b,0x90,0xd2,0xc6,0xde,0x86,0x9d,0x80,
+ 0x07,0x2d,0x9b,0xa6,0x36,0xac,0x8d,0x88,0x8e,0xe8,0x64,0xeb,0x35,0x7f,0x84,0x4e,
+ 0x28,0x9d,0xf0,0x77,0x1e,0x8f,0x8f,0xd8,0xc8,0x3d,0xdd,0xec,0x47,0x39,0x5d,0xc7,
+ 0xb9,0xcb,0xca,0xcc,0x62,0xa4,0xef,0x9d,0x3c,0x5c,0x81,0x72,0x91,0xbd,0x6f,0x25,
+ 0x0a,0x90,0xf9,0x02,0x81,0x80,0x51,0x42,0x23,0x64,0x3d,0xbc,0xcb,0xcb,0x77,0xd4,
+ 0x5c,0x6b,0xf4,0x16,0x3a,0x6b,0x05,0x5f,0xd4,0xf8,0x59,0xe6,0x98,0x0c,0x43,0x7e,
+ 0x6b,0x17,0x0d,0x01,0x23,0x6e,0x4c,0xff,0x35,0xe4,0xc5,0xba,0xe8,0x9e,0x12,0x94,
+ 0x34,0x78,0xe4,0x3d,0x35,0xa1,0xd4,0xa9,0xa3,0x7e,0xe4,0x57,0xef,0xa4,0x9a,0x6a,
+ 0x32,0xb3,0x9f,0xf8,0x3a,0xcf,0xea,0xf4,0xc7,0x59,0x92,0xd4,0x2a,0x5b,0x26,0x83,
+ 0x78,0x30,0x5f,0xdf,0x46,0xa6,0xb0,0x28,0x37,0x2b,0x55,0x08,0x4c,0xb6,0x6b,0xb8,
+ 0xa9,0x11,0x7d,0x0b,0xab,0x97,0x4d,0x8c,0xc3,0xbf,0x3b,0xcd,0x3e,0xad,0x80,0xce,
+ 0xe8,0xc6,0x01,0x35,0xd2,0x3e,0x31,0xdc,0x96,0xd7,0xc3,0xab,0x65,0xd1,0xc4,0xa3,
+ 0x47,0x14,0xa9,0xba,0xd0,0x30,
+ ),
+};
+
+START_TEST(test_load)
+{
+ private_key_t *privkey;
+ public_key_t *pubkey;
+
+ privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
+ BUILD_BLOB_ASN1_DER, keys[_i], BUILD_END);
+ ck_assert(privkey != NULL);
+ pubkey = privkey->get_public_key(privkey);
+ ck_assert(pubkey != NULL);
+
+ test_good_sig(privkey, pubkey);
+
+ test_bad_sigs(pubkey);
+
+ pubkey->destroy(pubkey);
+ privkey->destroy(privkey);
+}
+END_TEST
+
+Suite *rsa_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+ int gen_count = countof(key_sizes);
+
+ s = suite_create("rsa");
+
+ if (getenv("TESTS_REDUCED_KEYLENGTHS") != NULL)
+ {
+ gen_count = min(1, gen_count);
+ }
+
+ tc = tcase_create("generate");
+ tcase_add_loop_test(tc, test_gen, 0, gen_count);
+ tcase_set_timeout(tc, 8);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("load");
+ tcase_add_loop_test(tc, test_load, 0, countof(keys));
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_settings.c b/src/libstrongswan/tests/suites/test_settings.c
new file mode 100644
index 000000000..096465191
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_settings.c
@@ -0,0 +1,920 @@
+/*
+ * Copyright (C) 2014 Tobias Brunner
+ * 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 "test_suite.h"
+
+#include <unistd.h>
+
+#include <utils/settings.h>
+#include <utils/chunk.h>
+#include <utils/utils.h>
+#include <collections/linked_list.h>
+
+static char *path = "/tmp/strongswan-settings-test";
+static settings_t *settings;
+
+static void create_settings(chunk_t contents)
+{
+ ck_assert(chunk_write(contents, path, 0022, TRUE));
+ settings = settings_create(path);
+}
+
+START_SETUP(setup_base_config)
+{
+ create_settings(chunk_from_str(
+ "main {\n"
+ " key1 = val1\n"
+ " # this gets overridden below\n"
+ " key2 = val2\n"
+ " none = \n"
+ " sub1 {\n"
+ " key = value\n"
+ " key2 = value2\n"
+ " subsub {\n"
+ " foo = bar\n"
+ " }\n"
+ " # subsub is a section and a value\n"
+ " subsub = section value\n"
+ " }\n"
+ " sub% {\n"
+ " id = %any\n"
+ " }\n"
+ " key2 = with spaces\n"
+ "}\n"
+ "out = side\n"
+ "other {\n"
+ " key1 = other val\n"
+ " empty {\n"
+ " }\n"
+ "}"));
+}
+END_SETUP
+
+START_TEARDOWN(teardown_config)
+{
+ settings->destroy(settings);
+ unlink(path);
+}
+END_TEARDOWN
+
+#define verify_string(expected, key, ...) \
+ ck_assert_str_eq(expected, settings->get_str(settings, key, NULL, ##__VA_ARGS__))
+#define verify_null(key, ...) \
+ ck_assert(!settings->get_str(settings, key, NULL, ##__VA_ARGS__))
+
+START_TEST(test_get_str)
+{
+ verify_string("val1", "main.key1");
+ verify_string("val1", "main..key1");
+ verify_string("val1", ".main.key1");
+ verify_string("with spaces", "main.key2");
+ verify_string("value", "main.sub1.key");
+ verify_string("value2", "main.sub1.key2");
+ verify_string("bar", "main.sub1.subsub.foo");
+ verify_string("section value", "main.sub1.subsub");
+ verify_string("%any", "main.sub%%.id");
+ verify_string("side", "out");
+ verify_string("other val", "other.key1");
+
+ /* FIXME: should this rather be undefined i.e. return the default value? */
+ verify_string("", "main.none");
+
+ verify_null("main.key3");
+ verify_null("other.sub");
+}
+END_TEST
+
+enum {
+ KEY1,
+ SUB1
+} settings_test_enum;
+
+enum_name_t *test_settings_test_names;
+
+ENUM_BEGIN(test_settings_test_names, KEY1, SUB1,
+ "key1", "sub1");
+ENUM_END(test_settings_test_names, SUB1);
+
+START_TEST(test_get_str_printf)
+{
+ verify_string("val1", "%s.key1", "main");
+ verify_string("val1", "%s.%s", "main", "key1");
+ verify_string("val1", "%s.%N", "main", test_settings_test_names, KEY1);
+ verify_string("val1", "%s.%s%d", "main", "key", 1);
+ verify_string("bar", "%s.sub1.%s.foo", "main", "subsub");
+ verify_string("bar", "%s.%N.%s.foo", "main", test_settings_test_names, SUB1, "subsub");
+ verify_string("bar", "%s.sub%d.%s.foo", "main", 1, "subsub");
+ verify_string("%any", "%s.sub%%.id", "main");
+
+ /* FIXME: this is a bit inconsistent, while this works */
+ verify_string("value2", "main.%s%u.key2", "sub", 1);
+ /* this won't because no argument is consumed for %u so key1 will be tried
+ * granted, we never actually used any other specifiers, but we should
+ * probably document it at least */
+ verify_null("main.%s%u.key%d", "sub", 1, 2);
+
+ verify_null("%s.%s%d", "main", "key", 3);
+}
+END_TEST
+
+START_TEST(test_set_str)
+{
+ settings->set_str(settings, "main.key1", "val");
+ verify_string("val", "main.key1");
+ settings->set_str(settings, "main.key1", "longer value");
+ verify_string("longer value", "main.key1");
+ settings->set_str(settings, "main", "main val");
+ verify_string("main val", "main");
+ settings->set_str(settings, "main.sub1.new", "added");
+ verify_string("added", "main.sub1.new");
+ settings->set_str(settings, "main.sub2.newsub.foo", "bar");
+ verify_string("bar", "main.sub2.newsub.foo");
+ settings->set_str(settings, "new.newsub.foo", "bar");
+ verify_string("bar", "new.newsub.foo");
+ settings->set_str(settings, "main.key1", NULL);
+ verify_null("main.key1");
+}
+END_TEST
+
+START_TEST(test_set_str_printf)
+{
+ settings->set_str(settings, "%s.key1", "val", "main");
+ verify_string("val", "main.key1");
+ settings->set_str(settings, "main.%N.new", "added", test_settings_test_names, SUB1);
+ verify_string("added", "main.sub1.new");
+ settings->set_str(settings, "main.%s%d.newsub.%s", "bar", "sub", 2, "foo");
+ verify_string("bar", "main.sub2.newsub.foo");
+}
+END_TEST
+
+START_TEST(test_set_default_str)
+{
+ settings->set_default_str(settings, "main.key1", "default");
+ verify_string("val1", "main.key1");
+ settings->set_default_str(settings, "main.sub1.new", "added");
+ verify_string("added", "main.sub1.new");
+ settings->set_str(settings, "main.sub1.new", "changed");
+ verify_string("changed", "main.sub1.new");
+}
+END_TEST
+
+START_SETUP(setup_bool_config)
+{
+ create_settings(chunk_from_str(
+ "main {\n"
+ " key1 = yes\n"
+ " key2 = true\n"
+ " key3 = Enabled\n"
+ " key4 = 1\n"
+ " key5 = no\n"
+ " key6 = FALSE\n"
+ " key7 = disabled\n"
+ " key8 = 0\n"
+ " key9 = 5\n"
+ " none = \n"
+ " foo = bar\n"
+ "}"));
+}
+END_SETUP
+
+#define verify_bool(expected, def, key, ...) \
+ ck_assert(expected == settings->get_bool(settings, key, def, ##__VA_ARGS__))
+
+START_TEST(test_get_bool)
+{
+ verify_bool(TRUE, FALSE, "main.key1");
+ verify_bool(TRUE, FALSE, "main.key2");
+ verify_bool(TRUE, FALSE, "main.key3");
+ verify_bool(TRUE, FALSE, "main.key4");
+ verify_bool(FALSE, TRUE, "main.key5");
+ verify_bool(FALSE, TRUE, "main.key6");
+ verify_bool(FALSE, TRUE, "main.key7");
+ verify_bool(FALSE, TRUE, "main.key8");
+
+ verify_bool(FALSE, FALSE, "main.none");
+ verify_bool(TRUE, TRUE, "main.none");
+ verify_bool(FALSE, FALSE, "main.foo");
+ verify_bool(TRUE, TRUE, "main.foo");
+
+ verify_bool(FALSE, FALSE, "main.key9");
+ verify_bool(TRUE, TRUE, "main.key9");
+ verify_bool(FALSE, FALSE, "main");
+ verify_bool(TRUE, TRUE, "main");
+
+}
+END_TEST
+
+START_TEST(test_set_bool)
+{
+ settings->set_str(settings, "main.key1", "no");
+ verify_bool(FALSE, TRUE, "main.key1");
+ settings->set_bool(settings, "main.key2", FALSE);
+ verify_bool(FALSE, TRUE, "main.key2");
+ settings->set_str(settings, "main.key3", NULL);
+ verify_bool(FALSE, FALSE, "main.key3");
+ verify_bool(TRUE, TRUE, "main.key3");
+ settings->set_bool(settings, "main.key5", TRUE);
+ verify_bool(TRUE, FALSE, "main.key5");
+ settings->set_bool(settings, "main.new", TRUE);
+ verify_bool(TRUE, FALSE, "main.new");
+}
+END_TEST
+
+START_SETUP(setup_int_config)
+{
+ create_settings(chunk_from_str(
+ "main {\n"
+ " key1 = 5\n"
+ " # gets cut off\n"
+ " key2 = 5.5\n"
+ " key3 = -42\n"
+ " none = \n"
+ " foo1 = bar\n"
+ " foo2 = bar13\n"
+ " foo3 = 13bar\n"
+ "}"));
+}
+END_SETUP
+
+#define verify_int(expected, def, key, ...) \
+ ck_assert_int_eq(expected, settings->get_int(settings, key, def, ##__VA_ARGS__))
+
+START_TEST(test_get_int)
+{
+ verify_int(5, 0, "main.key1");
+ verify_int(5, 0, "main.key2");
+ verify_int(-42, 0, "main.key3");
+
+ /* FIXME: do we want this behavior? */
+ verify_int(0, 11, "main.none");
+ verify_int(0, 11, "main.foo1");
+ verify_int(0, 11, "main.foo2");
+ verify_int(13, 11, "main.foo3");
+
+ verify_int(13, 13, "main.key4");
+ verify_int(-13, -13, "main");
+}
+END_TEST
+
+START_TEST(test_set_int)
+{
+ settings->set_str(settings, "main.key1", "13");
+ verify_int(13, 0, "main.key1");
+ settings->set_int(settings, "main.key2", 6);
+ verify_int(6, 0, "main.key2");
+ settings->set_int(settings, "main.key3", -6);
+ verify_int(-6, 0, "main.key3");
+ settings->set_str(settings, "main.key3", NULL);
+ verify_int(15, 15, "main.key3");
+ settings->set_int(settings, "main.new", 314);
+ verify_int(314, 0, "main.new");
+}
+END_TEST
+
+START_SETUP(setup_double_config)
+{
+ create_settings(chunk_from_str(
+ "main {\n"
+ " key1 = 5\n"
+ " key2 = 5.5\n"
+ " key3 = -42\n"
+ " key4 = -42.5\n"
+ " none = \n"
+ " foo1 = bar\n"
+ " foo2 = bar13.5\n"
+ " foo3 = 13.5bar\n"
+ "}"));
+}
+END_SETUP
+
+#define verify_double(expected, def, key, ...) \
+ ck_assert(expected == settings->get_double(settings, key, def, ##__VA_ARGS__))
+
+START_TEST(test_get_double)
+{
+ verify_double(5, 0, "main.key1");
+ verify_double(5.5, 0, "main.key2");
+ verify_double(-42, 0, "main.key3");
+ verify_double(-42.5, 0, "main.key4");
+
+ /* FIXME: do we want this behavior? */
+ verify_double(0, 11.5, "main.none");
+ verify_double(0, 11.5, "main.foo1");
+ verify_double(0, 11.5, "main.foo2");
+ verify_double(13.5, 11.5, "main.foo3");
+
+ verify_double(11.5, 11.5, "main.key5");
+ verify_double(-11.5, -11.5, "main");
+}
+END_TEST
+
+START_TEST(test_set_double)
+{
+ settings->set_str(settings, "main.key1", "5.5");
+ verify_double(5.5, 0, "main.key1");
+ settings->set_double(settings, "main.key2", 13);
+ verify_double(13, 0, "main.key2");
+ settings->set_double(settings, "main.key3", -13.5);
+ verify_double(-13.5, 0, "main.key3");
+ settings->set_double(settings, "main.key4", 11.5);
+ verify_double(11.5, 0, "main.key4");
+ settings->set_str(settings, "main.key4", NULL);
+ verify_double(42.5, 42.5, "main.key4");
+ settings->set_double(settings, "main.new", 3.14);
+ verify_double(3.14, 0, "main.new");
+}
+END_TEST
+
+START_SETUP(setup_time_config)
+{
+ create_settings(chunk_from_str(
+ "main {\n"
+ " key1 = 5s\n"
+ " key2 = 5m\n"
+ " key3 = 5h\n"
+ " key4 = 5d\n"
+ " none = \n"
+ " foo1 = bar\n"
+ " foo2 = bar13\n"
+ " foo3 = 13bar\n"
+ "}"));
+}
+END_SETUP
+
+#define verify_time(expected, def, key, ...) \
+ ck_assert_int_eq(expected, settings->get_time(settings, key, def, ##__VA_ARGS__))
+
+START_TEST(test_get_time)
+{
+ verify_time(5, 0, "main.key1");
+ verify_time(300, 0, "main.key2");
+ verify_time(18000, 0, "main.key3");
+ verify_time(432000, 0, "main.key4");
+
+ /* FIXME: do we want this behavior? */
+ verify_time(0, 11, "main.none");
+ verify_time(0, 11, "main.foo1");
+ verify_time(0, 11, "main.foo2");
+ verify_time(13, 11, "main.foo3");
+
+ verify_time(11, 11, "main.key5");
+ verify_time(11, 11, "main");
+}
+END_TEST
+
+START_TEST(test_set_time)
+{
+ settings->set_str(settings, "main.key1", "15m");
+ verify_time(900, 0, "main.key1");
+ settings->set_time(settings, "main.key2", 15);
+ verify_time(15, 0, "main.key2");
+ settings->set_str(settings, "main.key3", NULL);
+ verify_time(300, 300, "main.key3");
+ settings->set_time(settings, "main.new", 314);
+ verify_time(314, 0, "main.new");
+}
+END_TEST
+
+static bool verify_section(linked_list_t *verifier, char *section)
+{
+ enumerator_t *enumerator;
+ char *current;
+ bool result = FALSE;
+
+ enumerator = verifier->create_enumerator(verifier);
+ while (enumerator->enumerate(enumerator, &current))
+ {
+ if (streq(current, section))
+ {
+ verifier->remove_at(verifier, enumerator);
+ result = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return result;
+}
+
+static void verify_sections(linked_list_t *verifier, char *parent)
+{
+ enumerator_t *enumerator;
+ char *section;
+
+ enumerator = settings->create_section_enumerator(settings, parent);
+ while (enumerator->enumerate(enumerator, &section))
+ {
+ ck_assert(verify_section(verifier, section));
+ }
+ enumerator->destroy(enumerator);
+ ck_assert_int_eq(0, verifier->get_count(verifier));
+ verifier->destroy(verifier);
+}
+
+START_TEST(test_section_enumerator)
+{
+ linked_list_t *verifier;
+
+ verifier = linked_list_create_with_items("sub1", "sub%", NULL);
+ verify_sections(verifier, "main");
+
+ settings->set_str(settings, "main.sub2.new", "added");
+ verifier = linked_list_create_with_items("sub1", "sub%", "sub2", NULL);
+ verify_sections(verifier, "main");
+
+ verifier = linked_list_create_with_items("subsub", NULL);
+ verify_sections(verifier, "main.sub1");
+
+ verifier = linked_list_create_with_items(NULL);
+ verify_sections(verifier, "main.sub%%");
+
+ verifier = linked_list_create_with_items(NULL);
+ verify_sections(verifier, "main.key1");
+
+ verifier = linked_list_create_with_items(NULL);
+ verify_sections(verifier, "main.unknown");
+}
+END_TEST
+
+static bool verify_key_value(linked_list_t *keys, linked_list_t *values,
+ char *key, char *value)
+{
+ enumerator_t *enum_keys, *enum_values;
+ char *current_key, *current_value;
+ bool result = FALSE;
+
+ enum_keys = keys->create_enumerator(keys);
+ enum_values = values->create_enumerator(values);
+ while (enum_keys->enumerate(enum_keys, &current_key) &&
+ enum_values->enumerate(enum_values, &current_value))
+ {
+ if (streq(current_key, key))
+ {
+ ck_assert_str_eq(current_value, value);
+ keys->remove_at(keys, enum_keys);
+ values->remove_at(values, enum_values);
+ result = TRUE;
+ break;
+ }
+ }
+ enum_keys->destroy(enum_keys);
+ enum_values->destroy(enum_values);
+ return result;
+}
+
+static void verify_key_values(linked_list_t *keys, linked_list_t *values,
+ char *parent)
+{
+ enumerator_t *enumerator;
+ char *key, *value;
+
+ enumerator = settings->create_key_value_enumerator(settings, parent);
+ while (enumerator->enumerate(enumerator, &key, &value))
+ {
+ ck_assert(verify_key_value(keys, values, key, value));
+ }
+ enumerator->destroy(enumerator);
+ ck_assert_int_eq(0, keys->get_count(keys));
+ keys->destroy(keys);
+ values->destroy(values);
+}
+
+START_TEST(test_key_value_enumerator)
+{
+ linked_list_t *keys, *values;
+
+ keys = linked_list_create_with_items("key1", "key2", "none", NULL);
+ values = linked_list_create_with_items("val1", "with spaces", "", NULL);
+ verify_key_values(keys, values, "main");
+
+ keys = linked_list_create_with_items("key", "key2", "subsub", NULL);
+ values = linked_list_create_with_items("value", "value2", "section value", NULL);
+ verify_key_values(keys, values, "main.sub1");
+
+ settings->set_str(settings, "main.sub2.new", "added");
+ keys = linked_list_create_with_items("new", NULL);
+ values = linked_list_create_with_items("added", NULL);
+ verify_key_values(keys, values, "main.sub2");
+
+ keys = linked_list_create_with_items(NULL);
+ values = linked_list_create_with_items(NULL);
+ verify_key_values(keys, values, "other.empty");
+
+ settings->set_str(settings, "other.empty.new", "added");
+ keys = linked_list_create_with_items("new", NULL);
+ values = linked_list_create_with_items("added", NULL);
+ verify_key_values(keys, values, "other.empty");
+
+ keys = linked_list_create_with_items(NULL);
+ values = linked_list_create_with_items(NULL);
+ verify_key_values(keys, values, "main.unknown");
+}
+END_TEST
+
+#define include1 "/tmp/strongswan-settings-test-include1"
+#define include2 "/tmp/strongswan-settings-test-include2"
+
+START_SETUP(setup_include_config)
+{
+ chunk_t inc1 = chunk_from_str(
+ "main {\n"
+ " key1 = n1\n"
+ " key2 = n2\n"
+ " none = \n"
+ " sub1 {\n"
+ " key3 = value\n"
+ " }\n"
+ " sub2 {\n"
+ " sub3 = val3\n"
+ " }\n"
+ " include " include2 "\n"
+ "}");
+ chunk_t inc2 = chunk_from_str(
+ "key2 = v2\n"
+ "sub1 {\n"
+ " key = val\n"
+ "}");
+ ck_assert(chunk_write(inc1, include1, 0022, TRUE));
+ ck_assert(chunk_write(inc2, include2, 0022, TRUE));
+}
+END_SETUP
+
+START_TEARDOWN(teardown_include_config)
+{
+ settings->destroy(settings);
+ unlink(include2);
+ unlink(include1);
+ unlink(path);
+}
+END_TEARDOWN
+
+static void verify_include()
+{
+ verify_string("n1", "main.key1");
+ verify_string("v2", "main.key2");
+ verify_string("", "main.none");
+ verify_string("val", "main.sub1.key");
+ verify_string("v2", "main.sub1.key2");
+ verify_string("val", "main.sub1.sub1.key");
+ verify_string("value", "main.sub1.key3");
+ verify_string("value", "main.sub1.include");
+ verify_string("val3", "main.sub2.sub3");
+}
+
+START_TEST(test_include)
+{
+ chunk_t contents = chunk_from_str(
+ "main {\n"
+ " key1 = val1\n"
+ " key2 = val2\n"
+ " none = x\n"
+ " sub1 {\n"
+ " include = value\n"
+ " key2 = value2\n"
+ " include " include2 "\n"
+ " }\n"
+ "}\n"
+ "# currently there must be a newline after include statements\n"
+ "include " include1 "\n");
+
+ create_settings(contents);
+ verify_include();
+}
+END_TEST
+
+START_TEST(test_load_files)
+{
+ chunk_t contents = chunk_from_str(
+ "main {\n"
+ " key1 = val1\n"
+ " key2 = val2\n"
+ " none = x\n"
+ " sub1 {\n"
+ " include = value\n"
+ " key2 = v2\n"
+ " sub1 {\n"
+ " key = val\n"
+ " }\n"
+ " }\n"
+ "}");
+
+ create_settings(contents);
+
+ ck_assert(settings->load_files(settings, include1, TRUE));
+ verify_include();
+
+ ck_assert(settings->load_files(settings, include2, FALSE));
+ verify_null("main.key1");
+ verify_string("v2", "key2");
+ verify_string("val", "sub1.key");
+ verify_null("main.sub1.key3");
+}
+END_TEST
+
+START_TEST(test_load_files_section)
+{
+ chunk_t contents = chunk_from_str(
+ "main {\n"
+ " key1 = val1\n"
+ " key2 = val2\n"
+ " none = x\n"
+ " sub1 {\n"
+ " include = value\n"
+ " key2 = value2\n"
+ " }\n"
+ "}");
+
+ create_settings(contents);
+
+ ck_assert(settings->load_files_section(settings, include1, TRUE, ""));
+ ck_assert(settings->load_files_section(settings, include2, TRUE, "main.sub1"));
+ verify_include();
+
+ /* non existing files are no failure */
+ ck_assert(settings->load_files_section(settings, include1".conf", TRUE, ""));
+ verify_include();
+
+ /* unreadable files are */
+ ck_assert(chunk_write(contents, include1".no", 0444, TRUE));
+ ck_assert(!settings->load_files_section(settings, include1".no", TRUE, ""));
+ unlink(include1".no");
+ verify_include();
+
+ ck_assert(settings->load_files_section(settings, include2, FALSE, "main"));
+ verify_null("main.key1");
+ verify_string("v2", "main.key2");
+ verify_string("val", "main.sub1.key");
+ verify_null("main.sub1.key3");
+ verify_null("main.sub2.sub3");
+
+ ck_assert(settings->load_files_section(settings, include2, TRUE, "main.sub2"));
+ verify_string("v2", "main.sub2.key2");
+ verify_string("val", "main.sub2.sub1.key");
+}
+END_TEST
+
+START_SETUP(setup_fallback_config)
+{
+ create_settings(chunk_from_str(
+ "main {\n"
+ " key1 = val1\n"
+ " sub1 {\n"
+ " key1 = val1\n"
+ " }\n"
+ "}\n"
+ "sub {\n"
+ " key1 = subval1\n"
+ " key2 = subval2\n"
+ " subsub {\n"
+ " subkey1 = subsubval1\n"
+ " }\n"
+ "}\n"
+ "base {\n"
+ " key1 = baseval1\n"
+ " key2 = baseval2\n"
+ " sub1 {\n"
+ " key1 = subbase1\n"
+ " key2 = subbase2\n"
+ " key3 = subbase3\n"
+ " subsub {\n"
+ " subkey1 = subsubbaseval1\n"
+ " subkey2 = subsubbaseval2\n"
+ " }\n"
+ " }\n"
+ " sub2 {\n"
+ " key4 = subbase4\n"
+ " }\n"
+ "}"));
+}
+END_SETUP
+
+START_TEST(test_add_fallback)
+{
+ linked_list_t *keys, *values;
+
+ settings->add_fallback(settings, "main.sub1", "sub");
+ verify_string("val1", "main.sub1.key1");
+ verify_string("subval2", "main.sub1.key2");
+ verify_string("subsubval1", "main.sub1.subsub.subkey1");
+
+ /* fallbacks are preserved even if the complete config is replaced */
+ settings->load_files(settings, path, FALSE);
+ verify_string("val1", "main.sub1.key1");
+ verify_string("subval2", "main.sub1.key2");
+ verify_string("subsubval1", "main.sub1.subsub.subkey1");
+
+ keys = linked_list_create_with_items("sub1", NULL);
+ verify_sections(keys, "main");
+ keys = linked_list_create_with_items("subsub", NULL);
+ verify_sections(keys, "main.sub1");
+
+ keys = linked_list_create_with_items("key1", NULL);
+ values = linked_list_create_with_items("val1", NULL);
+ verify_key_values(keys, values, "main");
+
+ keys = linked_list_create_with_items("key1", "key2", NULL);
+ values = linked_list_create_with_items("val1", "subval2", NULL);
+ verify_key_values(keys, values, "main.sub1");
+
+ keys = linked_list_create_with_items("subkey1", NULL);
+ values = linked_list_create_with_items("subsubval1", NULL);
+ verify_key_values(keys, values, "main.sub1.subsub");
+
+ settings->add_fallback(settings, "main", "base");
+ verify_string("val1", "main.key1");
+ verify_string("baseval2", "main.key2");
+ verify_string("val1", "main.sub1.key1");
+ verify_string("subval2", "main.sub1.key2");
+ verify_string("subsubval1", "main.sub1.subsub.subkey1");
+ verify_string("subsubbaseval2", "main.sub1.subsub.subkey2");
+ verify_string("subbase3", "main.sub1.key3");
+ verify_string("subbase4", "main.sub2.key4");
+
+
+ keys = linked_list_create_with_items("sub1", "sub2", NULL);
+ verify_sections(keys, "main");
+ keys = linked_list_create_with_items("subsub", NULL);
+ verify_sections(keys, "main.sub1");
+
+ keys = linked_list_create_with_items("key1", "key2", NULL);
+ values = linked_list_create_with_items("val1", "baseval2", NULL);
+ verify_key_values(keys, values, "main");
+
+ keys = linked_list_create_with_items("key1", "key2", "key3", NULL);
+ values = linked_list_create_with_items("val1", "subval2", "subbase3", NULL);
+ verify_key_values(keys, values, "main.sub1");
+
+ keys = linked_list_create_with_items("subkey1", "subkey2", NULL);
+ values = linked_list_create_with_items("subsubval1", "subsubbaseval2", NULL);
+ verify_key_values(keys, values, "main.sub1.subsub");
+
+ settings->set_str(settings, "main.sub1.key2", "val2");
+ verify_string("val2", "main.sub1.key2");
+ settings->set_str(settings, "main.sub1.subsub.subkey2", "val2");
+ verify_string("val2", "main.sub1.subsub.subkey2");
+ verify_string("subsubval1", "main.sub1.subsub.subkey1");
+}
+END_TEST
+
+START_TEST(test_add_fallback_printf)
+{
+ settings->add_fallback(settings, "%s.sub1", "sub", "main");
+ verify_string("val1", "main.sub1.key1");
+ verify_string("subval2", "main.sub1.key2");
+ verify_string("subsubval1", "main.sub1.subsub.subkey1");
+
+ settings->add_fallback(settings, "%s.%s2", "%s.%s1", "main", "sub");
+ verify_string("val1", "main.sub2.key1");
+ verify_string("subval2", "main.sub2.key2");
+ verify_string("subsubval1", "main.sub2.subsub.subkey1");
+}
+END_TEST
+
+START_SETUP(setup_invalid_config)
+{
+ create_settings(chunk_from_str(
+ "# section without name\n"
+ "{\n"
+ " key1 = val1\n"
+ "}\n"
+ "main {\n"
+ " key2 = val2\n"
+ " # value without key\n"
+ " = val3\n"
+ " key4 = val4\n"
+ " # key without value does not change it\n"
+ " key4\n"
+ " # subsection without name\n"
+ " {\n"
+ " key5 = val5\n"
+ " }\n"
+ " # empty include pattern\n"
+ " include\n"
+ " key6 = val6\n"
+ "}"));
+}
+END_SETUP
+
+START_TEST(test_invalid)
+{
+ linked_list_t *keys, *values;
+ chunk_t contents;
+
+ verify_null("key1");
+ verify_null(".key1");
+ verify_null("%s.key1", "");
+ verify_string("val2", "main.key2");
+ verify_string("val4", "main.key4");
+ verify_null("main..key5");
+ verify_string("val6", "main.key6");
+
+ keys = linked_list_create_with_items("main", NULL);
+ verify_sections(keys, "");
+
+ keys = linked_list_create_with_items(NULL);
+ verify_sections(keys, "main");
+
+ keys = linked_list_create_with_items("key2", "key4", "key6", NULL);
+ values = linked_list_create_with_items("val2", "val4", "val6", NULL);
+ verify_key_values(keys, values, "main");
+
+ /* FIXME: we should probably fix this */
+ contents = chunk_from_str(
+ "requires = newline");
+ ck_assert(chunk_write(contents, path, 0022, TRUE));
+ ck_assert(!settings->load_files(settings, path, FALSE));
+
+ contents = chunk_from_str(
+ "unterminated {\n"
+ " not = valid\n");
+ ck_assert(chunk_write(contents, path, 0022, TRUE));
+ ck_assert(!settings->load_files(settings, path, FALSE));
+
+ contents = chunk_from_str(
+ "singleline { not = valid }\n");
+ ck_assert(chunk_write(contents, path, 0022, TRUE));
+ ck_assert(!settings->load_files(settings, path, FALSE));
+}
+END_TEST
+
+Suite *settings_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("settings");
+
+ tc = tcase_create("get/set_str (basic behavior)");
+ tcase_add_checked_fixture(tc, setup_base_config, teardown_config);
+ tcase_add_test(tc, test_get_str);
+ tcase_add_test(tc, test_get_str_printf);
+ tcase_add_test(tc, test_set_str);
+ tcase_add_test(tc, test_set_str_printf);
+ tcase_add_test(tc, test_set_default_str);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("get/set_bool");
+ tcase_add_checked_fixture(tc, setup_bool_config, teardown_config);
+ tcase_add_test(tc, test_get_bool);
+ tcase_add_test(tc, test_set_bool);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("get/set_int");
+ tcase_add_checked_fixture(tc, setup_int_config, teardown_config);
+ tcase_add_test(tc, test_get_int);
+ tcase_add_test(tc, test_set_int);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("get/set_double");
+ tcase_add_checked_fixture(tc, setup_double_config, teardown_config);
+ tcase_add_test(tc, test_get_double);
+ tcase_add_test(tc, test_set_double);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("get/set_time");
+ tcase_add_checked_fixture(tc, setup_time_config, teardown_config);
+ tcase_add_test(tc, test_get_time);
+ tcase_add_test(tc, test_set_time);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("section enumerator");
+ tcase_add_checked_fixture(tc, setup_base_config, teardown_config);
+ tcase_add_test(tc, test_section_enumerator);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("key/value enumerator");
+ tcase_add_checked_fixture(tc, setup_base_config, teardown_config);
+ tcase_add_test(tc, test_key_value_enumerator);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("include/load_files[_section]");
+ tcase_add_checked_fixture(tc, setup_include_config, teardown_include_config);
+ tcase_add_test(tc, test_include);
+ tcase_add_test(tc, test_load_files);
+ tcase_add_test(tc, test_load_files_section);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("fallback");
+ tcase_add_checked_fixture(tc, setup_fallback_config, teardown_config);
+ tcase_add_test(tc, test_add_fallback);
+ tcase_add_test(tc, test_add_fallback_printf);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("invalid data");
+ tcase_add_checked_fixture(tc, setup_invalid_config, teardown_config);
+ tcase_add_test(tc, test_invalid);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_stream.c b/src/libstrongswan/tests/suites/test_stream.c
new file mode 100644
index 000000000..2d3173d46
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_stream.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * 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 "test_suite.h"
+
+#include <unistd.h>
+
+static char* services[] = {
+ "unix:///tmp/strongswan-test-service.sck",
+ "tcp://127.0.0.1:7766",
+ "tcp://[::1]:7766",
+};
+
+static char msg[] = "testmessage";
+static int msglen = 12;
+
+static bool servicing(void *data, stream_t *stream)
+{
+ char buf[64];
+ ssize_t len, total;
+
+ ck_assert(streq((char*)data, "test"));
+
+ for (total = 0; total < msglen;)
+ {
+ len = stream->read(stream, buf, sizeof(buf), TRUE);
+ ck_assert(len > 0);
+ total += len;
+ }
+ for (total = 0; total < msglen;)
+ {
+ len = stream->write(stream, buf, len, TRUE);
+ ck_assert(len > 0);
+ total += len;
+ }
+
+ return FALSE;
+}
+
+START_TEST(test_sync)
+{
+ char buf[64];
+ stream_service_t *service;
+ stream_t *stream;
+ ssize_t len, total;
+
+ lib->processor->set_threads(lib->processor, 8);
+
+ service = lib->streams->create_service(lib->streams, services[_i], 1);
+ ck_assert(service != NULL);
+ service->on_accept(service, servicing, "test", JOB_PRIO_HIGH, 1);
+
+ stream = lib->streams->connect(lib->streams, services[_i]);
+ ck_assert(stream != NULL);
+ for (total = 0; total < msglen;)
+ {
+ len = stream->write(stream, msg, msglen, TRUE);
+ ck_assert(len > 0);
+ total += len;
+ }
+ for (total = 0; total < msglen;)
+ {
+ len = stream->read(stream, buf, sizeof(buf), TRUE);
+ ck_assert(len > 0);
+ total += len;
+ }
+ ck_assert(streq(buf, msg));
+ stream->destroy(stream);
+
+ service->destroy(service);
+}
+END_TEST
+
+static bool on_write(void *data, stream_t *stream)
+{
+ ssize_t len, total;
+
+ ck_assert(streq((char*)data, "test-write"));
+ for (total = 0; total < msglen;)
+ {
+ len = stream->write(stream, msg, msglen, TRUE);
+ ck_assert(len > 0);
+ total += len;
+ }
+ return FALSE;
+}
+
+static bool read_done = FALSE;
+
+static bool on_read(void *data, stream_t *stream)
+{
+ ssize_t len, total;
+ char buf[64];
+
+ ck_assert(streq((char*)data, "test-read"));
+ for (total = 0; total < msglen;)
+ {
+ len = stream->read(stream, buf, sizeof(buf), TRUE);
+ ck_assert(len > 0);
+ total += len;
+ }
+ ck_assert(streq(buf, msg));
+ read_done = TRUE;
+ return FALSE;
+}
+
+START_TEST(test_async)
+{
+ stream_service_t *service;
+ stream_t *stream;
+
+
+ lib->processor->set_threads(lib->processor, 8);
+
+ service = lib->streams->create_service(lib->streams, services[_i], 1);
+ ck_assert(service != NULL);
+ service->on_accept(service, servicing, "test", JOB_PRIO_HIGH, 0);
+
+ stream = lib->streams->connect(lib->streams, services[_i]);
+ ck_assert(stream != NULL);
+ read_done = FALSE;
+ stream->on_write(stream, (stream_cb_t)on_write, "test-write");
+ stream->on_read(stream, (stream_cb_t)on_read, "test-read");
+
+ while (!read_done)
+ {
+ usleep(1000);
+ }
+ stream->destroy(stream);
+
+ service->destroy(service);
+}
+END_TEST
+
+static bool all(void *data, stream_t *stream)
+{
+ char buf[64], *pos;
+ ssize_t len;
+ int i;
+
+ pos = buf;
+ for (i = 0; i < msglen; i++)
+ {
+ len = stream->read(stream, pos, 1, TRUE);
+ ck_assert_int_eq(len, 1);
+ pos += len;
+ }
+ pos = buf;
+ for (i = 0; i < msglen; i++)
+ {
+ len = stream->write(stream, pos, 1, TRUE);
+ ck_assert_int_eq(len, 1);
+ pos += len;
+ }
+
+ return FALSE;
+}
+
+START_TEST(test_all)
+{
+ char buf[64];
+ stream_service_t *service;
+ stream_t *stream;
+
+ lib->processor->set_threads(lib->processor, 8);
+
+ service = lib->streams->create_service(lib->streams, services[_i], 1);
+ ck_assert(service != NULL);
+ service->on_accept(service, all, NULL, JOB_PRIO_HIGH, 1);
+
+ stream = lib->streams->connect(lib->streams, services[_i]);
+ ck_assert(stream != NULL);
+ ck_assert(stream->write_all(stream, msg, msglen));
+ ck_assert(stream->read_all(stream, buf, msglen));
+ ck_assert(streq(buf, msg));
+ stream->destroy(stream);
+
+ service->destroy(service);
+}
+END_TEST
+
+static bool concurrency(void *data, stream_t *stream)
+{
+ static refcount_t refs = 0;
+ u_int current;
+ ssize_t len;
+
+ current = ref_get(&refs);
+ ck_assert(current <= 3);
+ len = stream->write(stream, "x", 1, TRUE);
+ ck_assert_int_eq(len, 1);
+ usleep(1000);
+ ignore_result(ref_put(&refs));
+
+ return FALSE;
+}
+
+START_TEST(test_concurrency)
+{
+ stream_service_t *service;
+ stream_t *streams[10];
+ ssize_t len;
+ char x;
+ int i;
+
+ lib->processor->set_threads(lib->processor, 8);
+
+ service = lib->streams->create_service(lib->streams, services[_i], 10);
+ ck_assert(service != NULL);
+ service->on_accept(service, concurrency, NULL, JOB_PRIO_HIGH, 3);
+
+ for (i = 0; i < countof(streams); i++)
+ {
+ streams[i] = lib->streams->connect(lib->streams, services[_i]);
+ ck_assert(streams[i] != NULL);
+ }
+ for (i = 0; i < countof(streams); i++)
+ {
+ len = streams[i]->read(streams[i], &x, 1, TRUE);
+ ck_assert_int_eq(len, 1);
+ ck_assert_int_eq(x, 'x');
+ }
+ for (i = 0; i < countof(streams); i++)
+ {
+ streams[i]->destroy(streams[i]);
+ }
+ service->destroy(service);
+}
+END_TEST
+
+Suite *stream_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("stream");
+
+ tc = tcase_create("sync");
+ tcase_add_loop_test(tc, test_sync, 0, countof(services));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("async");
+ tcase_add_loop_test(tc, test_async, 0, countof(services));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("all");
+ tcase_add_loop_test(tc, test_all, 0, countof(services));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("concurrency");
+ tcase_add_loop_test(tc, test_concurrency, 0, countof(services));
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_test_rng.c b/src/libstrongswan/tests/suites/test_test_rng.c
new file mode 100644
index 000000000..9a983b677
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_test_rng.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 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 "test_suite.h"
+
+#include <tests/utils/test_rng.h>
+#include <utils/test.h>
+
+START_TEST(test_test_rng)
+{
+ rng_t *entropy;
+ chunk_t in, in1, in2, out;
+
+ in1 = chunk_from_chars(0x01, 0x02, 0x03, 0x04, 0x05, 0x06);
+ in2 = chunk_from_chars(0x07, 0x08);
+ in = chunk_cat("cc", in1, in2);
+
+ entropy = test_rng_create(in);
+ ck_assert(entropy->allocate_bytes(entropy, 6, &out));
+ ck_assert(chunk_equals(in1, out));
+ ck_assert(entropy->get_bytes(entropy, 2, out.ptr));
+ ck_assert(memeq(in2.ptr, out.ptr, in2.len));
+ ck_assert(!entropy->get_bytes(entropy, 4, out.ptr));
+ chunk_free(&out);
+ ck_assert(!entropy->allocate_bytes(entropy, 4, &out));
+ entropy->destroy(entropy);
+ chunk_free(&in);
+}
+END_TEST
+
+
+Suite *test_rng_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("test_rng");
+
+ tc = tcase_create("test_rng");
+ tcase_add_test(tc, test_test_rng);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_threading.c b/src/libstrongswan/tests/suites/test_threading.c
new file mode 100644
index 000000000..844959e46
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_threading.c
@@ -0,0 +1,1466 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * Copyright (C) 2008 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 "test_suite.h"
+
+#include <sched.h>
+#include <unistd.h>
+
+#include <threading/thread.h>
+#include <threading/mutex.h>
+#include <threading/condvar.h>
+#include <threading/rwlock.h>
+#include <threading/rwlock_condvar.h>
+#include <threading/spinlock.h>
+#include <threading/semaphore.h>
+#include <threading/thread_value.h>
+
+/*******************************************************************************
+ * recursive mutex test
+ */
+
+#define THREADS 20
+
+/**
+ * Thread barrier data
+ */
+typedef struct {
+ mutex_t *mutex;
+ condvar_t *cond;
+ int count;
+ int current;
+ bool active;
+} barrier_t;
+
+/**
+ * Create a thread barrier for count threads
+ */
+static barrier_t* barrier_create(int count)
+{
+ barrier_t *this;
+
+ INIT(this,
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .cond = condvar_create(CONDVAR_TYPE_DEFAULT),
+ .count = count,
+ );
+
+ return this;
+}
+
+/**
+ * Destroy a thread barrier
+ */
+static void barrier_destroy(barrier_t *this)
+{
+ this->mutex->destroy(this->mutex);
+ this->cond->destroy(this->cond);
+ free(this);
+}
+
+/**
+ * Wait to have configured number of threads in barrier
+ */
+static bool barrier_wait(barrier_t *this)
+{
+ bool winner = FALSE;
+
+ this->mutex->lock(this->mutex);
+ if (!this->active)
+ { /* first, reset */
+ this->active = TRUE;
+ this->current = 0;
+ }
+
+ this->current++;
+ while (this->current < this->count)
+ {
+ this->cond->wait(this->cond, this->mutex);
+ }
+ if (this->active)
+ { /* first, win */
+ winner = TRUE;
+ this->active = FALSE;
+ }
+ this->mutex->unlock(this->mutex);
+ this->cond->broadcast(this->cond);
+ sched_yield();
+
+ return winner;
+}
+
+/**
+ * Barrier for some tests
+ */
+static barrier_t *barrier;
+
+/**
+ * A mutex for tests requiring one
+ */
+static mutex_t *mutex;
+
+/**
+ * A condvar for tests requiring one
+ */
+static condvar_t *condvar;
+
+/**
+ * A counter for signaling
+ */
+static int sigcount;
+
+static void *mutex_run(void *data)
+{
+ int locked = 0;
+ int i;
+
+ /* wait for all threads before getting in action */
+ barrier_wait(barrier);
+
+ for (i = 0; i < 100; i++)
+ {
+ mutex->lock(mutex);
+ mutex->lock(mutex);
+ mutex->lock(mutex);
+ locked++;
+ sched_yield();
+ if (locked > 1)
+ {
+ fail("two threads locked the mutex concurrently");
+ }
+ locked--;
+ mutex->unlock(mutex);
+ mutex->unlock(mutex);
+ mutex->unlock(mutex);
+ }
+ return NULL;
+}
+
+START_TEST(test_mutex)
+{
+ thread_t *threads[THREADS];
+ int i;
+
+ barrier = barrier_create(THREADS);
+ mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
+
+ for (i = 0; i < 10; i++)
+ {
+ mutex->lock(mutex);
+ mutex->unlock(mutex);
+ }
+ for (i = 0; i < 10; i++)
+ {
+ mutex->lock(mutex);
+ }
+ for (i = 0; i < 10; i++)
+ {
+ mutex->unlock(mutex);
+ }
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(mutex_run, NULL);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ }
+
+ mutex->destroy(mutex);
+ barrier_destroy(barrier);
+}
+END_TEST
+
+/**
+ * Spinlock for testing
+ */
+static spinlock_t *spinlock;
+
+static void *spinlock_run(void *data)
+{
+ int i, *locked = (int*)data;
+
+ barrier_wait(barrier);
+
+ for (i = 0; i < 1000; i++)
+ {
+ spinlock->lock(spinlock);
+ (*locked)++;
+ ck_assert_int_eq(*locked, 1);
+ (*locked)--;
+ spinlock->unlock(spinlock);
+ }
+ return NULL;
+}
+
+START_TEST(test_spinlock)
+{
+ thread_t *threads[THREADS];
+ int i, locked = 0;
+
+ barrier = barrier_create(THREADS);
+ spinlock = spinlock_create();
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(spinlock_run, &locked);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ }
+
+ spinlock->destroy(spinlock);
+ barrier_destroy(barrier);
+}
+END_TEST
+
+static void *condvar_run(void *data)
+{
+ mutex->lock(mutex);
+ sigcount++;
+ condvar->signal(condvar);
+ mutex->unlock(mutex);
+ return NULL;
+}
+
+START_TEST(test_condvar)
+{
+ thread_t *threads[THREADS];
+ int i;
+
+ mutex = mutex_create(MUTEX_TYPE_DEFAULT);
+ condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
+ sigcount = 0;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(condvar_run, NULL);
+ }
+
+ mutex->lock(mutex);
+ while (sigcount < THREADS)
+ {
+ condvar->wait(condvar, mutex);
+ }
+ mutex->unlock(mutex);
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ }
+
+ mutex->destroy(mutex);
+ condvar->destroy(condvar);
+}
+END_TEST
+
+static void *condvar_recursive_run(void *data)
+{
+ mutex->lock(mutex);
+ mutex->lock(mutex);
+ mutex->lock(mutex);
+ sigcount++;
+ condvar->signal(condvar);
+ mutex->unlock(mutex);
+ mutex->unlock(mutex);
+ mutex->unlock(mutex);
+ return NULL;
+}
+
+START_TEST(test_condvar_recursive)
+{
+ thread_t *threads[THREADS];
+ int i;
+
+ mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
+ condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
+ sigcount = 0;
+
+ mutex->lock(mutex);
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(condvar_recursive_run, NULL);
+ }
+
+ mutex->lock(mutex);
+ mutex->lock(mutex);
+ while (sigcount < THREADS)
+ {
+ condvar->wait(condvar, mutex);
+ }
+ mutex->unlock(mutex);
+ mutex->unlock(mutex);
+ mutex->unlock(mutex);
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ }
+
+ mutex->destroy(mutex);
+ condvar->destroy(condvar);
+}
+END_TEST
+
+static void *condvar_run_broad(void *data)
+{
+ mutex->lock(mutex);
+ while (sigcount < 0)
+ {
+ condvar->wait(condvar, mutex);
+ }
+ mutex->unlock(mutex);
+ return NULL;
+}
+
+START_TEST(test_condvar_broad)
+{
+ thread_t *threads[THREADS];
+ int i;
+
+ mutex = mutex_create(MUTEX_TYPE_DEFAULT);
+ condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
+ sigcount = 0;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(condvar_run_broad, NULL);
+ }
+
+ sched_yield();
+
+ mutex->lock(mutex);
+ sigcount = 1;
+ condvar->broadcast(condvar);
+ mutex->unlock(mutex);
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ }
+
+ mutex->destroy(mutex);
+ condvar->destroy(condvar);
+}
+END_TEST
+
+START_TEST(test_condvar_timed)
+{
+ thread_t *thread;
+ timeval_t start, end, diff = { .tv_usec = 50000 };
+
+ mutex = mutex_create(MUTEX_TYPE_DEFAULT);
+ condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
+ sigcount = 0;
+
+ mutex->lock(mutex);
+ while (TRUE)
+ {
+ time_monotonic(&start);
+ if (condvar->timed_wait(condvar, mutex, diff.tv_usec / 1000))
+ {
+ break;
+ }
+ }
+ time_monotonic(&end);
+ mutex->unlock(mutex);
+ timersub(&end, &start, &end);
+ ck_assert_msg(timercmp(&end, &diff, >), "end: %u.%u, diff: %u.%u",
+ end.tv_sec, end.tv_usec, diff.tv_sec, diff.tv_usec);
+
+ thread = thread_create(condvar_run, NULL);
+
+ mutex->lock(mutex);
+ while (sigcount == 0)
+ {
+ ck_assert(!condvar->timed_wait(condvar, mutex, 1000));
+ }
+ mutex->unlock(mutex);
+
+ thread->join(thread);
+ mutex->destroy(mutex);
+ condvar->destroy(condvar);
+}
+END_TEST
+
+START_TEST(test_condvar_timed_abs)
+{
+ thread_t *thread;
+ timeval_t start, end, abso, diff = { .tv_usec = 50000 };
+
+ mutex = mutex_create(MUTEX_TYPE_DEFAULT);
+ condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
+ sigcount = 0;
+
+ mutex->lock(mutex);
+ while (TRUE)
+ {
+ time_monotonic(&start);
+ timeradd(&start, &diff, &abso);
+ if (condvar->timed_wait_abs(condvar, mutex, abso))
+ {
+ break;
+ }
+ }
+ time_monotonic(&end);
+ mutex->unlock(mutex);
+ ck_assert_msg(timercmp(&end, &diff, >), "end: %u.%u, diff: %u.%u",
+ end.tv_sec, end.tv_usec, abso.tv_sec, abso.tv_usec);
+
+ thread = thread_create(condvar_run, NULL);
+
+ time_monotonic(&start);
+ diff.tv_sec = 1;
+ timeradd(&start, &diff, &abso);
+ mutex->lock(mutex);
+ while (sigcount == 0)
+ {
+ ck_assert(!condvar->timed_wait_abs(condvar, mutex, abso));
+ }
+ mutex->unlock(mutex);
+
+ thread->join(thread);
+ mutex->destroy(mutex);
+ condvar->destroy(condvar);
+}
+END_TEST
+
+static void *condvar_cancel_run(void *data)
+{
+ thread_cancelability(FALSE);
+
+ mutex->lock(mutex);
+
+ sigcount++;
+ condvar->broadcast(condvar);
+
+ thread_cleanup_push((void*)mutex->unlock, mutex);
+ thread_cancelability(TRUE);
+ while (TRUE)
+ {
+ condvar->wait(condvar, mutex);
+ }
+ thread_cleanup_pop(TRUE);
+
+ return NULL;
+}
+
+START_TEST(test_condvar_cancel)
+{
+ thread_t *threads[THREADS];
+ int i;
+
+ mutex = mutex_create(MUTEX_TYPE_DEFAULT);
+ condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
+ sigcount = 0;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(condvar_cancel_run, NULL);
+ }
+
+ /* wait for all threads */
+ mutex->lock(mutex);
+ while (sigcount < THREADS)
+ {
+ condvar->wait(condvar, mutex);
+ }
+ mutex->unlock(mutex);
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->cancel(threads[i]);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ }
+
+ mutex->destroy(mutex);
+ condvar->destroy(condvar);
+}
+END_TEST
+
+/**
+ * RWlock for different tests
+ */
+static rwlock_t *rwlock;
+
+static void *rwlock_run(refcount_t *refs)
+{
+ rwlock->read_lock(rwlock);
+ ref_get(refs);
+ sched_yield();
+ ignore_result(ref_put(refs));
+ rwlock->unlock(rwlock);
+
+ if (rwlock->try_write_lock(rwlock))
+ {
+ ck_assert_int_eq(*refs, 0);
+ sched_yield();
+ rwlock->unlock(rwlock);
+ }
+
+ rwlock->write_lock(rwlock);
+ ck_assert_int_eq(*refs, 0);
+ sched_yield();
+ rwlock->unlock(rwlock);
+
+ rwlock->read_lock(rwlock);
+ rwlock->read_lock(rwlock);
+ ref_get(refs);
+ sched_yield();
+ ignore_result(ref_put(refs));
+ rwlock->unlock(rwlock);
+ rwlock->unlock(rwlock);
+
+ return NULL;
+}
+
+START_TEST(test_rwlock)
+{
+ thread_t *threads[THREADS];
+ refcount_t refs = 0;
+ int i;
+
+ rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create((void*)rwlock_run, &refs);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ }
+
+ rwlock->destroy(rwlock);
+}
+END_TEST
+
+/**
+ * Rwlock condvar
+ */
+static rwlock_condvar_t *rwcond;
+
+static void *rwlock_condvar_run(void *data)
+{
+ rwlock->write_lock(rwlock);
+ sigcount++;
+ rwcond->signal(rwcond);
+ rwlock->unlock(rwlock);
+ return NULL;
+}
+
+START_TEST(test_rwlock_condvar)
+{
+ thread_t *threads[THREADS];
+ int i;
+
+ rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
+ rwcond = rwlock_condvar_create();
+ sigcount = 0;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(rwlock_condvar_run, NULL);
+ }
+
+ rwlock->write_lock(rwlock);
+ while (sigcount < THREADS)
+ {
+ rwcond->wait(rwcond, rwlock);
+ }
+ rwlock->unlock(rwlock);
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ }
+
+ rwlock->destroy(rwlock);
+ rwcond->destroy(rwcond);
+}
+END_TEST
+
+static void *rwlock_condvar_run_broad(void *data)
+{
+ rwlock->write_lock(rwlock);
+ while (sigcount < 0)
+ {
+ rwcond->wait(rwcond, rwlock);
+ }
+ rwlock->unlock(rwlock);
+ return NULL;
+}
+
+START_TEST(test_rwlock_condvar_broad)
+{
+ thread_t *threads[THREADS];
+ int i;
+
+ rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
+ rwcond = rwlock_condvar_create();
+ sigcount = 0;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(rwlock_condvar_run_broad, NULL);
+ }
+
+ sched_yield();
+
+ rwlock->write_lock(rwlock);
+ sigcount = 1;
+ rwcond->broadcast(rwcond);
+ rwlock->unlock(rwlock);
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ }
+
+ rwlock->destroy(rwlock);
+ rwcond->destroy(rwcond);
+}
+END_TEST
+
+START_TEST(test_rwlock_condvar_timed)
+{
+ thread_t *thread;
+ timeval_t start, end, diff = { .tv_usec = 50000 };
+
+ rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
+ rwcond = rwlock_condvar_create();
+ sigcount = 0;
+
+ rwlock->write_lock(rwlock);
+ while (TRUE)
+ {
+ time_monotonic(&start);
+ if (rwcond->timed_wait(rwcond, rwlock, diff.tv_usec / 1000))
+ {
+ break;
+ }
+ }
+ rwlock->unlock(rwlock);
+ time_monotonic(&end);
+ timersub(&end, &start, &end);
+ ck_assert_msg(timercmp(&end, &diff, >), "end: %u.%u, diff: %u.%u",
+ end.tv_sec, end.tv_usec, diff.tv_sec, diff.tv_usec);
+
+ thread = thread_create(rwlock_condvar_run, NULL);
+
+ rwlock->write_lock(rwlock);
+ while (sigcount == 0)
+ {
+ ck_assert(!rwcond->timed_wait(rwcond, rwlock, 1000));
+ }
+ rwlock->unlock(rwlock);
+
+ thread->join(thread);
+ rwlock->destroy(rwlock);
+ rwcond->destroy(rwcond);
+}
+END_TEST
+
+START_TEST(test_rwlock_condvar_timed_abs)
+{
+ thread_t *thread;
+ timeval_t start, end, abso, diff = { .tv_usec = 50000 };
+
+ rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
+ rwcond = rwlock_condvar_create();
+ sigcount = 0;
+
+ rwlock->write_lock(rwlock);
+ while (TRUE)
+ {
+ time_monotonic(&start);
+ timeradd(&start, &diff, &abso);
+ if (rwcond->timed_wait_abs(rwcond, rwlock, abso))
+ {
+ break;
+ }
+ }
+ rwlock->unlock(rwlock);
+ time_monotonic(&end);
+ ck_assert_msg(timercmp(&end, &abso, >), "end: %u.%u, abso: %u.%u",
+ end.tv_sec, end.tv_usec, abso.tv_sec, abso.tv_usec);
+
+ thread = thread_create(rwlock_condvar_run, NULL);
+
+ time_monotonic(&start);
+ diff.tv_sec = 1;
+ timeradd(&start, &diff, &abso);
+ rwlock->write_lock(rwlock);
+ while (sigcount == 0)
+ {
+ ck_assert(!rwcond->timed_wait_abs(rwcond, rwlock, abso));
+ }
+ rwlock->unlock(rwlock);
+
+ thread->join(thread);
+ rwlock->destroy(rwlock);
+ rwcond->destroy(rwcond);
+}
+END_TEST
+
+static void *rwlock_condvar_cancel_run(void *data)
+{
+ thread_cancelability(FALSE);
+
+ rwlock->write_lock(rwlock);
+
+ sigcount++;
+ rwcond->broadcast(rwcond);
+
+ thread_cleanup_push((void*)rwlock->unlock, rwlock);
+ thread_cancelability(TRUE);
+ while (TRUE)
+ {
+ rwcond->wait(rwcond, rwlock);
+ }
+ thread_cleanup_pop(TRUE);
+
+ return NULL;
+}
+
+START_TEST(test_rwlock_condvar_cancel)
+{
+ thread_t *threads[THREADS];
+ int i;
+
+ rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
+ rwcond = rwlock_condvar_create();
+ sigcount = 0;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(rwlock_condvar_cancel_run, NULL);
+ }
+
+ /* wait for all threads */
+ rwlock->write_lock(rwlock);
+ while (sigcount < THREADS)
+ {
+ rwcond->wait(rwcond, rwlock);
+ }
+ rwlock->unlock(rwlock);
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->cancel(threads[i]);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ }
+
+ rwlock->destroy(rwlock);
+ rwcond->destroy(rwcond);
+}
+END_TEST
+
+/**
+ * Semaphore for different tests
+ */
+static semaphore_t *semaphore;
+
+static void *semaphore_run(void *data)
+{
+ semaphore->post(semaphore);
+ return NULL;
+}
+
+START_TEST(test_semaphore)
+{
+ thread_t *threads[THREADS];
+ int i, initial = 5;
+
+ semaphore = semaphore_create(initial);
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(semaphore_run, NULL);
+ }
+ for (i = 0; i < THREADS + initial; i++)
+ {
+ semaphore->wait(semaphore);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ }
+
+ semaphore->destroy(semaphore);
+}
+END_TEST
+
+START_TEST(test_semaphore_timed)
+{
+ thread_t *thread;
+ timeval_t start, end, diff = { .tv_usec = 50000 };
+
+ semaphore = semaphore_create(0);
+
+ time_monotonic(&start);
+ ck_assert(semaphore->timed_wait(semaphore, diff.tv_usec / 1000));
+ time_monotonic(&end);
+ timersub(&end, &start, &end);
+ ck_assert_msg(timercmp(&end, &diff, >), "end: %u.%u, diff: %u.%u",
+ end.tv_sec, end.tv_usec, diff.tv_sec, diff.tv_usec);
+
+ thread = thread_create(semaphore_run, NULL);
+
+ ck_assert(!semaphore->timed_wait(semaphore, 1000));
+
+ thread->join(thread);
+ semaphore->destroy(semaphore);
+}
+END_TEST
+
+START_TEST(test_semaphore_timed_abs)
+{
+ thread_t *thread;
+ timeval_t start, end, abso, diff = { .tv_usec = 50000 };
+
+ semaphore = semaphore_create(0);
+
+ time_monotonic(&start);
+ timeradd(&start, &diff, &abso);
+ ck_assert(semaphore->timed_wait_abs(semaphore, abso));
+ time_monotonic(&end);
+ ck_assert_msg(timercmp(&end, &abso, >), "end: %u.%u, abso: %u.%u",
+ end.tv_sec, end.tv_usec, abso.tv_sec, abso.tv_usec);
+
+ thread = thread_create(semaphore_run, NULL);
+
+ time_monotonic(&start);
+ diff.tv_sec = 1;
+ timeradd(&start, &diff, &abso);
+ ck_assert(!semaphore->timed_wait_abs(semaphore, abso));
+
+ thread->join(thread);
+ semaphore->destroy(semaphore);
+}
+END_TEST
+
+static void *semaphore_cancel_run(void *data)
+{
+ refcount_t *ready = (refcount_t*)data;
+
+ thread_cancelability(FALSE);
+ ref_get(ready);
+
+ thread_cancelability(TRUE);
+ semaphore->wait(semaphore);
+
+ ck_assert(FALSE);
+ return NULL;
+}
+
+START_TEST(test_semaphore_cancel)
+{
+ thread_t *threads[THREADS];
+ refcount_t ready = 0;
+ int i;
+
+ semaphore = semaphore_create(0);
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(semaphore_cancel_run, &ready);
+ }
+ while (ready < THREADS)
+ {
+ sched_yield();
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->cancel(threads[i]);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ }
+
+ semaphore->destroy(semaphore);
+}
+END_TEST
+
+static void *join_run(void *data)
+{
+ /* force some context switches */
+ sched_yield();
+ return (void*)((uintptr_t)data + THREADS);
+}
+
+START_TEST(test_join)
+{
+ thread_t *threads[THREADS];
+ int i;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(join_run, (void*)(uintptr_t)i);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ ck_assert_int_eq((uintptr_t)threads[i]->join(threads[i]), i + THREADS);
+ }
+}
+END_TEST
+
+static void *exit_join_run(void *data)
+{
+ sched_yield();
+ thread_exit((void*)((uintptr_t)data + THREADS));
+ /* not reached */
+ ck_assert(FALSE);
+ return NULL;
+}
+
+START_TEST(test_join_exit)
+{
+ thread_t *threads[THREADS];
+ int i;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(exit_join_run, (void*)(uintptr_t)i);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ ck_assert_int_eq((uintptr_t)threads[i]->join(threads[i]), i + THREADS);
+ }
+}
+END_TEST
+
+static void *detach_run(void *data)
+{
+ refcount_t *running = (refcount_t*)data;
+
+ ignore_result(ref_put(running));
+ return NULL;
+}
+
+START_TEST(test_detach)
+{
+ thread_t *threads[THREADS];
+ int i;
+ refcount_t running = 0;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ ref_get(&running);
+ threads[i] = thread_create(detach_run, &running);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->detach(threads[i]);
+ }
+ while (running > 0)
+ {
+ sched_yield();
+ }
+ /* no checks done here, but we check that thread state gets cleaned
+ * up with leak detective. */
+}
+END_TEST
+
+static void *detach_exit_run(void *data)
+{
+ refcount_t *running = (refcount_t*)data;
+
+ ignore_result(ref_put(running));
+ thread_exit(NULL);
+ /* not reached */
+ ck_assert(FALSE);
+ return NULL;
+}
+
+START_TEST(test_detach_exit)
+{
+ thread_t *threads[THREADS];
+ int i;
+ refcount_t running = 0;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ ref_get(&running);
+ threads[i] = thread_create(detach_exit_run, &running);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->detach(threads[i]);
+ }
+ while (running > 0)
+ {
+ sched_yield();
+ }
+ /* no checks done here, but we check that thread state gets cleaned
+ * up with leak detective. */
+}
+END_TEST
+
+static void *cancel_run(void *data)
+{
+ /* default cancellability should be TRUE, so don't change it */
+ while (TRUE)
+ {
+ sleep(10);
+ }
+ return NULL;
+}
+
+START_TEST(test_cancel)
+{
+ thread_t *threads[THREADS];
+ int i;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(cancel_run, NULL);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->cancel(threads[i]);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ }
+}
+END_TEST
+
+static void *cancel_onoff_run(void *data)
+{
+ bool *cancellable = (bool*)data;
+
+ thread_cancelability(FALSE);
+ *cancellable = FALSE;
+
+ /* we should not get cancelled here */
+ usleep(50000);
+
+ *cancellable = TRUE;
+ thread_cancelability(TRUE);
+
+ /* but here */
+ while (TRUE)
+ {
+ sleep(10);
+ }
+ return NULL;
+}
+
+START_TEST(test_cancel_onoff)
+{
+ thread_t *threads[THREADS];
+ bool cancellable[THREADS];
+ int i;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ cancellable[i] = TRUE;
+ threads[i] = thread_create(cancel_onoff_run, &cancellable[i]);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ /* wait until thread has cleared its cancellability */
+ while (cancellable[i])
+ {
+ sched_yield();
+ }
+ threads[i]->cancel(threads[i]);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ ck_assert(cancellable[i]);
+ }
+}
+END_TEST
+
+static void *cancel_point_run(void *data)
+{
+ thread_cancelability(FALSE);
+ while (TRUE)
+ {
+ /* implicitly enables cancellability */
+ thread_cancellation_point();
+ }
+ return NULL;
+}
+
+START_TEST(test_cancel_point)
+{
+ thread_t *threads[THREADS];
+ int i;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(cancel_point_run, NULL);
+ }
+ sched_yield();
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->cancel(threads[i]);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ }
+}
+END_TEST
+
+static void cleanup1(void *data)
+{
+ uintptr_t *value = (uintptr_t*)data;
+
+ ck_assert_int_eq(*value, 1);
+ (*value)++;
+}
+
+static void cleanup2(void *data)
+{
+ uintptr_t *value = (uintptr_t*)data;
+
+ ck_assert_int_eq(*value, 2);
+ (*value)++;
+}
+
+static void cleanup3(void *data)
+{
+ uintptr_t *value = (uintptr_t*)data;
+
+ ck_assert_int_eq(*value, 3);
+ (*value)++;
+}
+
+static void *cleanup_run(void *data)
+{
+ thread_cleanup_push(cleanup3, data);
+ thread_cleanup_push(cleanup2, data);
+ thread_cleanup_push(cleanup1, data);
+ return NULL;
+}
+
+START_TEST(test_cleanup)
+{
+ thread_t *threads[THREADS];
+ uintptr_t values[THREADS];
+ int i;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ values[i] = 1;
+ threads[i] = thread_create(cleanup_run, &values[i]);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ ck_assert_int_eq(values[i], 4);
+ }
+}
+END_TEST
+
+static void *cleanup_exit_run(void *data)
+{
+ thread_cleanup_push(cleanup3, data);
+ thread_cleanup_push(cleanup2, data);
+ thread_cleanup_push(cleanup1, data);
+ thread_exit(NULL);
+ ck_assert(FALSE);
+ return NULL;
+}
+
+START_TEST(test_cleanup_exit)
+{
+ thread_t *threads[THREADS];
+ uintptr_t values[THREADS];
+ int i;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ values[i] = 1;
+ threads[i] = thread_create(cleanup_exit_run, &values[i]);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ ck_assert_int_eq(values[i], 4);
+ }
+}
+END_TEST
+
+static void *cleanup_cancel_run(void *data)
+{
+ thread_cancelability(FALSE);
+
+ thread_cleanup_push(cleanup3, data);
+ thread_cleanup_push(cleanup2, data);
+ thread_cleanup_push(cleanup1, data);
+
+ thread_cancelability(TRUE);
+
+ while (TRUE)
+ {
+ sleep(1);
+ }
+ return NULL;
+}
+
+START_TEST(test_cleanup_cancel)
+{
+ thread_t *threads[THREADS];
+ uintptr_t values[THREADS];
+ int i;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ values[i] = 1;
+ threads[i] = thread_create(cleanup_cancel_run, &values[i]);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->cancel(threads[i]);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ ck_assert_int_eq(values[i], 4);
+ }
+}
+END_TEST
+
+static void *cleanup_pop_run(void *data)
+{
+ thread_cleanup_push(cleanup3, data);
+ thread_cleanup_push(cleanup2, data);
+ thread_cleanup_push(cleanup1, data);
+
+ thread_cleanup_push(cleanup2, data);
+ thread_cleanup_pop(FALSE);
+
+ thread_cleanup_pop(TRUE);
+ return NULL;
+}
+
+START_TEST(test_cleanup_pop)
+{
+ thread_t *threads[THREADS];
+ uintptr_t values[THREADS];
+ int i;
+
+ for (i = 0; i < THREADS; i++)
+ {
+ values[i] = 1;
+ threads[i] = thread_create(cleanup_pop_run, &values[i]);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ ck_assert_int_eq(values[i], 4);
+ }
+}
+END_TEST
+
+static thread_value_t *tls[10];
+
+static void *tls_run(void *data)
+{
+ uintptr_t value = (uintptr_t)data;
+ int i, j;
+
+ for (i = 0; i < countof(tls); i++)
+ {
+ ck_assert(tls[i]->get(tls[i]) == NULL);
+ }
+ for (i = 0; i < countof(tls); i++)
+ {
+ tls[i]->set(tls[i], (void*)(value * i));
+ }
+ for (j = 0; j < 1000; j++)
+ {
+ for (i = 0; i < countof(tls); i++)
+ {
+ tls[i]->set(tls[i], (void*)(value * i));
+ ck_assert(tls[i]->get(tls[i]) == (void*)(value * i));
+ }
+ sched_yield();
+ }
+ for (i = 0; i < countof(tls); i++)
+ {
+ ck_assert(tls[i]->get(tls[i]) == (void*)(value * i));
+ }
+ return (void*)(value + 1);
+}
+
+START_TEST(test_tls)
+{
+ thread_t *threads[THREADS];
+ int i;
+
+ for (i = 0; i < countof(tls); i++)
+ {
+ tls[i] = thread_value_create(NULL);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i] = thread_create(tls_run, (void*)(uintptr_t)i);
+ }
+
+ ck_assert_int_eq((uintptr_t)tls_run((void*)(uintptr_t)(THREADS + 1)),
+ THREADS + 2);
+
+ for (i = 0; i < THREADS; i++)
+ {
+ ck_assert_int_eq((uintptr_t)threads[i]->join(threads[i]), i + 1);
+ }
+ for (i = 0; i < countof(tls); i++)
+ {
+ tls[i]->destroy(tls[i]);
+ }
+}
+END_TEST
+
+static void tls_cleanup(void *data)
+{
+ uintptr_t *value = (uintptr_t*)data;
+
+ (*value)--;
+}
+
+static void *tls_cleanup_run(void *data)
+{
+ int i;
+
+ for (i = 0; i < countof(tls); i++)
+ {
+ tls[i]->set(tls[i], data);
+ }
+ return NULL;
+}
+
+START_TEST(test_tls_cleanup)
+{
+ thread_t *threads[THREADS];
+ uintptr_t values[THREADS], main_value = countof(tls);
+ int i;
+
+ for (i = 0; i < countof(tls); i++)
+ {
+ tls[i] = thread_value_create(tls_cleanup);
+ }
+ for (i = 0; i < THREADS; i++)
+ {
+ values[i] = countof(tls);
+ threads[i] = thread_create(tls_cleanup_run, &values[i]);
+ }
+
+ tls_cleanup_run(&main_value);
+
+ for (i = 0; i < THREADS; i++)
+ {
+ threads[i]->join(threads[i]);
+ ck_assert_int_eq(values[i], 0);
+ }
+ for (i = 0; i < countof(tls); i++)
+ {
+ tls[i]->destroy(tls[i]);
+ }
+ ck_assert_int_eq(main_value, 0);
+}
+END_TEST
+
+Suite *threading_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("threading");
+
+ tc = tcase_create("recursive mutex");
+ tcase_add_test(tc, test_mutex);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("spinlock");
+ tcase_add_test(tc, test_spinlock);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("condvar");
+ tcase_add_test(tc, test_condvar);
+ tcase_add_test(tc, test_condvar_recursive);
+ tcase_add_test(tc, test_condvar_broad);
+ tcase_add_test(tc, test_condvar_timed);
+ tcase_add_test(tc, test_condvar_timed_abs);
+ tcase_add_test(tc, test_condvar_cancel);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("rwlock");
+ tcase_add_test(tc, test_rwlock);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("rwlock condvar");
+ tcase_add_test(tc, test_rwlock_condvar);
+ tcase_add_test(tc, test_rwlock_condvar_broad);
+ tcase_add_test(tc, test_rwlock_condvar_timed);
+ tcase_add_test(tc, test_rwlock_condvar_timed_abs);
+ tcase_add_test(tc, test_rwlock_condvar_cancel);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("semaphore");
+ tcase_add_test(tc, test_semaphore);
+ tcase_add_test(tc, test_semaphore_timed);
+ tcase_add_test(tc, test_semaphore_timed_abs);
+ tcase_add_test(tc, test_semaphore_cancel);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("thread joining");
+ tcase_add_test(tc, test_join);
+ tcase_add_test(tc, test_join_exit);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("thread detaching");
+ tcase_add_test(tc, test_detach);
+ tcase_add_test(tc, test_detach_exit);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("thread cancellation");
+ tcase_add_test(tc, test_cancel);
+ tcase_add_test(tc, test_cancel_onoff);
+ tcase_add_test(tc, test_cancel_point);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("thread cleanup");
+ tcase_add_test(tc, test_cleanup);
+ tcase_add_test(tc, test_cleanup_exit);
+ tcase_add_test(tc, test_cleanup_cancel);
+ tcase_add_test(tc, test_cleanup_pop);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("thread local storage");
+ tcase_add_test(tc, test_tls);
+ tcase_add_test(tc, test_tls_cleanup);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_utils.c b/src/libstrongswan/tests/suites/test_utils.c
new file mode 100644
index 000000000..0260726b2
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_utils.c
@@ -0,0 +1,743 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * 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 "test_suite.h"
+
+#include <library.h>
+#include <utils/utils.h>
+#include <ipsec/ipsec_types.h>
+
+#include <time.h>
+
+/*******************************************************************************
+ * object storage on lib
+ */
+
+START_TEST(test_objects)
+{
+ char *k1 = "key1", *k2 = "key2";
+ char *v1 = "val1", *val;
+
+ ck_assert(lib->get(lib, k1) == NULL);
+
+ ck_assert(lib->set(lib, k1, v1));
+ ck_assert(!lib->set(lib, k1, v1));
+
+ val = lib->get(lib, k1);
+ ck_assert(val != NULL);
+ ck_assert(streq(val, v1));
+
+ ck_assert(lib->set(lib, k1, NULL));
+ ck_assert(!lib->set(lib, k2, NULL));
+
+ ck_assert(lib->get(lib, k1) == NULL);
+}
+END_TEST
+
+/*******************************************************************************
+ * test return_... functions
+ */
+
+START_TEST(test_return_functions)
+{
+ ck_assert(return_null() == NULL);
+ ck_assert(return_null("asdf", 5, NULL, 1, "qwer") == NULL);
+
+ ck_assert(return_true() == TRUE);
+ ck_assert(return_true("asdf", 5, NULL, 1, "qwer") == TRUE);
+
+ ck_assert(return_false() == FALSE);
+ ck_assert(return_false("asdf", 5, NULL, 1, "qwer") == FALSE);
+
+ ck_assert(return_failed() == FAILED);
+ ck_assert(return_failed("asdf", 5, NULL, 1, "qwer") == FAILED);
+
+ ck_assert(return_success() == SUCCESS);
+ ck_assert(return_success("asdf", 5, NULL, 1, "qwer") == SUCCESS);
+
+ /* just make sure this works */
+ nop();
+ nop("asdf", 5, NULL, 1, "qwer");
+}
+END_TEST
+
+/*******************************************************************************
+ * timeval_add_ms
+ */
+
+START_TEST(test_timeval_add_ms)
+{
+ timeval_t tv;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ timeval_add_ms(&tv, 0);
+ ck_assert_int_eq(tv.tv_sec, 0);
+ ck_assert_int_eq(tv.tv_usec, 0);
+
+ timeval_add_ms(&tv, 1);
+ ck_assert_int_eq(tv.tv_sec, 0);
+ ck_assert_int_eq(tv.tv_usec, 1000);
+
+ timeval_add_ms(&tv, 0);
+ ck_assert_int_eq(tv.tv_sec, 0);
+ ck_assert_int_eq(tv.tv_usec, 1000);
+
+ timeval_add_ms(&tv, 999);
+ ck_assert_int_eq(tv.tv_sec, 1);
+ ck_assert_int_eq(tv.tv_usec, 0);
+
+ timeval_add_ms(&tv, 0);
+ ck_assert_int_eq(tv.tv_sec, 1);
+ ck_assert_int_eq(tv.tv_usec, 0);
+
+ timeval_add_ms(&tv, 1000);
+ ck_assert_int_eq(tv.tv_sec, 2);
+ ck_assert_int_eq(tv.tv_usec, 0);
+
+ timeval_add_ms(&tv, 1500);
+ ck_assert_int_eq(tv.tv_sec, 3);
+ ck_assert_int_eq(tv.tv_usec, 500000);
+}
+END_TEST
+
+/*******************************************************************************
+ * htoun/untoh
+ */
+
+START_TEST(test_htoun)
+{
+ chunk_t net64, expected;
+ u_int16_t host16 = 513;
+ u_int32_t net16 = 0, host32 = 67305985;
+ u_int64_t net32 = 0, host64 = 578437695752307201ULL;
+
+ net64 = chunk_alloca(16);
+ memset(net64.ptr, 0, net64.len);
+
+ expected = chunk_from_chars(0x00, 0x02, 0x01, 0x00);
+ htoun16((char*)&net16 + 1, host16);
+ ck_assert(chunk_equals(expected, chunk_from_thing(net16)));
+
+ expected = chunk_from_chars(0x00, 0x00, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00);
+ htoun32((u_int16_t*)&net32 + 1, host32);
+ ck_assert(chunk_equals(expected, chunk_from_thing(net32)));
+
+ expected = chunk_from_chars(0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x07, 0x06, 0x05,
+ 0x04, 0x03, 0x02, 0x01,
+ 0x00, 0x00, 0x00, 0x00);
+ htoun64((u_int32_t*)net64.ptr + 1, host64);
+ ck_assert(chunk_equals(expected, net64));
+}
+END_TEST
+
+START_TEST(test_untoh)
+{
+ chunk_t net;
+ u_int16_t host16;
+ u_int32_t host32;
+ u_int64_t host64;
+
+ net = chunk_from_chars(0x00, 0x02, 0x01, 0x00);
+ host16 = untoh16(net.ptr + 1);
+ ck_assert(host16 == 513);
+
+ net = chunk_from_chars(0x00, 0x00, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00);
+ host32 = untoh32(net.ptr + 2);
+ ck_assert(host32 == 67305985);
+
+ net = chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x06, 0x05,
+ 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00);
+ host64 = untoh64(net.ptr + 4);
+ ck_assert(host64 == 578437695752307201ULL);
+}
+END_TEST
+
+/*******************************************************************************
+ * pad_len/round_up/down
+ */
+
+START_TEST(test_round)
+{
+ ck_assert_int_eq(pad_len(0, 4), 0);
+ ck_assert_int_eq(pad_len(1, 4), 3);
+ ck_assert_int_eq(pad_len(2, 4), 2);
+ ck_assert_int_eq(pad_len(3, 4), 1);
+ ck_assert_int_eq(pad_len(4, 4), 0);
+ ck_assert_int_eq(pad_len(5, 4), 3);
+
+ ck_assert_int_eq(round_up(0, 4), 0);
+ ck_assert_int_eq(round_up(1, 4), 4);
+ ck_assert_int_eq(round_up(2, 4), 4);
+ ck_assert_int_eq(round_up(3, 4), 4);
+ ck_assert_int_eq(round_up(4, 4), 4);
+ ck_assert_int_eq(round_up(5, 4), 8);
+
+ ck_assert_int_eq(round_down(0, 4), 0);
+ ck_assert_int_eq(round_down(1, 4), 0);
+ ck_assert_int_eq(round_down(2, 4), 0);
+ ck_assert_int_eq(round_down(3, 4), 0);
+ ck_assert_int_eq(round_down(4, 4), 4);
+ ck_assert_int_eq(round_down(5, 4), 4);
+}
+END_TEST
+
+/*******************************************************************************
+ * strpfx
+ */
+
+static struct {
+ char *str;
+ char *pfx;
+ bool prefix;
+ bool case_prefix;
+} strpfx_data[] = {
+ {"", "", TRUE, TRUE},
+ {"abc", "", TRUE, TRUE},
+ {"abc", "a", TRUE, TRUE},
+ {"abc", "ab", TRUE, TRUE},
+ {"abc", "abc", TRUE, TRUE},
+ {"abc", "abcd", FALSE, FALSE},
+ {"abc", "AB", FALSE, TRUE},
+ {"ABC", "ab", FALSE, TRUE},
+ {" abc", "abc", FALSE, FALSE},
+};
+
+START_TEST(test_strpfx)
+{
+ bool prefix;
+
+ prefix = strpfx(strpfx_data[_i].str, strpfx_data[_i].pfx);
+ ck_assert(prefix == strpfx_data[_i].prefix);
+ prefix = strcasepfx(strpfx_data[_i].str, strpfx_data[_i].pfx);
+ ck_assert(prefix == strpfx_data[_i].case_prefix);
+}
+END_TEST
+
+/*******************************************************************************
+ * memxor
+ */
+
+static void do_memxor(chunk_t a, chunk_t b, chunk_t exp)
+{
+ chunk_t dst;
+
+ dst = chunk_clonea(a);
+ dst.len = b.len;
+ memxor(dst.ptr, b.ptr, b.len);
+ ck_assert(chunk_equals(dst, exp));
+}
+
+START_TEST(test_memxor)
+{
+ chunk_t a, b, dst;
+ int i;
+
+ a = chunk_alloca(64);
+ memset(a.ptr, 0, a.len);
+ b = chunk_alloca(64);
+ for (i = 0; i < 64; i++)
+ {
+ b.ptr[i] = i;
+ b.len = i;
+ do_memxor(a, b, b);
+ }
+ b.len = 64;
+ do_memxor(a, b, b);
+
+ dst = chunk_clonea(a);
+ memxor(dst.ptr, b.ptr, b.len);
+ ck_assert(chunk_equals(dst, b));
+
+ memxor(dst.ptr, b.ptr, 0);
+ memxor(dst.ptr, b.ptr, 1);
+ memxor(dst.ptr + 1, b.ptr + 1, 1);
+ memxor(dst.ptr + 2, b.ptr + 2, b.len - 2);
+ ck_assert(chunk_equals(dst, a));
+}
+END_TEST
+
+START_TEST(test_memxor_aligned)
+{
+ u_int64_t a = 0, b = 0;
+ chunk_t ca, cb;
+ int i;
+
+ ca = chunk_from_thing(a);
+ cb = chunk_from_thing(b);
+
+ for (i = 0; i < 8; i++)
+ {
+ cb.ptr[i] = i + 1;
+ }
+
+ /* 64-bit aligned */
+ memxor(ca.ptr, cb.ptr, 8);
+ ck_assert(a == b);
+ /* 32-bit aligned source */
+ a = 0;
+ memxor(ca.ptr, cb.ptr + 4, 4);
+ ck_assert(chunk_equals(ca, chunk_from_chars(0x05, 0x06, 0x07, 0x08,
+ 0x00, 0x00, 0x00, 0x00)));
+ /* 16-bit aligned source */
+ a = 0;
+ memxor(ca.ptr, cb.ptr + 2, 6);
+ ck_assert(chunk_equals(ca, chunk_from_chars(0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x00, 0x00)));
+ /* 8-bit aligned source */
+ a = 0;
+ memxor(ca.ptr, cb.ptr + 1, 7);
+ ck_assert(chunk_equals(ca, chunk_from_chars(0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x00)));
+}
+END_TEST
+
+/*******************************************************************************
+ * memstr
+ */
+
+static struct {
+ char *haystack;
+ char *needle;
+ size_t n;
+ int offset;
+} memstr_data[] = {
+ {NULL, NULL, 0, -1},
+ {NULL, NULL, 3, -1},
+ {NULL, "abc", 0, -1},
+ {NULL, "abc", 3, -1},
+ {"", "", 0, -1},
+ {"abc", NULL, 3, -1},
+ {"abc", "", 3, -1},
+ {"abc", "abc", 3, 0},
+ {" abc", "abc", 4, 1},
+ {" abc", "abc", 3, -1},
+ {"abcabc", "abc", 6, 0},
+ {" abc ", "abc", 5, 1},
+};
+
+START_TEST(test_memstr)
+{
+ char *ret;
+
+ ret = memstr(memstr_data[_i].haystack, memstr_data[_i].needle, memstr_data[_i].n);
+ if (memstr_data[_i].offset >= 0)
+ {
+ ck_assert(ret == memstr_data[_i].haystack + memstr_data[_i].offset);
+ }
+ else
+ {
+ ck_assert(ret == NULL);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * utils_memrchr
+ */
+
+static struct {
+ char *s;
+ int c;
+ size_t n;
+ int offset;
+} memrchr_data[] = {
+ {NULL, 'f', 0, -1},
+ {NULL, 'f', 3, -1},
+ {"", 'f', 0, -1},
+ {"", '\0', 1, 0},
+ {"foo", '\0', 3, -1},
+ {"foo", '\0', 4, 3},
+ {"foo", 'f', 3, 0},
+ {"foo", 'o', 3, 2},
+ {"foo", 'o', 2, 1},
+ {"foo", 'o', 1, -1},
+ {"foo", 'o', 0, -1},
+ {"foo", 'x', 3, -1},
+};
+
+START_TEST(test_utils_memrchr)
+{
+ void *ret;
+
+ ret = utils_memrchr(memrchr_data[_i].s, memrchr_data[_i].c, memrchr_data[_i].n);
+ if (memrchr_data[_i].offset >= 0)
+ {
+ ck_assert(ret == memrchr_data[_i].s + memrchr_data[_i].offset);
+ }
+ else
+ {
+ ck_assert(ret == NULL);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * translate
+ */
+
+static struct {
+ char *in;
+ char *from;
+ char *to;
+ char *out;
+} translate_data[] = {
+ {NULL, "", "", NULL},
+ {"abc", "", "", "abc"},
+ {"abc", "", "x", "abc"},
+ {"abc", "x", "", "abc"},
+ {"abc", "abc", "xyz", "xyz"},
+ {"aabbcc", "abc", "xyz", "xxyyzz"},
+ {"abbaccb", "abc", "xyz", "xyyxzzy"},
+ {"abxyzc", "abc", "xyz", "xyxyzz"},
+ {"abcdef", "abc", "xyz", "xyzdef"},
+ {"aaa", "abc", "xyz", "xxx"},
+ {"abc", "aaa", "xyz", "xbc"},
+ {"abc", "abc", "xxx", "xxx"},
+};
+
+START_TEST(test_translate)
+{
+ char *str, *ret;
+
+ str = strdupnull(translate_data[_i].in);
+ ret = translate(str, translate_data[_i].from, translate_data[_i].to);
+ ck_assert(ret == str);
+ if (ret != translate_data[_i].out)
+ {
+ ck_assert_str_eq(str, translate_data[_i].out);
+ }
+ free(str);
+}
+END_TEST
+
+/*******************************************************************************
+ * strreplace
+ */
+
+static struct {
+ char *in;
+ char *out;
+ char *search;
+ char *replace;
+ bool allocated;
+} strreplace_data[] = {
+ /* invalid arguments */
+ {NULL, NULL, NULL, NULL, FALSE},
+ {"", "", NULL, NULL, FALSE},
+ {"", "", "", NULL, FALSE},
+ {"", "", NULL, "", FALSE},
+ {"", "", "", "", FALSE},
+ {"", "", "", "asdf", FALSE},
+ {"", "", "asdf", "", FALSE},
+ {"asdf", "asdf", NULL, NULL, FALSE},
+ {"asdf", "asdf", "", NULL, FALSE},
+ {"asdf", "asdf", NULL, "", FALSE},
+ {"asdf", "asdf", "", "", FALSE},
+ {"asdf", "asdf", "", "asdf", FALSE},
+ {"asdf", "asdf", "asdf", NULL, FALSE},
+ {"qwer", "qwer", "", "asdf", FALSE},
+ /* replacement shorter */
+ {"asdf", "", "asdf", "", TRUE},
+ {"asdfasdf", "", "asdf", "", TRUE},
+ {"asasdfdf", "asdf", "asdf", "", TRUE},
+ {"asdf", "df", "as", "", TRUE},
+ {"asdf", "as", "df", "", TRUE},
+ {"qwer", "qwer", "asdf", "", FALSE},
+ /* replacement same length */
+ {"a", "b", "a", "b", TRUE},
+ {"aaa", "bbb", "a", "b", TRUE},
+ {"aaa", "bbb", "aaa", "bbb", TRUE},
+ {"asdf", "asdf", "asdf", "asdf", TRUE},
+ {"qwer", "qwer", "asdf", "asdf", FALSE},
+ /* replacement longer */
+ {"asdf", "asdf", "", "asdf", FALSE},
+ {"asdf", "asdfasdf", "asdf", "asdfasdf", TRUE},
+ {"asdf", "asdfsdf", "a", "asdf", TRUE},
+ {"asdf", "asdasdf", "f", "asdf", TRUE},
+ {"aaa", "asdfasdfasdf", "a", "asdf", TRUE},
+ {"qwer", "qwer", "asdf", "asdfasdf", FALSE},
+ /* real examples */
+ {"http://x.org/no/spaces", "http://x.org/no/spaces", " ", "%20", FALSE},
+ {"http://x.org/end ", "http://x.org/end%20", " ", "%20", TRUE},
+ {" http://x.org/start", "%20http://x.org/start", " ", "%20", TRUE},
+ {" http://x.org/both ", "%20http://x.org/both%20", " ", "%20", TRUE},
+ {"http://x.org/ /slash", "http://x.org/%20/slash", " ", "%20", TRUE},
+ {"http://x.org/ /three", "http://x.org/%20%20%20/three", " ", "%20", TRUE},
+ {"http://x.org/ ", "http://x.org/%20%20%20%20%20%20", " ", "%20", TRUE},
+ {"http://x.org/%20/encoded", "http://x.org/%20/encoded", " ", "%20", FALSE},
+};
+
+START_TEST(test_strreplace)
+{
+ char *ret;
+
+ ret = strreplace(strreplace_data[_i].in, strreplace_data[_i].search,
+ strreplace_data[_i].replace);
+ if (ret && strreplace_data[_i].out)
+ {
+ ck_assert_str_eq(ret, strreplace_data[_i].out);
+ }
+ else
+ {
+ ck_assert(ret == strreplace_data[_i].out);
+ }
+ if (strreplace_data[_i].allocated)
+ {
+ ck_assert(ret != strreplace_data[_i].in);
+ free(ret);
+ }
+ else
+ {
+ ck_assert(ret == strreplace_data[_i].in);
+ }
+}
+END_TEST
+
+/*******************************************************************************
+ * path_dirname/basename
+ */
+
+static struct {
+ char *path;
+ char *dir;
+ char *base;
+} path_data[] = {
+ {NULL, ".", "."},
+ {"", ".", "."},
+ {".", ".", "."},
+ {"..", ".", ".."},
+ {"/", "/", "/"},
+ {"//", "/", "/"},
+ {"foo", ".", "foo"},
+ {"f/", ".", "f"},
+ {"foo/", ".", "foo"},
+ {"foo//", ".", "foo"},
+ {"/f", "/", "f"},
+ {"/f/", "/", "f"},
+ {"/foo", "/", "foo"},
+ {"/foo/", "/", "foo"},
+ {"//foo/", "/", "foo"},
+ {"foo/bar", "foo", "bar"},
+ {"foo//bar", "foo", "bar"},
+ {"/foo/bar", "/foo", "bar"},
+ {"/foo/bar/", "/foo", "bar"},
+ {"/foo/bar/baz", "/foo/bar", "baz"},
+};
+
+START_TEST(test_path_dirname)
+{
+ char *dir;
+
+ dir = path_dirname(path_data[_i].path);
+ ck_assert_str_eq(path_data[_i].dir, dir);
+ free(dir);
+}
+END_TEST
+
+START_TEST(test_path_basename)
+{
+ char *base;
+
+ base = path_basename(path_data[_i].path);
+ ck_assert_str_eq(path_data[_i].base, base);
+ free(base);
+}
+END_TEST
+
+/*******************************************************************************
+ * time_printf_hook
+ */
+
+static struct {
+ time_t in;
+ bool utc;
+ char *out;
+} time_data[] = {
+ {UNDEFINED_TIME, FALSE, "--- -- --:--:-- ----"},
+ {UNDEFINED_TIME, TRUE , "--- -- --:--:-- UTC ----"},
+ {1, FALSE, "Jan 01 01:00:01 1970"},
+ {1, TRUE , "Jan 01 00:00:01 UTC 1970"},
+ {1341150196, FALSE, "Jul 01 15:43:16 2012"},
+ {1341150196, TRUE , "Jul 01 13:43:16 UTC 2012"},
+};
+
+START_TEST(test_time_printf_hook)
+{
+ char buf[32];
+ int len;
+
+ len = snprintf(buf, sizeof(buf), "%T", &time_data[_i].in, time_data[_i].utc);
+ ck_assert(len >= 0 && len < sizeof(buf));
+ ck_assert_str_eq(buf, time_data[_i].out);
+}
+END_TEST
+
+/*******************************************************************************
+ * time_delta_printf_hook
+ */
+
+static struct {
+ time_t a;
+ time_t b;
+ char *out;
+} time_delta_data[] = {
+ {0, 0, "0 seconds"},
+ {0, 1, "1 second"},
+ {0, -1, "1 second"},
+ {1, 0, "1 second"},
+ {0, 2, "2 seconds"},
+ {2, 0, "2 seconds"},
+ {0, 60, "60 seconds"},
+ {0, 120, "120 seconds"},
+ {0, 121, "2 minutes"},
+ {0, 3600, "60 minutes"},
+ {0, 7200, "120 minutes"},
+ {0, 7201, "2 hours"},
+ {0, 86400, "24 hours"},
+ {0, 172800, "48 hours"},
+ {0, 172801, "2 days"},
+ {172801, 86400, "24 hours"},
+};
+
+START_TEST(test_time_delta_printf_hook)
+{
+ char buf[16];
+ int len;
+
+ len = snprintf(buf, sizeof(buf), "%V", &time_delta_data[_i].a, &time_delta_data[_i].b);
+ ck_assert(len >= 0 && len < sizeof(buf));
+ ck_assert_str_eq(buf, time_delta_data[_i].out);
+}
+END_TEST
+
+/*******************************************************************************
+ * mark_from_string
+ */
+
+static struct {
+ char *s;
+ bool ok;
+ mark_t m;
+} mark_data[] = {
+ {NULL, FALSE, { 0 }},
+ {"", TRUE, { 0, 0xffffffff }},
+ {"/", TRUE, { 0, 0 }},
+ {"42", TRUE, { 42, 0xffffffff }},
+ {"0x42", TRUE, { 0x42, 0xffffffff }},
+ {"x", FALSE, { 0 }},
+ {"42/", TRUE, { 0, 0 }},
+ {"42/0", TRUE, { 0, 0 }},
+ {"42/x", FALSE, { 0 }},
+ {"42/42", TRUE, { 42, 42 }},
+ {"42/0xff", TRUE, { 42, 0xff }},
+ {"0x42/0xff", TRUE, { 0x42, 0xff }},
+ {"/0xff", TRUE, { 0, 0xff }},
+ {"/x", FALSE, { 0 }},
+ {"x/x", FALSE, { 0 }},
+ {"0xffffffff/0x0000ffff", TRUE, { 0x0000ffff, 0x0000ffff }},
+ {"0xffffffff/0xffffffff", TRUE, { 0xffffffff, 0xffffffff }},
+};
+
+START_TEST(test_mark_from_string)
+{
+ mark_t mark;
+
+ if (mark_from_string(mark_data[_i].s, &mark))
+ {
+ ck_assert_int_eq(mark.value, mark_data[_i].m.value);
+ ck_assert_int_eq(mark.mask, mark_data[_i].m.mask);
+ }
+ else
+ {
+ ck_assert(!mark_data[_i].ok);
+ }
+}
+END_TEST
+
+Suite *utils_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ /* force a timezone to match non-UTC conversions */
+ setenv("TZ", "Europe/Zurich", 1);
+ tzset();
+
+ s = suite_create("utils");
+
+ tc = tcase_create("objects");
+ tcase_add_test(tc, test_objects);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("return functions");
+ tcase_add_test(tc, test_return_functions);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("timeval_add_ms");
+ tcase_add_test(tc, test_timeval_add_ms);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("htoun,untoh");
+ tcase_add_test(tc, test_htoun);
+ tcase_add_test(tc, test_untoh);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("round");
+ tcase_add_test(tc, test_round);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("string helper");
+ tcase_add_loop_test(tc, test_strpfx, 0, countof(strpfx_data));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("memxor");
+ tcase_add_test(tc, test_memxor);
+ tcase_add_test(tc, test_memxor_aligned);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("memstr");
+ tcase_add_loop_test(tc, test_memstr, 0, countof(memstr_data));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("utils_memrchr");
+ tcase_add_loop_test(tc, test_utils_memrchr, 0, countof(memrchr_data));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("translate");
+ tcase_add_loop_test(tc, test_translate, 0, countof(translate_data));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("strreplace");
+ tcase_add_loop_test(tc, test_strreplace, 0, countof(strreplace_data));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("path_dirname/basename");
+ tcase_add_loop_test(tc, test_path_dirname, 0, countof(path_data));
+ tcase_add_loop_test(tc, test_path_basename, 0, countof(path_data));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("printf_hooks");
+ tcase_add_loop_test(tc, test_time_printf_hook, 0, countof(time_data));
+ tcase_add_loop_test(tc, test_time_delta_printf_hook, 0, countof(time_delta_data));
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("mark_from_string");
+ tcase_add_loop_test(tc, test_mark_from_string, 0, countof(mark_data));
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_vectors.c b/src/libstrongswan/tests/suites/test_vectors.c
new file mode 100644
index 000000000..242ac9d09
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_vectors.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * 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 "test_suite.h"
+
+/*******************************************************************************
+ * Check if test vectors have been successful during transform registration
+ */
+
+START_TEST(test_vectors)
+{
+ u_int failed = lib->crypto->get_test_vector_failures(lib->crypto);
+ fail_if(failed > 0, "%u test vectors failed", failed);
+}
+END_TEST
+
+
+Suite *vectors_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("vectors");
+
+ tc = tcase_create("failures");
+ tcase_add_test(tc, test_vectors);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_watcher.c b/src/libstrongswan/tests/suites/test_watcher.c
new file mode 100644
index 000000000..9415bead9
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_watcher.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * 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 "test_suite.h"
+
+#include <library.h>
+
+#include <sched.h>
+#include <unistd.h>
+#include <errno.h>
+
+static char testbuf[1] = "";
+
+static bool readcb(void *data, int fd, watcher_event_t event)
+{
+ ck_assert_int_eq(*(int*)data, fd);
+ ck_assert_int_eq(event, WATCHER_READ);
+
+ if (recv(fd, testbuf, 1, MSG_DONTWAIT) != 1)
+ {
+ ck_assert(errno == EAGAIN || errno == EWOULDBLOCK);
+ }
+ return TRUE;
+}
+
+START_TEST(test_read)
+{
+ int fd[2];
+ char c;
+
+ lib->processor->set_threads(lib->processor, 8);
+
+ ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != -1);
+
+ lib->watcher->add(lib->watcher, fd[0], WATCHER_READ, readcb, &fd[0]);
+
+ for (c = 'a'; c <= 'z'; c++)
+ {
+ ck_assert_int_eq(write(fd[1], &c, 1), 1);
+ while (testbuf[0] != c)
+ {
+ sched_yield();
+ }
+ }
+
+ lib->watcher->remove(lib->watcher, fd[0]);
+ close(fd[0]);
+ close(fd[1]);
+
+ lib->processor->cancel(lib->processor);
+}
+END_TEST
+
+static bool writecb(void *data, int fd, watcher_event_t event)
+{
+ ck_assert_int_eq(event, WATCHER_WRITE);
+ if (send(fd, data, 1, MSG_DONTWAIT) != 1)
+ {
+ ck_assert(errno == EAGAIN || errno == EWOULDBLOCK);
+ }
+ return TRUE;
+}
+
+START_TEST(test_write)
+{
+ int fd[2];
+ char in = 'x', out;
+
+ lib->processor->set_threads(lib->processor, 8);
+
+ ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != -1);
+
+ lib->watcher->add(lib->watcher, fd[1], WATCHER_WRITE, writecb, &in);
+
+ ck_assert_int_eq(read(fd[0], &out, 1), 1);
+ ck_assert_int_eq(out, in);
+
+ lib->watcher->remove(lib->watcher, fd[1]);
+ close(fd[1]);
+ close(fd[0]);
+
+ lib->processor->cancel(lib->processor);
+}
+END_TEST
+
+static bool multiread(void *data, int fd, watcher_event_t event)
+{
+ ck_assert_int_eq(event, WATCHER_READ);
+ if (recv(fd, data, 1, MSG_DONTWAIT) != 1)
+ {
+ ck_assert(errno == EAGAIN || errno == EWOULDBLOCK);
+ }
+ return TRUE;
+}
+
+START_TEST(test_multiread)
+{
+ int fd[10][2], i;
+ char in, out[countof(fd)];
+
+ lib->processor->set_threads(lib->processor, 8);
+
+ for (i = 0; i < countof(fd); i++)
+ {
+ ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, fd[i]) != -1);
+ lib->watcher->add(lib->watcher, fd[i][0],
+ WATCHER_READ, multiread, &out[i]);
+ }
+
+ for (i = 0; i < countof(fd); i++)
+ {
+ for (in = 'a'; in <= 'z'; in++)
+ {
+ ck_assert_int_eq(write(fd[i][1], &in, 1), 1);
+ while (out[i] != in)
+ {
+ sched_yield();
+ }
+ }
+ }
+
+ for (i = 0; i < countof(fd); i++)
+ {
+ lib->watcher->remove(lib->watcher, fd[i][0]);
+ close(fd[i][1]);
+ close(fd[i][0]);
+ }
+
+ lib->processor->cancel(lib->processor);
+}
+END_TEST
+
+static bool multiwrite(void *data, int fd, watcher_event_t event)
+{
+ ck_assert_int_eq(event, WATCHER_WRITE);
+ if (send(fd, data, 1, MSG_DONTWAIT) != 1)
+ {
+ ck_assert(errno == EAGAIN || errno == EWOULDBLOCK);
+ }
+ return TRUE;
+}
+
+START_TEST(test_multiwrite)
+{
+ int fd[10][2], i, j;
+ u_char out, in[countof(fd)];
+
+ lib->processor->set_threads(lib->processor, 8);
+
+ for (i = 0; i < countof(fd); i++)
+ {
+ ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, fd[i]) != -1);
+ in[i] = i;
+ lib->watcher->add(lib->watcher, fd[i][1],
+ WATCHER_WRITE, multiwrite, &in[i]);
+ }
+
+ for (j = 0; j < 10; j++)
+ {
+ for (i = 0; i < countof(fd); i++)
+ {
+ ck_assert_int_eq(read(fd[i][0], &out, 1), 1);
+ ck_assert_int_eq(out, i);
+ }
+ }
+
+ for (i = 0; i < countof(fd); i++)
+ {
+ lib->watcher->remove(lib->watcher, fd[i][1]);
+ close(fd[i][1]);
+ close(fd[i][0]);
+ }
+
+ lib->processor->cancel(lib->processor);
+}
+END_TEST
+
+Suite *watcher_suite_create()
+{
+ Suite *s;
+ TCase *tc;
+
+ s = suite_create("watcher");
+
+ tc = tcase_create("read");
+ tcase_add_test(tc, test_read);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("write");
+ tcase_add_test(tc, test_write);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("multiread");
+ tcase_add_test(tc, test_multiread);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("multiwrite");
+ tcase_add_test(tc, test_multiwrite);
+ suite_add_tcase(s, tc);
+
+ return s;
+}