diff options
Diffstat (limited to 'src/irmd/oap/tests/common.c')
| -rw-r--r-- | src/irmd/oap/tests/common.c | 286 |
1 files changed, 273 insertions, 13 deletions
diff --git a/src/irmd/oap/tests/common.c b/src/irmd/oap/tests/common.c index 0a1af100..16d52c63 100644 --- a/src/irmd/oap/tests/common.c +++ b/src/irmd/oap/tests/common.c @@ -29,39 +29,47 @@ #include <string.h> #include <stdio.h> -int load_srv_kex_config(const struct name_info * info, +int load_srv_sec_config(const struct name_info * info, struct sec_config * cfg) { (void) info; memset(cfg, 0, sizeof(*cfg)); + cfg->a.req = test_cfg.srv.req_auth; + + /* Digest is kept without kex, as in parse_sec_config */ + SET_KEX_DIGEST_NID(cfg, test_cfg.srv.md); + if (test_cfg.srv.kex == NID_undef) return 0; SET_KEX_ALGO_NID(cfg, test_cfg.srv.kex); SET_KEX_CIPHER_NID(cfg, test_cfg.srv.cipher); SET_KEX_KDF_NID(cfg, test_cfg.srv.kdf); - SET_KEX_DIGEST_NID(cfg, test_cfg.srv.md); SET_KEX_KEM_MODE(cfg, test_cfg.srv.kem_mode); return 0; } -int load_cli_kex_config(const struct name_info * info, +int load_cli_sec_config(const struct name_info * info, struct sec_config * cfg) { (void) info; memset(cfg, 0, sizeof(*cfg)); + cfg->a.req = test_cfg.cli.req_auth; + + /* Digest is kept without kex, as in parse_sec_config */ + SET_KEX_DIGEST_NID(cfg, test_cfg.cli.md); + if (test_cfg.cli.kex == NID_undef) return 0; SET_KEX_ALGO_NID(cfg, test_cfg.cli.kex); SET_KEX_CIPHER_NID(cfg, test_cfg.cli.cipher); SET_KEX_KDF_NID(cfg, test_cfg.cli.kdf); - SET_KEX_DIGEST_NID(cfg, test_cfg.cli.md); SET_KEX_KEM_MODE(cfg, test_cfg.cli.kem_mode); return 0; @@ -152,13 +160,15 @@ void oap_test_teardown(struct oap_test_ctx * ctx) if (ctx->cli.state != NULL) { res.key = ctx->cli.key; oap_cli_complete(ctx->cli.state, &ctx->cli.info, dummy, - &ctx->data, &res); + &ctx->data, &res, NULL, NULL); ctx->cli.state = NULL; } freebuf(ctx->data); freebuf(ctx->resp_hdr); freebuf(ctx->req_hdr); + freebuf(ctx->srv_crt); + freebuf(ctx->cli_crt); crypt_free_crt(ctx->im_ca); crypt_free_crt(ctx->root_ca); @@ -170,7 +180,7 @@ void oap_test_teardown(struct oap_test_ctx * ctx) int oap_cli_prepare_ctx(struct oap_test_ctx * ctx) { return oap_cli_prepare(&ctx->cli.state, &ctx->cli.info, &ctx->req_hdr, - ctx->data); + ctx->data, ctx->rekey); } int oap_srv_process_ctx(struct oap_test_ctx * ctx) @@ -179,7 +189,9 @@ int oap_srv_process_ctx(struct oap_test_ctx * ctx) int ret; ret = oap_srv_process(&ctx->srv.info, ctx->req_hdr, - &ctx->resp_hdr, &ctx->data, &res); + &ctx->resp_hdr, &ctx->data, &res, ctx->rekey, + ctx->rekey ? &ctx->srv_crt : NULL, + ctx->rekey ? NULL : &ctx->srv_crt); if (ret == 0) ctx->srv.nid = res.nid; @@ -192,7 +204,9 @@ int oap_cli_complete_ctx(struct oap_test_ctx * ctx) int ret; ret = oap_cli_complete(ctx->cli.state, &ctx->cli.info, ctx->resp_hdr, - &ctx->data, &res); + &ctx->data, &res, + ctx->rekey ? &ctx->cli_crt : NULL, + ctx->rekey ? NULL : &ctx->cli_crt); ctx->cli.state = NULL; if (ret == 0) @@ -243,6 +257,249 @@ int roundtrip_auth_only(const char * root_ca, return TEST_RC_FAIL; } +static const char * rekey_mode(bool srv_auth, + bool cli_auth) +{ + if (srv_auth && cli_auth) + return "mutual"; + + if (srv_auth) + return "srv-only"; + + if (cli_auth) + return "cli-only"; + + return "none"; +} + +int roundtrip_rekey(const char * root_ca, + const char * im_ca_str, + bool srv_auth, + bool cli_auth) +{ + struct oap_test_ctx ctx; + uint8_t key0[SYMMKEYSZ]; + const char * mode = rekey_mode(srv_auth, cli_auth); + + TEST_START("(%s)", mode); + + if (oap_test_setup(&ctx, root_ca, im_ca_str) < 0) + goto fail; + + if (oap_cli_prepare_ctx(&ctx) < 0) { + printf("Initial client prepare failed.\n"); + goto fail_cleanup; + } + + if (oap_srv_process_ctx(&ctx) < 0) { + printf("Initial server process failed.\n"); + goto fail_cleanup; + } + + if (oap_cli_complete_ctx(&ctx) < 0) { + printf("Initial client complete failed.\n"); + goto fail_cleanup; + } + + if (memcmp(ctx.cli.key, ctx.srv.key, SYMMKEYSZ) != 0) { + printf("Initial keys do not match.\n"); + goto fail_cleanup; + } + + /* The client caches the server cert only if the server authed. */ + if (srv_auth && ctx.cli_crt.len == 0) { + printf("Server cert was not cached for re-key.\n"); + goto fail_cleanup; + } + + /* The server caches the client cert only if the client authed. */ + if (cli_auth && ctx.srv_crt.len == 0) { + printf("Client cert was not cached by the server.\n"); + goto fail_cleanup; + } + + memcpy(key0, ctx.cli.key, SYMMKEYSZ); + + /* Re-key: cert dropped on the wire, verified against the cache. */ + freebuf(ctx.req_hdr); + freebuf(ctx.resp_hdr); + freebuf(ctx.data); + + ctx.rekey = true; + + if (oap_cli_prepare_ctx(&ctx) < 0) { + printf("Re-key client prepare failed.\n"); + goto fail_cleanup; + } + + if (oap_srv_process_ctx(&ctx) < 0) { + printf("Re-key server process failed.\n"); + goto fail_cleanup; + } + + if (oap_cli_complete_ctx(&ctx) < 0) { + printf("Re-key client complete failed.\n"); + goto fail_cleanup; + } + + if (memcmp(ctx.cli.key, ctx.srv.key, SYMMKEYSZ) != 0) { + printf("Re-key keys do not match.\n"); + goto fail_cleanup; + } + + if (memcmp(ctx.cli.key, key0, SYMMKEYSZ) == 0) { + printf("Re-key did not produce a fresh key.\n"); + goto fail_cleanup; + } + + if (ctx.cli.nid == NID_undef || ctx.srv.nid == NID_undef) { + printf("Cipher not set after re-key.\n"); + goto fail_cleanup; + } + + oap_test_teardown(&ctx); + + TEST_SUCCESS("(%s)", mode); + + return TEST_RC_SUCCESS; + fail_cleanup: + oap_test_teardown(&ctx); + fail: + TEST_FAIL("(%s)", mode); + return TEST_RC_FAIL; +} + +int roundtrip_rekey_badcache(const char * root_ca, + const char * im_ca_str, + bool cli_auth) +{ + struct oap_test_ctx ctx; + const char * mode = rekey_mode(true, cli_auth); + + TEST_START("(%s)", mode); + + if (oap_test_setup(&ctx, root_ca, im_ca_str) < 0) + goto fail; + + if (oap_cli_prepare_ctx(&ctx) < 0) { + printf("Initial client prepare failed.\n"); + goto fail_cleanup; + } + + if (oap_srv_process_ctx(&ctx) < 0) { + printf("Initial server process failed.\n"); + goto fail_cleanup; + } + + if (oap_cli_complete_ctx(&ctx) < 0) { + printf("Initial client complete failed.\n"); + goto fail_cleanup; + } + + if (ctx.cli_crt.len == 0) { + printf("Server cert was not cached.\n"); + goto fail_cleanup; + } + + /* Corrupt the client's cached server cert: re-key must fail closed. */ + ctx.cli_crt.data[ctx.cli_crt.len / 2] ^= 0xFF; + + freebuf(ctx.req_hdr); + freebuf(ctx.resp_hdr); + freebuf(ctx.data); + + ctx.rekey = true; + + if (oap_cli_prepare_ctx(&ctx) < 0) { + printf("Re-key client prepare failed.\n"); + goto fail_cleanup; + } + + if (oap_srv_process_ctx(&ctx) < 0) { + printf("Re-key server process failed.\n"); + goto fail_cleanup; + } + + if (oap_cli_complete_ctx(&ctx) == 0) { + printf("Re-key accepted a corrupted cached cert.\n"); + goto fail_cleanup; + } + + oap_test_teardown(&ctx); + + TEST_SUCCESS("(%s)", mode); + + return TEST_RC_SUCCESS; + fail_cleanup: + oap_test_teardown(&ctx); + fail: + TEST_FAIL("(%s)", mode); + return TEST_RC_FAIL; +} + +int roundtrip_rekey_srv_badcache(const char * root_ca, + const char * im_ca_str, + bool srv_auth) +{ + struct oap_test_ctx ctx; + const char * mode = rekey_mode(srv_auth, true); + + TEST_START("(%s)", mode); + + if (oap_test_setup(&ctx, root_ca, im_ca_str) < 0) + goto fail; + + if (oap_cli_prepare_ctx(&ctx) < 0) { + printf("Initial client prepare failed.\n"); + goto fail_cleanup; + } + + if (oap_srv_process_ctx(&ctx) < 0) { + printf("Initial server process failed.\n"); + goto fail_cleanup; + } + + if (oap_cli_complete_ctx(&ctx) < 0) { + printf("Initial client complete failed.\n"); + goto fail_cleanup; + } + + if (ctx.srv_crt.len == 0) { + printf("Client cert was not cached by the server.\n"); + goto fail_cleanup; + } + + /* Corrupt the server's cached client cert: re-key must fail closed. */ + ctx.srv_crt.data[ctx.srv_crt.len / 2] ^= 0xFF; + + freebuf(ctx.req_hdr); + freebuf(ctx.resp_hdr); + freebuf(ctx.data); + + ctx.rekey = true; + + if (oap_cli_prepare_ctx(&ctx) < 0) { + printf("Re-key client prepare failed.\n"); + goto fail_cleanup; + } + + if (oap_srv_process_ctx(&ctx) == 0) { + printf("Server accepted a corrupted cached client cert.\n"); + goto fail_cleanup; + } + + oap_test_teardown(&ctx); + + TEST_SUCCESS("(%s)", mode); + + return TEST_RC_SUCCESS; + fail_cleanup: + oap_test_teardown(&ctx); + fail: + TEST_FAIL("(%s)", mode); + return TEST_RC_FAIL; +} + int roundtrip_kex_only(void) { struct name_info cli_info; @@ -271,14 +528,15 @@ int roundtrip_kex_only(void) } if (oap_cli_prepare(&cli_state, &cli_info, &req_hdr, - data) < 0) { + data, false) < 0) { printf("Client prepare failed.\n"); goto fail_cleanup; } res.key = srv_key; - if (oap_srv_process(&srv_info, req_hdr, &resp_hdr, &data, &res) < 0) { + if (oap_srv_process(&srv_info, req_hdr, &resp_hdr, &data, &res, + false, NULL, NULL) < 0) { printf("Server process failed.\n"); goto fail_cleanup; } @@ -287,7 +545,8 @@ int roundtrip_kex_only(void) res.key = cli_key; - if (oap_cli_complete(cli_state, &cli_info, resp_hdr, &data, &res) < 0) { + if (oap_cli_complete(cli_state, &cli_info, resp_hdr, &data, &res, + NULL, NULL) < 0) { printf("Client complete failed.\n"); cli_state = NULL; goto fail_cleanup; @@ -316,7 +575,8 @@ int roundtrip_kex_only(void) fail_cleanup: if (cli_state != NULL) { res.key = cli_key; - oap_cli_complete(cli_state, &cli_info, resp_hdr, &data, &res); + oap_cli_complete(cli_state, &cli_info, resp_hdr, &data, + &res, NULL, NULL); } freebuf(resp_hdr); freebuf(req_hdr); @@ -396,7 +656,7 @@ int corrupted_response(const char * root_ca, res.key = ctx.cli.key; if (oap_cli_complete(ctx.cli.state, &ctx.cli.info, ctx.resp_hdr, - &ctx.data, &res) == 0) { + &ctx.data, &res, NULL, NULL) == 0) { printf("Client should reject corrupted response.\n"); ctx.cli.state = NULL; goto fail_cleanup; |
