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 <rsalz@openssl.org>
This commit is contained in:
Emilia Kasper 2016-04-07 19:07:50 +02:00
parent d82c27589b
commit a263f320eb
13 changed files with 479 additions and 519 deletions

View file

@ -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`

View file

@ -11,6 +11,7 @@
#include <string.h>
#include <openssl/bio.h>
#include <openssl/x509_vfy.h>
#include <openssl/ssl.h>
#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);

View file

@ -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 */

View file

@ -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;

View file

@ -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").")");
}
}
}

View file

@ -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

View file

@ -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",
},
},
);

View file

@ -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);

View file

@ -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;
}

View file

@ -15,12 +15,18 @@
#include <openssl/ssl.h>
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|.

View file

@ -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)

View file

@ -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

View file

@ -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 <val> - set proxy policy rights\n");
fprintf(stderr,
" -proxy_cond <val> - 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);
}