diff options
author | Yves-Alexis Perez <corsac@debian.org> | 2014-03-11 20:48:48 +0100 |
---|---|---|
committer | Yves-Alexis Perez <corsac@debian.org> | 2014-03-11 20:48:48 +0100 |
commit | 15fb7904f4431a6e7c305fd08732458f7f885e7e (patch) | |
tree | c93b60ee813af70509f00f34e29ebec311762427 /src/libstrongswan/tests/suites | |
parent | 5313d2d78ca150515f7f5eb39801c100690b6b29 (diff) | |
download | vyos-strongswan-15fb7904f4431a6e7c305fd08732458f7f885e7e.tar.gz vyos-strongswan-15fb7904f4431a6e7c305fd08732458f7f885e7e.zip |
Imported Upstream version 5.1.2
Diffstat (limited to 'src/libstrongswan/tests/suites')
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, ¶meters); + 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, >ests[_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, ¤t)) + { + 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, §ion)) + { + 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, ¤t_key) && + enum_values->enumerate(enum_values, ¤t_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; +} |