diff --git a/test/README.ssltest.md b/test/README.ssltest.md index b65a0d73acce622e5eb2c2daa87c1e5e8d183c73..2957d85d99cada675d43ff4b57da6fd4b255dca9 100644 --- a/test/README.ssltest.md +++ b/test/README.ssltest.md @@ -59,6 +59,11 @@ The test section supports the following options: * Protocol - expected negotiated protocol. One of SSLv3, TLSv1, TLSv1.1, TLSv1.2. +* ClientVerifyCallback - the client's custom certificate verify callback. + Used to test callback behaviour. One of + - AcceptAll - accepts all certificates. + - RejectAll - rejects all certificates. + ## Configuring the client and server The client and server configurations can be any valid `SSL_CTX` diff --git a/test/handshake_helper.c b/test/handshake_helper.c index 4682d45bfb40a6e0b6ff4c4735801fe02bbf6028..0a27324899c569b292e095e0a99be95b18039231 100644 --- a/test/handshake_helper.c +++ b/test/handshake_helper.c @@ -11,6 +11,7 @@ #include #include +#include #include #include "handshake_helper.h" @@ -40,6 +41,37 @@ static void info_callback(const SSL *s, int where, int ret) } } +static int verify_reject_callback(X509_STORE_CTX *ctx, void *arg) { + X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION); + return 0; +} + +static int verify_accept_callback(X509_STORE_CTX *ctx, void *arg) { + return 1; +} + +/* + * Configure callbacks and other properties that can't be set directly + * in the server/client CONF. + */ +static void configure_handshake(SSL_CTX *server_ctx, SSL_CTX *client_ctx, + const SSL_TEST_CTX *test_ctx) +{ + switch (test_ctx->client_verify_callback) { + case SSL_TEST_VERIFY_ACCEPT_ALL: + SSL_CTX_set_cert_verify_callback(client_ctx, &verify_accept_callback, + NULL); + break; + case SSL_TEST_VERIFY_REJECT_ALL: + SSL_CTX_set_cert_verify_callback(client_ctx, &verify_reject_callback, + NULL); + break; + default: + break; + } +} + + typedef enum { PEER_SUCCESS, PEER_RETRY, @@ -139,7 +171,8 @@ static handshake_status_t handshake_status(peer_status_t last_status, return INTERNAL_ERROR; } -HANDSHAKE_RESULT do_handshake(SSL_CTX *server_ctx, SSL_CTX *client_ctx) +HANDSHAKE_RESULT do_handshake(SSL_CTX *server_ctx, SSL_CTX *client_ctx, + const SSL_TEST_CTX *test_ctx) { SSL *server, *client; BIO *client_to_server, *server_to_client; @@ -149,6 +182,8 @@ HANDSHAKE_RESULT do_handshake(SSL_CTX *server_ctx, SSL_CTX *client_ctx) peer_status_t client_status = PEER_RETRY, server_status = PEER_RETRY; handshake_status_t status = HANDSHAKE_RETRY; + configure_handshake(server_ctx, client_ctx, test_ctx); + server = SSL_new(server_ctx); client = SSL_new(client_ctx); OPENSSL_assert(server != NULL && client != NULL); diff --git a/test/handshake_helper.h b/test/handshake_helper.h index 56dfb197e21a46f4f637eb690a7b5f933336aecd..5f1ca04ee105c1e98e97c0e3c8672cf42a76fc81 100644 --- a/test/handshake_helper.h +++ b/test/handshake_helper.h @@ -30,6 +30,7 @@ typedef struct handshake_result { } HANDSHAKE_RESULT; /* Do a handshake and report some information about the result. */ -HANDSHAKE_RESULT do_handshake(SSL_CTX *server_ctx, SSL_CTX *client_ctx); +HANDSHAKE_RESULT do_handshake(SSL_CTX *server_ctx, SSL_CTX *client_ctx, + const SSL_TEST_CTX *test_ctx); #endif /* HEADER_HANDSHAKE_HELPER_H */ diff --git a/test/recipes/80-test_ssl_new.t b/test/recipes/80-test_ssl_new.t index a0183585cb7879f3b5aefa28bee7d2b7139a6a70..57def45072ecc7ba55a24503a6a3defb6bcd2825 100644 --- a/test/recipes/80-test_ssl_new.t +++ b/test/recipes/80-test_ssl_new.t @@ -20,8 +20,9 @@ setup("test_ssl_new"); $ENV{TEST_CERTS_DIR} = srctop_dir("test", "certs"); -my @conf_srcs = glob(srctop_file("test", "ssl-tests", "*.conf")); -my @conf_files = map {basename($_)} @conf_srcs; +my @conf_srcs = glob(srctop_file("test", "ssl-tests", "*.conf.in")); +my @conf_files = map { basename($_) } @conf_srcs; +map { s/\.in// } @conf_files; # 02-protocol-version.conf test results depend on the configuration of enabled # protocols. We only verify generated sources in the default configuration. @@ -39,7 +40,7 @@ foreach my $conf (@conf_files) { # We hard-code the number of tests to double-check that the globbing above # finds all files as expected. -plan tests => 2; # = scalar @conf_files +plan tests => 3; # = scalar @conf_srcs sub test_conf { plan tests => 3; diff --git a/test/recipes/80-test_ssl_old.t b/test/recipes/80-test_ssl_old.t index 61fc423424ac7b2f1d839813cb7a067108f50eeb..37635308ea8aca90de2a52de51fb2e0167003f91 100644 --- a/test/recipes/80-test_ssl_old.t +++ b/test/recipes/80-test_ssl_old.t @@ -79,8 +79,6 @@ my $client_sess="client.ss"; plan tests => 1 # For testss + 14 # For the first testssl - + 16 # For the first testsslproxy - + 16 # For the second testsslproxy ; subtest 'test_ss' => sub { @@ -98,13 +96,6 @@ subtest 'test_ss' => sub { note('test_ssl -- key U'); testssl("keyU.ss", $Ucert, $CAcert); -note('test_ssl -- key P1'); -testsslproxy("keyP1.ss", "certP1.ss", "intP1.ss", "AB"); - -note('test_ssl -- key P2'); -testsslproxy("keyP2.ss", "certP2.ss", "intP2.ss", "BC"); - - # ----------- # subtest functions sub testss { @@ -832,77 +823,3 @@ sub testssl { } }; } - -sub testsslproxy { - my $key = shift || srctop_file("apps","server.pem"); - my $cert = shift || srctop_file("apps","server.pem"); - my $CAtmp = shift; - my @CA = $CAtmp ? ("-CAfile", $CAtmp) : ("-CApath", bldtop_dir("certs")); - my @extra = @_; - - my @ssltest = ("ssltest_old", - "-s_key", $key, "-s_cert", $cert, - "-c_key", $key, "-c_cert", $cert); - - # plan tests => 16; - - note('Testing a lot of proxy conditions.'); - - # We happen to know that certP1.ss has policy letters "AB" and - # certP2.ss has policy letters "BC". However, because certP2.ss - # has certP1.ss as issuer, when it's used, both their policy - # letters get combined into just "B". - # The policy letter(s) then get filtered with the given auth letter - # in the table below, and the result gets tested with the given - # condition. For details, read ssltest_old.c - # - # certfilename => [ [ auth, cond, expected result ] ... ] - my %expected = ( "certP1.ss" => [ [ [ 'A', 'A' ], 1 ], - [ [ 'A', 'B' ], 0 ], - [ [ 'A', 'C' ], 0 ], - [ [ 'A', 'A|B&!C' ], 1 ], - [ [ 'B', 'A' ], 0 ], - [ [ 'B', 'B' ], 1 ], - [ [ 'B', 'C' ], 0 ], - [ [ 'B', 'A|B&!C' ], 1 ], - [ [ 'C', 'A' ], 0 ], - [ [ 'C', 'B' ], 0 ], - [ [ 'C', 'C' ], 0 ], - [ [ 'C', 'A|B&!C' ], 0 ], - [ [ 'BC', 'A' ], 0 ], - [ [ 'BC', 'B' ], 1 ], - [ [ 'BC', 'C' ], 0 ], - [ [ 'BC', 'A|B&!C' ], 1 ] ], - "certP2.ss" => [ [ [ 'A', 'A' ], 0 ], - [ [ 'A', 'B' ], 0 ], - [ [ 'A', 'C' ], 0 ], - [ [ 'A', 'A|B&!C' ], 0 ], - [ [ 'B', 'A' ], 0 ], - [ [ 'B', 'B' ], 1 ], - [ [ 'B', 'C' ], 0 ], - [ [ 'B', 'A|B&!C' ], 1 ], - [ [ 'C', 'A' ], 0 ], - [ [ 'C', 'B' ], 0 ], - [ [ 'C', 'C' ], 0 ], - [ [ 'C', 'A|B&!C' ], 0 ], - [ [ 'BC', 'A' ], 0 ], - [ [ 'BC', 'B' ], 1 ], - [ [ 'BC', 'C' ], 0 ], - [ [ 'BC', 'A|B&!C' ], 1 ] ] ); - - SKIP: { - skip "Neither SSLv3 nor any TLS version are supported by this OpenSSL build", scalar(@{$expected{$cert}}) - if $no_anytls; - - foreach (@{$expected{$cert}}) { - my $auth = $_->[0]->[0]; - my $cond = $_->[0]->[1]; - my $res = $_->[1]; - is(run(test([@ssltest, "-server_auth", @CA, - "-proxy", "-proxy_auth", $auth, - "-proxy_cond", $cond])), $res, - "test tlsv1, server auth, proxy auth $auth and cond $cond (expect " - .($res ? "success" : "failure").")"); - } - } -} diff --git a/test/ssl-tests/03-custom_verify.conf b/test/ssl-tests/03-custom_verify.conf new file mode 100644 index 0000000000000000000000000000000000000000..182a95d12402ac18d956599220c8cb7106bde989 --- /dev/null +++ b/test/ssl-tests/03-custom_verify.conf @@ -0,0 +1,238 @@ +# Generated with generate_ssl_tests.pl + +num_tests = 9 + +test-0 = 0-verify-success +test-1 = 1-verify-custom-reject +test-2 = 2-verify-custom-allow +test-3 = 3-noverify-success +test-4 = 4-noverify-ignore-custom-reject +test-5 = 5-noverify-accept-custom-allow +test-6 = 6-verify-fail-no-root +test-7 = 7-verify-custom-success-no-root +test-8 = 8-verify-custom-fail-no-root +# =========================================================== + +[0-verify-success] +ssl_conf = 0-verify-success-ssl + +[0-verify-success-ssl] +server = 0-verify-success-server +client = 0-verify-success-client + +[0-verify-success-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + + +[0-verify-success-client] +CipherString = DEFAULT +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + + +[test-0] +ExpectedResult = Success + + +# =========================================================== + +[1-verify-custom-reject] +ssl_conf = 1-verify-custom-reject-ssl + +[1-verify-custom-reject-ssl] +server = 1-verify-custom-reject-server +client = 1-verify-custom-reject-client + +[1-verify-custom-reject-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + + +[1-verify-custom-reject-client] +CipherString = DEFAULT +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + + +[test-1] +ClientAlert = HandshakeFailure +ClientVerifyCallback = RejectAll +ExpectedResult = ClientFail + + +# =========================================================== + +[2-verify-custom-allow] +ssl_conf = 2-verify-custom-allow-ssl + +[2-verify-custom-allow-ssl] +server = 2-verify-custom-allow-server +client = 2-verify-custom-allow-client + +[2-verify-custom-allow-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + + +[2-verify-custom-allow-client] +CipherString = DEFAULT +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + + +[test-2] +ClientVerifyCallback = AcceptAll +ExpectedResult = Success + + +# =========================================================== + +[3-noverify-success] +ssl_conf = 3-noverify-success-ssl + +[3-noverify-success-ssl] +server = 3-noverify-success-server +client = 3-noverify-success-client + +[3-noverify-success-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + + +[3-noverify-success-client] +CipherString = DEFAULT + + +[test-3] +ExpectedResult = Success + + +# =========================================================== + +[4-noverify-ignore-custom-reject] +ssl_conf = 4-noverify-ignore-custom-reject-ssl + +[4-noverify-ignore-custom-reject-ssl] +server = 4-noverify-ignore-custom-reject-server +client = 4-noverify-ignore-custom-reject-client + +[4-noverify-ignore-custom-reject-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + + +[4-noverify-ignore-custom-reject-client] +CipherString = DEFAULT + + +[test-4] +ClientVerifyCallback = RejectAll +ExpectedResult = Success + + +# =========================================================== + +[5-noverify-accept-custom-allow] +ssl_conf = 5-noverify-accept-custom-allow-ssl + +[5-noverify-accept-custom-allow-ssl] +server = 5-noverify-accept-custom-allow-server +client = 5-noverify-accept-custom-allow-client + +[5-noverify-accept-custom-allow-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + + +[5-noverify-accept-custom-allow-client] +CipherString = DEFAULT + + +[test-5] +ClientVerifyCallback = AcceptAll +ExpectedResult = Success + + +# =========================================================== + +[6-verify-fail-no-root] +ssl_conf = 6-verify-fail-no-root-ssl + +[6-verify-fail-no-root-ssl] +server = 6-verify-fail-no-root-server +client = 6-verify-fail-no-root-client + +[6-verify-fail-no-root-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + + +[6-verify-fail-no-root-client] +CipherString = DEFAULT +VerifyMode = Peer + + +[test-6] +ClientAlert = UnknownCA +ExpectedResult = ClientFail + + +# =========================================================== + +[7-verify-custom-success-no-root] +ssl_conf = 7-verify-custom-success-no-root-ssl + +[7-verify-custom-success-no-root-ssl] +server = 7-verify-custom-success-no-root-server +client = 7-verify-custom-success-no-root-client + +[7-verify-custom-success-no-root-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + + +[7-verify-custom-success-no-root-client] +CipherString = DEFAULT +VerifyMode = Peer + + +[test-7] +ClientVerifyCallback = AcceptAll +ExpectedResult = Success + + +# =========================================================== + +[8-verify-custom-fail-no-root] +ssl_conf = 8-verify-custom-fail-no-root-ssl + +[8-verify-custom-fail-no-root-ssl] +server = 8-verify-custom-fail-no-root-server +client = 8-verify-custom-fail-no-root-client + +[8-verify-custom-fail-no-root-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + + +[8-verify-custom-fail-no-root-client] +CipherString = DEFAULT +VerifyMode = Peer + + +[test-8] +ClientAlert = HandshakeFailure +ClientVerifyCallback = RejectAll +ExpectedResult = ClientFail + + diff --git a/test/ssl-tests/03-custom_verify.conf.in b/test/ssl-tests/03-custom_verify.conf.in new file mode 100644 index 0000000000000000000000000000000000000000..e2f9dc7277ea2129c5810a28cc3f2f840afad035 --- /dev/null +++ b/test/ssl-tests/03-custom_verify.conf.in @@ -0,0 +1,127 @@ +# -*- mode: perl; -*- + +## SSL test configurations + +package ssltests; + +our @tests = ( + + # Sanity-check that verification indeed succeeds without the + # restrictive callback. + { + name => "verify-success", + server => { }, + client => { }, + test => { "ExpectedResult" => "Success" }, + }, + + # Same test as above but with a custom callback that always fails. + { + name => "verify-custom-reject", + server => { }, + client => { }, + test => { + "ClientVerifyCallback" => "RejectAll", + "ExpectedResult" => "ClientFail", + "ClientAlert" => "HandshakeFailure", + }, + }, + + # Same test as above but with a custom callback that always succeeds. + { + name => "verify-custom-allow", + server => { }, + client => { }, + test => { + "ClientVerifyCallback" => "AcceptAll", + "ExpectedResult" => "Success", + }, + }, + + # Sanity-check that verification indeed succeeds if peer verification + # is not requested. + { + name => "noverify-success", + server => { }, + client => { + "VerifyMode" => undef, + "VerifyCAFile" => undef, + }, + test => { "ExpectedResult" => "Success" }, + }, + + # Same test as above but with a custom callback that always fails. + # The callback return has no impact on handshake success in this mode. + { + name => "noverify-ignore-custom-reject", + server => { }, + client => { + "VerifyMode" => undef, + "VerifyCAFile" => undef, + }, + test => { + "ClientVerifyCallback" => "RejectAll", + "ExpectedResult" => "Success", + }, + }, + + # Same test as above but with a custom callback that always succeeds. + # The callback return has no impact on handshake success in this mode. + { + name => "noverify-accept-custom-allow", + server => { }, + client => { + "VerifyMode" => undef, + "VerifyCAFile" => undef, + }, + test => { + "ClientVerifyCallback" => "AcceptAll", + "ExpectedResult" => "Success", + }, + }, + + # Sanity-check that verification indeed fails without the + # permissive callback. + { + name => "verify-fail-no-root", + server => { }, + client => { + # Don't set up the client root file. + "VerifyCAFile" => undef, + }, + test => { + "ExpectedResult" => "ClientFail", + "ClientAlert" => "UnknownCA", + }, + }, + + # Same test as above but with a custom callback that always succeeds. + { + name => "verify-custom-success-no-root", + server => { }, + client => { + "VerifyCAFile" => undef, + }, + test => { + "ClientVerifyCallback" => "AcceptAll", + "ExpectedResult" => "Success" + }, + }, + + # Same test as above but with a custom callback that always fails. + { + name => "verify-custom-fail-no-root", + server => { }, + client => { + "VerifyCAFile" => undef, + }, + test => { + "ClientVerifyCallback" => "RejectAll", + "ExpectedResult" => "ClientFail", + "ClientAlert" => "HandshakeFailure", + }, + }, + + + +); diff --git a/test/ssl_test.c b/test/ssl_test.c index dfe71cbc5614547f85bdc14554ec16313098dfd9..b3faffc99914d83b3451bf2164841dad642366e2 100644 --- a/test/ssl_test.c +++ b/test/ssl_test.c @@ -44,8 +44,8 @@ static int check_result(HANDSHAKE_RESULT result, SSL_TEST_CTX *test_ctx) { if (result.result != test_ctx->expected_result) { fprintf(stderr, "ExpectedResult mismatch: expected %s, got %s.\n", - ssl_test_result_t_name(test_ctx->expected_result), - ssl_test_result_t_name(result.result)); + ssl_test_result_name(test_ctx->expected_result), + ssl_test_result_name(result.result)); return 0; } return 1; @@ -160,7 +160,7 @@ static int execute_test(SSL_TEST_FIXTURE fixture) if (test_ctx == NULL) goto err; - result = do_handshake(server_ctx, client_ctx); + result = do_handshake(server_ctx, client_ctx, test_ctx); ret = check_test(result, test_ctx); diff --git a/test/ssl_test_ctx.c b/test/ssl_test_ctx.c index 0c1bbbde9e87d3becead878872e51a298b349c5b..5db7bd45ce2bdfe599e36435e6886d988821c5c1 100644 --- a/test/ssl_test_ctx.c +++ b/test/ssl_test_ctx.c @@ -71,7 +71,7 @@ __owur static int parse_expected_result(SSL_TEST_CTX *test_ctx, const char *valu return 1; } -const char *ssl_test_result_t_name(ssl_test_result_t result) +const char *ssl_test_result_name(ssl_test_result_t result) { return enum_name(ssl_test_results, OSSL_NELEM(ssl_test_results), result); } @@ -82,6 +82,7 @@ const char *ssl_test_result_t_name(ssl_test_result_t result) static const test_enum ssl_alerts[] = { {"UnknownCA", SSL_AD_UNKNOWN_CA}, + {"HandshakeFailure", SSL_AD_HANDSHAKE_FAILURE}, }; __owur static int parse_alert(int *alert, const char *value) @@ -126,6 +127,34 @@ const char *ssl_protocol_name(int protocol) return enum_name(ssl_protocols, OSSL_NELEM(ssl_protocols), protocol); } +/***********************/ +/* CertVerifyCallback. */ +/***********************/ + +static const test_enum ssl_verify_callbacks[] = { + {"None", SSL_TEST_VERIFY_NONE}, + {"AcceptAll", SSL_TEST_VERIFY_ACCEPT_ALL}, + {"RejectAll", SSL_TEST_VERIFY_REJECT_ALL}, +}; + +__owur static int parse_client_verify_callback(SSL_TEST_CTX *test_ctx, + const char *value) +{ + int ret_value; + if (!parse_enum(ssl_verify_callbacks, OSSL_NELEM(ssl_verify_callbacks), + &ret_value, value)) { + return 0; + } + test_ctx->client_verify_callback = ret_value; + return 1; +} + +const char *ssl_verify_callback_name(ssl_verify_callback_t callback) +{ + return enum_name(ssl_verify_callbacks, OSSL_NELEM(ssl_verify_callbacks), + callback); +} + /*************************************************************/ /* Known test options and their corresponding parse methods. */ @@ -141,6 +170,7 @@ static const ssl_test_ctx_option ssl_test_ctx_options[] = { { "ClientAlert", &parse_client_alert }, { "ServerAlert", &parse_server_alert }, { "Protocol", &parse_protocol }, + { "ClientVerifyCallback", &parse_client_verify_callback }, }; @@ -153,7 +183,6 @@ SSL_TEST_CTX *SSL_TEST_CTX_new() SSL_TEST_CTX *ret; ret = OPENSSL_zalloc(sizeof(*ret)); OPENSSL_assert(ret != NULL); - ret->expected_result = SSL_TEST_SUCCESS; return ret; } diff --git a/test/ssl_test_ctx.h b/test/ssl_test_ctx.h index a183272b4e3a8f1e5f7a7a0a75f81aab966d2c66..9aaa4cea505473bb6cf65900fb831b8a6d776421 100644 --- a/test/ssl_test_ctx.h +++ b/test/ssl_test_ctx.h @@ -15,12 +15,18 @@ #include typedef enum { - SSL_TEST_SUCCESS, /* Default */ + SSL_TEST_SUCCESS = 0, /* Default */ SSL_TEST_SERVER_FAIL, SSL_TEST_CLIENT_FAIL, SSL_TEST_INTERNAL_ERROR } ssl_test_result_t; +typedef enum { + SSL_TEST_VERIFY_NONE = 0, /* Default */ + SSL_TEST_VERIFY_ACCEPT_ALL, + SSL_TEST_VERIFY_REJECT_ALL +} ssl_verify_callback_t; + typedef struct ssl_test_ctx { /* Test expectations. */ /* Defaults to SUCCESS. */ @@ -34,11 +40,14 @@ typedef struct ssl_test_ctx { /* Negotiated protocol version. 0 if no expectation. */ /* See ssl.h for protocol versions. */ int protocol; + /* One of a number of predefined custom callbacks. */ + ssl_verify_callback_t client_verify_callback; } SSL_TEST_CTX; -const char *ssl_test_result_t_name(ssl_test_result_t result); +const char *ssl_test_result_name(ssl_test_result_t result); const char *ssl_alert_name(int alert); const char *ssl_protocol_name(int protocol); +const char *ssl_verify_callback_name(ssl_verify_callback_t verify_callback); /* * Load the test case context from |conf|. diff --git a/test/ssl_test_ctx_test.c b/test/ssl_test_ctx_test.c index 3c6fa715f2fb68e9bc03b5c0e5b2bb820972fcc2..792f5e811fdbcb6c9fe0d51293127242291f3400 100644 --- a/test/ssl_test_ctx_test.c +++ b/test/ssl_test_ctx_test.c @@ -37,26 +37,32 @@ static int SSL_TEST_CTX_equal(SSL_TEST_CTX *ctx, SSL_TEST_CTX *ctx2) { if (ctx->expected_result != ctx2->expected_result) { fprintf(stderr, "ExpectedResult mismatch: %s vs %s.\n", - ssl_test_result_t_name(ctx->expected_result), - ssl_test_result_t_name(ctx2->expected_result)); + ssl_test_result_name(ctx->expected_result), + ssl_test_result_name(ctx2->expected_result)); return 0; } if (ctx->client_alert != ctx2->client_alert) { fprintf(stderr, "ClientAlert mismatch: %s vs %s.\n", - ssl_alert_name(ctx->expected_result), - ssl_alert_name(ctx2->expected_result)); + ssl_alert_name(ctx->client_alert), + ssl_alert_name(ctx2->client_alert)); return 0; } if (ctx->server_alert != ctx2->server_alert) { fprintf(stderr, "ServerAlert mismatch: %s vs %s.\n", - ssl_alert_name(ctx->expected_result), - ssl_alert_name(ctx2->expected_result)); + ssl_alert_name(ctx->server_alert), + ssl_alert_name(ctx2->server_alert)); return 0; } if (ctx->protocol != ctx2->protocol) { fprintf(stderr, "ClientAlert mismatch: %s vs %s.\n", - ssl_protocol_name(ctx->expected_result), - ssl_protocol_name(ctx2->expected_result)); + ssl_protocol_name(ctx->protocol), + ssl_protocol_name(ctx2->protocol)); + return 0; + } + if (ctx->client_verify_callback != ctx2->client_verify_callback) { + fprintf(stderr, "ClientVerifyCallback mismatch: %s vs %s.\n", + ssl_verify_callback_name(ctx->client_verify_callback), + ssl_verify_callback_name(ctx2->client_verify_callback)); return 0; } @@ -136,6 +142,7 @@ static int test_good_configuration() fixture.expected_ctx->client_alert = SSL_AD_UNKNOWN_CA; fixture.expected_ctx->server_alert = 0; /* No alert. */ fixture.expected_ctx->protocol = TLS1_1_VERSION; + fixture.expected_ctx->client_verify_callback = SSL_TEST_VERIFY_REJECT_ALL, EXECUTE_SSL_TEST_CTX_TEST(); } @@ -144,6 +151,7 @@ static const char *bad_configurations[] = { "ssltest_unknown_expected_result", "ssltest_unknown_alert", "ssltest_unknown_protocol", + "ssltest_unknown_verify_callback", }; static int test_bad_configuration(int idx) diff --git a/test/ssl_test_ctx_test.conf b/test/ssl_test_ctx_test.conf index 2e6800e90d2de43b0aa74c0ff8b4947f0f9b9af8..3b146052c1e2e8f0e4e44fb92f6e3098fc29276e 100644 --- a/test/ssl_test_ctx_test.conf +++ b/test/ssl_test_ctx_test.conf @@ -4,6 +4,7 @@ ExpectedResult = ServerFail ClientAlert = UnknownCA Protocol = TLSv1.1 +ClientVerifyCallback = RejectAll [ssltest_unknown_option] UnknownOption = Foo @@ -16,3 +17,6 @@ ServerAlert = Foo [ssltest_unknown_protocol] Protocol = Foo + +[ssltest_unknown_verify_callback] +ClientVerifyCallback = Foo diff --git a/test/ssltest_old.c b/test/ssltest_old.c index c7f3e1872d2dfa4cfbaede8614c3dab003b25e99..eb35c1d6c0803779a65788d87e931052ae313880 100644 --- a/test/ssltest_old.c +++ b/test/ssltest_old.c @@ -223,9 +223,6 @@ static int app_verify_callback(X509_STORE_CTX *ctx, void *arg); struct app_verify_arg { char *string; int app_verify; - int allow_proxy_certs; - char *proxy_auth; - char *proxy_cond; }; #ifndef OPENSSL_NO_DH @@ -809,10 +806,6 @@ static void sv_usage(void) #endif fprintf(stderr, " -server_auth - check server certificate\n"); fprintf(stderr, " -client_auth - do client authentication\n"); - fprintf(stderr, " -proxy - allow proxy certificates\n"); - fprintf(stderr, " -proxy_auth - set proxy policy rights\n"); - fprintf(stderr, - " -proxy_cond - expression to test proxy policy rights\n"); fprintf(stderr, " -v - more output\n"); fprintf(stderr, " -d - debug output\n"); fprintf(stderr, " -reuse - use session-id reuse\n"); @@ -1069,7 +1062,7 @@ int main(int argc, char *argv[]) int client_auth = 0; int server_auth = 0, i; struct app_verify_arg app_verify_arg = - { APP_CALLBACK_STRING, 0, 0, NULL, NULL }; + { APP_CALLBACK_STRING, 0 }; char *p; SSL_CTX *c_ctx = NULL; const SSL_METHOD *meth = NULL; @@ -1179,15 +1172,7 @@ int main(int argc, char *argv[]) server_auth = 1; else if (strcmp(*argv, "-client_auth") == 0) client_auth = 1; - else if (strcmp(*argv, "-proxy_auth") == 0) { - if (--argc < 1) - goto bad; - app_verify_arg.proxy_auth = *(++argv); - } else if (strcmp(*argv, "-proxy_cond") == 0) { - if (--argc < 1) - goto bad; - app_verify_arg.proxy_cond = *(++argv); - } else if (strcmp(*argv, "-v") == 0) + else if (strcmp(*argv, "-v") == 0) verbose = 1; else if (strcmp(*argv, "-d") == 0) debug = 1; @@ -1307,8 +1292,6 @@ int main(int argc, char *argv[]) #endif else if (strcmp(*argv, "-app_verify") == 0) { app_verify_arg.app_verify = 1; - } else if (strcmp(*argv, "-proxy") == 0) { - app_verify_arg.allow_proxy_certs = 1; } #ifndef OPENSSL_NO_NEXTPROTONEG else if (strcmp(*argv, "-npn_client") == 0) { @@ -3027,23 +3010,6 @@ int doit(SSL *s_ssl, SSL *c_ssl, long count) return (ret); } -static CRYPTO_ONCE proxy_auth_ex_data_once = CRYPTO_ONCE_STATIC_INIT; -static volatile int proxy_auth_ex_data_idx = -1; - -static void do_get_proxy_auth_ex_data_idx(void) -{ - proxy_auth_ex_data_idx = X509_STORE_CTX_get_ex_new_index(0, - "SSLtest for verify callback", - NULL, NULL, NULL); -} - -static int get_proxy_auth_ex_data_idx(void) -{ - CRYPTO_THREAD_run_once(&proxy_auth_ex_data_once, - do_get_proxy_auth_ex_data_idx); - return proxy_auth_ex_data_idx; -} - static int verify_callback(int ok, X509_STORE_CTX *ctx) { char *s, buf[256]; @@ -3076,341 +3042,13 @@ static int verify_callback(int ok, X509_STORE_CTX *ctx) } } - if (ok == 1) { - X509 *xs = X509_STORE_CTX_get_current_cert(ctx); - if (X509_get_extension_flags(xs) & EXFLAG_PROXY) { - unsigned int *letters = X509_STORE_CTX_get_ex_data(ctx, - get_proxy_auth_ex_data_idx - ()); - - if (letters) { - int found_any = 0; - int i; - PROXY_CERT_INFO_EXTENSION *pci = - X509_get_ext_d2i(xs, NID_proxyCertInfo, - NULL, NULL); - - switch (OBJ_obj2nid(pci->proxyPolicy->policyLanguage)) { - case NID_Independent: - /* - * Completely meaningless in this program, as there's no - * way to grant explicit rights to a specific PrC. - * Basically, using id-ppl-Independent is the perfect way - * to grant no rights at all. - */ - fprintf(stderr, " Independent proxy certificate"); - for (i = 0; i < 26; i++) - letters[i] = 0; - break; - case NID_id_ppl_inheritAll: - /* - * This is basically a NOP, we simply let the current - * rights stand as they are. - */ - fprintf(stderr, " Proxy certificate inherits all"); - break; - default: - s = (char *) - pci->proxyPolicy->policy->data; - i = pci->proxyPolicy->policy->length; - - /* - * The algorithm works as follows: it is assumed that - * previous iterations or the initial granted rights has - * already set some elements of `letters'. What we need - * to do is to clear those that weren't granted by the - * current PrC as well. The easiest way to do this is to - * add 1 to all the elements whose letters are given with - * the current policy. That way, all elements that are - * set by the current policy and were already set by - * earlier policies and through the original grant of - * rights will get the value 2 or higher. The last thing - * to do is to sweep through `letters' and keep the - * elements having the value 2 as set, and clear all the - * others. - */ - - printf(" Certificate proxy rights = %*.*s", i, - i, s); - while (i-- > 0) { - int c = *s++; - if (isascii(c) && isalpha(c)) { - if (islower(c)) - c = toupper(c); - letters[c - 'A']++; - } - } - for (i = 0; i < 26; i++) - if (letters[i] < 2) - letters[i] = 0; - else - letters[i] = 1; - } - - found_any = 0; - printf(", resulting proxy rights = "); - for (i = 0; i < 26; i++) - if (letters[i]) { - printf("%c", i + 'A'); - found_any = 1; - } - if (!found_any) - printf("none"); - printf("\n"); - - PROXY_CERT_INFO_EXTENSION_free(pci); - } - } - } - return (ok); } -static void process_proxy_debug(int indent, const char *format, ...) -{ - /* That's 80 > */ - static const char indentation[] = - ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" - ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"; - char my_format[256]; - va_list args; - - BIO_snprintf(my_format, sizeof(my_format), "%*.*s %s", - indent, indent, indentation, format); - - va_start(args, format); - vfprintf(stderr, my_format, args); - va_end(args); -} - -/*- - * Priority levels: - * 0 [!]var, () - * 1 & ^ - * 2 | - */ -static int process_proxy_cond_adders(unsigned int letters[26], - const char *cond, const char **cond_end, - int *pos, int indent); -static int process_proxy_cond_val(unsigned int letters[26], const char *cond, - const char **cond_end, int *pos, int indent) -{ - int c; - int ok = 1; - int negate = 0; - - while (isspace((int)*cond)) { - cond++; - (*pos)++; - } - c = *cond; - - if (debug) - process_proxy_debug(indent, - "Start process_proxy_cond_val at position %d: %s\n", - *pos, cond); - - while (c == '!') { - negate = !negate; - cond++; - (*pos)++; - while (isspace((int)*cond)) { - cond++; - (*pos)++; - } - c = *cond; - } - - if (c == '(') { - cond++; - (*pos)++; - ok = process_proxy_cond_adders(letters, cond, cond_end, pos, - indent + 1); - cond = *cond_end; - if (ok < 0) - goto end; - while (isspace((int)*cond)) { - cond++; - (*pos)++; - } - c = *cond; - if (c != ')') { - fprintf(stderr, - "Weird condition character in position %d: " - "%c\n", *pos, c); - ok = -1; - goto end; - } - cond++; - (*pos)++; - } else if (isascii(c) && isalpha(c)) { - if (islower(c)) - c = toupper(c); - ok = letters[c - 'A']; - cond++; - (*pos)++; - } else { - fprintf(stderr, - "Weird condition character in position %d: " "%c\n", *pos, c); - ok = -1; - goto end; - } - end: - *cond_end = cond; - if (ok >= 0 && negate) - ok = !ok; - - if (debug) - process_proxy_debug(indent, - "End process_proxy_cond_val at position %d: %s, returning %d\n", - *pos, cond, ok); - - return ok; -} - -static int process_proxy_cond_multipliers(unsigned int letters[26], - const char *cond, - const char **cond_end, int *pos, - int indent) -{ - int ok; - char c; - - if (debug) - process_proxy_debug(indent, - "Start process_proxy_cond_multipliers at position %d: %s\n", - *pos, cond); - - ok = process_proxy_cond_val(letters, cond, cond_end, pos, indent + 1); - cond = *cond_end; - if (ok < 0) - goto end; - - while (ok >= 0) { - while (isspace((int)*cond)) { - cond++; - (*pos)++; - } - c = *cond; - - switch (c) { - case '&': - case '^': - { - int save_ok = ok; - - cond++; - (*pos)++; - ok = process_proxy_cond_val(letters, - cond, cond_end, pos, indent + 1); - cond = *cond_end; - if (ok < 0) - break; - - switch (c) { - case '&': - ok &= save_ok; - break; - case '^': - ok ^= save_ok; - break; - default: - fprintf(stderr, "SOMETHING IS SERIOUSLY WRONG!" - " STOPPING\n"); - EXIT(1); - } - } - break; - default: - goto end; - } - } - end: - if (debug) - process_proxy_debug(indent, - "End process_proxy_cond_multipliers at position %d: %s, returning %d\n", - *pos, cond, ok); - - *cond_end = cond; - return ok; -} - -static int process_proxy_cond_adders(unsigned int letters[26], - const char *cond, const char **cond_end, - int *pos, int indent) -{ - int ok; - char c; - - if (debug) - process_proxy_debug(indent, - "Start process_proxy_cond_adders at position %d: %s\n", - *pos, cond); - - ok = process_proxy_cond_multipliers(letters, cond, cond_end, pos, - indent + 1); - cond = *cond_end; - if (ok < 0) - goto end; - - while (ok >= 0) { - while (isspace((int)*cond)) { - cond++; - (*pos)++; - } - c = *cond; - - switch (c) { - case '|': - { - int save_ok = ok; - - cond++; - (*pos)++; - ok = process_proxy_cond_multipliers(letters, - cond, cond_end, pos, - indent + 1); - cond = *cond_end; - if (ok < 0) - break; - - switch (c) { - case '|': - ok |= save_ok; - break; - default: - fprintf(stderr, "SOMETHING IS SERIOUSLY WRONG!" - " STOPPING\n"); - EXIT(1); - } - } - break; - default: - goto end; - } - } - end: - if (debug) - process_proxy_debug(indent, - "End process_proxy_cond_adders at position %d: %s, returning %d\n", - *pos, cond, ok); - - *cond_end = cond; - return ok; -} - -static int process_proxy_cond(unsigned int letters[26], - const char *cond, const char **cond_end) -{ - int pos = 1; - return process_proxy_cond_adders(letters, cond, cond_end, &pos, 1); -} - static int app_verify_callback(X509_STORE_CTX *ctx, void *arg) { int ok = 1; struct app_verify_arg *cb_arg = arg; - unsigned int letters[26]; /* only used with proxy_auth */ if (cb_arg->app_verify) { char *s = NULL, buf[256]; @@ -3428,61 +3066,9 @@ static int app_verify_callback(X509_STORE_CTX *ctx, void *arg) } return (1); } - if (cb_arg->proxy_auth) { - int found_any = 0, i; - char *sp; - - for (i = 0; i < 26; i++) - letters[i] = 0; - for (sp = cb_arg->proxy_auth; *sp; sp++) { - int c = *sp; - if (isascii(c) && isalpha(c)) { - if (islower(c)) - c = toupper(c); - letters[c - 'A'] = 1; - } - } - printf(" Initial proxy rights = "); - for (i = 0; i < 26; i++) - if (letters[i]) { - printf("%c", i + 'A'); - found_any = 1; - } - if (!found_any) - printf("none"); - printf("\n"); - - X509_STORE_CTX_set_ex_data(ctx, - get_proxy_auth_ex_data_idx(), letters); - } - if (cb_arg->allow_proxy_certs) { - X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS); - } ok = X509_verify_cert(ctx); - if (cb_arg->proxy_auth) { - if (ok > 0) { - const char *cond_end = NULL; - - ok = process_proxy_cond(letters, cb_arg->proxy_cond, &cond_end); - - if (ok < 0) - EXIT(3); - if (*cond_end) { - fprintf(stderr, - "Stopped processing condition before it's end.\n"); - ok = 0; - } - if (!ok) - fprintf(stderr, - "Proxy rights check with condition '%s' invalid\n", - cb_arg->proxy_cond); - else - printf("Proxy rights check with condition '%s' ok\n", - cb_arg->proxy_cond); - } - } return (ok); }