From a263f320ebdb32ccc058ef02a617edbfe4a63e7f Mon Sep 17 00:00:00 2001 From: Emilia Kasper Date: Thu, 7 Apr 2016 19:07:50 +0200 Subject: [PATCH] Remove proxy tests. Add verify callback tests. The old proxy tests test the implementation of an application proxy policy callback defined in the test itself, which is not particularly useful. It is, however, useful to test cert verify overrides in general. Therefore, replace these tests with tests for cert verify callback behaviour. Also glob the ssl test inputs on the .in files to catch missing generated files. Reviewed-by: Rich Salz --- test/README.ssltest.md | 5 + test/handshake_helper.c | 37 ++- test/handshake_helper.h | 3 +- test/recipes/80-test_ssl_new.t | 7 +- test/recipes/80-test_ssl_old.t | 83 ----- test/ssl-tests/03-custom_verify.conf | 238 ++++++++++++++ test/ssl-tests/03-custom_verify.conf.in | 127 +++++++ test/ssl_test.c | 6 +- test/ssl_test_ctx.c | 33 +- test/ssl_test_ctx.h | 13 +- test/ssl_test_ctx_test.c | 24 +- test/ssl_test_ctx_test.conf | 4 + test/ssltest_old.c | 418 +----------------------- 13 files changed, 479 insertions(+), 519 deletions(-) create mode 100644 test/ssl-tests/03-custom_verify.conf create mode 100644 test/ssl-tests/03-custom_verify.conf.in diff --git a/test/README.ssltest.md b/test/README.ssltest.md index b65a0d73ac..2957d85d99 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 4682d45bfb..0a27324899 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 56dfb197e2..5f1ca04ee1 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 a0183585cb..57def45072 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 61fc423424..37635308ea 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 0000000000..182a95d124 --- /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 0000000000..e2f9dc7277 --- /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 dfe71cbc56..b3faffc999 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 0c1bbbde9e..5db7bd45ce 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 a183272b4e..9aaa4cea50 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 3c6fa715f2..792f5e811f 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 2e6800e90d..3b146052c1 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 c7f3e1872d..eb35c1d6c0 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); } -- 2.25.1