summaryrefslogtreecommitdiff
path: root/src/irmd/oap
diff options
context:
space:
mode:
Diffstat (limited to 'src/irmd/oap')
-rw-r--r--src/irmd/oap/auth.c5
-rw-r--r--src/irmd/oap/cli.c2
-rw-r--r--src/irmd/oap/srv.c25
-rw-r--r--src/irmd/oap/tests/oap_test.c79
-rw-r--r--src/irmd/oap/tests/oap_test_ml_dsa.c1
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;
}