summaryrefslogtreecommitdiff
path: root/src/irmd/oap/tests/oap_test_pqc.c
diff options
context:
space:
mode:
authorDimitri Staessens <dimitri@ouroboros.rocks>2026-02-17 22:37:39 +0100
committerSander Vrijders <sander@ouroboros.rocks>2026-02-18 07:53:35 +0100
commit040bdfb18684d809cb5edacf9867d3378b7e093b (patch)
treed0b337c83ea4af5312834541acce584719a52ca0 /src/irmd/oap/tests/oap_test_pqc.c
parent2c717b2fc9773a74d6c9df01a2f873deea163918 (diff)
downloadouroboros-040bdfb18684d809cb5edacf9867d3378b7e093b.tar.gz
ouroboros-040bdfb18684d809cb5edacf9867d3378b7e093b.zip
lib: Add SLH-DSA tests and per-algorithm PQC gating
This replaces the single HAVE_OPENSSL_PQC/DISABLE_PQC with per-algorithm CMake variables (ML-KEM, ML-DSA, SLH-DSA), gated by the OpenSSL versions: ML-KEM and ML-DSA require >= 3.4, SLH-DSA >= 3.5. SLH-DSA was already working, but now added explicit authentication tests for it with a full certificate chain (root CA, intermediate CA, server) to show full support. Rename PQC test files and cert headers to use algorithm-specific names (ml_kem, ml_dsa, slh_dsa) and move cert headers to include/test/certs/. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
Diffstat (limited to 'src/irmd/oap/tests/oap_test_pqc.c')
-rw-r--r--src/irmd/oap/tests/oap_test_pqc.c447
1 files changed, 0 insertions, 447 deletions
diff --git a/src/irmd/oap/tests/oap_test_pqc.c b/src/irmd/oap/tests/oap_test_pqc.c
deleted file mode 100644
index bbaf9f7b..00000000
--- a/src/irmd/oap/tests/oap_test_pqc.c
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2026
- *
- * Unit tests of OAP post-quantum key exchange
- *
- * 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 200809L
-#endif
-
-#include "config.h"
-
-#include <ouroboros/crypt.h>
-#include <ouroboros/flow.h>
-#include <ouroboros/name.h>
-#include <ouroboros/random.h>
-#include <test/test.h>
-
-#include <test/certs_pqc.h>
-
-#include "oap.h"
-#include "common.h"
-
-#include <stdbool.h>
-#include <string.h>
-
-#ifdef HAVE_OPENSSL
-#include <openssl/evp.h>
-#endif
-
-#define CLI_AUTH 1
-#define NO_CLI_AUTH 0
-#define CLI_ENCAP KEM_MODE_CLIENT_ENCAP
-#define SRV_ENCAP KEM_MODE_SERVER_ENCAP
-
-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];
-}
-
-struct test_cfg test_cfg;
-
-/* KEM keypair storage for tests (server-side keypair for KEM modes) */
-static void * test_kem_pkp = NULL; /* Private key pair */
-static uint8_t test_kem_pk[4096]; /* Public key buffer */
-static size_t test_kem_pk_len = 0;
-
-/* Mock load - called by load_*_credentials in common.c */
-int mock_load_credentials(void ** pkp,
- void ** crt)
-{
- *pkp = NULL;
- *crt = NULL;
-
- if (crypt_load_privkey_str(server_pkp_ml, pkp) < 0)
- return -1;
-
- if (crypt_load_crt_str(signed_server_crt_ml, crt) < 0) {
- crypt_free_key(*pkp);
- *pkp = NULL;
- return -1;
- }
-
- return 0;
-}
-
-int load_server_kem_keypair(const char * name,
- bool raw_fmt,
- void ** pkp)
-{
-#ifdef HAVE_OPENSSL
- struct sec_config local_cfg;
- ssize_t pk_len;
-
- (void) name;
- (void) raw_fmt;
-
- /*
- * Uses reference counting. The caller will call
- * EVP_PKEY_free which decrements the count.
- */
- if (test_kem_pkp != NULL) {
- if (EVP_PKEY_up_ref((EVP_PKEY *)test_kem_pkp) != 1)
- return -1;
-
- *pkp = test_kem_pkp;
- return 0;
- }
-
- /*
- * Generate a new KEM keypair from test_cfg.srv.kex.
- */
- memset(&local_cfg, 0, sizeof(local_cfg));
- if (test_cfg.srv.kex == NID_undef)
- goto fail;
-
- SET_KEX_ALGO_NID(&local_cfg, test_cfg.srv.kex);
-
- pk_len = kex_pkp_create(&local_cfg, &test_kem_pkp, test_kem_pk);
- if (pk_len < 0)
- goto fail;
-
- test_kem_pk_len = (size_t) pk_len;
-
- if (EVP_PKEY_up_ref((EVP_PKEY *)test_kem_pkp) != 1)
- goto fail_ref;
-
- *pkp = test_kem_pkp;
-
- return 0;
- fail_ref:
- kex_pkp_destroy(test_kem_pkp);
- test_kem_pkp = NULL;
- test_kem_pk_len = 0;
- fail:
- return -1;
-
-#else
- (void) name;
- (void) raw_fmt;
- (void) pkp;
- return -1;
-#endif
-}
-
-int load_server_kem_pk(const char * name,
- struct sec_config * cfg,
- buffer_t * pk)
-{
- ssize_t len;
-
- (void) name;
-
- if (test_kem_pk_len > 0) {
- pk->data = malloc(test_kem_pk_len);
- if (pk->data == NULL)
- return -1;
- memcpy(pk->data, test_kem_pk, test_kem_pk_len);
- pk->len = test_kem_pk_len;
- return 0;
- }
-
- /* Generate keypair on demand if not already done */
- len = kex_pkp_create(cfg, &test_kem_pkp, test_kem_pk);
- if (len < 0)
- return -1;
-
- test_kem_pk_len = (size_t) len;
- pk->data = malloc(test_kem_pk_len);
- if (pk->data == NULL)
- return -1;
- memcpy(pk->data, test_kem_pk, test_kem_pk_len);
- pk->len = test_kem_pk_len;
-
- return 0;
-}
-
-static void reset_kem_state(void)
-{
- if (test_kem_pkp != NULL) {
- kex_pkp_destroy(test_kem_pkp);
- test_kem_pkp = NULL;
- }
- test_kem_pk_len = 0;
-}
-
-static void test_cfg_init(int kex,
- int cipher,
- int kdf,
- int kem_mode,
- bool cli_auth)
-{
- memset(&test_cfg, 0, sizeof(test_cfg));
-
- /* Server config */
- test_cfg.srv.kex = kex;
- test_cfg.srv.cipher = cipher;
- test_cfg.srv.kdf = kdf;
- test_cfg.srv.kem_mode = kem_mode;
- test_cfg.srv.auth = true;
-
- /* Client config */
- test_cfg.cli.kex = kex;
- test_cfg.cli.cipher = cipher;
- test_cfg.cli.kdf = kdf;
- test_cfg.cli.kem_mode = kem_mode;
- test_cfg.cli.auth = cli_auth;
-}
-
-static int oap_test_setup_kem(struct oap_test_ctx * ctx,
- const char * root_ca,
- const char * im_ca)
-{
- reset_kem_state();
- return oap_test_setup(ctx, root_ca, im_ca);
-}
-
-static void oap_test_teardown_kem(struct oap_test_ctx * ctx)
-{
- oap_test_teardown(ctx);
-}
-
-static int test_oap_roundtrip_auth_only(void)
-{
- test_cfg_init(NID_undef, NID_undef, NID_undef, 0, false);
-
- return roundtrip_auth_only(root_ca_crt_ml, im_ca_crt_ml);
-}
-
-static int test_oap_corrupted_request(void)
-{
- test_cfg_init(NID_MLKEM768, NID_aes_256_gcm, get_random_kdf(),
- SRV_ENCAP, CLI_AUTH);
-
- return corrupted_request(root_ca_crt_ml, im_ca_crt_ml);
-}
-
-static int test_oap_corrupted_response(void)
-{
- test_cfg_init(NID_MLKEM768, NID_aes_256_gcm, get_random_kdf(),
- SRV_ENCAP, NO_CLI_AUTH);
-
- return corrupted_response(root_ca_crt_ml, im_ca_crt_ml);
-}
-
-static int test_oap_truncated_request(void)
-{
- test_cfg_init(NID_MLKEM768, NID_aes_256_gcm, get_random_kdf(),
- SRV_ENCAP, NO_CLI_AUTH);
-
- return truncated_request(root_ca_crt_ml, im_ca_crt_ml);
-}
-
-static int test_oap_roundtrip_kem(int kex,
- int kem_mode)
-{
- struct oap_test_ctx ctx;
- const char * kex_str = kex_nid_to_str(kex);
- const char * mode_str = kem_mode == CLI_ENCAP ? "cli" : "srv";
-
- test_cfg_init(kex, NID_aes_256_gcm, get_random_kdf(),
- kem_mode, NO_CLI_AUTH);
-
- TEST_START("(%s, %s encaps)", kex_str, mode_str);
-
- if (oap_test_setup_kem(&ctx, root_ca_crt_ml, im_ca_crt_ml) < 0)
- goto fail;
-
- if (oap_cli_prepare_ctx(&ctx) < 0) {
- printf("Client prepare failed.\n");
- goto fail_cleanup;
- }
-
- if (oap_srv_process_ctx(&ctx) < 0) {
- printf("Server process failed.\n");
- goto fail_cleanup;
- }
-
- if (oap_cli_complete_ctx(&ctx) < 0) {
- printf("Client complete failed.\n");
- goto fail_cleanup;
- }
-
- if (memcmp(ctx.cli.key, ctx.srv.key, SYMMKEYSZ) != 0) {
- printf("Client and server keys do not match!\n");
- goto fail_cleanup;
- }
-
- if (ctx.cli.nid == NID_undef ||
- ctx.srv.nid == NID_undef) {
- printf("Cipher not set in flow.\n");
- goto fail_cleanup;
- }
-
- oap_test_teardown_kem(&ctx);
-
- TEST_SUCCESS("(%s, %s encaps)", kex_str, mode_str);
- return TEST_RC_SUCCESS;
-
- fail_cleanup:
- oap_test_teardown_kem(&ctx);
- fail:
- TEST_FAIL("(%s, %s encaps)", kex_str, mode_str);
- return TEST_RC_FAIL;
-}
-
-static int test_oap_roundtrip_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_oap_roundtrip_kem(kex_supported_nids[i], SRV_ENCAP);
- ret |= test_oap_roundtrip_kem(kex_supported_nids[i], CLI_ENCAP);
- }
-
- return ret;
-}
-
-static int test_oap_kem_srv_uncfg(int kex)
-{
- struct oap_test_ctx ctx;
- const char * kex_str = kex_nid_to_str(kex);
-
- memset(&test_cfg, 0, sizeof(test_cfg));
-
- /* Server: auth only, no KEX configured */
- test_cfg.srv.auth = true;
-
- /* Client: requests KEM with server-side encapsulation */
- test_cfg.cli.kex = kex;
- test_cfg.cli.cipher = NID_aes_256_gcm;
- test_cfg.cli.kdf = get_random_kdf();
- test_cfg.cli.kem_mode = SRV_ENCAP;
- test_cfg.cli.auth = false;
-
- TEST_START("(%s)", kex_str);
-
- if (oap_test_setup_kem(&ctx, root_ca_crt_ml,
- im_ca_crt_ml) < 0)
- goto fail;
-
- if (oap_cli_prepare_ctx(&ctx) < 0) {
- printf("Client prepare failed.\n");
- goto fail_cleanup;
- }
-
- if (oap_srv_process_ctx(&ctx) < 0) {
- printf("Server process failed.\n");
- goto fail_cleanup;
- }
-
- if (oap_cli_complete_ctx(&ctx) < 0) {
- printf("Client complete failed.\n");
- goto fail_cleanup;
- }
-
- if (memcmp(ctx.cli.key, ctx.srv.key, SYMMKEYSZ) != 0) {
- printf("Client and server keys do not match!\n");
- goto fail_cleanup;
- }
-
- if (ctx.cli.nid == NID_undef ||
- ctx.srv.nid == NID_undef) {
- printf("Cipher not set in flow.\n");
- goto fail_cleanup;
- }
-
- oap_test_teardown_kem(&ctx);
-
- TEST_SUCCESS("(%s)", kex_str);
- return TEST_RC_SUCCESS;
-
- fail_cleanup:
- oap_test_teardown_kem(&ctx);
- fail:
- TEST_FAIL("(%s)", kex_str);
- return TEST_RC_FAIL;
-}
-
-static int test_oap_kem_srv_uncfg_all(void)
-{
- int ret = 0;
- int i;
-
- for (i = 0; kex_supported_nids[i] != NID_undef; i++) {
- const char * algo;
-
- algo = kex_nid_to_str(kex_supported_nids[i]);
-
- if (!IS_KEM_ALGORITHM(algo))
- continue;
-
- ret |= test_oap_kem_srv_uncfg(kex_supported_nids[i]);
- }
-
- return ret;
-}
-
-int oap_test_pqc(int argc,
- char **argv)
-{
- int ret = 0;
-
- (void) argc;
- (void) argv;
-
-#ifdef HAVE_OPENSSL_PQC
- ret |= test_oap_roundtrip_auth_only();
-
- ret |= test_oap_roundtrip_kem_all();
-
- ret |= test_oap_kem_srv_uncfg_all();
-
- ret |= test_oap_corrupted_request();
- ret |= test_oap_corrupted_response();
- ret |= test_oap_truncated_request();
-#else
- (void) test_oap_roundtrip_auth_only;
- (void) test_oap_roundtrip_kem;
- (void) test_oap_roundtrip_kem_all;
- (void) test_oap_kem_srv_uncfg;
- (void) test_oap_kem_srv_uncfg_all;
- (void) test_oap_corrupted_request;
- (void) test_oap_corrupted_response;
- (void) test_oap_truncated_request;
-
- ret = TEST_RC_SKIP;
-#endif
-
- return ret;
-}