diff options
author | Dimitri Staessens <dmarc-noreply@freelists.org> | 2025-07-13 07:42:58 +0200 |
---|---|---|
committer | Sander Vrijders <sander@ouroboros.rocks> | 2025-07-16 08:34:17 +0200 |
commit | 2e505c2dc7a7e849fe7a327f9cbdfc587477a3d1 (patch) | |
tree | c303098450a9a361d3d16738a78cbfdc452326f6 /src/irmd/tests | |
parent | 589e273a446cdcec7e9c5e3a85256b7b8554e4f0 (diff) | |
download | ouroboros-2e505c2dc7a7e849fe7a327f9cbdfc587477a3d1.tar.gz ouroboros-2e505c2dc7a7e849fe7a327f9cbdfc587477a3d1.zip |
irmd: Initial Flow Allocation Protocol Header
This adds the initial version for the flow allocation protocol header
between IRMd instances. This is a step towards flow authentication.
The header supports secure and authenticated flow allocation,
supporting certificate-based authentication and ephemeral key
exchange for end-to-end encryption.
id: 128-bit identifier for the entity.
timestamp: 64-bit timestamp (replay protection).
certificate: Certificate for authentication.
public key: ECDHE public key for key exchange.
data: Application data.
signature: Signature for integrity/authenticity.
Authentication and encryption require OpenSSL to be installed.
The IRMd compares the allocation request delay with the MPL of the
Layer over which the flow allocation was sent. MPL is now reported by
the Layer in ms instead of seconds.
Time functions revised for consistency and adds some tests.
The TPM can now print thread running times in Debug builds
(TPM_DEBUG_REPORT_INTERVAL) and abort processes with hung threads
(TPM_DEBUG_ABORT_TIMEOUT). Long running threads waiting for input
should call tpm_wait_work() to avoid trigger a process abort.
Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks>
Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
Diffstat (limited to 'src/irmd/tests')
-rw-r--r-- | src/irmd/tests/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/irmd/tests/irm_test.c | 33 | ||||
-rw-r--r-- | src/irmd/tests/oap_test.c | 273 |
3 files changed, 310 insertions, 0 deletions
diff --git a/src/irmd/tests/CMakeLists.txt b/src/irmd/tests/CMakeLists.txt index 99743052..e860acce 100644 --- a/src/irmd/tests/CMakeLists.txt +++ b/src/irmd/tests/CMakeLists.txt @@ -3,6 +3,8 @@ get_filename_component(src_folder "${tmp}" NAME) create_test_sourcelist(${src_folder}_tests test_suite.c # Add new tests here + irm_test.c + oap_test.c ) add_executable(${src_folder}_test EXCLUDE_FROM_ALL ${${src_folder}_tests}) @@ -21,3 +23,5 @@ foreach(test ${tests_to_run}) get_filename_component(test_name ${test} NAME_WE) add_test(irmd/${test_name} ${C_TEST_PATH}/${src_folder}_test ${test_name}) endforeach(test) + +set_property(TEST irmd/oap_test PROPERTY SKIP_RETURN_CODE 1) diff --git a/src/irmd/tests/irm_test.c b/src/irmd/tests/irm_test.c new file mode 100644 index 00000000..d440289c --- /dev/null +++ b/src/irmd/tests/irm_test.c @@ -0,0 +1,33 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Unit tests of IRMd 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/. + */ + + + +int irm_test(int argc, + char **argv) +{ + int ret = 0; + + (void) argc; + (void) argv; + + return ret; +} diff --git a/src/irmd/tests/oap_test.c b/src/irmd/tests/oap_test.c new file mode 100644 index 00000000..e9f67505 --- /dev/null +++ b/src/irmd/tests/oap_test.c @@ -0,0 +1,273 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Unit tests of Ouroboros flow allocation protocol + * 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 "oap.c" + +#include <ouroboros/random.h> +#include <ouroboros/test.h> + +static const char * pkp_str = \ +"-----BEGIN EC PRIVATE KEY-----\n" +"MHcCAQEEIC13y+5jdKe80HBJD7WITpQamcn3rrkTX1r0v+JwSk4NoAoGCCqGSM49\n" +"AwEHoUQDQgAEcC0yLAfUtufH8cdLybrdWPc6U+xRuhDhqqrEcBO5+eob2xyqEaNk\n" +"nIV/86724zPptGRahWz0rzW2PvNppJdNBg==\n" +"-----END EC PRIVATE KEY-----\n"; + +/* Valid signed server certificate for server-2.unittest.o7s */ +static const char * crt_str = \ +"-----BEGIN CERTIFICATE-----\n" +"MIIDgjCCAyigAwIBAgICEAIwCgYIKoZIzj0EAwIwWzELMAkGA1UEBhMCQkUxDDAK\n" +"BgNVBAgMA09WTDEMMAoGA1UECgwDbzdzMRUwEwYDVQQLDAx1bml0dGVzdC5vN3Mx\n" +"GTAXBgNVBAMMEGltMi51bml0dGVzdC5vN3MwHhcNMjUwNzA0MTMxODI5WhcNMzUw\n" +"NzAyMTMxODI5WjBwMQswCQYDVQQGEwJCRTEMMAoGA1UECAwDT1ZMMQ4wDAYDVQQH\n" +"DAVHaGVudDEMMAoGA1UECgwDbzdzMRUwEwYDVQQLDAx1bml0dGVzdC5vN3MxHjAc\n" +"BgNVBAMMFXNlcnZlci0yLnVuaXR0ZXN0Lm83czBZMBMGByqGSM49AgEGCCqGSM49\n" +"AwEHA0IABHAtMiwH1Lbnx/HHS8m63Vj3OlPsUboQ4aqqxHATufnqG9scqhGjZJyF\n" +"f/Ou9uMz6bRkWoVs9K81tj7zaaSXTQajggHFMIIBwTAJBgNVHRMEAjAAMBEGCWCG\n" +"SAGG+EIBAQQEAwIGQDA6BglghkgBhvhCAQ0ELRYrR3JpbGxlZCBDaGVlc2UgR2Vu\n" +"ZXJhdGVkIFNlcnZlciBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUTt3xHTwE9amoglxh\n" +"cEMqWv+PpDMwgb8GA1UdIwSBtzCBtIAUFfeZRx8QWWKQr7Aw8zjDu2shvcShgZek\n" +"gZQwgZExCzAJBgNVBAYTAkJFMQwwCgYDVQQIDANPVkwxDjAMBgNVBAcMBUdoZW50\n" +"MQwwCgYDVQQKDANvN3MxFTATBgNVBAsMDHVuaXR0ZXN0Lm83czEZMBcGA1UEAwwQ\n" +"Y2EyLnVuaXR0ZXN0Lm83czEkMCIGCSqGSIb3DQEJARYVZHVtbXlAb3Vyb2Jvcm9z\n" +"LnJvY2tzggIQAjAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEw\n" +"EQYDVR0fBAowCDAGoASgAoYAMCoGCCsGAQUFBwEBBB4wHDAMBggrBgEFBQcwAoYA\n" +"MAwGCCsGAQUFBzABhgAwIAYDVR0RBBkwF4IVc2VydmVyLTEudW5pdHRlc3Qubzdz\n" +"MAoGCCqGSM49BAMCA0gAMEUCIQDHuDb62w/Uah4nKwUFoJVkr4rgdNGh2Rn3SWaK\n" +"0FV/gAIgOLKorTwSgrTFdyOUkuPOhRs8BEMpah+dp8UTO8AnLvY=\n" +"-----END CERTIFICATE-----\n"; + +static int test_oap_hdr_init_fini(void) +{ + struct oap_hdr oap_hdr; + struct timespec now; + uint64_t stamp; + buffer_t ephkey = BUF_INIT; + buffer_t data = BUF_INIT; + uint8_t buf[OAP_ID_SIZE]; + buffer_t id; + void * pkp = NULL; + void * pubcrt = NULL; + + TEST_START(); + + random_buffer(buf, OAP_ID_SIZE); + id.data = buf; + id.len = OAP_ID_SIZE; + + clock_gettime(CLOCK_REALTIME, &now); + stamp = TS_TO_UINT64(now); + + if (oap_hdr_init(id, pkp, pubcrt, ephkey, data, &oap_hdr) < 0) { + printf("Failed to init OAP request header.\n"); + goto fail_req_hdr; + } + + if (oap_hdr.hdr.len != OAP_HDR_MIN_SIZE) { + printf("OAP request header wrong: %zu < %zu.\n", + oap_hdr.hdr.len, OAP_HDR_MIN_SIZE); + goto fail_req_hdr_chk; + } + + if (oap_hdr.id.len != OAP_ID_SIZE) { + printf("OAP request header ID wrong size: %zu != %zu.\n", + oap_hdr.id.len, (size_t) OAP_ID_SIZE); + goto fail_req_hdr_chk; + } + + if (memcmp(oap_hdr.id.data, id.data, OAP_ID_SIZE) != 0) { + printf("OAP request header ID mismatch.\n"); + goto fail_req_hdr_chk; + } + + if (oap_hdr.timestamp < stamp) { + printf("OAP request header timestamp is too old.\n"); + goto fail_req_hdr_chk; + } + + if (oap_hdr.timestamp > stamp + 1 * BILLION) { + printf("OAP request header timestamp is too new.\n"); + goto fail_req_hdr_chk; + } + + oap_hdr_fini(&oap_hdr); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + + fail_req_hdr_chk: + oap_hdr_fini(&oap_hdr); + fail_req_hdr: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_oap_hdr_init_fini_data(void) + +{ + struct oap_hdr oap_hdr; + buffer_t data; + buffer_t ephkey = BUF_INIT; + uint8_t buf[OAP_ID_SIZE]; + buffer_t id; + void * pkp = NULL; + void * pubcrt = NULL; + + TEST_START(); + + random_buffer(buf, OAP_ID_SIZE); + id.data = buf; + id.len = OAP_ID_SIZE; + + data.len = 100; + data.data = malloc(data.len); + if (data.data == NULL) { + printf("Failed to allocate data buffer.\n"); + goto fail_data; + } + + random_buffer(data.data, data.len); + + if (oap_hdr_init(id, pkp, pubcrt, ephkey, data, &oap_hdr) < 0) { + printf("Failed to create OAP request header.\n"); + goto fail_req_hdr; + } + + if (oap_hdr.hdr.len != OAP_HDR_MIN_SIZE + data.len) { + printf("OAP request header wrong: %zu < %zu.\n", + oap_hdr.hdr.len, OAP_HDR_MIN_SIZE + data.len); + goto fail_req_hdr_sz; + } + + oap_hdr_fini(&oap_hdr); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + + fail_req_hdr_sz: + oap_hdr_fini(&oap_hdr); + fail_req_hdr: + freebuf(data); + fail_data: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_oap_hdr_init_fini_signed(void) +{ + struct oap_hdr oap_hdr; + buffer_t ephkey = BUF_INIT; + buffer_t data = BUF_INIT; + buffer_t sign; + buffer_t id; + uint8_t buf[OAP_ID_SIZE]; + void * pkp; + void * pk; + void * pubcrt; + void * pubcrt2; + + TEST_START(); + + random_buffer(buf, OAP_ID_SIZE); + id.data = buf; + id.len = OAP_ID_SIZE; + + if (crypt_load_privkey_str(pkp_str, &pkp) < 0) { + printf("Failed to load private key.\n"); + goto fail_pkp; + } + + if (crypt_load_crt_str(crt_str, &pubcrt) < 0) { + printf("Failed to load public certificate.\n"); + goto fail_pubcrt; + } + + if (oap_hdr_init(id, pkp, pubcrt, ephkey, data, &oap_hdr) < 0) { + printf("Failed to create OAP request header.\n"); + goto fail_req_hdr; + } + + if (crypt_load_crt_der(oap_hdr.crt, &pubcrt2) < 0) { + printf("Failed to load public certificate from DER.\n"); + goto fail_crt_der; + } + + if (crypt_get_pubkey_crt(pubcrt2, &pk) < 0) { + printf("Failed to get public key from certificate.\n"); + goto fail_crt_pk; + } + + sign = oap_hdr.hdr; + sign.len -= (oap_hdr.sig.len + sizeof(uint16_t)); + + if (auth_verify_sig(pk, sign, oap_hdr.sig) < 0) { + printf("Failed to verify OAP request header signature.\n"); + goto fail_check_sig; + } + + oap_hdr_fini(&oap_hdr); + + crypt_free_crt(pubcrt2); + crypt_free_crt(pubcrt); + crypt_free_key(pk); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + + fail_check_sig: + crypt_free_key(pk); + fail_crt_pk: + crypt_free_crt(pubcrt2); + fail_crt_der: + oap_hdr_fini(&oap_hdr); + fail_req_hdr: + crypt_free_crt(pubcrt); + fail_pubcrt: + crypt_free_key(pkp); + fail_pkp: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +int oap_test(int argc, + char **argv) +{ + int ret = 0; + + (void) argc; + (void) argv; + + ret |= test_oap_hdr_init_fini(); + ret |= test_oap_hdr_init_fini_data(); +#ifdef HAVE_OPENSSL + ret |= test_oap_hdr_init_fini_signed(); +#else + (void) test_oap_hdr_init_fini_signed; + + ret = TEST_RC_SKIP; +#endif + return ret; +} |