diff options
author | Todd Short <tshort@akamai.com> | 2021-01-27 14:23:33 -0500 |
---|---|---|
committer | Todd Short <todd.short@me.com> | 2023-03-28 13:49:54 -0400 |
commit | 3c95ef22df55cb2d9dc64ce1f3be6e5a8ee63206 (patch) | |
tree | 0f7fcff4ec4735c778595db4f4a85bce70715d8b /test | |
parent | 5ab3f71a33cb0140fc29ae9244cd4f8331c2f3a5 (diff) | |
download | openssl-new-3c95ef22df55cb2d9dc64ce1f3be6e5a8ee63206.tar.gz |
RFC7250 (RPK) support
Add support for the RFC7250 certificate-type extensions.
Alows the use of only private keys for connection (i.e. certs not needed).
Add APIs
Add unit tests
Add documentation
Add s_client/s_server support
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18185)
Diffstat (limited to 'test')
-rw-r--r-- | test/build.info | 8 | ||||
-rw-r--r-- | test/ext_internal_test.c | 2 | ||||
-rw-r--r-- | test/recipes/70-test_certtypeext.t | 96 | ||||
-rw-r--r-- | test/recipes/90-test_rpk.t | 23 | ||||
-rw-r--r-- | test/rpktest.c | 759 | ||||
-rw-r--r-- | test/sslapitest.c | 22 |
6 files changed, 907 insertions, 3 deletions
diff --git a/test/build.info b/test/build.info index 56d53445dc..4599770106 100644 --- a/test/build.info +++ b/test/build.info @@ -66,6 +66,10 @@ IF[{- !$disabled{tests} -}] bio_tfo_test membio_test bio_dgram_test list_test fips_version_test \ x509_test hpke_test pairwise_fail_test nodefltctxtest + IF[{- !$disabled{'rpk'} -}] + PROGRAMS{noinst}=rpktest + ENDIF + IF[{- !$disabled{'deprecated-3.0'} -}] PROGRAMS{noinst}=enginetest ENDIF @@ -485,6 +489,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[sslapitest]=../include ../apps/include .. DEPEND[sslapitest]=../libcrypto ../libssl libtestutil.a + SOURCE[rpktest]=rpktest.c helpers/ssltestlib.c + INCLUDE[rpktest]=../include ../apps/include .. + DEPEND[rpktest]=../libcrypto ../libssl libtestutil.a + SOURCE[defltfips_test]=defltfips_test.c INCLUDE[defltfips_test]=../include ../apps/include DEPEND[defltfips_test]=../libcrypto libtestutil.a diff --git a/test/ext_internal_test.c b/test/ext_internal_test.c index 97a538abf9..b86f82ebf9 100644 --- a/test/ext_internal_test.c +++ b/test/ext_internal_test.c @@ -61,6 +61,8 @@ static EXT_LIST ext_list[] = { EXT_ENTRY(extended_master_secret), EXT_ENTRY(signature_algorithms_cert), EXT_ENTRY(post_handshake_auth), + EXT_ENTRY(client_cert_type), + EXT_ENTRY(server_cert_type), EXT_ENTRY(signature_algorithms), EXT_ENTRY(supported_versions), EXT_ENTRY(psk_kex_modes), diff --git a/test/recipes/70-test_certtypeext.t b/test/recipes/70-test_certtypeext.t new file mode 100644 index 0000000000..963468a052 --- /dev/null +++ b/test/recipes/70-test_certtypeext.t @@ -0,0 +1,96 @@ +#! /usr/bin/env perl +# Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +use strict; +use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/; +use OpenSSL::Test::Utils; +use TLSProxy::Proxy; + +my $test_name = "test_certtypeext"; +setup($test_name); + +plan skip_all => "TLSProxy isn't usable on $^O" + if $^O =~ /^(VMS)$/; + +plan skip_all => "$test_name needs the dynamic engine feature enabled" + if disabled("engine") || disabled("dynamic-engine"); + +plan skip_all => "$test_name needs the sock feature enabled" + if disabled("sock"); + +plan skip_all => "$test_name needs TLSv1.2 enabled" + if disabled("tls1_2"); + +my $proxy = TLSProxy::Proxy->new( + \&certtype_filter, + cmdstr(app(["openssl"]), display => 1), + srctop_file("apps", "server.pem"), + (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE}) +); + +use constant { + SERVER_CERT_TYPE => 0, + CLIENT_CERT_TYPE => 1, + NO_CERT_TYPE => 2 +}; +my $testtype; + +# Test 1: Just do a verify without cert type +$proxy->clear(); +$proxy->clientflags("-tls1_2 -cert ".srctop_file("apps", "server.pem")); +$proxy->serverflags("-verify 4"); +$testtype = NO_CERT_TYPE; +$proxy->start() or plan skip_all => "Unable to start up Proxy for tests"; +plan tests => 4; +ok(TLSProxy::Message->success, "Simple verify"); + +# Test 2: Set a bogus server cert type +$proxy->clear(); +$proxy->serverflags("-enable_server_rpk"); +$testtype = SERVER_CERT_TYPE; +$proxy->start(); +ok(TLSProxy::Message->fail, "Unsupported server cert type"); + +# Test 3: Set a bogus client cert type +$proxy->clear(); +$proxy->serverflags("-enable_client_rpk"); +$testtype = CLIENT_CERT_TYPE; +$proxy->start(); +ok(TLSProxy::Message->success, "Unsupported client cert type, no verify"); + +# Test 4: Set a bogus server cert type with verify +$proxy->clear(); +$testtype = CLIENT_CERT_TYPE; +$proxy->clientflags("-tls1_2 -cert ".srctop_file("apps", "server.pem")); +$proxy->serverflags("-verify 4 -enable_client_rpk"); +$proxy->start(); +ok(TLSProxy::Message->fail, "Unsupported client cert type with verify"); + +sub certtype_filter +{ + my $proxy = shift; + my $message; + + # We're only interested in the initial ClientHello + return if $proxy->flight != 0; + + $message = ${$proxy->message_list}[0]; + + # Add unsupported and bogus client and server cert type to the client hello. + my $ct = pack "C5", 0x04, 0x01, 0x03, 0x55, 0x66; + if ($testtype == CLIENT_CERT_TYPE) { + print "SETTING CLIENT CERT TYPE\n"; + $message->set_extension(TLSProxy::Message::EXT_CLIENT_CERT_TYPE, $ct); + } + if ($testtype == SERVER_CERT_TYPE) { + print "SETTING SERVER CERT TYPE\n"; + $message->set_extension(TLSProxy::Message::EXT_SERVER_CERT_TYPE, $ct); + } + + $message->repack(); +} diff --git a/test/recipes/90-test_rpk.t b/test/recipes/90-test_rpk.t new file mode 100644 index 0000000000..2036817199 --- /dev/null +++ b/test/recipes/90-test_rpk.t @@ -0,0 +1,23 @@ +#! /usr/bin/env perl +# Copyright 2016-2023 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +use OpenSSL::Test::Utils; +use OpenSSL::Test qw/:DEFAULT srctop_dir bldtop_dir/; + +BEGIN { + setup("test_rpk"); +} + +use lib srctop_dir('Configurations'); +use lib bldtop_dir('.'); + +plan skip_all => "RPK is disabled in this OpenSSL build" if disabled("tls1_2") && disabled("tls1_3"); + +plan tests => 1; + +ok(run(test(["rpktest", srctop_dir("test", "certs")])), "running rpktest"); diff --git a/test/rpktest.c b/test/rpktest.c new file mode 100644 index 0000000000..89e1fcf638 --- /dev/null +++ b/test/rpktest.c @@ -0,0 +1,759 @@ +/* + * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#include <openssl/ssl.h> + +#include "helpers/ssltestlib.h" +#include "internal/dane.h" +#include "testutil.h" + +#undef OSSL_NO_USABLE_TLS1_3 +#if defined(OPENSSL_NO_TLS1_3) \ + || (defined(OPENSSL_NO_EC) && defined(OPENSSL_NO_DH)) +/* + * If we don't have ec or dh then there are no built-in groups that are usable + * with TLSv1.3 + */ +# define OSSL_NO_USABLE_TLS1_3 +#endif + +static char *certsdir = NULL; +static char *rootcert = NULL; +static char *cert = NULL; +static char *privkey = NULL; +static char *cert2 = NULL; +static char *privkey2 = NULL; +static char *cert448 = NULL; +static char *privkey448 = NULL; +static char *cert25519 = NULL; +static char *privkey25519 = NULL; +static OSSL_LIB_CTX *libctx = NULL; +static OSSL_PROVIDER *defctxnull = NULL; + +static const unsigned char cert_type_rpk[] = { TLSEXT_cert_type_rpk, TLSEXT_cert_type_x509 }; +static const unsigned char SID_CTX[] = { 'r', 'p', 'k' }; + +static int rpk_verify_client_cb(int ok, X509_STORE_CTX *ctx) +{ + int err = X509_STORE_CTX_get_error(ctx); + + if (X509_STORE_CTX_get0_rpk(ctx) != NULL) { + if (err != X509_V_OK) { + TEST_info("rpk_verify_client_cb: ok=%d err=%d", ok, err); + return 0; + } + } + return 1; +} +static int rpk_verify_server_cb(int ok, X509_STORE_CTX *ctx) +{ + int err = X509_STORE_CTX_get_error(ctx); + + if (X509_STORE_CTX_get0_rpk(ctx) != NULL) { + if (err != X509_V_OK) { + TEST_info("rpk_verify_server_cb: ok=%d err=%d", ok, err); + return 0; + } + } + return 1; +} + +/* + * Test dimensions: + * (2) server_cert_type RPK off/on for server + * (2) client_cert_type RPK off/on for server + * (2) server_cert_type RPK off/on for client + * (2) client_cert_type RPK off/on for client + * (4) RSA vs ECDSA vs Ed25519 vs Ed448 certificates + * (2) TLSv1.2 vs TLSv1.3 + * + * Tests: + * idx = 0 - is the normal success case, certificate, single peer key + * idx = 1 - only a private key + * idx = 2 - add client authentication + * idx = 3 - add second peer key (rootcert.pem) + * idx = 4 - add second peer key (different, RSA or ECDSA) + * idx = 5 - reverse peer keys (rootcert.pem, different order) + * idx = 6 - reverse peer keys (RSA or ECDSA, different order) + * idx = 7 - expects failure due to mismatched key (RSA or ECDSA) + * idx = 8 - expects failure due to no configured key on client + * idx = 9 - add client authentication (PHA) + * idx = 10 - add client authentication (privake key only) + * idx = 11 - simple resumption + * idx = 12 - simple resumption, no ticket + * idx = 13 - resumption with client authentication + * idx = 14 - resumption with client authentication, no ticket + * idx = 15 - like 0, but use non-default libctx + * + * 16 * 2 * 4 * 2 * 2 * 2 * 2 = 2048 tests + */ +static int test_rpk(int idx) +{ +# define RPK_TESTS 16 +# define RPK_DIMS (2 * 4 * 2 * 2 * 2 * 2) + SSL_CTX *cctx = NULL, *sctx = NULL; + SSL *clientssl = NULL, *serverssl = NULL; + EVP_PKEY *pkey = NULL, *other_pkey = NULL, *root_pkey = NULL; + X509 *x509 = NULL, *other_x509 = NULL, *root_x509 = NULL; + int testresult = 0, ret, expected = 1; + int client_expected = X509_V_OK; + int verify; + int tls_version; + char *cert_file = NULL; + char *privkey_file = NULL; + char *other_cert_file = NULL; + SSL_SESSION *client_sess = NULL; + SSL_SESSION *server_sess = NULL; + int idx_server_server_rpk, idx_server_client_rpk; + int idx_client_server_rpk, idx_client_client_rpk; + int idx_cert, idx_prot; + int client_auth = 0; + int resumption = 0; + long server_verify_result = 0; + long client_verify_result = 0; + OSSL_LIB_CTX *test_libctx = NULL; + + if (!TEST_int_le(idx, RPK_TESTS * RPK_DIMS)) + return 0; + + idx_server_server_rpk = idx / (RPK_TESTS * 2 * 4 * 2 * 2 * 2); + idx %= RPK_TESTS * 2 * 4 * 2 * 2 * 2; + idx_server_client_rpk = idx / (RPK_TESTS * 2 * 4 * 2 * 2); + idx %= RPK_TESTS * 2 * 4 * 2 * 2; + idx_client_server_rpk = idx / (RPK_TESTS * 2 * 4 * 2); + idx %= RPK_TESTS * 2 * 4 * 2; + idx_client_client_rpk = idx / (RPK_TESTS * 2 * 4); + idx %= RPK_TESTS * 2 * 4; + idx_cert = idx / (RPK_TESTS * 2); + idx %= RPK_TESTS * 2; + idx_prot = idx / RPK_TESTS; + idx %= RPK_TESTS; + + /* Load "root" cert/pubkey */ + root_x509 = load_cert_pem(rootcert, NULL); + if (!TEST_ptr(root_x509)) + goto end; + root_pkey = X509_get0_pubkey(root_x509); + if (!TEST_ptr(root_pkey)) + goto end; + + switch (idx_cert) { + case 0: + /* use RSA */ + cert_file = cert; + privkey_file = privkey; + other_cert_file = cert2; + break; +#ifndef OPENSSL_NO_ECDSA + case 1: + /* use ECDSA */ + cert_file = cert2; + privkey_file = privkey2; + other_cert_file = cert; + break; + case 2: + /* use Ed448 */ + cert_file = cert448; + privkey_file = privkey448; + other_cert_file = cert; + break; + case 3: + /* use Ed25519 */ + cert_file = cert25519; + privkey_file = privkey25519; + other_cert_file = cert; + break; +#endif + default: + testresult = TEST_skip("EDCSA disabled"); + goto end; + } + /* Load primary cert */ + x509 = load_cert_pem(cert_file, NULL); + if (!TEST_ptr(x509)) + goto end; + pkey = X509_get0_pubkey(x509); + /* load other cert */ + other_x509 = load_cert_pem(other_cert_file, NULL); + if (!TEST_ptr(other_x509)) + goto end; + other_pkey = X509_get0_pubkey(other_x509); +#ifdef OPENSSL_NO_ECDSA + /* Can't get other_key if it's ECDSA */ + if (other_pkey == NULL && idx_cert == 0 + && (idx == 4 || idx == 6 || idx == 7)) { + testresult = TEST_skip("EDCSA disabled"); + goto end; + } +#endif + + switch (idx_prot) { + case 0: +#ifdef OSSL_NO_USABLE_TLS1_3 + testresult = TEST_skip("TLSv1.3 disabled"); + goto end; +#else + tls_version = TLS1_3_VERSION; + break; +#endif + case 1: +#ifdef OPENSSL_NO_TLS1_2 + testresult = TEST_skip("TLSv1.2 disabled"); + goto end; +#else + tls_version = TLS1_2_VERSION; + break; +#endif + default: + goto end; + } + + if (idx == 15) { + test_libctx = libctx; + defctxnull = OSSL_PROVIDER_load(NULL, "null"); + if (!TEST_ptr(defctxnull)) + goto end; + } + if (!TEST_true(create_ssl_ctx_pair(test_libctx, + TLS_server_method(), TLS_client_method(), + tls_version, tls_version, + &sctx, &cctx, NULL, NULL))) + goto end; + + if (idx_server_server_rpk) + if (!TEST_true(SSL_CTX_set1_server_cert_type(sctx, cert_type_rpk, sizeof(cert_type_rpk)))) + goto end; + if (idx_server_client_rpk) + if (!TEST_true(SSL_CTX_set1_client_cert_type(sctx, cert_type_rpk, sizeof(cert_type_rpk)))) + goto end; + if (idx_client_server_rpk) + if (!TEST_true(SSL_CTX_set1_server_cert_type(cctx, cert_type_rpk, sizeof(cert_type_rpk)))) + goto end; + if (idx_client_client_rpk) + if (!TEST_true(SSL_CTX_set1_client_cert_type(cctx, cert_type_rpk, sizeof(cert_type_rpk)))) + goto end; + if (!TEST_true(SSL_CTX_set_session_id_context(sctx, SID_CTX, sizeof(SID_CTX)))) + goto end; + if (!TEST_true(SSL_CTX_set_session_id_context(cctx, SID_CTX, sizeof(SID_CTX)))) + goto end; + + if (!TEST_int_gt(SSL_CTX_dane_enable(sctx), 0)) + goto end; + if (!TEST_int_gt(SSL_CTX_dane_enable(cctx), 0)) + goto end; + + /* NEW */ + SSL_CTX_set_verify(cctx, SSL_VERIFY_PEER, rpk_verify_client_cb); + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL))) + goto end; + + if (!TEST_int_gt(SSL_dane_enable(serverssl, NULL), 0)) + goto end; + if (!TEST_int_gt(SSL_dane_enable(clientssl, "example.com"), 0)) + goto end; + + /* Set private key and certificate */ + if (!TEST_int_eq(SSL_use_PrivateKey_file(serverssl, privkey_file, SSL_FILETYPE_PEM), 1)) + goto end; + /* Only a private key */ + if (idx == 1) { + if (idx_server_server_rpk == 0 || idx_client_server_rpk == 0) + expected = 0; + } else { + /* Add certificate */ + if (!TEST_int_eq(SSL_use_certificate_file(serverssl, cert_file, SSL_FILETYPE_PEM), 1)) + goto end; + if (!TEST_int_eq(SSL_check_private_key(serverssl), 1)) + goto end; + } + + switch (idx) { + default: + if (!TEST_true(idx < RPK_TESTS)) + goto end; + break; + case 0: + if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) + goto end; + break; + case 1: + if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) + goto end; + break; + case 2: + if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) + goto end; + if (!TEST_true(SSL_add_expected_rpk(serverssl, pkey))) + goto end; + /* Use the same key for client auth */ + if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1)) + goto end; + if (!TEST_int_eq(SSL_use_certificate_file(clientssl, cert_file, SSL_FILETYPE_PEM), 1)) + goto end; + if (!TEST_int_eq(SSL_check_private_key(clientssl), 1)) + goto end; + SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb); + client_auth = 1; + break; + case 3: + if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) + goto end; + if (!TEST_true(SSL_add_expected_rpk(clientssl, root_pkey))) + goto end; + break; + case 4: + if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) + goto end; + if (!TEST_true(SSL_add_expected_rpk(clientssl, other_pkey))) + goto end; + break; + case 5: + if (!TEST_true(SSL_add_expected_rpk(clientssl, root_pkey))) + goto end; + if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) + goto end; + break; + case 6: + if (!TEST_true(SSL_add_expected_rpk(clientssl, other_pkey))) + goto end; + if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) + goto end; + break; + case 7: + if (idx_server_server_rpk == 1 && idx_client_server_rpk == 1) + client_expected = -1; + if (!TEST_true(SSL_add_expected_rpk(clientssl, other_pkey))) + goto end; + client_verify_result = X509_V_ERR_DANE_NO_MATCH; + break; + case 8: + if (idx_server_server_rpk == 1 && idx_client_server_rpk == 1) + client_expected = -1; + /* no peer keys */ + client_verify_result = X509_V_ERR_RPK_UNTRUSTED; + break; + case 9: + if (tls_version != TLS1_3_VERSION) { + testresult = TEST_skip("PHA requires TLSv1.3"); + goto end; + } + if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) + goto end; + if (!TEST_true(SSL_add_expected_rpk(serverssl, pkey))) + goto end; + /* Use the same key for client auth */ + if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1)) + goto end; + if (!TEST_int_eq(SSL_use_certificate_file(clientssl, cert_file, SSL_FILETYPE_PEM), 1)) + goto end; + if (!TEST_int_eq(SSL_check_private_key(clientssl), 1)) + goto end; + SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_POST_HANDSHAKE, rpk_verify_server_cb); + SSL_set_post_handshake_auth(clientssl, 1); + client_auth = 1; + break; + case 10: + if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) + goto end; + if (!TEST_true(SSL_add_expected_rpk(serverssl, pkey))) + goto end; + /* Use the same key for client auth */ + if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1)) + goto end; + /* Since there's no cert, this is expected to fail without RPK support */ + if (!idx_server_client_rpk || !idx_client_client_rpk) + expected = 0; + SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb); + client_auth = 1; + break; + case 11: + if (!idx_server_server_rpk || !idx_client_server_rpk) { + testresult = TEST_skip("Only testing resumption with server RPK"); + goto end; + } + if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) + goto end; + resumption = 1; + break; + case 12: + if (!idx_server_server_rpk || !idx_client_server_rpk) { + testresult = TEST_skip("Only testing resumption with server RPK"); + goto end; + } + if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) + goto end; + SSL_set_options(serverssl, SSL_OP_NO_TICKET); + SSL_set_options(clientssl, SSL_OP_NO_TICKET); + resumption = 1; + break; + case 13: + if (!idx_server_server_rpk || !idx_client_server_rpk) { + testresult = TEST_skip("Only testing resumption with server RPK"); + goto end; + } + if (!idx_server_client_rpk || !idx_client_client_rpk) { + testresult = TEST_skip("Only testing client authentication resumption with client RPK"); + goto end; + } + if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) + goto end; + if (!TEST_true(SSL_add_expected_rpk(serverssl, pkey))) + goto end; + /* Use the same key for client auth */ + if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1)) + goto end; + if (!TEST_int_eq(SSL_use_certificate_file(clientssl, cert_file, SSL_FILETYPE_PEM), 1)) + goto end; + if (!TEST_int_eq(SSL_check_private_key(clientssl), 1)) + goto end; + SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb); + client_auth = 1; + resumption = 1; + break; + case 14: + if (!idx_server_server_rpk || !idx_client_server_rpk) { + testresult = TEST_skip("Only testing resumption with server RPK"); + goto end; + } + if (!idx_server_client_rpk || !idx_client_client_rpk) { + testresult = TEST_skip("Only testing client authentication resumption with client RPK"); + goto end; + } + if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) + goto end; + if (!TEST_true(SSL_add_expected_rpk(serverssl, pkey))) + goto end; + /* Use the same key for client auth */ + if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1)) + goto end; + if (!TEST_int_eq(SSL_use_certificate_file(clientssl, cert_file, SSL_FILETYPE_PEM), 1)) + goto end; + if (!TEST_int_eq(SSL_check_private_key(clientssl), 1)) + goto end; + SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb); + SSL_set_options(serverssl, SSL_OP_NO_TICKET); + SSL_set_options(clientssl, SSL_OP_NO_TICKET); + client_auth = 1; + resumption = 1; + break; + case 15: + if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey))) + goto end; + break; + } + + ret = create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE); + if (!TEST_int_eq(expected, ret)) + goto end; + + /* Make sure client gets RPK or certificate as configured */ + if (expected == 1) { + if (idx_server_server_rpk && idx_client_server_rpk) { + if (!TEST_long_eq(SSL_get_verify_result(clientssl), client_verify_result)) + goto end; + if (!TEST_ptr(SSL_get0_peer_rpk(clientssl))) + goto end; + if (!TEST_int_eq(SSL_get_negotiated_server_cert_type(serverssl), TLSEXT_cert_type_rpk)) + goto end; + if (!TEST_int_eq(SSL_get_negotiated_server_cert_type(clientssl), TLSEXT_cert_type_rpk)) + goto end; + } else { + if (!TEST_ptr(SSL_get0_peer_certificate(clientssl))) + goto end; + if (!TEST_int_eq(SSL_get_negotiated_server_cert_type(serverssl), TLSEXT_cert_type_x509)) + goto end; + if (!TEST_int_eq(SSL_get_negotiated_server_cert_type(clientssl), TLSEXT_cert_type_x509)) + goto end; + } + } + + if (idx == 9) { + /* Make PHA happen... */ + if (!TEST_true(SSL_verify_client_post_handshake(serverssl))) + goto end; + if (!TEST_true(SSL_do_handshake(serverssl))) + goto end; + if (!TEST_int_le(SSL_read(clientssl, NULL, 0), 0)) + goto end; + if (!TEST_int_le(SSL_read(serverssl, NULL, 0), 0)) + goto end; + } + + /* Make sure server gets an RPK or certificate as configured */ + if (client_auth) { + if (idx_server_client_rpk && idx_client_client_rpk) { + if (!TEST_long_eq(SSL_get_verify_result(serverssl), server_verify_result)) + goto end; + if (!TEST_ptr(SSL_get0_peer_rpk(serverssl))) + goto end; + if (!TEST_int_eq(SSL_get_negotiated_client_cert_type(serverssl), TLSEXT_cert_type_rpk)) + goto end; + if (!TEST_int_eq(SSL_get_negotiated_client_cert_type(clientssl), TLSEXT_cert_type_rpk)) + goto end; + } else { + /* only if connection is expected to succeed */ + if (expected == 1 && !TEST_ptr(SSL_get0_peer_certificate(serverssl))) + goto end; + if (!TEST_int_eq(SSL_get_negotiated_client_cert_type(serverssl), TLSEXT_cert_type_x509)) + goto end; + if (!TEST_int_eq(SSL_get_negotiated_client_cert_type(clientssl), TLSEXT_cert_type_x509)) + goto end; + } + } + + if (resumption) { + EVP_PKEY *client_pkey = NULL; + EVP_PKEY *server_pkey = NULL; + + if (!TEST_ptr((client_sess = SSL_get1_session(clientssl))) + || !TEST_ptr((client_pkey = SSL_SESSION_get0_peer_rpk(client_sess)))) + goto end; + if (client_auth) { + if (!TEST_ptr((server_sess = SSL_get1_session(serverssl))) + || !TEST_ptr((server_pkey = SSL_SESSION_get0_peer_rpk(server_sess)))) + goto end; + } + SSL_shutdown(clientssl); + SSL_shutdown(serverssl); + SSL_free(clientssl); + SSL_free(serverssl); + serverssl = clientssl = NULL; + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL)) + || !TEST_true(SSL_set_session(clientssl, client_sess))) + goto end; + + /* Set private key (and maybe certificate) */ + if (!TEST_int_eq(SSL_use_PrivateKey_file(serverssl, privkey_file, SSL_FILETYPE_PEM), 1)) + goto end; + if (!TEST_int_eq(SSL_use_certificate_file(serverssl, cert_file, SSL_FILETYPE_PEM), 1)) + goto end; + if (!TEST_int_eq(SSL_check_private_key(serverssl), 1)) + goto end; + if (!TEST_int_gt(SSL_dane_enable(serverssl, "example.com"), 0)) + goto end; + if (!TEST_int_gt(SSL_dane_enable(clientssl, "example.com"), 0)) + goto end; + + switch (idx) { + default: + break; + case 11: + if (!TEST_true(SSL_add_expected_rpk(clientssl, client_pkey))) + goto end; + break; + case 12: + if (!TEST_true(SSL_add_expected_rpk(clientssl, client_pkey))) + goto end; + SSL_set_options(clientssl, SSL_OP_NO_TICKET); + SSL_set_options(serverssl, SSL_OP_NO_TICKET); + break; + case 13: + if (!TEST_true(SSL_add_expected_rpk(clientssl, client_pkey))) + goto end; + if (!TEST_true(SSL_add_expected_rpk(serverssl, server_pkey))) + goto end; + /* Use the same key for client auth */ + if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1)) + goto end; + if (!TEST_int_eq(SSL_use_certificate_file(clientssl, cert_file, SSL_FILETYPE_PEM), 1)) + goto end; + if (!TEST_int_eq(SSL_check_private_key(clientssl), 1)) + goto end; + SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb); + break; + case 14: + if (!TEST_true(SSL_add_expected_rpk(clientssl, client_pkey))) + goto end; + if (!TEST_true(SSL_add_expected_rpk(serverssl, server_pkey))) + goto end; + /* Use the same key for client auth */ + if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1)) + goto end; + if (!TEST_int_eq(SSL_use_certificate_file(clientssl, cert_file, SSL_FILETYPE_PEM), 1)) + goto end; + if (!TEST_int_eq(SSL_check_private_key(clientssl), 1)) + goto end; + SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb); + SSL_set_options(serverssl, SSL_OP_NO_TICKET); + SSL_set_options(clientssl, SSL_OP_NO_TICKET); + break; + } + + ret = create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE); + if (!TEST_int_eq(expected, ret)) + goto end; + verify = SSL_get_verify_result(clientssl); + if (!TEST_int_eq(client_expected, verify)) + goto end; + if (!TEST_true(SSL_session_reused(clientssl))) + goto end; + + if (!TEST_ptr(SSL_get0_peer_rpk(clientssl))) + goto end; + if (!TEST_int_eq(SSL_get_negotiated_server_cert_type(serverssl), TLSEXT_cert_type_rpk)) + goto end; + if (!TEST_int_eq(SSL_get_negotiated_server_cert_type(clientssl), TLSEXT_cert_type_rpk)) + goto end; + + if (client_auth) { + if (!TEST_ptr(SSL_get0_peer_rpk(serverssl))) + goto end; + if (!TEST_int_eq(SSL_get_negotiated_client_cert_type(serverssl), TLSEXT_cert_type_rpk)) + goto end; + if (!TEST_int_eq(SSL_get_negotiated_client_cert_type(clientssl), TLSEXT_cert_type_rpk)) + goto end; + } + } + + testresult = 1; + + end: + OSSL_PROVIDER_unload(defctxnull); + defctxnull = NULL; + SSL_SESSION_free(client_sess); + SSL_SESSION_free(server_sess); + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + X509_free(x509); + X509_free(other_x509); + X509_free(root_x509); + + if (testresult == 0) { + TEST_info("idx_ss_rpk=%d, idx_sc_rpk=%d, idx_cs_rpk=%d, idx_cc_rpk=%d, idx_cert=%d, idx_prot=%d, idx=%d", + idx_server_server_rpk, idx_server_client_rpk, + idx_client_server_rpk, idx_client_client_rpk, + idx_cert, idx_prot, idx); + } + return testresult; +} + +static int test_rpk_api(void) +{ + int ret = 0; + SSL_CTX *cctx = NULL, *sctx = NULL; + unsigned char cert_type_dups[] = { TLSEXT_cert_type_rpk, + TLSEXT_cert_type_x509, + TLSEXT_cert_type_x509 }; + unsigned char cert_type_bad[] = { 0xFF }; + unsigned char cert_type_extra[] = { TLSEXT_cert_type_rpk, + TLSEXT_cert_type_x509, + 0xFF }; + unsigned char cert_type_unsup[] = { TLSEXT_cert_type_pgp, + TLSEXT_cert_type_1609dot2 }; + unsigned char cert_type_just_x509[] = { TLSEXT_cert_type_x509 }; + unsigned char cert_type_just_rpk[] = { TLSEXT_cert_type_rpk }; + + if (!TEST_true(create_ssl_ctx_pair(NULL, + TLS_server_method(), TLS_client_method(), + TLS1_2_VERSION, TLS1_2_VERSION, + &sctx, &cctx, NULL, NULL))) + goto end; + + if (!TEST_false(SSL_CTX_set1_server_cert_type(sctx, cert_type_dups, sizeof(cert_type_dups)))) + goto end; + + if (!TEST_false(SSL_CTX_set1_server_cert_type(sctx, cert_type_bad, sizeof(cert_type_bad)))) + goto end; + + if (!TEST_false(SSL_CTX_set1_server_cert_type(sctx, cert_type_extra, sizeof(cert_type_extra)))) + goto end; + + if (!TEST_false(SSL_CTX_set1_server_cert_type(sctx, cert_type_unsup, sizeof(cert_type_unsup)))) + goto end; + + if (!TEST_true(SSL_CTX_set1_server_cert_type(sctx, cert_type_just_x509, sizeof(cert_type_just_x509)))) + goto end; + + if (!TEST_true(SSL_CTX_set1_server_cert_type(sctx, cert_type_just_rpk, sizeof(cert_type_just_rpk)))) + goto end; + + ret = 1; + end: + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + return ret; +} +OPT_TEST_DECLARE_USAGE("certdir\n") + +int setup_tests(void) +{ + if (!test_skip_common_options()) { + TEST_error("Error parsing test options\n"); + return 0; + } + + if (!TEST_ptr(certsdir = test_get_argument(0))) + return 0; + + rootcert = test_mk_file_path(certsdir, "rootcert.pem"); + if (rootcert == NULL) + goto err; + + cert = test_mk_file_path(certsdir, "servercert.pem"); + if (cert == NULL) + goto err; + + privkey = test_mk_file_path(certsdir, "serverkey.pem"); + if (privkey == NULL) + goto err; + + cert2 = test_mk_file_path(certsdir, "server-ecdsa-cert.pem"); + if (cert2 == NULL) + goto err; + + privkey2 = test_mk_file_path(certsdir, "server-ecdsa-key.pem"); + if (privkey2 == NULL) + goto err; + + cert448 = test_mk_file_path(certsdir, "server-ed448-cert.pem"); + if (cert2 == NULL) + goto err; + + privkey448 = test_mk_file_path(certsdir, "server-ed448-key.pem"); + if (privkey2 == NULL) + goto err; + + cert25519 = test_mk_file_path(certsdir, "server-ed25519-cert.pem"); + if (cert2 == NULL) + goto err; + + privkey25519 = test_mk_file_path(certsdir, "server-ed25519-key.pem"); + if (privkey2 == NULL) + goto err; + + libctx = OSSL_LIB_CTX_new(); + if (libctx == NULL) + goto err; + + ADD_TEST(test_rpk_api); + ADD_ALL_TESTS(test_rpk, RPK_TESTS * RPK_DIMS); + return 1; + + err: + return 0; +} + +void cleanup_tests(void) +{ + OPENSSL_free(rootcert); + OPENSSL_free(cert); + OPENSSL_free(privkey); + OPENSSL_free(cert2); + OPENSSL_free(privkey2); + OPENSSL_free(cert448); + OPENSSL_free(privkey448); + OPENSSL_free(cert25519); + OPENSSL_free(privkey25519); + OSSL_LIB_CTX_free(libctx); + } diff --git a/test/sslapitest.c b/test/sslapitest.c index 9cf4cf7d35..ae4977bfde 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -8090,7 +8090,7 @@ static int test_ticket_callbacks(int tst) gen_tick_called = dec_tick_called = tick_key_cb_called = 0; /* Which tests the ticket key callback should request renewal for */ - + if (tst == 10 || tst == 11 || tst == 16 || tst == 17) tick_key_renew = 1; else if (tst == 12 || tst == 13 || tst == 18 || tst == 19) @@ -9558,9 +9558,12 @@ static int create_cert_key(int idx, char *certfilename, char *privkeyfilename) * correctly establish a TLS (1.3) connection. * Test 0: Signature algorithm with built-in hashing functionality: "xorhmacsig" * Test 1: Signature algorithm using external SHA2 hashing: "xorhmacsha2sig" + * Test 2: Test 0 using RPK + * Test 3: Test 1 using RPK */ static int test_pluggable_signature(int idx) { + static const unsigned char cert_type_rpk[] = { TLSEXT_cert_type_rpk, TLSEXT_cert_type_x509 }; SSL_CTX *cctx = NULL, *sctx = NULL; SSL *clientssl = NULL, *serverssl = NULL; int testresult = 0; @@ -9568,10 +9571,12 @@ static int test_pluggable_signature(int idx) OSSL_PROVIDER *defaultprov = OSSL_PROVIDER_load(libctx, "default"); char *certfilename = "tls-prov-cert.pem"; char *privkeyfilename = "tls-prov-key.pem"; + int sigidx = idx % 2; + int rpkidx = idx / 2; /* create key and certificate for the different algorithm types */ if (!TEST_ptr(tlsprov) - || !TEST_true(create_cert_key(idx, certfilename, privkeyfilename))) + || !TEST_true(create_cert_key(sigidx, certfilename, privkeyfilename))) goto end; if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), @@ -9583,6 +9588,13 @@ static int test_pluggable_signature(int idx) NULL, NULL))) goto end; + /* Enable RPK for server cert */ + if (rpkidx) { + if (!TEST_true(SSL_set1_server_cert_type(serverssl, cert_type_rpk, sizeof(cert_type_rpk))) + || !TEST_true(SSL_set1_server_cert_type(clientssl, cert_type_rpk, sizeof(cert_type_rpk)))) + goto end; + } + /* This is necessary to pass minimal setup w/o other groups configured */ if (!TEST_true(SSL_set1_groups_list(serverssl, "xorgroup")) || !TEST_true(SSL_set1_groups_list(clientssl, "xorgroup"))) @@ -9596,6 +9608,10 @@ static int test_pluggable_signature(int idx) if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) goto end; + /* If using RPK, make sure we got one */ + if (rpkidx && !TEST_long_eq(SSL_get_verify_result(clientssl), X509_V_ERR_RPK_UNTRUSTED)) + goto end; + testresult = 1; end: @@ -11083,7 +11099,7 @@ int setup_tests(void) #endif #ifndef OPENSSL_NO_TLS1_3 ADD_ALL_TESTS(test_pluggable_group, 2); - ADD_ALL_TESTS(test_pluggable_signature, 2); + ADD_ALL_TESTS(test_pluggable_signature, 4); #endif #ifndef OPENSSL_NO_TLS1_2 ADD_TEST(test_ssl_dup); |