diff options
Diffstat (limited to 'src/irmd/oap')
| -rw-r--r-- | src/irmd/oap/auth.c | 5 | ||||
| -rw-r--r-- | src/irmd/oap/cli.c | 2 | ||||
| -rw-r--r-- | src/irmd/oap/srv.c | 25 | ||||
| -rw-r--r-- | src/irmd/oap/tests/oap_test.c | 79 | ||||
| -rw-r--r-- | src/irmd/oap/tests/oap_test_ml_dsa.c | 1 |
5 files changed, 97 insertions, 15 deletions
diff --git a/src/irmd/oap/auth.c b/src/irmd/oap/auth.c index a11ab158..d165de73 100644 --- a/src/irmd/oap/auth.c +++ b/src/irmd/oap/auth.c @@ -174,6 +174,7 @@ int oap_check_hdr(const struct oap_hdr * hdr) fail_replay: pthread_mutex_unlock(&oap_auth.replay.mtx); free(new); + return -EREPLAY; fail_stamp: return -EAUTH; } @@ -183,7 +184,7 @@ int oap_auth_peer(char * name, const struct oap_hdr * peer_hdr) { void * crt; - void * pk; + void * pk = NULL; buffer_t sign; /* Signed region */ uint8_t * id = peer_hdr->id.data; @@ -244,8 +245,8 @@ int oap_auth_peer(char * name, return 0; fail_check_sig: - crypt_free_key(pk); fail_crt: + crypt_free_key(pk); crypt_free_crt(crt); fail_check: return -EAUTH; diff --git a/src/irmd/oap/cli.c b/src/irmd/oap/cli.c index 8ecd317d..7a202da7 100644 --- a/src/irmd/oap/cli.c +++ b/src/irmd/oap/cli.c @@ -50,7 +50,7 @@ struct oap_cli_ctx { uint8_t __id[OAP_ID_SIZE]; buffer_t id; - uint8_t kex_buf[MSGBUFSZ]; + uint8_t kex_buf[CRYPT_KEY_BUFSZ]; uint8_t req_hash[MAX_HASH_SIZE]; size_t req_hash_len; int req_md_nid; diff --git a/src/irmd/oap/srv.c b/src/irmd/oap/srv.c index 36391e50..587a8f9f 100644 --- a/src/irmd/oap/srv.c +++ b/src/irmd/oap/srv.c @@ -180,11 +180,7 @@ static int negotiate_cipher(const struct oap_hdr * peer_hdr, cli_rank = crypt_kdf_rank(peer_hdr->kdf_nid); srv_rank = crypt_kdf_rank(kcfg->k.nid); - /* - * For client-encap KEM, the KDF is baked into - * the ciphertext. The server must use the client's - * KDF and can only verify the minimum. - */ + /* Client-encap KEM bakes KDF into ciphertext; verify min. */ if (OAP_KEX_ROLE(peer_hdr) == KEM_MODE_CLIENT_ENCAP) { if (srv_rank > cli_rank) { log_err_id(id, "Client KDF too weak."); @@ -384,15 +380,16 @@ int oap_srv_process(const struct name_info * info, struct oap_hdr peer_hdr; struct oap_hdr local_hdr; struct sec_config kcfg; - uint8_t kex_buf[MSGBUFSZ]; + uint8_t kex_buf[CRYPT_KEY_BUFSZ]; uint8_t hash_buf[MAX_HASH_SIZE]; buffer_t req_hash = BUF_INIT; ssize_t hash_ret; - char cli_name[NAME_SIZE + 1]; /* TODO */ + char cli_name[NAME_SIZE + 1]; uint8_t * id; void * pkp = NULL; void * crt = NULL; int req_md_nid; + int ret; assert(info != NULL); assert(rsp_buf != NULL); @@ -427,8 +424,13 @@ int oap_srv_process(const struct name_info * info, id = peer_hdr.id.data; /* Logging */ - if (oap_check_hdr(&peer_hdr) < 0) { - log_err_id(id, "OAP header failed replay check."); + ret = oap_check_hdr(&peer_hdr); + if (ret == -EREPLAY) { + log_warn_id(id, "OAP header failed replay check."); + goto fail_replay; + } + if (ret < 0) { + log_err_id(id, "OAP header check failed."); goto fail_auth; } @@ -491,6 +493,11 @@ int oap_srv_process(const struct name_info * info, fail_cred: return -EAUTH; + fail_replay: + crypt_free_crt(crt); + crypt_free_key(pkp); + return -EREPLAY; + fail_kex: crypt_free_crt(crt); crypt_free_key(pkp); diff --git a/src/irmd/oap/tests/oap_test.c b/src/irmd/oap/tests/oap_test.c index 2f0f0b4d..a525d988 100644 --- a/src/irmd/oap/tests/oap_test.c +++ b/src/irmd/oap/tests/oap_test.c @@ -32,6 +32,7 @@ #include <ouroboros/crypt.h> #include <ouroboros/endian.h> +#include <ouroboros/errno.h> #include <ouroboros/flow.h> #include <ouroboros/name.h> #include <ouroboros/random.h> @@ -1053,9 +1054,9 @@ static int test_oap_replay_packet(void) freebuf(ctx.req_hdr); ctx.req_hdr = saved_req; - /* Replayed request should fail */ - if (oap_srv_process_ctx(&ctx) == 0) { - printf("Server should reject replayed packet.\n"); + /* Replay must return -EREPLAY so callers can drop silently. */ + if (oap_srv_process_ctx(&ctx) != -EREPLAY) { + printf("Replayed packet rejection != -EREPLAY.\n"); goto fail_cleanup; } @@ -1071,6 +1072,74 @@ static int test_oap_replay_packet(void) return TEST_RC_FAIL; } +/* Server rejects client certificate when root CA is missing from store */ +static int test_oap_missing_root_ca(void) +{ + struct oap_test_ctx ctx; + void * im_ca = NULL; + + test_default_cfg(); + + TEST_START(); + + memset(&ctx, 0, sizeof(ctx)); + + strcpy(ctx.srv.info.name, "test-1.unittest.o7s"); + strcpy(ctx.cli.info.name, "test-1.unittest.o7s"); + + if (oap_auth_init() < 0) { + printf("Failed to init OAP.\n"); + goto fail; + } + + /* Load intermediate CA but intentionally omit the root CA */ + if (crypt_load_crt_str(im_ca_crt_ec, &im_ca) < 0) { + printf("Failed to load intermediate CA cert.\n"); + goto fail_fini; + } + + ctx.im_ca = im_ca; + + if (oap_auth_add_ca_crt(im_ca) < 0) { + printf("Failed to add intermediate CA cert to store.\n"); + goto fail_fini; + } + + if (oap_cli_prepare_ctx(&ctx) < 0) { + printf("Client prepare failed.\n"); + goto fail_fini; + } + + /* Server processes and signs response - succeeds without root CA */ + if (oap_srv_process_ctx(&ctx) < 0) { + printf("Server process failed.\n"); + goto fail_teardown; + } + + /* Client verifies server certificate against trust store: + * should reject because root CA is not in the store */ + if (oap_cli_complete_ctx(&ctx) == 0) { + printf("Client should reject without root CA.\n"); + goto fail_teardown; + } + + oap_test_teardown(&ctx); + + TEST_SUCCESS(); + return TEST_RC_SUCCESS; + + fail_teardown: + oap_test_teardown(&ctx); + TEST_FAIL(); + return TEST_RC_FAIL; + fail_fini: + crypt_free_crt(im_ca); + oap_auth_fini(); + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + /* Test that client rejects server with wrong certificate name */ static int test_oap_server_name_mismatch(void) { @@ -1149,6 +1218,7 @@ int oap_test(int argc, ret |= test_oap_outdated_packet(); ret |= test_oap_future_packet(); ret |= test_oap_replay_packet(); + ret |= test_oap_missing_root_ca(); ret |= test_oap_server_name_mismatch(); #else (void) test_oap_roundtrip_auth_only; @@ -1173,9 +1243,12 @@ int oap_test(int argc, (void) test_oap_outdated_packet; (void) test_oap_future_packet; (void) test_oap_replay_packet; + (void) test_oap_missing_root_ca; (void) test_oap_server_name_mismatch; ret = TEST_RC_SKIP; #endif + crypt_cleanup(); + return ret; } diff --git a/src/irmd/oap/tests/oap_test_ml_dsa.c b/src/irmd/oap/tests/oap_test_ml_dsa.c index f9e6bdb2..81b307ab 100644 --- a/src/irmd/oap/tests/oap_test_ml_dsa.c +++ b/src/irmd/oap/tests/oap_test_ml_dsa.c @@ -442,6 +442,7 @@ int oap_test_ml_dsa(int argc, ret = TEST_RC_SKIP; #endif + crypt_cleanup(); return ret; } |
