diff options
Diffstat (limited to 'src/lib/tests')
| -rw-r--r-- | src/lib/tests/CMakeLists.txt | 26 | ||||
| -rw-r--r-- | src/lib/tests/auth_test.c | 548 | ||||
| -rw-r--r-- | src/lib/tests/auth_test_pqc.c | 356 | ||||
| -rw-r--r-- | src/lib/tests/bitmap_test.c | 27 | ||||
| -rw-r--r-- | src/lib/tests/btree_test.c | 2 | ||||
| -rw-r--r-- | src/lib/tests/crc32_test.c | 2 | ||||
| -rw-r--r-- | src/lib/tests/crypt_test.c | 459 | ||||
| -rw-r--r-- | src/lib/tests/hash_test.c | 202 | ||||
| -rw-r--r-- | src/lib/tests/kex_test.c | 844 | ||||
| -rw-r--r-- | src/lib/tests/kex_test_pqc.c | 549 | ||||
| -rw-r--r-- | src/lib/tests/md5_test.c | 2 | ||||
| -rw-r--r-- | src/lib/tests/sha3_test.c | 2 | ||||
| -rw-r--r-- | src/lib/tests/shm_rbuff_test.c | 113 | ||||
| -rw-r--r-- | src/lib/tests/sockets_test.c | 102 | ||||
| -rw-r--r-- | src/lib/tests/time_test.c | 529 | ||||
| -rw-r--r-- | src/lib/tests/time_utils_test.c | 164 | ||||
| -rw-r--r-- | src/lib/tests/tpm_test.c | 104 |
17 files changed, 3726 insertions, 305 deletions
diff --git a/src/lib/tests/CMakeLists.txt b/src/lib/tests/CMakeLists.txt index 9e23b0ee..23d01f9b 100644 --- a/src/lib/tests/CMakeLists.txt +++ b/src/lib/tests/CMakeLists.txt @@ -1,27 +1,31 @@ get_filename_component(PARENT_PATH ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) get_filename_component(PARENT_DIR ${PARENT_PATH} NAME) +compute_test_prefix() + create_test_sourcelist(${PARENT_DIR}_tests test_suite.c # Add new tests here + auth_test.c + auth_test_pqc.c bitmap_test.c btree_test.c crc32_test.c + crypt_test.c + hash_test.c + kex_test.c + kex_test_pqc.c md5_test.c sha3_test.c - shm_rbuff_test.c - time_utils_test.c + sockets_test.c + time_test.c + tpm_test.c ) -add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${${PARENT_DIR}_tests}) +add_executable(${PARENT_DIR}_test ${${PARENT_DIR}_tests}) +disable_test_logging_for_target(${PARENT_DIR}_test) target_link_libraries(${PARENT_DIR}_test ouroboros-common) -add_dependencies(check ${PARENT_DIR}_test) - -set(tests_to_run ${${PARENT_DIR}_tests}) -remove(tests_to_run test_suite.c) +add_dependencies(build_tests ${PARENT_DIR}_test) -foreach (test ${tests_to_run}) - get_filename_component(test_name ${test} NAME_WE) - add_test(${test_name} ${C_TEST_PATH}/${PARENT_DIR}_test ${test_name}) -endforeach (test) +ouroboros_register_tests(TARGET ${PARENT_DIR}_test TESTS ${${PARENT_DIR}_tests}) diff --git a/src/lib/tests/auth_test.c b/src/lib/tests/auth_test.c new file mode 100644 index 00000000..b3f09277 --- /dev/null +++ b/src/lib/tests/auth_test.c @@ -0,0 +1,548 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Test of the authentication functions + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#include "config.h" + +#include <test/test.h> +#include <ouroboros/crypt.h> +#include <ouroboros/random.h> +#include <ouroboros/utils.h> + +#include <test/certs.h> + +#define TEST_MSG_SIZE 1500 + +static int test_auth_create_destroy_ctx(void) +{ + struct auth_ctx * ctx; + + TEST_START(); + + ctx = auth_create_ctx(); + if (ctx == NULL) { + printf("Failed to create auth context.\n"); + goto fail_create; + } + + auth_destroy_ctx(ctx); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_create: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_load_free_crt(void) +{ + void * crt; + + TEST_START(); + + if (crypt_load_crt_str(root_ca_crt_ec, &crt) < 0) { + printf("Failed to load certificate string.\n"); + goto fail_load; + } + + crypt_free_crt(crt); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_load: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_crypt_get_pubkey_crt(void) +{ + void * pk; + void * crt; + + TEST_START(); + + if (crypt_load_crt_str(signed_server_crt_ec, &crt) < 0) { + printf("Failed to load server certificate from string.\n"); + goto fail_load; + } + + if (crypt_get_pubkey_crt(crt, &pk) < 0) { + printf("Failed to get public key from certificate.\n"); + goto fail_get_pubkey; + } + + crypt_free_key(pk); + crypt_free_crt(crt); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + + fail_get_pubkey: + crypt_free_crt(crt); + fail_load: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_check_crt_name(void) +{ + void * crt; + + TEST_START(); + + if (crypt_load_crt_str(signed_server_crt_ec, &crt) < 0) { + printf("Failed to load certificate from string.\n"); + goto fail_load; + } + + if (crypt_check_crt_name(crt, "test-1.unittest.o7s") < 0) { + printf("Failed to verify correct name.\n"); + goto fail_check; + } + + if (crypt_check_crt_name(crt, "bogus.name") == 0) { + printf("Failed to detect incorrect name.\n"); + goto fail_check; + } + + crypt_free_crt(crt); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_check: + crypt_free_crt(crt); + fail_load: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_load_free_privkey(void) +{ + void * key; + + TEST_START(); + + if (crypt_load_privkey_str(server_pkp_ec, &key) < 0) { + printf("Failed to load server key pair from string.\n"); + goto fail_load; + } + + crypt_free_key(key); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_load: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_load_free_pubkey(void) +{ + void * key; + + TEST_START(); + + if (crypt_load_pubkey_str(server_pk_ec, &key) < 0) { + printf("Failed to load server public key from string.\n"); + goto fail_load; + } + + crypt_free_key(key); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_load: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_crypt_check_pubkey_crt(void) +{ + void * pk; + void * crt_pk; + void * crt; + + TEST_START(); + + if (crypt_load_crt_str(signed_server_crt_ec, &crt) < 0) { + printf("Failed to load public certificate from string.\n"); + goto fail_crt; + } + + if (crypt_load_pubkey_str(server_pk_ec, &pk) < 0) { + printf("Failed to load public key from string.\n"); + goto fail_pubkey; + } + + if (crypt_get_pubkey_crt(crt, &crt_pk) < 0) { + printf("Failed to get public key from certificate.\n"); + goto fail_get_pubkey; + } + + if (crypt_cmp_key(pk, crt_pk) != 0) { + printf("Public keys do not match .\n"); + goto fail_check; + } + + + crypt_free_key(crt_pk); + crypt_free_key(pk); + crypt_free_crt(crt); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_check: + crypt_free_key(crt_pk); + fail_get_pubkey: + crypt_free_key(pk); + fail_pubkey: + crypt_free_crt(crt); + fail_crt: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_store_add(void) +{ + struct auth_ctx * ctx; + void * _root_ca_crt; + + TEST_START(); + + ctx = auth_create_ctx(); + if (ctx == NULL) { + printf("Failed to create auth context.\n"); + goto fail_create; + } + + if (crypt_load_crt_str(root_ca_crt_ec, &_root_ca_crt) < 0) { + printf("Failed to load root crt from string.\n"); + goto fail_load; + } + + if (auth_add_crt_to_store(ctx, _root_ca_crt) < 0) { + printf("Failed to add root crt to auth store.\n"); + goto fail_add; + } + + crypt_free_crt(_root_ca_crt); + auth_destroy_ctx(ctx); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + + fail_add: + crypt_free_crt(_root_ca_crt); + fail_load: + crypt_free_crt(_root_ca_crt); + fail_create: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_verify_crt(void) +{ + struct auth_ctx * auth; + void * _server_crt; + void * _signed_server_crt; + void * _root_ca_crt; + void * _im_ca_crt; + + TEST_START(); + + auth = auth_create_ctx(); + if (auth == NULL) { + printf("Failed to create auth context.\n"); + goto fail_create_ctx; + } + + if (crypt_load_crt_str(server_crt_ec, &_server_crt) < 0) { + printf("Failed to load self-signed crt from string.\n"); + goto fail_load_server_crt; + } + + if (crypt_load_crt_str(signed_server_crt_ec, &_signed_server_crt) < 0) { + printf("Failed to load signed crt from string.\n"); + goto fail_load_signed_server_crt; + } + + if (crypt_load_crt_str(root_ca_crt_ec, &_root_ca_crt) < 0) { + printf("Failed to load root crt from string.\n"); + goto fail_load_root_ca_crt; + } + + if (crypt_load_crt_str(im_ca_crt_ec, &_im_ca_crt) < 0) { + printf("Failed to load intermediate crt from string.\n"); + goto fail_load_im_ca_crt; + } + + if (auth_add_crt_to_store(auth, _root_ca_crt) < 0) { + printf("Failed to add root ca crt to auth store.\n"); + goto fail_verify; + } + + if (auth_add_crt_to_store(auth, _im_ca_crt) < 0) { + printf("Failed to add intermediate ca crt to auth store.\n"); + goto fail_verify; + } + + if (auth_verify_crt(auth, _signed_server_crt) < 0) { + printf("Failed to verify signed crt with ca crt.\n"); + goto fail_verify; + } + + if (auth_verify_crt(auth, _server_crt) == 0) { + printf("Failed to detect untrusted crt.\n"); + goto fail_verify; + } + + crypt_free_crt(_im_ca_crt); + crypt_free_crt(_root_ca_crt); + crypt_free_crt(_signed_server_crt); + crypt_free_crt(_server_crt); + + auth_destroy_ctx(auth); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_verify: + crypt_free_crt(_im_ca_crt); + fail_load_im_ca_crt: + crypt_free_crt(_root_ca_crt); + fail_load_root_ca_crt: + crypt_free_crt(_signed_server_crt); + fail_load_signed_server_crt: + crypt_free_crt(_server_crt); + fail_load_server_crt: + auth_destroy_ctx(auth); + fail_create_ctx: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +int test_auth_sign(void) +{ + uint8_t buf[TEST_MSG_SIZE]; + void * pkp; + void * pk; + buffer_t msg; + buffer_t sig; + + TEST_START(); + + msg.data = buf; + msg.len = sizeof(buf); + + if (random_buffer(msg.data, msg.len) < 0) { + printf("Failed to generate random message.\n"); + goto fail_init; + } + + if (crypt_load_privkey_str(server_pkp_ec, &pkp) < 0) { + printf("Failed to load server key pair from string.\n"); + goto fail_init; + } + + if (crypt_load_pubkey_str(server_pk_ec, &pk) < 0) { + printf("Failed to load public key.\n"); + goto fail_pubkey; + } + + if (auth_sign(pkp, 0, msg, &sig) < 0) { + printf("Failed to sign message.\n"); + goto fail_sign; + } + + if (auth_verify_sig(pk, 0, msg, sig) < 0) { + printf("Failed to verify signature.\n"); + goto fail_verify; + } + + freebuf(sig); + + crypt_free_key(pk); + crypt_free_key(pkp); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_verify: + freebuf(sig); + fail_sign: + crypt_free_key(pk); + fail_pubkey: + crypt_free_key(pkp); + fail_init: + return TEST_RC_FAIL; +} + +int test_auth_bad_signature(void) +{ + uint8_t buf[TEST_MSG_SIZE]; + void * pkp; + void * pk; + buffer_t msg; + buffer_t sig; + buffer_t fake_sig; + + TEST_START(); + + msg.data = buf; + msg.len = sizeof(buf); + + if (random_buffer(msg.data, msg.len) < 0) { + printf("Failed to generate random message.\n"); + goto fail_init; + } + + if (crypt_load_privkey_str(server_pkp_ec, &pkp) < 0) { + printf("Failed to load server key pair from string.\n"); + goto fail_init; + } + + if (crypt_load_pubkey_str(server_pk_ec, &pk) < 0) { + printf("Failed to load public key.\n"); + goto fail_pubkey; + } + + if (auth_sign(pkp, 0, msg, &sig) < 0) { + printf("Failed to sign message.\n"); + goto fail_sign; + } + + fake_sig.data = malloc(sig.len); + if (fake_sig.data == NULL) { + printf("Failed to allocate memory for fake signature.\n"); + goto fail_malloc; + } + + fake_sig.len = sig.len; + if (random_buffer(fake_sig.data, fake_sig.len) < 0) { + printf("Failed to generate random fake signature.\n"); + goto fail_malloc; + } + + if (auth_verify_sig(pk, 0, msg, fake_sig) == 0) { + printf("Failed to detect bad signature.\n"); + goto fail_verify; + } + + freebuf(fake_sig); + freebuf(sig); + + crypt_free_key(pk); + crypt_free_key(pkp); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_verify: + freebuf(fake_sig); + fail_malloc: + freebuf(sig); + fail_sign: + crypt_free_key(pk); + fail_pubkey: + crypt_free_key(pkp); + fail_init: + return TEST_RC_FAIL; +} + +#define SSC_BUF_SIZE 4096 /* OpenSSL version my return different lengths */ +int test_crt_str(void) +{ + char str[SSC_BUF_SIZE]; + void * crt; + + TEST_START(); + + if (crypt_load_crt_str(signed_server_crt_ec, &crt) < 0) { + printf("Failed to load certificate from string.\n"); + goto fail_load; + } + + if (crypt_crt_str(crt, str) < 0) { + printf("Failed to convert certificate to string.\n"); + goto fail_to_str; + } + + printf("Certificate string:\n%s\n", str); + + crypt_free_crt(crt); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + + fail_to_str: + crypt_free_crt(crt); + fail_load: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +int auth_test(int argc, + char ** argv) +{ + int ret = 0; + + (void) argc; + (void) argv; + + ret |= test_auth_create_destroy_ctx(); +#ifdef HAVE_OPENSSL + ret |= test_load_free_crt(); + ret |= test_check_crt_name(); + ret |= test_crypt_get_pubkey_crt(); + ret |= test_load_free_privkey(); + ret |= test_load_free_pubkey(); + ret |= test_crypt_check_pubkey_crt(); + ret |= test_store_add(); + ret |= test_verify_crt(); + ret |= test_auth_sign(); + ret |= test_auth_bad_signature(); + ret |= test_crt_str(); +#else + (void) test_load_free_crt; + (void) test_check_crt_name; + (void) test_crypt_get_pubkey_crt; + (void) test_load_free_privkey; + (void) test_load_free_pubkey; + (void) test_crypt_check_pubkey_crt; + (void) test_store_add; + (void) test_verify_crt; + (void) test_auth_sign; + (void) test_auth_bad_signature; + (void) test_crt_str; + + ret = TEST_RC_SKIP; +#endif + return ret; +} diff --git a/src/lib/tests/auth_test_pqc.c b/src/lib/tests/auth_test_pqc.c new file mode 100644 index 00000000..349636d2 --- /dev/null +++ b/src/lib/tests/auth_test_pqc.c @@ -0,0 +1,356 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2026 + * + * Test of the PQC authentication functions (ML-DSA-65) + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#include "config.h" + +#include <test/test.h> +#include <ouroboros/crypt.h> +#include <ouroboros/random.h> +#include <ouroboros/utils.h> + +#include <test/certs_pqc.h> + +#define TEST_MSG_SIZE 1500 + +static int test_auth_create_destroy_ctx(void) +{ + struct auth_ctx * ctx; + + TEST_START(); + + ctx = auth_create_ctx(); + if (ctx == NULL) { + printf("Failed to create auth context.\n"); + goto fail_create; + } + + auth_destroy_ctx(ctx); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_create: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_load_free_crt(void) +{ + void * crt; + + TEST_START(); + + if (crypt_load_crt_str(root_ca_crt_ml, &crt) < 0) { + printf("Failed to load root crt from string.\n"); + goto fail_load; + } + + crypt_free_crt(crt); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_load: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_load_free_privkey(void) +{ + void * key; + + TEST_START(); + + if (crypt_load_privkey_str(server_pkp_ml, &key) < 0) { + printf("Failed to load server key pair from string.\n"); + goto fail_load; + } + + crypt_free_key(key); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_load: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_load_free_pubkey(void) +{ + void * key; + + TEST_START(); + + if (crypt_load_pubkey_str(server_pk_ml, &key) < 0) { + printf("Failed to load server public key from string.\n"); + goto fail_load; + } + + crypt_free_key(key); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_load: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_verify_crt(void) +{ + struct auth_ctx * auth; + void * _server_crt; + void * _signed_server_crt; + void * _root_ca_crt; + void * _im_ca_crt; + + TEST_START(); + + auth = auth_create_ctx(); + if (auth == NULL) { + printf("Failed to create auth context.\n"); + goto fail_create_ctx; + } + + if (crypt_load_crt_str(server_crt_ml, &_server_crt) < 0) { + printf("Failed to load self-signed crt from string.\n"); + goto fail_load_server_crt; + } + + if (crypt_load_crt_str(signed_server_crt_ml, &_signed_server_crt) < 0) { + printf("Failed to load signed crt from string.\n"); + goto fail_load_signed_server_crt; + } + + if (crypt_load_crt_str(root_ca_crt_ml, &_root_ca_crt) < 0) { + printf("Failed to load root crt from string.\n"); + goto fail_load_root_ca_crt; + } + + if (crypt_load_crt_str(im_ca_crt_ml, &_im_ca_crt) < 0) { + printf("Failed to load intermediate crt from string.\n"); + goto fail_load_im_ca_crt; + } + + if (auth_add_crt_to_store(auth, _root_ca_crt) < 0) { + printf("Failed to add root ca crt to auth store.\n"); + goto fail_verify; + } + + if (auth_add_crt_to_store(auth, _im_ca_crt) < 0) { + printf("Failed to add intermediate ca crt to auth store.\n"); + goto fail_verify; + } + + if (auth_verify_crt(auth, _signed_server_crt) < 0) { + printf("Failed to verify signed crt with ca crt.\n"); + goto fail_verify; + } + + if (auth_verify_crt(auth, _server_crt) == 0) { + printf("Failed to detect untrusted crt.\n"); + goto fail_verify; + } + + crypt_free_crt(_im_ca_crt); + crypt_free_crt(_root_ca_crt); + crypt_free_crt(_signed_server_crt); + crypt_free_crt(_server_crt); + + auth_destroy_ctx(auth); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_verify: + crypt_free_crt(_im_ca_crt); + fail_load_im_ca_crt: + crypt_free_crt(_root_ca_crt); + fail_load_root_ca_crt: + crypt_free_crt(_signed_server_crt); + fail_load_signed_server_crt: + crypt_free_crt(_server_crt); + fail_load_server_crt: + auth_destroy_ctx(auth); + fail_create_ctx: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_auth_sign(void) +{ + uint8_t buf[TEST_MSG_SIZE]; + void * pkp; + void * pk; + buffer_t msg; + buffer_t sig; + + TEST_START(); + + msg.data = buf; + msg.len = sizeof(buf); + + if (random_buffer(msg.data, msg.len) < 0) { + printf("Failed to generate random message.\n"); + goto fail_init; + } + + if (crypt_load_privkey_str(server_pkp_ml, &pkp) < 0) { + printf("Failed to load server key pair from string.\n"); + goto fail_init; + } + + if (crypt_load_pubkey_str(server_pk_ml, &pk) < 0) { + printf("Failed to load public key from string.\n"); + goto fail_pubkey; + } + + if (auth_sign(pkp, 0, msg, &sig) < 0) { + printf("Failed to sign message.\n"); + goto fail_sign; + } + + if (auth_verify_sig(pk, 0, msg, sig) < 0) { + printf("Failed to verify signature.\n"); + goto fail_verify; + } + + freebuf(sig); + + crypt_free_key(pk); + crypt_free_key(pkp); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_verify: + freebuf(sig); + fail_sign: + crypt_free_key(pk); + fail_pubkey: + crypt_free_key(pkp); + fail_init: + return TEST_RC_FAIL; +} + +static int test_auth_bad_signature(void) +{ + uint8_t buf[TEST_MSG_SIZE]; + void * pkp; + void * pk; + buffer_t msg; + buffer_t sig; + buffer_t fake_sig; + + TEST_START(); + + msg.data = buf; + msg.len = sizeof(buf); + + if (random_buffer(msg.data, msg.len) < 0) { + printf("Failed to generate random message.\n"); + goto fail_init; + } + + if (crypt_load_privkey_str(server_pkp_ml, &pkp) < 0) { + printf("Failed to load server key pair from string.\n"); + goto fail_init; + } + + if (crypt_load_pubkey_str(server_pk_ml, &pk) < 0) { + printf("Failed to load public key from string.\n"); + goto fail_pubkey; + } + + if (auth_sign(pkp, 0, msg, &sig) < 0) { + printf("Failed to sign message.\n"); + goto fail_sign; + } + + fake_sig.data = malloc(sig.len); + if (fake_sig.data == NULL) { + printf("Failed to allocate memory for fake signature.\n"); + goto fail_malloc; + } + + fake_sig.len = sig.len; + if (random_buffer(fake_sig.data, fake_sig.len) < 0) { + printf("Failed to generate random fake signature.\n"); + goto fail_malloc; + } + + if (auth_verify_sig(pk, 0, msg, fake_sig) == 0) { + printf("Failed to detect bad ML-DSA-65 signature.\n"); + goto fail_verify; + } + + freebuf(fake_sig); + freebuf(sig); + + crypt_free_key(pk); + crypt_free_key(pkp); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_verify: + freebuf(fake_sig); + fail_malloc: + freebuf(sig); + fail_sign: + crypt_free_key(pk); + fail_pubkey: + crypt_free_key(pkp); + fail_init: + return TEST_RC_FAIL; +} + +int auth_test_pqc(int argc, + char ** argv) +{ + int ret = 0; + + (void) argc; + (void) argv; + +#ifdef HAVE_OPENSSL_PQC + ret |= test_auth_create_destroy_ctx(); + ret |= test_load_free_crt(); + ret |= test_load_free_privkey(); + ret |= test_load_free_pubkey(); + ret |= test_verify_crt(); + ret |= test_auth_sign(); + ret |= test_auth_bad_signature(); +#else + (void) test_auth_create_destroy_ctx; + (void) test_load_free_crt; + (void) test_load_free_privkey; + (void) test_load_free_pubkey; + (void) test_verify_crt; + (void) test_auth_sign; + (void) test_auth_bad_signature; + + ret = TEST_RC_SKIP; +#endif + return ret; +} diff --git a/src/lib/tests/bitmap_test.c b/src/lib/tests/bitmap_test.c index 0815ecff..4dbd6653 100644 --- a/src/lib/tests/bitmap_test.c +++ b/src/lib/tests/bitmap_test.c @@ -1,5 +1,5 @@ /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024 * * Test of the bitmap * @@ -27,7 +27,8 @@ #define BITMAP_SIZE 200 -int bitmap_test(int argc, char ** argv) +int bitmap_test(int argc, + char ** argv) { struct bmp * bmp; ssize_t bits = BITMAP_SIZE; @@ -60,27 +61,23 @@ int bitmap_test(int argc, char ** argv) if (!bmp_is_id_valid(bmp, id)) { if (i < BITMAP_SIZE + offset) { printf("Failed valid ID %d (%zd).\n", i, id); - bmp_destroy(bmp); - return -1; + goto fail; } if (id >= offset && id < bits + offset) { printf("Valid ID %zd returned invalid.\n", id); - bmp_destroy(bmp); - return -1; + goto fail; } continue; } if (!bmp_is_id_used(bmp, id)) { printf("ID not marked in use.\n"); - bmp_destroy(bmp); - return -1; + goto fail; } if (id != i) { printf("Wrong ID returned.\n"); - bmp_destroy(bmp); - return -1; + goto fail; } } @@ -89,20 +86,24 @@ int bitmap_test(int argc, char ** argv) if (bmp_release(bmp, r)) { printf("Failed to release ID.\n"); - return -1; + goto fail; } id = bmp_allocate(bmp); if (!bmp_is_id_valid(bmp, id)) continue; + if (id != r) { printf("Wrong prev ID returned.\n"); - bmp_destroy(bmp); - return -1; + goto fail; } } bmp_destroy(bmp); return 0; + + fail: + bmp_destroy(bmp); + return -1; } diff --git a/src/lib/tests/btree_test.c b/src/lib/tests/btree_test.c index 9dc59d32..8bd30370 100644 --- a/src/lib/tests/btree_test.c +++ b/src/lib/tests/btree_test.c @@ -1,5 +1,5 @@ /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024 * * Test of the B-tree implementation * diff --git a/src/lib/tests/crc32_test.c b/src/lib/tests/crc32_test.c index a0f70423..a26c8220 100644 --- a/src/lib/tests/crc32_test.c +++ b/src/lib/tests/crc32_test.c @@ -1,5 +1,5 @@ /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024 * * Test of the CRC32 function * diff --git a/src/lib/tests/crypt_test.c b/src/lib/tests/crypt_test.c new file mode 100644 index 00000000..e250ad2a --- /dev/null +++ b/src/lib/tests/crypt_test.c @@ -0,0 +1,459 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Test of the cryptography functions + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#include "config.h" + +#include <test/test.h> +#include <ouroboros/random.h> +#include <ouroboros/crypt.h> +#include <ouroboros/utils.h> + +#include <stdio.h> + +#define TEST_PACKET_SIZE 1500 + +extern const uint16_t crypt_supported_nids[]; +extern const uint16_t md_supported_nids[]; + +static int test_crypt_create_destroy(void) +{ + struct crypt_ctx * ctx; + uint8_t key[SYMMKEYSZ]; + struct crypt_sk sk = { + .nid = NID_aes_256_gcm, + .key = key, + .rot_bit = KEY_ROTATION_BIT + }; + + TEST_START(); + + memset(key, 0, sizeof(key)); + + ctx = crypt_create_ctx(&sk); + if (ctx == NULL) { + printf("Failed to initialize cryptography.\n"); + goto fail; + } + + crypt_destroy_ctx(ctx); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_crypt_encrypt_decrypt(int nid) +{ + uint8_t pkt[TEST_PACKET_SIZE]; + struct crypt_ctx * ctx; + uint8_t key[SYMMKEYSZ]; + struct crypt_sk sk = { + .nid = NID_aes_256_gcm, + .key = key, + .rot_bit = KEY_ROTATION_BIT + }; + buffer_t in; + buffer_t out; + buffer_t out2; + const char * cipher; + + cipher = crypt_nid_to_str(nid); + TEST_START("(%s)", cipher); + + if (random_buffer(key, sizeof(key)) < 0) { + printf("Failed to generate random key.\n"); + goto fail_init; + } + + if (random_buffer(pkt, sizeof(pkt)) < 0) { + printf("Failed to generate random data.\n"); + goto fail_init; + } + + ctx = crypt_create_ctx(&sk); + if (ctx == NULL) { + printf("Failed to initialize cryptography.\n"); + goto fail_init; + } + + in.len = sizeof(pkt); + in.data = pkt; + + if (crypt_encrypt(ctx, in, &out) < 0) { + printf("Encryption failed.\n"); + goto fail_encrypt; + } + + if (out.len < in.len) { + printf("Encryption returned too little data.\n"); + goto fail_encrypt; + } + + if (crypt_decrypt(ctx, out, &out2) < 0) { + printf("Decryption failed.\n"); + goto fail_decrypt; + } + + if (out2.len != in.len) { + printf("Decrypted data length does not match original.\n"); + goto fail_chk; + } + + if (memcmp(in.data, out2.data, in.len) != 0) { + printf("Decrypted data does not match original.\n"); + goto fail_chk; + } + + crypt_destroy_ctx(ctx); + freebuf(out2); + freebuf(out); + + TEST_SUCCESS("(%s)", cipher); + + return TEST_RC_SUCCESS; + fail_chk: + freebuf(out2); + fail_decrypt: + freebuf(out); + fail_encrypt: + crypt_destroy_ctx(ctx); + fail_init: + TEST_FAIL("(%s)", cipher); + return TEST_RC_FAIL; +} + +static int test_encrypt_decrypt_all(void) +{ + int ret = 0; + int i; + + for (i = 0; crypt_supported_nids[i] != NID_undef; i++) + ret |= test_crypt_encrypt_decrypt(crypt_supported_nids[i]); + + return ret; +} + +#ifdef HAVE_OPENSSL +#include <openssl/evp.h> +#include <openssl/obj_mac.h> + +static int test_cipher_nid_values(void) +{ + int i; + + TEST_START(); + + /* Loop over all supported ciphers and verify NIDs match OpenSSL's */ + for (i = 0; crypt_supported_nids[i] != NID_undef; i++) { + uint16_t our_nid = crypt_supported_nids[i]; + const char * str = crypt_nid_to_str(our_nid); + const EVP_CIPHER * cipher; + int openssl_nid; + + if (str == NULL) { + printf("crypt_nid_to_str failed for NID %u\n", our_nid); + goto fail; + } + + cipher = EVP_get_cipherbyname(str); + if (cipher == NULL) { + printf("OpenSSL doesn't recognize cipher '%s'\n", str); + goto fail; + } + + openssl_nid = EVP_CIPHER_nid(cipher); + + if (our_nid != openssl_nid) { + printf("NID mismatch for '%s': ours=%u, OpenSSL=%d\n", + str, our_nid, openssl_nid); + goto fail; + } + + /* Test reverse conversion */ + if (crypt_str_to_nid(str) != our_nid) { + printf("crypt_str_to_nid failed for '%s'\n", str); + goto fail; + } + } + + /* Test error cases */ + if (crypt_str_to_nid("invalid") != NID_undef) { + printf("crypt_str_to_nid: no NID_undef for invalid.\n"); + goto fail; + } + + if (crypt_nid_to_str(9999) != NULL) { + printf("crypt_nid_to_str should return NULL for invalid NID\n"); + goto fail; + } + + if (crypt_str_to_nid(NULL) != NID_undef) { + printf("crypt_str_to_nid should return NID_undef for NULL\n"); + goto fail; + } + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_md_nid_values(void) +{ + int i; + + TEST_START(); + + for (i = 0; md_supported_nids[i] != NID_undef; i++) { + uint16_t our_nid = md_supported_nids[i]; + const EVP_MD * md; + int openssl_nid; + + md = EVP_get_digestbynid(our_nid); + if (md == NULL) { + printf("OpenSSL doesn't recognize NID %u\n", our_nid); + goto fail; + } + + openssl_nid = EVP_MD_nid(md); + if (our_nid != openssl_nid) { + printf("NID mismatch: ours=%u, OpenSSL=%d\n", + our_nid, openssl_nid); + goto fail; + } + } + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} +#endif + +static int test_key_rotation(void) +{ + uint8_t pkt[TEST_PACKET_SIZE]; + struct crypt_ctx * tx_ctx; + struct crypt_ctx * rx_ctx; + uint8_t key[SYMMKEYSZ]; + struct crypt_sk sk = { + .nid = NID_aes_256_gcm, + .key = key, + .rot_bit = 7 + }; + buffer_t in; + buffer_t enc; + buffer_t dec; + uint32_t i; + uint32_t threshold; + + TEST_START(); + + if (random_buffer(key, sizeof(key)) < 0) { + printf("Failed to generate random key.\n"); + goto fail; + } + + if (random_buffer(pkt, sizeof(pkt)) < 0) { + printf("Failed to generate random data.\n"); + goto fail; + } + + tx_ctx = crypt_create_ctx(&sk); + if (tx_ctx == NULL) { + printf("Failed to create TX context.\n"); + goto fail; + } + + rx_ctx = crypt_create_ctx(&sk); + if (rx_ctx == NULL) { + printf("Failed to create RX context.\n"); + goto fail_tx; + } + + in.len = sizeof(pkt); + in.data = pkt; + + threshold = (1U << sk.rot_bit); + + /* Encrypt and decrypt across multiple rotations */ + for (i = 0; i < threshold * 3; i++) { + if (crypt_encrypt(tx_ctx, in, &enc) < 0) { + printf("Encryption failed at packet %u.\n", i); + goto fail_rx; + } + + if (crypt_decrypt(rx_ctx, enc, &dec) < 0) { + printf("Decryption failed at packet %u.\n", i); + freebuf(enc); + goto fail_rx; + } + + if (dec.len != in.len || + memcmp(in.data, dec.data, in.len) != 0) { + printf("Data mismatch at packet %u.\n", i); + freebuf(dec); + freebuf(enc); + goto fail_rx; + } + + freebuf(dec); + freebuf(enc); + } + + crypt_destroy_ctx(rx_ctx); + crypt_destroy_ctx(tx_ctx); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_rx: + crypt_destroy_ctx(rx_ctx); + fail_tx: + crypt_destroy_ctx(tx_ctx); + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_key_phase_bit(void) +{ + uint8_t pkt[TEST_PACKET_SIZE]; + struct crypt_ctx * ctx; + uint8_t key[SYMMKEYSZ]; + struct crypt_sk sk = { + .nid = NID_aes_256_gcm, + .key = key, + .rot_bit = 7 + }; + buffer_t in; + buffer_t out; + uint32_t count; + uint32_t threshold; + uint8_t phase_before; + uint8_t phase_after; + int ivsz; + + TEST_START(); + + if (random_buffer(key, sizeof(key)) < 0) { + printf("Failed to generate random key.\n"); + goto fail; + } + + if (random_buffer(pkt, sizeof(pkt)) < 0) { + printf("Failed to generate random data.\n"); + goto fail; + } + + ctx = crypt_create_ctx(&sk); + if (ctx == NULL) { + printf("Failed to initialize cryptography.\n"); + goto fail; + } + + ivsz = crypt_get_ivsz(ctx); + if (ivsz <= 0) { + printf("Invalid IV size.\n"); + goto fail_ctx; + } + + in.len = sizeof(pkt); + in.data = pkt; + + /* Encrypt packets up to just before rotation threshold */ + threshold = (1U << sk.rot_bit); + + /* Encrypt threshold - 1 packets (indices 0 to threshold-2) */ + for (count = 0; count < threshold - 1; count++) { + if (crypt_encrypt(ctx, in, &out) < 0) { + printf("Encryption failed at count %u.\n", count); + goto fail_ctx; + } + freebuf(out); + } + + /* Packet at index threshold-1: phase should still be initial */ + if (crypt_encrypt(ctx, in, &out) < 0) { + printf("Encryption failed before rotation.\n"); + goto fail_ctx; + } + phase_before = (out.data[0] & 0x80) ? 1 : 0; + freebuf(out); + + /* Packet at index threshold: phase should have toggled */ + if (crypt_encrypt(ctx, in, &out) < 0) { + printf("Encryption failed at rotation threshold.\n"); + goto fail_ctx; + } + phase_after = (out.data[0] & 0x80) ? 1 : 0; + freebuf(out); + + /* Phase bit should have toggled */ + if (phase_before == phase_after) { + printf("Phase bit did not toggle: before=%u, after=%u.\n", + phase_before, phase_after); + goto fail_ctx; + } + + crypt_destroy_ctx(ctx); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_ctx: + crypt_destroy_ctx(ctx); + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +int crypt_test(int argc, + char ** argv) +{ + int ret = 0; + + (void) argc; + (void) argv; + + ret |= test_crypt_create_destroy(); + ret |= test_encrypt_decrypt_all(); +#ifdef HAVE_OPENSSL + ret |= test_cipher_nid_values(); + ret |= test_md_nid_values(); + ret |= test_key_rotation(); + ret |= test_key_phase_bit(); +#else + (void) test_key_rotation; + (void) test_key_phase_bit; + + return TEST_RC_SKIP; +#endif + return ret; +} diff --git a/src/lib/tests/hash_test.c b/src/lib/tests/hash_test.c new file mode 100644 index 00000000..fb428b47 --- /dev/null +++ b/src/lib/tests/hash_test.c @@ -0,0 +1,202 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Test of the hashing functions + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#include <ouroboros/hash.h> +#include <test/test.h> + +#include <stdlib.h> +#include <stdint.h> +#include <assert.h> +#include <string.h> +#include <stdio.h> + +/* + * Test vectors calculated at + * https://www.lammertbies.nl/comm/info/crc-calculation.html + */ + +struct vec_entry { + char * in; + char * out; +}; + +static int test_crc32(void) +{ + int ret = 0; + + struct vec_entry vec [] = { + { "0", "f4dbdf21" }, + { "123456789", "cbf43926" }, + { "987654321", "015f0201" }, + { NULL, NULL } + }; + + struct vec_entry * cur = vec; + + TEST_START(); + + while (cur->in != NULL) { + uint8_t crc[4]; + char res[9]; + + str_hash(HASH_CRC32, crc, cur->in); + + sprintf(res, HASH_FMT32, HASH_VAL32(crc)); + if (strcmp(res, cur->out) != 0) { + printf("Hash failed %s != %s.\n", res, cur->out); + ret |= -1; + } + + ++cur; + } + + TEST_END(ret); + + return ret; +} + +static int test_md5(void) +{ + int ret = 0; + + struct vec_entry vec [] = {{ + "abc", + "900150983cd24fb0d6963f7d28e17f72" + }, { + "The quick brown fox jumps over the lazy dog", + "9e107d9d372bb6826bd81d3542a419d6" + }, { + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "8215ef0796a20bcaaae116d3876c664a" + }, { + NULL, + NULL + }}; + + struct vec_entry * cur = vec; + + TEST_START(); + + + while (cur->in != NULL) { + uint8_t md5[16]; + char res[33]; + + str_hash(HASH_MD5, md5, cur->in); + + sprintf(res, HASH_FMT128, HASH_VAL128(md5)); + if (strcmp(res, cur->out) != 0) { + printf("Hash failed %s != %s.\n", res, cur->out); + ret |= -1; + } + + ++cur; + } + + TEST_END(ret); + + return ret; +} + +static int test_sha3(void) +{ + int ret = 0; + + uint8_t sha3[64]; + char res[129]; + + char * in = "abc"; + + char * out = + "e642824c3f8cf24ad09234ee7d3c766f" + "c9a3a5168d0c94ad73b46fdf"; + + TEST_START(); + + str_hash(HASH_SHA3_224, sha3, in); + + sprintf(res, HASH_FMT224, HASH_VAL224(sha3)); + if (strcmp(res, out) != 0) { + printf("SHA3-224 failed %s != %s", res, out); + ret |= -1; + } + + out = + "3a985da74fe225b2045c172d6bd390bd" + "855f086e3e9d525b46bfe24511431532"; + + str_hash(HASH_SHA3_256, sha3, in); + + sprintf(res, HASH_FMT256, HASH_VAL256(sha3)); + if (strcmp(res, out) != 0) { + printf("SHA3-256 failed %s != %s.\n", res, out); + ret |= -1; + } + + out = + "ec01498288516fc926459f58e2c6ad8d" + "f9b473cb0fc08c2596da7cf0e49be4b2" + "98d88cea927ac7f539f1edf228376d25"; + + str_hash(HASH_SHA3_384, sha3, in); + + sprintf(res, HASH_FMT384, HASH_VAL384(sha3)); + if (strcmp(res, out) != 0) { + printf("SHA3-384failed %s != %s.'n", res, out); + ret |= -1; + } + + out = + "b751850b1a57168a5693cd924b6b096e" + "08f621827444f70d884f5d0240d2712e" + "10e116e9192af3c91a7ec57647e39340" + "57340b4cf408d5a56592f8274eec53f0"; + + str_hash(HASH_SHA3_512, sha3, in); + + sprintf(res, HASH_FMT512, HASH_VAL512(sha3)); + if (strcmp(res, out) != 0) { + printf("SHA3-512 failed %s != %s.\n", res, out); + ret |= -1; + } + + TEST_END(ret); + + return ret; +} + +int hash_test(int argc, + char ** argv) +{ + int ret = 0; + + (void) argc; + (void) argv; + + ret |= test_crc32(); + + ret |= test_md5(); + + ret |= test_sha3(); + + return ret; +} diff --git a/src/lib/tests/kex_test.c b/src/lib/tests/kex_test.c new file mode 100644 index 00000000..0a588550 --- /dev/null +++ b/src/lib/tests/kex_test.c @@ -0,0 +1,844 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Test of the key exchange functions + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#define _POSIX_C_SOURCE 200809L + +#include "config.h" + +#include <test/test.h> +#include <ouroboros/utils.h> +#include <ouroboros/crypt.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#ifdef HAVE_OPENSSL +#include <openssl/evp.h> +#include <openssl/x509.h> +#endif + +/* Test configuration strings */ +#define KEX_CONFIG_CUSTOM \ + "kex=X25519\n" + +#define KEX_CONFIG_NONE \ + "none\n" + +#define KEX_CONFIG_WHITESPACE \ + "# Comment line\n" \ + "kex = X448" \ + "\n" \ + "# Another comment\n" + +#define KEX_CONFIG_CIPHER \ + "kex=X25519\n" \ + "cipher=chacha20-poly1305\n" + +#define KEX_CONFIG_DIGEST \ + "kex=X25519\n" \ + "digest=sha384\n" + +/* Test key material for key loading tests */ +#define X25519_PRIVKEY_PEM \ + "-----BEGIN PRIVATE KEY-----\n" \ + "MC4CAQAwBQYDK2VuBCIEIJDd3+/0k2IZlaH5sZ9Z2e5J8dV2U0nsXaSUm70ZaMhL\n" \ + "-----END PRIVATE KEY-----\n" + +#define X25519_PUBKEY_PEM \ + "-----BEGIN PUBLIC KEY-----\n" \ + "MCowBQYDK2VuAyEAKYLIycSZtLFlwAX07YWWgBAYhEnRxHfgK1TVw9+mtBs=\n" \ + "-----END PUBLIC KEY-----\n" + +/* Helper macro to open string constant as FILE stream */ +#define FMEMOPEN_STR(str) fmemopen((void *) (str), strlen(str), "r") + +extern const uint16_t kex_supported_nids[]; + +int parse_sec_config(struct sec_config * cfg, + FILE * fp); + +static int test_kex_create_destroy(void) +{ + struct sec_config cfg; + + TEST_START(); + + memset(&cfg, 0, sizeof(cfg)); + cfg.x.nid = NID_X9_62_prime256v1; + cfg.x.str = kex_nid_to_str(cfg.x.nid); + cfg.c.nid = NID_aes_256_gcm; + cfg.c.str = crypt_nid_to_str(cfg.c.nid); + + if (cfg.x.nid == NID_undef || cfg.c.nid == NID_undef) { + printf("Failed to initialize kex config.\n"); + goto fail; + } + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_kex_dh_pkp_create_destroy(void) +{ + struct sec_config kex; + void * pkp; + uint8_t buf[MSGBUFSZ]; + + TEST_START(); + + memset(&kex, 0, sizeof(kex)); + SET_KEX_ALGO(&kex, "prime256v1"); + + if (kex_pkp_create(&kex, &pkp, buf) < 0) { + printf("Failed to create DH PKP.\n"); + goto fail; + } + + kex_pkp_destroy(pkp); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_kex_get_algo_from_pk(const char * algo) +{ + struct sec_config kex; + void * pkp; + buffer_t pk; + ssize_t len; + uint8_t buf[MSGBUFSZ]; + char extracted_algo[256]; + + TEST_START("(%s)", algo); + + memset(&kex, 0, sizeof(kex)); + SET_KEX_ALGO(&kex, algo); + + len = kex_pkp_create(&kex, &pkp, buf); + if (len < 0) { + printf("Failed to create key pair.\n"); + goto fail; + } + + pk.len = (size_t) len; + pk.data = buf; + + /* Use raw decode for hybrid KEMs, DER for others */ + if (IS_HYBRID_KEM(algo)) { + if (kex_get_algo_from_pk_raw(pk, extracted_algo) < 0) { + printf("Failed to extract algo from pk.\n"); + goto fail_pkp; + } + } else { + if (kex_get_algo_from_pk_der(pk, extracted_algo) < 0) { + printf("Failed to extract algo from pk.\n"); + goto fail_pkp; + } + } + + /* All algorithms should now return the specific group name */ + if (strcmp(extracted_algo, algo) != 0) { + printf("Algo mismatch: expected %s, got %s.\n", + algo, extracted_algo); + goto fail_pkp; + } + + kex_pkp_destroy(pkp); + + TEST_SUCCESS("(%s)", algo); + + return TEST_RC_SUCCESS; + fail_pkp: + kex_pkp_destroy(pkp); + fail: + TEST_FAIL("(%s)", algo); + return TEST_RC_FAIL; +} + +static int test_kex_get_algo_from_pk_all(void) +{ + int ret = 0; + int i; + + for (i = 0; kex_supported_nids[i] != NID_undef; i++) { + const char * algo = kex_nid_to_str(kex_supported_nids[i]); + ret |= test_kex_get_algo_from_pk(algo); + } + + return ret; +} + +static int test_kex_dhe_derive(const char * algo) +{ + struct sec_config kex; + void * pkp1; + void * pkp2; + buffer_t pk1; + buffer_t pk2; + ssize_t len; + uint8_t buf1[MSGBUFSZ]; + uint8_t buf2[MSGBUFSZ]; + uint8_t s1[SYMMKEYSZ]; + uint8_t s2[SYMMKEYSZ]; + + TEST_START("(%s)", algo); + + memset(&kex, 0, sizeof(kex)); + SET_KEX_ALGO(&kex, algo); + + len = kex_pkp_create(&kex, &pkp1, buf1); + if (len < 0) { + printf("Failed to create first key pair for %s.\n", algo); + goto fail; + } + + pk1.len = (size_t) len; + pk1.data = buf1; + + len = kex_pkp_create(&kex, &pkp2, buf2); + if (len < 0) { + printf("Failed to create second key pair for %s.\n", algo); + goto fail_pkp1; + } + + pk2.len = (size_t) len; + pk2.data = buf2; + + if (kex_dhe_derive(&kex, pkp1, pk2, s1) < 0) { + printf("Failed to derive first key for %s.\n", algo); + goto fail_pkp2; + } + + if (kex_dhe_derive(&kex, pkp2, pk1, s2) < 0) { + printf("Failed to derive second key for %s.\n", algo); + goto fail_pkp2; + } + + if (memcmp(s1, s2, SYMMKEYSZ) != 0) { + printf("Derived keys do not match for %s.\n", algo); + goto fail_pkp2; + } + + kex_pkp_destroy(pkp2); + kex_pkp_destroy(pkp1); + + TEST_SUCCESS("(%s)", algo); + + return TEST_RC_SUCCESS; + fail_pkp2: + kex_pkp_destroy(pkp2); + fail_pkp1: + kex_pkp_destroy(pkp1); + fail: + TEST_FAIL("(%s)", algo); + return TEST_RC_FAIL; +} + +static int test_kex_validate_algo(void) +{ + TEST_START(); + + if (kex_validate_algo("prime256v1") != 0) { + printf("prime256v1 should be valid.\n"); + goto fail; + } + + if (kex_validate_algo("X25519") != 0) { + printf("X25519 should be valid.\n"); + goto fail; + } + +#ifdef HAVE_OPENSSL_PQC + if (kex_validate_algo("ML-KEM-768") != 0) { + printf("ML-KEM-768 should be valid.\n"); + goto fail; + } +#endif + + if (kex_validate_algo("ffdhe2048") != 0) { + printf("ffdhe2048 should be valid.\n"); + goto fail; + } + + if (kex_validate_algo("invalid_algo") == 0) { + printf("invalid_algo should be rejected.\n"); + goto fail; + } + + if (kex_validate_algo("rsa2048") == 0) { + printf("rsa2048 should be rejected.\n"); + goto fail; + } + + if (kex_validate_algo(NULL) == 0) { + printf("NULL should be rejected.\n"); + goto fail; + } + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_kex_dhe_corrupted_pubkey(const char * algo) +{ + struct sec_config kex; + void * pkp; + buffer_t pk; + ssize_t len; + uint8_t buf[MSGBUFSZ]; + uint8_t s[SYMMKEYSZ]; + + TEST_START("(%s)", algo); + + memset(&kex, 0, sizeof(kex)); + SET_KEX_ALGO(&kex, algo); + + len = kex_pkp_create(&kex, &pkp, buf); + if (len < 0) { + printf("Failed to create key pair.\n"); + goto fail; + } + + pk.len = (size_t) len; + pk.data = buf; + + /* Corrupt the public key */ + buf[0] ^= 0xFF; + buf[len - 1] ^= 0xFF; + + if (kex_dhe_derive(&kex, pkp, pk, s) == 0) { + printf("Should fail with corrupted public key.\n"); + goto fail_pkp; + } + + kex_pkp_destroy(pkp); + + TEST_SUCCESS("(%s)", algo); + + return TEST_RC_SUCCESS; + fail_pkp: + kex_pkp_destroy(pkp); + fail: + TEST_FAIL("(%s)", algo); + return TEST_RC_FAIL; +} + +static int test_kex_dhe_wrong_algo(void) +{ + struct sec_config kex1; + struct sec_config kex2; + void * pkp1; + void * pkp2; + buffer_t pk2; + ssize_t len; + uint8_t buf1[MSGBUFSZ]; + uint8_t buf2[MSGBUFSZ]; + uint8_t s[SYMMKEYSZ]; + const char * algo1 = "X25519"; + const char * algo2 = "X448"; + + TEST_START("(%s vs %s)", algo1, algo2); + + memset(&kex1, 0, sizeof(kex1)); + memset(&kex2, 0, sizeof(kex2)); + SET_KEX_ALGO(&kex1, algo1); + SET_KEX_ALGO(&kex2, algo2); + + if (kex_pkp_create(&kex1, &pkp1, buf1) < 0) { + printf("Failed to create first key pair.\n"); + goto fail; + } + + len = kex_pkp_create(&kex2, &pkp2, buf2); + if (len < 0) { + printf("Failed to create second key pair.\n"); + goto fail_pkp1; + } + + pk2.len = (size_t) len; + pk2.data = buf2; + + /* Try to derive with mismatched algorithms */ + if (kex_dhe_derive(&kex1, pkp1, pk2, s) == 0) { + printf("Should fail with mismatched algorithms.\n"); + goto fail_pkp2; + } + + kex_pkp_destroy(pkp2); + kex_pkp_destroy(pkp1); + + TEST_SUCCESS("(%s vs %s)", algo1, algo2); + + return TEST_RC_SUCCESS; + fail_pkp2: + kex_pkp_destroy(pkp2); + fail_pkp1: + kex_pkp_destroy(pkp1); + fail: + TEST_FAIL("(%s vs %s)", algo1, algo2); + return TEST_RC_FAIL; +} + +static int test_kex_load_dhe_privkey(void) +{ + void * key; + + TEST_START(); + + if (crypt_load_privkey_str(X25519_PRIVKEY_PEM, &key) < 0) { + printf("Failed to load X25519 private key.\n"); + goto fail; + } + + crypt_free_key(key); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_kex_load_dhe_pubkey(void) +{ + void * key; + + TEST_START(); + + if (crypt_load_pubkey_str(X25519_PUBKEY_PEM, &key) < 0) { + printf("Failed to load X25519 public key.\n"); + goto fail; + } + + crypt_free_key(key); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +#ifdef HAVE_OPENSSL +#include <openssl/obj_mac.h> + +static int test_kex_nid_values(void) +{ + int i; + + TEST_START(); + + /* Verify all KEX algorithm NIDs match OpenSSL's */ + for (i = 0; kex_supported_nids[i] != NID_undef; i++) { + uint16_t our_nid = kex_supported_nids[i]; + const char * kex_name; + int openssl_nid; + + kex_name = kex_nid_to_str(our_nid); + if (kex_name == NULL) { + printf("kex_nid_to_str failed for NID %u\n", our_nid); + goto fail; + } + + /* Test reverse conversion */ + if (kex_str_to_nid(kex_name) != our_nid) { + printf("kex_str_to_nid failed for '%s'\n", kex_name); + goto fail; + } + + /* Get OpenSSL's NID for this name */ + openssl_nid = OBJ_txt2nid(kex_name); + if (openssl_nid != NID_undef) { + /* OpenSSL recognizes this algorithm */ + if (our_nid != openssl_nid) { + printf("NID mismatch for '%s': " + "ours=%d, OpenSSL=%d\n", + kex_name, our_nid, openssl_nid); + goto fail; + } + } else { + /* Verify no NID collision with different algorithm */ + const char * ossl_name = OBJ_nid2sn(our_nid); + if (ossl_name != NULL && + strcmp(ossl_name, kex_name) != 0) { + printf("NID collision for '%d': " + "ours=%s, OpenSSL=%s\n", + our_nid, kex_name, ossl_name); + goto fail; + } + } + } + + /* Test error cases */ + if (kex_str_to_nid("invalid") != NID_undef) { + printf("kex_str_to_nid should return NID_undef for invalid\n"); + goto fail; + } + + if (kex_nid_to_str(9999) != NULL) { + printf("kex_nid_to_str should return NULL for invalid NID\n"); + goto fail; + } + + if (kex_str_to_nid(NULL) != NID_undef) { + printf("kex_str_to_nid should return NID_undef for NULL\n"); + goto fail; + } + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} +#endif + +static int test_kex_all(void) +{ + int ret = 0; + int i; + + for (i = 0; kex_supported_nids[i] != NID_undef; i++) { + const char * algo = kex_nid_to_str(kex_supported_nids[i]); + + /* KEM tests are in kex_test_pqc.c */ + if (IS_KEM_ALGORITHM(algo)) + continue; + + ret |= test_kex_dhe_derive(algo); + } + + return ret; +} + +static int test_kex_dhe_corrupted_pubkey_all(void) +{ + int ret = 0; + int i; + + /* Test corruption for all DHE algorithms */ + /* KEM error injection tests are in kex_test_pqc.c */ + for (i = 0; kex_supported_nids[i] != NID_undef; i++) { + const char * algo = kex_nid_to_str(kex_supported_nids[i]); + + if (IS_KEM_ALGORITHM(algo)) + continue; + + ret |= test_kex_dhe_corrupted_pubkey(algo); + } + + return ret; +} + +static int test_kex_parse_config_empty(void) +{ + struct sec_config kex; + FILE * fp; + + TEST_START(); + + memset(&kex, 0, sizeof(kex)); + + fp = FMEMOPEN_STR("\n"); + if (fp == NULL) { + printf("Failed to open memory stream.\n"); + goto fail; + } + + if (parse_sec_config(&kex, fp) < 0) { + printf("Failed to parse empty config.\n"); + fclose(fp); + goto fail; + } + + if (strcmp(kex.x.str, "prime256v1") != 0) { + printf("Empty config should use prime256v1.\n"); + fclose(fp); + goto fail; + } + + fclose(fp); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_kex_parse_config_custom(void) +{ + struct sec_config kex; + FILE * fp; + + TEST_START(); + + memset(&kex, 0, sizeof(kex)); + + fp = FMEMOPEN_STR(KEX_CONFIG_CUSTOM); + if (fp == NULL) { + printf("Failed to open memory stream.\n"); + goto fail; + } + + if (parse_sec_config(&kex, fp) < 0) { + printf("Failed to parse custom config.\n"); + fclose(fp); + goto fail; + } + + if (strcmp(kex.x.str, "X25519") != 0) { + printf("Algorithm not set correctly.\n"); + fclose(fp); + goto fail; + } + + fclose(fp); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_kex_parse_config_none(void) +{ + struct sec_config kex; + FILE * fp; + + TEST_START(); + + memset(&kex, 0, sizeof(kex)); + + fp = FMEMOPEN_STR(KEX_CONFIG_NONE); + if (fp == NULL) { + printf("Failed to open memory stream.\n"); + goto fail; + } + + if (parse_sec_config(&kex, fp) < 0) { + printf("Failed to parse 'none' config.\n"); + fclose(fp); + goto fail; + } + + if (kex.x.nid != NID_undef) { + printf("'none' keyword should disable encryption.\n"); + fclose(fp); + goto fail; + } + + fclose(fp); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_kex_parse_config_whitespace(void) +{ + struct sec_config kex; + FILE * fp; + + TEST_START(); + + memset(&kex, 0, sizeof(kex)); + + fp = FMEMOPEN_STR(KEX_CONFIG_WHITESPACE); + if (fp == NULL) { + printf("Failed to open memory stream.\n"); + goto fail; + } + + if (parse_sec_config(&kex, fp) < 0) { + printf("Failed to parse config with comments.\n"); + fclose(fp); + goto fail; + } + + if (strcmp(kex.x.str, "X448") != 0) { + printf("Algorithm with whitespace not parsed correctly.\n"); + fclose(fp); + goto fail; + } + + fclose(fp); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_kex_parse_config_cipher(void) +{ + struct sec_config kex; + FILE * fp; + + TEST_START(); + + memset(&kex, 0, sizeof(kex)); + + fp = FMEMOPEN_STR(KEX_CONFIG_CIPHER); + if (fp == NULL) { + printf("Failed to open memory stream.\n"); + goto fail; + } + + if (parse_sec_config(&kex, fp) < 0) { + printf("Failed to parse cipher config.\n"); + fclose(fp); + goto fail; + } + + if (strcmp(kex.x.str, "X25519") != 0) { + printf("Algorithm not set correctly.\n"); + fclose(fp); + goto fail; + } + + if (kex.c.nid != NID_chacha20_poly1305) { + printf("Cipher not set correctly.\n"); + fclose(fp); + goto fail; + } + + fclose(fp); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_kex_parse_config_digest(void) +{ + struct sec_config kex; + FILE * fp; + + TEST_START(); + + memset(&kex, 0, sizeof(kex)); + + fp = FMEMOPEN_STR(KEX_CONFIG_DIGEST); + if (fp == NULL) { + printf("Failed to open memory stream.\n"); + goto fail; + } + + if (parse_sec_config(&kex, fp) < 0) { + printf("Failed to parse digest config.\n"); + fclose(fp); + goto fail; + } + + if (strcmp(kex.x.str, "X25519") != 0) { + printf("Algorithm not set correctly.\n"); + fclose(fp); + goto fail; + } + + if (kex.d.nid != NID_sha384) { + printf("Digest not set correctly.\n"); + fclose(fp); + goto fail; + } + + fclose(fp); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +int kex_test(int argc, + char ** argv) +{ + int ret = 0; + + (void) argc; + (void) argv; + + ret |= test_kex_create_destroy(); + ret |= test_kex_parse_config_empty(); + ret |= test_kex_parse_config_none(); +#ifdef HAVE_OPENSSL + ret |= test_kex_parse_config_custom(); + ret |= test_kex_parse_config_whitespace(); + ret |= test_kex_parse_config_cipher(); + ret |= test_kex_parse_config_digest(); + ret |= test_kex_nid_values(); + ret |= test_kex_dh_pkp_create_destroy(); + ret |= test_kex_all(); + ret |= test_kex_validate_algo(); + ret |= test_kex_get_algo_from_pk_all(); + ret |= test_kex_dhe_wrong_algo(); + ret |= test_kex_dhe_corrupted_pubkey_all(); + ret |= test_kex_load_dhe_privkey(); + ret |= test_kex_load_dhe_pubkey(); +#else + (void) test_kex_parse_config_custom; + (void) test_kex_parse_config_whitespace; + (void) test_kex_parse_config_cipher; + (void) test_kex_parse_config_digest; + (void) test_kex_dh_pkp_create_destroy; + (void) test_kex_all; + (void) test_kex_validate_algo; + (void) test_kex_get_algo_from_pk_all; + (void) test_kex_dhe_wrong_algo(); + (void) test_kex_dhe_corrupted_pubkey_all; + (void) test_kex_load_dhe_privkey; + (void) test_kex_load_dhe_pubkey; + + ret = TEST_RC_SKIP; +#endif + return ret; +} diff --git a/src/lib/tests/kex_test_pqc.c b/src/lib/tests/kex_test_pqc.c new file mode 100644 index 00000000..d4579eca --- /dev/null +++ b/src/lib/tests/kex_test_pqc.c @@ -0,0 +1,549 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2026 + * + * Test of the post-quantum key exchange functions + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#define _POSIX_C_SOURCE 200809L + +#include "config.h" + +#include <test/test.h> +#include <ouroboros/utils.h> +#include <ouroboros/crypt.h> +#include <ouroboros/random.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#ifdef HAVE_OPENSSL +#include <openssl/evp.h> +#include <openssl/x509.h> +#endif + +extern const uint16_t kex_supported_nids[]; +extern const uint16_t md_supported_nids[]; + +static int get_random_kdf(void) +{ + static int idx = 0; + int count; + + if (md_supported_nids[0] == NID_undef) + return NID_undef; + + for (count = 0; md_supported_nids[count] != NID_undef; count++) + ; + + return md_supported_nids[(idx++) % count]; +} + +/* ML-KEM-768 test key material */ + +#define MLKEM768_PRIVKEY_PEM \ + "-----BEGIN PRIVATE KEY-----\n" \ + "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\n" \ + "108=\n" \ + "-----END PRIVATE KEY-----\n" + +#define MLKEM768_PUBKEY_PEM \ + "-----BEGIN PUBLIC KEY-----\n" \ + "MIIEsjALBglghkgBZQMEBAIDggShAMPIO3U2cWpYVzqVh5Vrp5FyZjN4BtdqGvHC\n" \ + "KJosh0dcP3lpn/RLr60oEaBDPCZmxvB1eGX6f7KoM0TpKjDZvC56qEPBlVagwK/l\n" \ + "Ir4cAY+1xntRT2hauqmIvTzmbsXkbj0olQRlp1W2Phn3OuR5CSJ1r7gju/djczOx\n" \ + "awYnDDtiFMMmmzHGZKbzlsfDH3yFldKpyQlMvhzacHOCsGW6QhP1aX6oi0y2FW8A\n" \ + "E/OnjAZmF2AqsQhGXfIKeGFSCkuVTFh6DBYMwSNnEqVJsjKXmn2UJLzDaWwHOxDY\n" \ + "UmIDL8xYtrnpoD7AWzcLyyZnoJ+nk1ZrxGb6Tz3wZYHFmK+EXTcIE5njZ27RhRl0\n" \ + "I+gDlXUoLpuHgnJYUjj1UVtAUwaDACpzQSsAfeIxqaYoL3vjpZZqCdQgbejwvKBm\n" \ + "u6y4Z5OiFcmFVRMkPDazSvM2FvDkjKiiSRjkFYQ0oUpMiB0HG9h6U4rBsYTxnfoU\n" \ + "RbQAGWbHtJEIpaU1WNIQAheYyJBUt1AXfdBVgP1FHlyGNrbnhW4kfimWj7knCIpb\n" \ + "PwuUIgGbsJWSJ9kwuh+YyTezcvixe0T4GF+bk+WTdGuAN2Ucf6EruCTrVcZ3KcaM\n" \ + "Njtou0IpnRIyxWyRIuibWlshHkwotixDU+x7iaF8M4UKRYUsjlNKEYy4iijWTtd4\n" \ + "gTqDxChSVXkRfJYceEhVoTjJYY8BWASnRSzAoV56jdKgIB4AMDdTzzKbGkEmnvfI\n" \ + "MiqiTl0zdKCSN89ZkOSCQAjxYewIop6qtI6zWSQTcle0TuRxMdPpcejXrZOaAaSo\n" \ + "xXA5DcSZHoVGljEmFm+5VuMmxLFiNbdJydHhmK+iLur3nKlyjffWkiUhmmpXQ3J1\n" \ + "SkzJBrPVyeg8pgOHXFrouFyoQorxrryJeNCDOCpAEMAGidXJs0O2UnmWdNO4qFqT\n" \ + "w8EUCaaGPUl2s+qgi9BEKYtpquQnv+r1Eu2TqRM4nSq0t7aqrALEnDKgx3ZDkXj7\n" \ + "FNZke73SWNF1ydh7BqupwrOgvbu1ylM6ZXPzwjWFhVQkRXtoHfpAyFNLV2q5Oolk\n" \ + "IPSEE9YAxOgSgPg4W8paZsWbNpbGsxzgQJh4MAApizZiqhdIt8CLEGZmNvpQMHrW\n" \ + "XYYDnykUlbRnA3xLm0CkDY1GL7ugL/OAyAEYd+3oTT45RVvwi3z2ljW3vJurn5+Q\n" \ + "G8SLEMh3d/WkreCpxpiob9iGgwkwlaSpjEI0aZ1nyAWjjpXor7jFlRuVBYrKk3r5\n" \ + "Fg7iQOHSSimlYYRQuOAGgIf5XwTsZygTxJF1BjUEgyhFVZvxSvxlghVTyWqBpk+V\n" \ + "YzehEKJaTSRHF7EUXSLlaUgsgr0ZPyxpf5uZF30pLLcmuk+FCfn0KkkFHHPxYp0n\n" \ + "fDC2oT/ZNvFCEuigRYdhWtkQbkRKQig6RQAlRH4LMssUMx1QTzDcJqwTjKz6Fyjs\n" \ + "ADlMCazbgDUVdzEyA1vpUcDRuLlzys8Jm+O5stdHgDT8DZRqWjhzLdQCv2TSttk4\n" \ + "meOqTx4TGR5rFvKHjZwmlTvmLg40tixFkmSD1uQKk+BkpvvTuw9k7vYJfeH+VB1d\n" \ + "WAaRntOp\n" \ + "-----END PUBLIC KEY-----\n" + +/* Helper macro to open string constant as FILE stream */ +#define FMEMOPEN_STR(str) fmemopen((void *) (str), strlen(str), "r") + +static int test_kex_load_kem_privkey(void) +{ + void * key; + + TEST_START(); + + if (crypt_load_privkey_str(MLKEM768_PRIVKEY_PEM, &key) < 0) { + printf("Failed to load ML-KEM-768 private key.\n"); + goto fail; + } + + crypt_free_key(key); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_kex_load_kem_pubkey(void) +{ + void * key; + + TEST_START(); + + if (crypt_load_pubkey_str(MLKEM768_PUBKEY_PEM, &key) < 0) { + printf("Failed to load ML-KEM-768 public key.\n"); + goto fail; + } + + crypt_free_key(key); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_kex_kem(const char * algo) +{ + struct sec_config kex; + void * pkp; + buffer_t pk; + buffer_t ct; + ssize_t len; + ssize_t ct_len; + uint8_t buf1[MSGBUFSZ]; + uint8_t buf2[MSGBUFSZ]; + uint8_t s1[SYMMKEYSZ]; + uint8_t s2[SYMMKEYSZ]; + int kdf; + + TEST_START("(%s)", algo); + + kdf = get_random_kdf(); + + memset(&kex, 0, sizeof(kex)); + SET_KEX_ALGO(&kex, algo); + + len = kex_pkp_create(&kex, &pkp, buf1); + if (len < 0) { + printf("Failed to create key pair for %s.\n", algo); + goto fail; + } + + pk.len = (size_t) len; + pk.data = buf1; + + if (IS_HYBRID_KEM(algo)) + ct_len = kex_kem_encap_raw(pk, buf2, kdf, s1); + else + ct_len = kex_kem_encap(pk, buf2, kdf, s1); + + if (ct_len < 0) { + printf("Failed to encapsulate for %s.\n", algo); + goto fail_pkp; + } + + ct.len = (size_t) ct_len; + ct.data = buf2; + + if (kex_kem_decap(pkp, ct, kdf, s2) < 0) { + printf("Failed to decapsulate for %s.\n", algo); + goto fail_pkp; + } + + if (memcmp(s1, s2, SYMMKEYSZ) != 0) { + printf("Shared secrets don't match for %s.\n", algo); + goto fail_pkp; + } + + kex_pkp_destroy(pkp); + + TEST_SUCCESS("(%s)", algo); + + return TEST_RC_SUCCESS; + fail_pkp: + kex_pkp_destroy(pkp); + fail: + TEST_FAIL("(%s)", algo); + return TEST_RC_FAIL; +} + +static int test_kex_kem_corrupted_ciphertext(const char * algo) +{ + struct sec_config kex; + void * pkp; + buffer_t pk; + buffer_t ct; + ssize_t len; + ssize_t ct_len; + uint8_t buf1[MSGBUFSZ]; + uint8_t buf2[MSGBUFSZ]; + uint8_t s1[SYMMKEYSZ]; + uint8_t s2[SYMMKEYSZ]; + int kdf; + + TEST_START("(%s)", algo); + + kdf = get_random_kdf(); + + memset(&kex, 0, sizeof(kex)); + SET_KEX_ALGO(&kex, algo); + + len = kex_pkp_create(&kex, &pkp, buf1); + if (len < 0) { + printf("Failed to create key pair.\n"); + goto fail; + } + + pk.len = (size_t) len; + pk.data = buf1; + + if (IS_HYBRID_KEM(algo)) + ct_len = kex_kem_encap_raw(pk, buf2, kdf, s1); + else + ct_len = kex_kem_encap(pk, buf2, kdf, s1); + + if (ct_len < 0) { + printf("Failed to encapsulate.\n"); + goto fail_pkp; + } + + ct.len = (size_t) ct_len; + ct.data = buf2; + + /* Corrupt the ciphertext */ + buf2[0] ^= 0xFF; + buf2[ct_len - 1] ^= 0xFF; + + /* ML-KEM uses implicit rejection */ + if (kex_kem_decap(pkp, ct, kdf, s2) < 0) { + printf("Decapsulation failed unexpectedly.\n"); + goto fail_pkp; + } + + /* The shared secrets should NOT match with corrupted CT */ + if (memcmp(s1, s2, SYMMKEYSZ) == 0) { + printf("Corrupted ciphertext produced same secret.\n"); + goto fail_pkp; + } + + kex_pkp_destroy(pkp); + + TEST_SUCCESS("(%s)", algo); + + return TEST_RC_SUCCESS; + fail_pkp: + kex_pkp_destroy(pkp); + fail: + TEST_FAIL("(%s)", algo); + return TEST_RC_FAIL; +} + +static int test_kex_kem_wrong_keypair(const char * algo) +{ + struct sec_config kex; + void * pkp1; + void * pkp2; + buffer_t pk1; + buffer_t ct; + ssize_t len; + ssize_t ct_len; + uint8_t buf1[MSGBUFSZ]; + uint8_t buf2[MSGBUFSZ]; + uint8_t buf3[MSGBUFSZ]; + uint8_t s1[SYMMKEYSZ]; + uint8_t s2[SYMMKEYSZ]; + + TEST_START("(%s)", algo); + + memset(&kex, 0, sizeof(kex)); + SET_KEX_ALGO(&kex, algo); + + len = kex_pkp_create(&kex, &pkp1, buf1); + if (len < 0) { + printf("Failed to create first key pair.\n"); + goto fail; + } + + pk1.len = (size_t) len; + pk1.data = buf1; + + if (kex_pkp_create(&kex, &pkp2, buf2) < 0) { + printf("Failed to create second key pair.\n"); + goto fail_pkp1; + } + + if (IS_HYBRID_KEM(algo)) + ct_len = kex_kem_encap_raw(pk1, buf3, NID_sha256, s1); + else + ct_len = kex_kem_encap(pk1, buf3, NID_sha256, s1); + + if (ct_len < 0) { + printf("Failed to encapsulate.\n"); + goto fail_pkp2; + } + + ct.len = (size_t) ct_len; + ct.data = buf3; + + if (kex_kem_decap(pkp2, ct, NID_sha256, s2) == 0) { + if (memcmp(s1, s2, SYMMKEYSZ) == 0) { + printf("Wrong keypair produced same secret.\n"); + goto fail_pkp2; + } + } + + kex_pkp_destroy(pkp2); + kex_pkp_destroy(pkp1); + + TEST_SUCCESS("(%s)", algo); + + return TEST_RC_SUCCESS; + fail_pkp2: + kex_pkp_destroy(pkp2); + fail_pkp1: + kex_pkp_destroy(pkp1); + fail: + TEST_FAIL("(%s)", algo); + return TEST_RC_FAIL; +} + +static int test_kex_kem_truncated_ciphertext(const char * algo) +{ + struct sec_config kex; + void * pkp; + buffer_t pk; + buffer_t ct; + ssize_t len; + ssize_t ct_len; + uint8_t buf1[MSGBUFSZ]; + uint8_t buf2[MSGBUFSZ]; + uint8_t s1[SYMMKEYSZ]; + uint8_t s2[SYMMKEYSZ]; + + TEST_START("(%s)", algo); + + memset(&kex, 0, sizeof(kex)); + SET_KEX_ALGO(&kex, algo); + + len = kex_pkp_create(&kex, &pkp, buf1); + if (len < 0) { + printf("Failed to create key pair.\n"); + goto fail; + } + + pk.len = (size_t) len; + pk.data = buf1; + + if (IS_HYBRID_KEM(algo)) + ct_len = kex_kem_encap_raw(pk, buf2, NID_sha256, s1); + else + ct_len = kex_kem_encap(pk, buf2, NID_sha256, s1); + + if (ct_len < 0) { + printf("Failed to encapsulate.\n"); + goto fail_pkp; + } + + /* Truncate the ciphertext */ + ct.len = (size_t) ct_len / 2; + ct.data = buf2; + + if (kex_kem_decap(pkp, ct, NID_sha256, s2) == 0) { + printf("Should fail with truncated ciphertext.\n"); + goto fail_pkp; + } + + kex_pkp_destroy(pkp); + + TEST_SUCCESS("(%s)", algo); + + return TEST_RC_SUCCESS; + fail_pkp: + kex_pkp_destroy(pkp); + fail: + TEST_FAIL("(%s)", algo); + return TEST_RC_FAIL; +} + +static int test_kex_kem_all(void) +{ + int ret = 0; + int i; + + for (i = 0; kex_supported_nids[i] != NID_undef; i++) { + const char * algo = kex_nid_to_str(kex_supported_nids[i]); + + if (!IS_KEM_ALGORITHM(algo)) + continue; + + ret |= test_kex_kem(algo); + } + + return ret; +} + +static int test_kex_kem_corrupted_ciphertext_all(void) +{ + int ret = 0; + int i; + + for (i = 0; kex_supported_nids[i] != NID_undef; i++) { + const char * algo = kex_nid_to_str(kex_supported_nids[i]); + + if (!IS_KEM_ALGORITHM(algo)) + continue; + + ret |= test_kex_kem_corrupted_ciphertext(algo); + } + + return ret; +} + +static int test_kex_kem_wrong_keypair_all(void) +{ + int ret = 0; + int i; + + for (i = 0; kex_supported_nids[i] != NID_undef; i++) { + const char * algo = kex_nid_to_str(kex_supported_nids[i]); + + if (!IS_KEM_ALGORITHM(algo)) + continue; + + ret |= test_kex_kem_wrong_keypair(algo); + } + + return ret; +} + +static int test_kex_kem_truncated_ciphertext_all(void) +{ + int ret = 0; + int i; + + for (i = 0; kex_supported_nids[i] != NID_undef; i++) { + const char * algo = kex_nid_to_str(kex_supported_nids[i]); + + if (!IS_KEM_ALGORITHM(algo)) + continue; + + ret |= test_kex_kem_truncated_ciphertext(algo); + } + + return ret; +} + +int kex_test_pqc(int argc, + char ** argv) +{ + int ret = 0; + + (void) argc; + (void) argv; + +#ifdef HAVE_OPENSSL_PQC + ret |= test_kex_load_kem_privkey(); + ret |= test_kex_load_kem_pubkey(); + ret |= test_kex_kem_all(); + ret |= test_kex_kem_corrupted_ciphertext_all(); + ret |= test_kex_kem_wrong_keypair_all(); + ret |= test_kex_kem_truncated_ciphertext_all(); +#else + (void) test_kex_load_kem_privkey; + (void) test_kex_load_kem_pubkey; + (void) test_kex_kem_all; + (void) test_kex_kem_corrupted_ciphertext_all; + (void) test_kex_kem_wrong_keypair_all; + (void) test_kex_kem_truncated_ciphertext_all; + + ret = TEST_RC_SKIP; +#endif + return ret; +} diff --git a/src/lib/tests/md5_test.c b/src/lib/tests/md5_test.c index b5ad127f..28e8f42f 100644 --- a/src/lib/tests/md5_test.c +++ b/src/lib/tests/md5_test.c @@ -1,5 +1,5 @@ /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024 * * Test of the MD5 function * diff --git a/src/lib/tests/sha3_test.c b/src/lib/tests/sha3_test.c index 4860cd9b..82b4ef0d 100644 --- a/src/lib/tests/sha3_test.c +++ b/src/lib/tests/sha3_test.c @@ -1,5 +1,5 @@ /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024 * * Test of the SHA3 function * diff --git a/src/lib/tests/shm_rbuff_test.c b/src/lib/tests/shm_rbuff_test.c deleted file mode 100644 index a3ed1449..00000000 --- a/src/lib/tests/shm_rbuff_test.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2021 - * - * Test of the shm_rbuff - * - * Dimitri Staessens <dimitri@ouroboros.rocks> - * Sander Vrijders <sander@ouroboros.rocks> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#define _POSIX_C_SOURCE 200112L - -#include "config.h" - -#include <ouroboros/shm_rbuff.h> - -#include <errno.h> -#include <stdio.h> -#include <unistd.h> - -int shm_rbuff_test(int argc, - char ** argv) -{ - struct shm_rbuff * rb; - size_t i; - - (void) argc; - (void) argv; - - printf("Test: create rbuff..."); - - rb = shm_rbuff_create(getpid(), 1); - if (rb == NULL) - goto err; - - printf("success.\n\n"); - printf("Test: write a value..."); - - if (shm_rbuff_write(rb, 1) < 0) - goto error; - - printf("success.\n\n"); - printf("Test: check queue length is 1..."); - - if (shm_rbuff_queued(rb) != 1) - goto error; - - printf("success.\n\n"); - printf("Test: read a value..."); - - if (shm_rbuff_read(rb) != 1) - goto error; - - printf("success.\n\n"); - printf("Test: check queue is empty..."); - - if (shm_rbuff_read(rb) != -EAGAIN) - goto error; - - printf("success.\n\n"); - printf("Test: fill the queue..."); - - for (i = 0; i < SHM_RBUFF_SIZE - 1; ++i) { - if (shm_rbuff_queued(rb) != i) - goto error; - if (shm_rbuff_write(rb, 1) < 0) - goto error; - } - - printf("success.\n\n"); - printf("Test: check queue is full..."); - - if (shm_rbuff_queued(rb) != SHM_RBUFF_SIZE - 1) - goto error; - - printf("success [%zd entries].\n\n", shm_rbuff_queued(rb)); - - printf("Test: check queue is full by writing value..."); - if (!(shm_rbuff_write(rb, 1) < 0)) - goto error; - - printf("success [%zd entries].\n\n", shm_rbuff_queued(rb)); - - /* empty the rbuff */ - while (shm_rbuff_read(rb) >= 0) - ; - - shm_rbuff_destroy(rb); - - return 0; - - error: - /* empty the rbuff */ - while (shm_rbuff_read(rb) >= 0) - ; - - shm_rbuff_destroy(rb); - err: - printf("failed.\n\n"); - return -1; -} diff --git a/src/lib/tests/sockets_test.c b/src/lib/tests/sockets_test.c new file mode 100644 index 00000000..ce9051b6 --- /dev/null +++ b/src/lib/tests/sockets_test.c @@ -0,0 +1,102 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Tests for socket.c + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#if defined(__linux__) || defined(__CYGWIN__) +#define _DEFAULT_SOURCE +#else +#define _POSIX_C_SOURCE 200112L +#endif + +#include <ouroboros/sockets.h> +#include <test/test.h> + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#define TEST_PID 1234 +#define TEST_PID_STR "1234" +#define TEST_SERVER_PATH "/tmp/test.sock" +#define TEST_SERVER_PREFIX "/tmp/ouroboros/test." +#define TEST_SOCK_PATH_PREFIX "var/run/ouroboros/test." + +static int test_sock_path(void) +{ + char * path; + char * exp = TEST_SOCK_PATH_PREFIX TEST_PID_STR SOCK_PATH_SUFFIX; + + TEST_START(); + + path = sock_path(TEST_PID, TEST_SOCK_PATH_PREFIX); + if (path == NULL) { + printf("Path is NULL.\n"); + goto fail_path; + } + + if (strcmp(path, exp) != 0) { + printf("Expected path '%s', got '%s'.\n", exp, path); + goto fail_cmp; + } + + free(path); + + TEST_SUCCESS(); + return TEST_RC_SUCCESS; + fail_cmp: + free(path); + fail_path: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_server_socket_open(void) +{ + int sockfd; + + TEST_START(); + + sockfd = server_socket_open(TEST_SERVER_PATH); + if (sockfd < 0) { + printf("Failed to open server socket.\n"); + goto fail_sock; + } + + close(sockfd); + + unlink(TEST_SERVER_PATH); + + TEST_SUCCESS(); + return TEST_RC_SUCCESS; + fail_sock: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +int sockets_test(void) +{ + int ret = 0; + + ret |= test_sock_path(); + ret |= test_server_socket_open(); + + return ret; +} diff --git a/src/lib/tests/time_test.c b/src/lib/tests/time_test.c new file mode 100644 index 00000000..4685310b --- /dev/null +++ b/src/lib/tests/time_test.c @@ -0,0 +1,529 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Test of the time utilities + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#define _POSIX_C_SOURCE 200809L + +#include <test/test.h> +#include <ouroboros/time.h> + +#include <stdio.h> + +static int ts_check(struct timespec * s, + time_t sec, + time_t nsec) +{ + return s->tv_sec == sec && s->tv_nsec == nsec; +} + +static int tv_check(struct timeval * v, + time_t sec, + time_t usec) +{ + return v->tv_sec == sec && v->tv_usec == usec; +} + + +static int test_time_ts_init(void) +{ + struct timespec s = TIMESPEC_INIT_S (100); + struct timespec ms = TIMESPEC_INIT_MS(100); + struct timespec us = TIMESPEC_INIT_US(100); + struct timespec ns = TIMESPEC_INIT_NS(100); + + TEST_START(); + + if (!ts_check(&s, 100, 0)) { + printf("timespec_init_s failed.\n"); + goto fail; + } + + if (!ts_check(&ms, 0, 100 * MILLION)) { + printf("timespec_init_ms failed.\n"); + goto fail; + } + + if (!ts_check(&us, 0, 100* 1000L)) { + printf("timespec_init_us failed.\n"); + goto fail; + } + + if (!ts_check(&ns, 0, 100)) { + printf("timespec_init_ns failed.\n"); + goto fail; + } + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_time_tv_init(void) +{ + struct timeval s = TIMEVAL_INIT_S (100); + struct timeval ms = TIMEVAL_INIT_MS(100); + struct timeval us = TIMEVAL_INIT_US(100); + + TEST_START(); + + if (!tv_check(&s, 100, 0)) { + printf("timeval_init_s failed.\n"); + goto fail; + } + + if (!tv_check(&ms, 0, 100 * 1000L)) { + printf("timeval_init_ms failed.\n"); + goto fail; + } + + if (!tv_check(&us, 0, 100)) { + printf("timeval_init_us failed.\n"); + goto fail; + } + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_ts_diff(void) +{ + struct timespec s0 = TIMESPEC_INIT_S (100); + struct timespec s1 = TIMESPEC_INIT_S (200); + struct timespec ms0 = TIMESPEC_INIT_MS(100); + struct timespec ms1 = TIMESPEC_INIT_MS(200); + struct timespec us0 = TIMESPEC_INIT_US(100); + struct timespec us1 = TIMESPEC_INIT_US(200); + struct timespec ns0 = TIMESPEC_INIT_NS(100); + struct timespec ns1 = TIMESPEC_INIT_NS(200); + struct timespec res; + + TEST_START(); + + ts_diff(&s0, &s1, &res); + if (!ts_check(&res, -100, 0)) { + printf("timespec_diff failed at s0 - s1.\n"); + goto fail; + } + + ts_diff(&s1, &s0, &res); + if (!ts_check(&res, 100, 0)) { + printf("timespec_diff failed at s1 - s0.\n"); + goto fail; + } + + ts_diff(&ms0, &ms1, &res); + if (!ts_check(&res, -1, 900 * MILLION)) { + printf("timespec_diff failed at ms0 - ms1.\n"); + goto fail; + } + + ts_diff(&ms1, &ms0, &res); + if (!ts_check(&res, 0, 100 * MILLION)) { + printf("timespec_diff failed at ms1 - ms0.\n"); + goto fail; + } + + ts_diff(&us0, &us1, &res); + if (!ts_check(&res, -1, 999900 * 1000L)) { + printf("timespec_diff failed at us0 - us1.\n"); + goto fail; + } + + ts_diff(&us1, &us0, &res); + if (!ts_check(&res, 0, 100 * 1000L)) { + printf("timespec_diff failed at us1 - us0.\n"); + goto fail; + } + + ts_diff(&ns0, &ns1, &res); + if (!ts_check(&res, -1, 999999900)) { + printf("timespec_diff failed at ns0 - ns1.\n"); + goto fail; + } + + ts_diff(&ns1, &ns0, &res); + if (!ts_check(&res, 0, 100)) { + printf("timespec_diff failed at ns1 - ns0.\n"); + goto fail; + } + + ts_diff(&s0, &ms0, &res); + if (!ts_check(&res, 99, 900 * MILLION)) { + printf("timespec_diff failed at s0 - ms0.\n"); + goto fail; + } + + ts_diff(&s0, &us0, &res); + if (!ts_check(&res, 99, 999900 * 1000L)) { + printf("timespec_diff failed at s0 - us0.\n"); + goto fail; + } + + ts_diff(&s0, &ns0, &res); + if (!ts_check(&res, 99, 999999900)) { + printf("timespec_diff failed at s0 - ns0.\n"); + goto fail; + } + + ts_diff(&ms0, &us0, &res); + if (!ts_check(&res, 0, 99900 * 1000L)) { + printf("timespec_diff failed at ms0 - us0.\n"); + goto fail; + } + + ts_diff(&ms0, &ns0, &res); + if (!ts_check(&res, 0, 99999900)) { + printf("timespec_diff failed at ms0 - ns0.\n"); + goto fail; + } + + ts_diff(&us0, &ns0, &res); + if (!ts_check(&res, 0, 99900)) { + printf("timespec_diff failed at us0 - ns0.\n"); + goto fail; + } + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_tv_diff(void) +{ + struct timeval s0 = TIMEVAL_INIT_S (100); + struct timeval s1 = TIMEVAL_INIT_S (200); + struct timeval ms0 = TIMEVAL_INIT_MS(100); + struct timeval ms1 = TIMEVAL_INIT_MS(200); + struct timeval us0 = TIMEVAL_INIT_US(100); + struct timeval us1 = TIMEVAL_INIT_US(200); + struct timeval res; + + TEST_START(); + + tv_diff(&s0, &s1, &res); + if (!tv_check(&res, -100, 0)) { + printf("timeval_diff failed at s0 - s1.\n"); + goto fail; + } + + tv_diff(&s1, &s0, &res); + if (!tv_check(&res, 100, 0)) { + printf("timeval_diff failed at s1 - s0.\n"); + goto fail; + } + + tv_diff(&ms0, &ms1, &res); + if (!tv_check(&res, -1, 900 * 1000L)) { + printf("timeval_diff failed at ms0 - ms1.\n"); + goto fail; + } + + tv_diff(&ms1, &ms0, &res); + if (!tv_check(&res, 0, 100 * 1000L)) { + printf("timeval_diff failed at ms1 - ms0.\n"); + goto fail; + } + + tv_diff(&us0, &us1, &res); + if (!tv_check(&res, -1, 999900)) { + printf("timeval_diff failed at us0 - us1.\n"); + goto fail; + } + + tv_diff(&us1, &us0, &res); + if (!tv_check(&res, 0, 100)) { + printf("timeval_diff failed at us1 - us0.\n"); + goto fail; + } + + tv_diff(&s0, &ms0, &res); + if (!tv_check(&res, 99, 900 * 1000L)) { + printf("timeval_diff failed at s0 - ms0.\n"); + goto fail; + } + + tv_diff(&s0, &us0, &res); + if (!tv_check(&res, 99, 999900)) { + printf("timeval_diff failed at s0 - us0.\n"); + goto fail; + } + + tv_diff(&ms0, &us0, &res); + if (!tv_check(&res, 0, 99900)) { + printf("timeval_diff failed at ms0 - us0.\n"); + goto fail; + } + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_ts_diff_time(void) +{ + struct timespec s0 = TIMESPEC_INIT_S (100); + struct timespec s1 = TIMESPEC_INIT_S (200); + struct timespec ms0 = TIMESPEC_INIT_MS(100); + struct timespec ms1 = TIMESPEC_INIT_MS(200); + struct timespec us0 = TIMESPEC_INIT_US(100); + struct timespec us1 = TIMESPEC_INIT_US(200); + struct timespec ns0 = TIMESPEC_INIT_NS(100); + struct timespec ns1 = TIMESPEC_INIT_NS(200); + + TEST_START(); + + if (ts_diff_ms(&s0, &s1) != -100 * 1000L) { + printf("timespec_diff_ms failed at s0 - s1.\n"); + goto fail; + } + + if (ts_diff_ms(&s1, &s0) != 100 * 1000L) { + printf("timespec_diff_ms failed at s1 - s0.\n"); + goto fail; + } + + if (ts_diff_us(&s0, &s1) != -100 * MILLION) { + printf("timespec_diff_us failed at s1 - s0.\n"); + goto fail; + } + + if (ts_diff_us(&s1, &s0) != 100 * MILLION) { + printf("timespec_diff_us failed at s0 - s1.\n"); + goto fail; + } + + if (ts_diff_ns(&s0, &s1) != -100 * BILLION) { + printf("timespec_diff_ns failed at s0 - s1.\n"); + goto fail; + } + + if (ts_diff_ns(&s1, &s0) != 100 * BILLION) { + printf("timespec_diff_ns failed at s1 - s0.\n"); + goto fail; + } + + if (ts_diff_ms(&ms0, &ms1) != -100) { + printf("timespec_diff_ms failed at ms0 - ms1.\n"); + goto fail; + } + + if (ts_diff_ms(&ms1, &ms0) != 100) { + printf("timespec_diff_ms failed at ms1 - ms0.\n"); + goto fail; + } + + if (ts_diff_us(&ms0, &ms1) != -100 * 1000L) { + printf("timespec_diff_us failed at ms0 - ms1.\n"); + goto fail; + } + + if (ts_diff_us(&ms1, &ms0) != 100 * 1000L) { + printf("timespec_diff_us failed at ms1 - ms0.\n"); + goto fail; + } + + if (ts_diff_ns(&ms0, &ms1) != -100 * MILLION) { + printf("timespec_diff_ns failed at ms0 - ms1.\n"); + goto fail; + } + + if (ts_diff_ns(&ms1, &ms0) != 100 * MILLION) { + printf("timespec_diff_ns failed at ms1 - ms0.\n"); + goto fail; + } + + if (ts_diff_ms(&us0, &us1) != 0) { + printf("timespec_diff_ms failed at us0 - us1.\n"); + goto fail; + } + + if (ts_diff_ms(&us1, &us0) != 0) { + printf("timespec_diff_ms failed at us1 - us0.\n"); + goto fail; + } + + if (ts_diff_us(&us0, &us1) != -100) { + printf("timespec_diff_us failed at us0 - us1.\n"); + goto fail; + } + + if (ts_diff_us(&us1, &us0) != 100) { + printf("timespec_diff_us failed at us1 - us0.\n"); + goto fail; + } + + if (ts_diff_ns(&us0, &us1) != -100 * 1000L) { + printf("timespec_diff_ns failed at us0 - us1.\n"); + goto fail; + } + + if (ts_diff_ns(&us1, &us0) != 100 * 1000L) { + printf("timespec_diff_ns failed at us1 - us0.\n"); + goto fail; + } + + if (ts_diff_ms(&ns0, &ns1) != 0) { + printf("timespec_diff_ms failed at ns0 - ns1.\n"); + goto fail; + } + + if (ts_diff_ms(&ns1, &ns0) != 0) { + printf("timespec_diff_ms failed at ns1 - ns0.\n"); + goto fail; + } + + if (ts_diff_us(&ns0, &ns1) != 0) { + printf("timespec_diff_us failed at ns0 - ns1.\n"); + goto fail; + } + + if (ts_diff_us(&ns1, &ns0) != 0) { + printf("timespec_diff_us failed at ns1 - ns0.\n"); + goto fail; + } + + if (ts_diff_ns(&ns0, &ns1) != -100) { + printf("timespec_diff_ns failed at ns0 - ns1.\n"); + goto fail; + } + + if (ts_diff_ns(&ns1, &ns0) != 100) { + printf("timespec_diff_ns failed at ns1 - ns0.\n"); + goto fail; + } + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_tv_diff_time(void) +{ + struct timeval s0 = TIMEVAL_INIT_S (100); + struct timeval s1 = TIMEVAL_INIT_S (200); + struct timeval ms0 = TIMEVAL_INIT_MS(100); + struct timeval ms1 = TIMEVAL_INIT_MS(200); + struct timeval us0 = TIMEVAL_INIT_US(100); + struct timeval us1 = TIMEVAL_INIT_US(200); + + TEST_START(); + + if (tv_diff_ms(&s0, &s1) != -100 * 1000L) { + printf("timeval_diff_ms failed at s0 - s1.\n"); + goto fail; + } + + if (tv_diff_ms(&s1, &s0) != 100 * 1000L) { + printf("timeval_diff_ms failed at s1 - s0.\n"); + goto fail; + } + + if (tv_diff_us(&s0, &s1) != -100 * MILLION) { + printf("timeval_diff_us failed at s0 - s1.\n"); + goto fail; + } + + if (tv_diff_us(&s1, &s0) != 100 * MILLION) { + printf("timeval_diff_us failed at s1 - s0.\n"); + goto fail; + } + + if (tv_diff_ms(&ms0, &ms1) != -100) { + printf("timeval_diff_ms failed at ms0 - ms1.\n"); + goto fail; + } + + if (tv_diff_ms(&ms1, &ms0) != 100) { + printf("timeval_diff_ms failed at ms1 - ms0.\n"); + goto fail; + } + + if (tv_diff_us(&ms0, &ms1) != -100 * 1000L) { + printf("timeval_diff_us failed at ms0 - ms1.\n"); + goto fail; + } + + if (tv_diff_us(&ms1, &ms0) != 100 * 1000L) { + printf("timeval_diff_us failed at ms1 - ms0.\n"); + goto fail; + } + + if (tv_diff_ms(&us0, &us1) != 0) { + printf("timeval_diff_ms failed at us0 - us1.\n"); + goto fail; + } + + if (tv_diff_ms(&us1, &us0) != 0) { + printf("timeval_diff_ms failed at us1 - us0.\n"); + goto fail; + } + + if (tv_diff_us(&us0, &us1) != -100) { + printf("timeval_diff_us failed at us0 - us1.\n"); + goto fail; + } + + if (tv_diff_us(&us1, &us0) != 100) { + printf("timeval_diff_us failed at us1 - us0.\n"); + goto fail; + } + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +int time_test(int argc, + char ** argv) +{ + int ret = 0; + + (void) argc; + (void) argv; + + ret |= test_time_ts_init(); + ret |= test_time_tv_init(); + ret |= test_ts_diff(); + ret |= test_tv_diff(); + ret |= test_ts_diff_time(); + ret |= test_tv_diff_time(); + + return ret; +} diff --git a/src/lib/tests/time_utils_test.c b/src/lib/tests/time_utils_test.c deleted file mode 100644 index fa65c4dc..00000000 --- a/src/lib/tests/time_utils_test.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2021 - * - * Test of the time utilities - * - * Dimitri Staessens <dimitri@ouroboros.rocks> - * Sander Vrijders <sander@ouroboros.rocks> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#define _POSIX_C_SOURCE 200809L - -#include <ouroboros/time_utils.h> - -#include <stdio.h> - -static void ts_print(struct timespec * s) -{ - printf("timespec is %zd:%ld.\n", (ssize_t) s->tv_sec, s->tv_nsec); -} - -static void tv_print(struct timeval * v) -{ - printf("timeval is %zd:%zu.\n", (ssize_t) v->tv_sec, (size_t) v->tv_usec); -} - -static void ts_init(struct timespec * s, - time_t sec, - time_t nsec) -{ - s->tv_sec = sec; - s->tv_nsec = nsec; -} - -static void tv_init(struct timeval * v, - time_t sec, - time_t usec) -{ - v->tv_sec = sec; - v->tv_usec = usec; -} - -static int ts_check(struct timespec * s, - time_t sec, - time_t nsec) -{ - return s->tv_sec == sec && s->tv_nsec == nsec; -} - -static int tv_check(struct timeval * v, - time_t sec, - time_t usec) -{ - return v->tv_sec == sec && v->tv_usec == usec; -} - -int time_utils_test(int argc, - char ** argv) -{ - struct timespec s0; - struct timespec s1; - struct timespec s2; - - struct timeval v0; - struct timeval v1; - struct timeval v2; - - (void) argc; - (void) argv; - - ts_init(&s0, 0, 0); - ts_init(&s1, 5, 0); - - ts_add(&s0, &s1, &s2); - if (!ts_check(&s2, 5, 0)) { - printf("ts_add failed.\n"); - ts_print(&s2); - return -1; - } - - tv_init(&v0, 0, 0); - tv_init(&v1, 5, 0); - - tv_add(&v0, &v1, &v2); - if (!tv_check(&v2, 5, 0)) { - printf("tv_add failed.\n"); - tv_print(&v2); - return -1; - } - - ts_init(&s0, 0, 500 * MILLION); - ts_init(&s1, 0, 600 * MILLION); - - ts_add(&s0, &s1, &s2); - if (!ts_check(&s2, 1, 100 * MILLION)) { - printf("ts_add with nano overflow failed.\n"); - ts_print(&s2); - return -1; - } - - tv_init(&v0, 0, 500 * 1000); - tv_init(&v1, 0, 600 * 1000); - - tv_add(&v0, &v1, &v2); - if (!tv_check(&v2, 1, 100 * 1000)) { - printf("tv_add with nano overflow failed.\n"); - tv_print(&v2); - return -1; - } - - ts_init(&s0, 0, 0); - ts_init(&s1, 5, 0); - - ts_diff(&s0, &s1, &s2); - if (!ts_check(&s2, -5, 0)) { - printf("ts_diff failed.\n"); - ts_print(&s2); - return -1; - } - - tv_init(&v0, 0, 0); - tv_init(&v1, 5, 0); - - tv_diff(&v0, &v1, &v2); - if (!tv_check(&v2, -5, 0)) { - printf("tv_diff failed.\n"); - tv_print(&v2); - return -1; - } - - ts_init(&s0, 0, 500 * MILLION); - ts_init(&s1, 0, 600 * MILLION); - - ts_diff(&s0, &s1, &s2); - if (!ts_check(&s2, -1, 900 * MILLION)) { - printf("ts_diff with nano underflow failed.\n"); - ts_print(&s2); - return -1; - } - - tv_init(&v0, 0, 500 * 1000); - tv_init(&v1, 0, 600 * 1000); - - tv_diff(&v0, &v1, &v2); - if (!tv_check(&v2, -1, 900 * 1000)) { - printf("tv_diff with nano underflow failed.\n"); - tv_print(&v2); - return -1; - } - - return 0; -} diff --git a/src/lib/tests/tpm_test.c b/src/lib/tests/tpm_test.c new file mode 100644 index 00000000..41bce964 --- /dev/null +++ b/src/lib/tests/tpm_test.c @@ -0,0 +1,104 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Tests for the threadpool manager + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + + +#include "tpm.c" + +#include <test/test.h> + +static void * test_func(void * o) +{ + (void) o; + + while(1) + sleep(1); + + return NULL; +} + +static int test_tpm_create_destroy(void) +{ + struct tpm *tpm; + + TEST_START(); + + tpm = tpm_create(2, 2, &test_func, NULL); + if (tpm == NULL) { + printf("Failed to initialize TPM.\n"); + goto fail; + } + + tpm_destroy(tpm); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_tpm_start_stop(void * (* fn)(void *), + void * o) +{ + struct tpm *tpm; + + TEST_START(); + + tpm = tpm_create(2, 2, fn, o); + if (tpm == NULL) { + printf("Failed to initialize TPM.\n"); + goto fail_create; + } + + if (tpm_start(tpm) < 0) { + printf("Failed to start TPM.\n"); + goto fail_start; + } + + tpm_stop(tpm); + + tpm_destroy(tpm); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_start: + tpm_destroy(tpm); + fail_create: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +int tpm_test(int argc, + char ** argv) +{ + int ret = 0; + + (void) argc; + (void) argv; + + ret |= test_tpm_create_destroy(); + ret |= test_tpm_start_stop(&test_func, NULL); + + return ret; +} |
