summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorEmilia Kasper <emilia@openssl.org>2016-03-17 15:14:30 +0100
committerEmilia Kasper <emilia@openssl.org>2016-04-05 13:44:46 +0200
commit453dfd8d5ee0893146e0fb61a5978ab59ba95c01 (patch)
tree6ada91599f4ebe125be3d34a69716b23a0688b05 /test
parent173f613b6a9029f34454b642ee4f3db6c6566fcb (diff)
New SSL test framework
Currently, SSL tests are configured via command-line switches to ssltest.c. This results in a lot of duplication between ssltest.c and apps, and a complex setup. ssltest.c is also simply old and needs maintenance. Instead, we already have a way to configure SSL servers and clients, so we leverage that. SSL tests can now be configured from a configuration file. Test servers and clients are configured using the standard ssl_conf module. Additional test settings are configured via a test configuration. Moreover, since the CONF language involves unnecessary boilerplate, the test conf itself is generated from a shorter Perl syntax. The generated testcase files are checked in to the repo to make it easier to verify that the intended test cases are in fact run; and to simplify debugging failures. To demonstrate the approach, min/max protocol tests are converted to the new format. This change also fixes MinProtocol and MaxProtocol handling. It was previously requested that an SSL_CTX have both the server and client flags set for these commands; this clearly can never work. Guide to this PR: - test/ssl_test.c - test framework - test/ssl_test_ctx.* - test configuration structure - test/handshake_helper.* - new SSL test handshaking code - test/ssl-tests/ - test configurations - test/generate_ssl_tests.pl - script for generating CONF-style test configurations from perl inputs Reviewed-by: Richard Levitte <levitte@openssl.org>
Diffstat (limited to 'test')
-rw-r--r--test/Makefile.in26
-rw-r--r--test/README.ssltest.md139
-rw-r--r--test/build.info13
-rw-r--r--test/generate_ssl_tests.pl104
-rw-r--r--test/handshake_helper.c239
-rw-r--r--test/handshake_helper.h35
-rw-r--r--test/recipes/80-test_ssl.t54
-rw-r--r--test/recipes/80-test_ssl_new.t80
-rw-r--r--test/recipes/80-test_ssl_test_ctx.t12
-rw-r--r--test/ssl-tests/01-simple.conf56
-rw-r--r--test/ssl-tests/01-simple.conf.in27
-rw-r--r--test/ssl-tests/02-protocol-version.conf10697
-rw-r--r--test/ssl-tests/02-protocol-version.conf.in115
-rw-r--r--test/ssl-tests/ssltests_base.pm17
-rw-r--r--test/ssl_test.c217
-rw-r--r--test/ssl_test.tmpl27
-rw-r--r--test/ssl_test_ctx.c205
-rw-r--r--test/ssl_test_ctx.h53
-rw-r--r--test/ssl_test_ctx_test.c179
-rw-r--r--test/ssl_test_ctx_test.conf18
-rw-r--r--test/testutil.c49
-rw-r--r--test/testutil.h13
22 files changed, 12310 insertions, 65 deletions
diff --git a/test/Makefile.in b/test/Makefile.in
index ee66729f06..aadf2c7670 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -85,6 +85,8 @@ CTTEST= ct_test
THREADSTEST= threadstest
AFALGTEST= afalgtest
D2ITEST = d2i_test
+SSLTESTCTXTEST = ssl_test_ctx_test
+NEWSSLTEST = ssl_test
TESTS= alltests
@@ -107,7 +109,8 @@ EXE= $(NPTEST)$(EXE_EXT) $(MEMLEAKTEST)$(EXE_EXT) \
$(CONSTTIMETEST)$(EXE_EXT) $(VERIFYEXTRATEST)$(EXE_EXT) \
$(CLIENTHELLOTEST)$(EXE_EXT) $(PACKETTEST)$(EXE_EXT) $(ASYNCTEST)$(EXE_EXT) \
$(DTLSV1LISTENTEST)$(EXE_EXT) $(CTTEST)$(EXE_EXT) $(THREADSTEST)$(EXE_EXT) \
- $(AFALGTEST)$(EXE_EXT) $(D2ITEST)$(EXE_EXT)
+ $(AFALGTEST)$(EXE_EXT) $(D2ITEST)$(EXE_EXT) $(SSLTESTCTXTEST)$(EXE_EXT) \
+ $(NEWSSLTEST)$(EXE_EXT)
# $(METHTEST)$(EXE_EXT)
@@ -125,7 +128,8 @@ OBJ= $(NPTEST).o $(MEMLEAKTEST).o \
$(HEARTBEATTEST).o $(P5_CRPT2_TEST).o \
$(CONSTTIMETEST).o $(VERIFYEXTRATEST).o $(CLIENTHELLOTEST).o \
$(PACKETTEST).o $(ASYNCTEST).o $(DTLSV1LISTENTEST).o $(CTTEST).o \
- $(THREADSTEST).o testutil.o $(AFALGTEST).o $(D2ITEST).o
+ $(THREADSTEST).o testutil.o $(AFALGTEST).o $(D2ITEST).o ssl_test_ctx.o \
+ $(SSLTESTCTXTEST).o $(NEWSSLTEST).o handshake_helper.o
SRC= $(NPTEST).c $(MEMLEAKTEST).c \
$(BNTEST).c $(ECTEST).c \
@@ -140,9 +144,10 @@ SRC= $(NPTEST).c $(MEMLEAKTEST).c \
$(HEARTBEATTEST).c $(P5_CRPT2_TEST).c \
$(CONSTTIMETEST).c $(VERIFYEXTRATEST).c $(CLIENTHELLOTEST).c \
$(PACKETTEST).c $(ASYNCTEST).c $(DTLSV1LISTENTEST).c $(CTTEST).c \
- $(THREADSTEST).c testutil.c $(AFALGTEST).c $(D2ITEST).c
+ $(THREADSTEST).c testutil.c $(AFALGTEST).c $(D2ITEST).c ssl_test_ctx.c \
+ $(SSLTESTCTXTEST).c $(NEWSSLTEST).c handshake_helper.c
-HEADER= testutil.h
+HEADER= testutil.h ssl_test_ctx.h handshake_helper.h
ALL= $(GENERAL) $(SRC) $(HEADER)
@@ -389,4 +394,17 @@ $(AFALGTEST)$(EXE_EXT): $(AFALGTEST).o $(DLIBCRYPTO)
$(D2ITEST)$(EXE_EXT): $(D2ITEST).o $(DLIBCRYPTO) testutil.o
@target=$(D2ITEST) testutil=testutil.o; $(BUILD_CMD)
+$(SSLTESTCTXTEST)$(EXE_EXT): $(SSLTESTCTXTEST).o testutil.o $(DLIBCRYPTO)
+ @target=$(SSLTESTCTXTEST); $(BUILD_CMD)
+
+$(SSLTESTCTXTEST)$(EXE_EXT): $(SSLTESTCTXTEST).o testutil.o ssl_test_ctx.o \
+ $(DLIBCRYPTO)
+ @target=$(SSLTESTCTXTEST) testutil="testutil.o ssl_test_ctx.o"; \
+ $(BUILD_CMD)
+
+$(NEWSSLTEST)$(EXE_EXT): $(NEWSSLTEST).o testutil.o ssl_test_ctx.o \
+ handshake_helper.o $(DLIBSSL) $(DLIBCRYPTO)
+ @target=$(NEWSSLTEST) testutil="testutil.o ssl_test_ctx.o \
+ handshake_helper.o"; $(BUILD_CMD)
+
# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/test/README.ssltest.md b/test/README.ssltest.md
new file mode 100644
index 0000000000..b65a0d73ac
--- /dev/null
+++ b/test/README.ssltest.md
@@ -0,0 +1,139 @@
+# SSL tests
+
+SSL testcases are configured in the `ssl-tests` directory.
+
+Each `ssl_*.conf.in` file contains a number of test configurations. These files
+are used to generate testcases in the OpenSSL CONF format.
+
+The precise test output can be dependent on the library configuration. The test
+harness generates the output files on the fly.
+
+However, for verification, we also include checked-in configuration outputs
+corresponding to the default configuration. These testcases live in
+`test/ssl-tests/*.conf` files. Therefore, whenever you're adding or updating a
+generated test, you should run
+
+```
+$ ./config
+$ cd test
+$ TOP=.. perl -I testlib/ generate_ssl_tests.pl ssl-tests/my.conf.in \
+ > ssl-tests/my.conf
+```
+
+where `my.conf.in` is your test input file.
+
+For example, to generate the test cases in `ssl-tests/01-simple.conf.in`, do
+
+```
+$ TOP=.. perl generate_ssl_tests.pl ssl-tests/01-simple.conf.in > ssl-tests/01-simple.conf
+```
+
+For more details, see `ssl-tests/01-simple.conf.in` for an example.
+
+## Configuring the test
+
+First, give your test a name. The names do not have to be unique.
+
+An example test input looks like this:
+
+```
+ {
+ name => "test-default",
+ server => { "CipherString" => "DEFAULT" },
+ client => { "CipherString" => "DEFAULT" },
+ test => { "ExpectedResult" => "Success" },
+ }
+```
+
+The test section supports the following options:
+
+* ExpectedResult - expected handshake outcome. One of
+ - Success - handshake success
+ - ServerFail - serverside handshake failure
+ - ClientFail - clientside handshake failure
+ - InternalError - some other error
+
+* ClientAlert, ServerAlert - expected alert. See `ssl_test_ctx.c` for known
+ values.
+
+* Protocol - expected negotiated protocol. One of
+ SSLv3, TLSv1, TLSv1.1, TLSv1.2.
+
+## Configuring the client and server
+
+The client and server configurations can be any valid `SSL_CTX`
+configurations. For details, see the manpages for `SSL_CONF_cmd`.
+
+Give your configurations as a dictionary of CONF commands, e.g.
+
+```
+server => {
+ "CipherString" => "DEFAULT",
+ "MinProtocol" => "TLSv1",
+}
+```
+
+### Default server and client configurations
+
+The default server certificate and CA files are added to the configurations
+automatically. Server certificate verification is requested by default.
+
+You can override these options by redefining them:
+
+```
+client => {
+ "VerifyCAFile" => "/path/to/custom/file"
+}
+```
+
+or by deleting them
+
+```
+client => {
+ "VerifyCAFile" => undef
+}
+```
+
+## Adding a test to the test harness
+
+Add your configuration file to `test/recipes/80-test_ssl_new.t`.
+
+## Running the tests with the test harness
+
+```
+HARNESS_VERBOSE=yes make TESTS=test_ssl_new test
+```
+
+## Running a test manually
+
+These steps are only needed during development. End users should run `make test`
+or follow the instructions above to run the SSL test suite.
+
+To run an SSL test manually from the command line, the `TEST_CERTS_DIR`
+environment variable to point to the location of the certs. E.g., from the root
+OpenSSL directory, do
+
+```
+$ TEST_CERTS_DIR=test/certs test/ssl_test test/ssl-tests/01-simple.conf
+```
+
+or for shared builds
+
+```
+$ TEST_CERTS_DIR=test/certs util/shlib_wrap.sh test/ssl_test \
+ test/ssl-tests/01-simple.conf
+```
+
+Note that the test expectations sometimes depend on the Configure settings. For
+example, the negotiated protocol depends on the set of available (enabled)
+protocols: a build with `enable-ssl3` has different test expectations than a
+build with `no-ssl3`.
+
+The Perl test harness automatically generates expected outputs, so users who
+just run `make test` do not need any extra steps.
+
+However, when running a test manually, keep in mind that the repository version
+of the generated `test/ssl-tests/*.conf` correspond to expected outputs in with
+the default Configure options. To run `ssl_test` manually from the command line
+in a build with a different configuration, you may need to generate the right
+`*.conf` file from the `*.conf.in` input first.
diff --git a/test/build.info b/test/build.info
index 083412cba8..2bbf1ba631 100644
--- a/test/build.info
+++ b/test/build.info
@@ -14,7 +14,8 @@ PROGRAMS=\
danetest heartbeat_test p5_crpt2_test \
constant_time_test verify_extra_test clienthellotest \
packettest asynctest secmemtest srptest memleaktest \
- dtlsv1listentest ct_test threadstest afalgtest d2i_test
+ dtlsv1listentest ct_test threadstest afalgtest d2i_test \
+ ssl_test_ctx_test ssl_test
SOURCE[aborttest]=aborttest.c
INCLUDE[aborttest]={- rel2abs(catdir($builddir,"../include")) -} ../include
@@ -224,4 +225,14 @@ SOURCE[d2i_test]=d2i_test.c testutil.c
INCLUDE[d2i_test]={- rel2abs(catdir($builddir,"../include")) -} .. ../include
DEPEND[d2i_test]=../libcrypto
+SOURCE[ssl_test_ctx_test]=ssl_test_ctx_test.c ssl_test_ctx.c testutil.c
+INCLUDE[ssl_test_ctx_test]={- rel2abs(catdir($builddir,"../include")) -} .. ../include
+DEPEND[ssl_test_ctx_test]=../libcrypto
+
+SOURCE[ssl_test]=ssl_test.c ssl_test_ctx.c testutil.c handshake_helper.c
+INCLUDE[ssl_test]={- rel2abs(catdir($builddir,"../include")) -} .. ../include
+DEPEND[ssl_test]=../libcrypto ../libssl
+
INCLUDE[testutil.o]=..
+INCLUDE[ssl_test_ctx.o]={- rel2abs(catdir($builddir,"../include")) -} ../include
+INCLUDE[handshake_helper.o]={- rel2abs(catdir($builddir,"../include")) -} ../include
diff --git a/test/generate_ssl_tests.pl b/test/generate_ssl_tests.pl
new file mode 100644
index 0000000000..713fb3f7c2
--- /dev/null
+++ b/test/generate_ssl_tests.pl
@@ -0,0 +1,104 @@
+#! /usr/bin/perl
+# -*- mode: perl; -*-
+
+## SSL testcase generator
+
+use strict;
+use warnings;
+
+use File::Basename;
+use File::Spec::Functions;
+
+use OpenSSL::Test qw/srctop_dir srctop_file/;
+use OpenSSL::Test::Utils;
+
+# This block needs to run before 'use lib srctop_dir' directives.
+BEGIN {
+ OpenSSL::Test::setup("no_test_here");
+}
+
+use lib srctop_dir("util"); # for with_fallback
+use lib srctop_dir("test", "ssl-tests"); # for ssltests_base
+
+use with_fallback qw(Text::Template);
+
+use vars qw/@ISA/;
+push (@ISA, qw/Text::Template/);
+
+use ssltests_base;
+
+sub print_templates {
+ my $source = srctop_file("test", "ssl_test.tmpl");
+ my $template = Text::Template->new(TYPE => 'FILE', SOURCE => $source);
+
+ print "# Generated with generate_ssl_tests.pl\n\n";
+
+ my $num = scalar @ssltests::tests;
+
+ # Add the implicit base configuration.
+ foreach my $test (@ssltests::tests) {
+ $test->{"server"} = { (%ssltests::base_server, %{$test->{"server"}}) };
+ $test->{"client"} = { (%ssltests::base_client, %{$test->{"client"}}) };
+ }
+
+ # ssl_test expects to find a
+ #
+ # num_tests = n
+ #
+ # directive in the file. It'll then look for configuration directives
+ # for n tests, that each look like this:
+ #
+ # test-n = test-section
+ #
+ # [test-section]
+ # (SSL modules for client and server configuration go here.)
+ #
+ # [test-n]
+ # (Test configuration goes here.)
+ print "num_tests = $num\n\n";
+
+ # The conf module locations must come before everything else, because
+ # they look like
+ #
+ # test-n = test-section
+ #
+ # and you can't mix and match them with sections.
+ my $idx = 0;
+
+ foreach my $test (@ssltests::tests) {
+ my $testname = "${idx}-" . $test->{'name'};
+ print "test-$idx = $testname\n";
+ $idx++;
+ }
+
+ $idx = 0;
+
+ foreach my $test (@ssltests::tests) {
+ my $testname = "${idx}-" . $test->{'name'};
+ my $text = $template->fill_in(
+ HASH => [{ idx => $idx, testname => $testname } , $test],
+ DELIMITERS => [ "{-", "-}" ]);
+ print "# ===========================================================\n\n";
+ print "$text\n";
+ $idx++;
+ }
+}
+
+# Shamelessly copied from Configure.
+sub read_config {
+ my $fname = shift;
+ open(INPUT, "< $fname")
+ or die "Can't open input file '$fname'!\n";
+ local $/ = undef;
+ my $content = <INPUT>;
+ close(INPUT);
+ eval $content;
+ warn $@ if $@;
+}
+
+my $input_file = shift;
+# Reads the tests into ssltests::tests.
+read_config($input_file);
+print_templates();
+
+1;
diff --git a/test/handshake_helper.c b/test/handshake_helper.c
new file mode 100644
index 0000000000..4682d45bfb
--- /dev/null
+++ b/test/handshake_helper.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL licenses, (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * https://www.openssl.org/source/license.html
+ * or in the file LICENSE in the source distribution.
+ */
+
+#include <string.h>
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+
+#include "handshake_helper.h"
+
+/*
+ * Since there appears to be no way to extract the sent/received alert
+ * from the SSL object directly, we use the info callback and stash
+ * the result in ex_data.
+ */
+typedef struct handshake_ex_data {
+ int alert_sent;
+ int alert_received;
+} HANDSHAKE_EX_DATA;
+
+static int ex_data_idx;
+
+static void info_callback(const SSL *s, int where, int ret)
+{
+ if (where & SSL_CB_ALERT) {
+ HANDSHAKE_EX_DATA *ex_data =
+ (HANDSHAKE_EX_DATA*)(SSL_get_ex_data(s, ex_data_idx));
+ if (where & SSL_CB_WRITE) {
+ ex_data->alert_sent = ret;
+ } else {
+ ex_data->alert_received = ret;
+ }
+ }
+}
+
+typedef enum {
+ PEER_SUCCESS,
+ PEER_RETRY,
+ PEER_ERROR
+} peer_status_t;
+
+static peer_status_t do_handshake_step(SSL *ssl)
+{
+ int ret;
+
+ ret = SSL_do_handshake(ssl);
+
+ if (ret == 1) {
+ return PEER_SUCCESS;
+ } else if (ret == 0) {
+ return PEER_ERROR;
+ } else {
+ int error = SSL_get_error(ssl, ret);
+ /* Memory bios should never block with SSL_ERROR_WANT_WRITE. */
+ if (error == SSL_ERROR_WANT_READ)
+ return PEER_RETRY;
+ else
+ return PEER_ERROR;
+ }
+}
+
+typedef enum {
+ /* Both parties succeeded. */
+ HANDSHAKE_SUCCESS,
+ /* Client errored. */
+ CLIENT_ERROR,
+ /* Server errored. */
+ SERVER_ERROR,
+ /* Peers are in inconsistent state. */
+ INTERNAL_ERROR,
+ /* One or both peers not done. */
+ HANDSHAKE_RETRY
+} handshake_status_t;
+
+/*
+ * Determine the handshake outcome.
+ * last_status: the status of the peer to have acted last.
+ * previous_status: the status of the peer that didn't act last.
+ * client_spoke_last: 1 if the client went last.
+ */
+static handshake_status_t handshake_status(peer_status_t last_status,
+ peer_status_t previous_status,
+ int client_spoke_last)
+{
+ switch (last_status) {
+ case PEER_SUCCESS:
+ switch (previous_status) {
+ case PEER_SUCCESS:
+ /* Both succeeded. */
+ return HANDSHAKE_SUCCESS;
+ case PEER_RETRY:
+ /* Let the first peer finish. */
+ return HANDSHAKE_RETRY;
+ case PEER_ERROR:
+ /*
+ * Second peer succeeded despite the fact that the first peer
+ * already errored. This shouldn't happen.
+ */
+ return INTERNAL_ERROR;
+ }
+
+ case PEER_RETRY:
+ if (previous_status == PEER_RETRY) {
+ /* Neither peer is done. */
+ return HANDSHAKE_RETRY;
+ } else {
+ /*
+ * Deadlock: second peer is waiting for more input while first
+ * peer thinks they're done (no more input is coming).
+ */
+ return INTERNAL_ERROR;
+ }
+ case PEER_ERROR:
+ switch (previous_status) {
+ case PEER_SUCCESS:
+ /*
+ * First peer succeeded but second peer errored.
+ * TODO(emilia): we should be able to continue here (with some
+ * application data?) to ensure the first peer receives the
+ * alert / close_notify.
+ */
+ return client_spoke_last ? CLIENT_ERROR : SERVER_ERROR;
+ case PEER_RETRY:
+ /* We errored; let the peer finish. */
+ return HANDSHAKE_RETRY;
+ case PEER_ERROR:
+ /* Both peers errored. Return the one that errored first. */
+ return client_spoke_last ? SERVER_ERROR : CLIENT_ERROR;
+ }
+ }
+ /* Control should never reach here. */
+ return INTERNAL_ERROR;
+}
+
+HANDSHAKE_RESULT do_handshake(SSL_CTX *server_ctx, SSL_CTX *client_ctx)
+{
+ SSL *server, *client;
+ BIO *client_to_server, *server_to_client;
+ HANDSHAKE_EX_DATA server_ex_data, client_ex_data;
+ HANDSHAKE_RESULT ret;
+ int client_turn = 1;
+ peer_status_t client_status = PEER_RETRY, server_status = PEER_RETRY;
+ handshake_status_t status = HANDSHAKE_RETRY;
+
+ server = SSL_new(server_ctx);
+ client = SSL_new(client_ctx);
+ OPENSSL_assert(server != NULL && client != NULL);
+
+ memset(&server_ex_data, 0, sizeof(server_ex_data));
+ memset(&client_ex_data, 0, sizeof(client_ex_data));
+ memset(&ret, 0, sizeof(ret));
+ ret.result = SSL_TEST_INTERNAL_ERROR;
+
+ client_to_server = BIO_new(BIO_s_mem());
+ server_to_client = BIO_new(BIO_s_mem());
+
+ OPENSSL_assert(client_to_server != NULL && server_to_client != NULL);
+
+ /* Non-blocking bio. */
+ BIO_set_nbio(client_to_server, 1);
+ BIO_set_nbio(server_to_client, 1);
+
+ SSL_set_connect_state(client);
+ SSL_set_accept_state(server);
+
+ /* The bios are now owned by the SSL object. */
+ SSL_set_bio(client, server_to_client, client_to_server);
+ OPENSSL_assert(BIO_up_ref(server_to_client) > 0);
+ OPENSSL_assert(BIO_up_ref(client_to_server) > 0);
+ SSL_set_bio(server, client_to_server, server_to_client);
+
+ ex_data_idx = SSL_get_ex_new_index(0, "ex data", NULL, NULL, NULL);
+ OPENSSL_assert(ex_data_idx >= 0);
+
+ OPENSSL_assert(SSL_set_ex_data(server, ex_data_idx,
+ &server_ex_data) == 1);
+ OPENSSL_assert(SSL_set_ex_data(client, ex_data_idx,
+ &client_ex_data) == 1);
+
+ SSL_set_info_callback(server, &info_callback);
+ SSL_set_info_callback(client, &info_callback);
+
+ /*
+ * Half-duplex handshake loop.
+ * Client and server speak to each other synchronously in the same process.
+ * We use non-blocking BIOs, so whenever one peer blocks for read, it
+ * returns PEER_RETRY to indicate that it's the other peer's turn to write.
+ * The handshake succeeds once both peers have succeeded. If one peer
+ * errors out, we also let the other peer retry (and presumably fail).
+ */
+ for(;;) {
+ if (client_turn) {
+ client_status = do_handshake_step(client);
+ status = handshake_status(client_status, server_status,
+ 1 /* client went last */);
+ } else {
+ server_status = do_handshake_step(server);
+ status = handshake_status(server_status, client_status,
+ 0 /* server went last */);
+ }
+
+ switch (status) {
+ case HANDSHAKE_SUCCESS:
+ ret.result = SSL_TEST_SUCCESS;
+ goto err;
+ case CLIENT_ERROR:
+ ret.result = SSL_TEST_CLIENT_FAIL;
+ goto err;
+ case SERVER_ERROR:
+ ret.result = SSL_TEST_SERVER_FAIL;
+ goto err;
+ case INTERNAL_ERROR:
+ ret.result = SSL_TEST_INTERNAL_ERROR;
+ goto err;
+ case HANDSHAKE_RETRY:
+ /* Continue. */
+ client_turn ^= 1;
+ break;
+ }
+ }
+ err:
+ ret.server_alert_sent = server_ex_data.alert_sent;
+ ret.server_alert_received = client_ex_data.alert_received;
+ ret.client_alert_sent = client_ex_data.alert_sent;
+ ret.client_alert_received = server_ex_data.alert_received;
+ ret.server_protocol = SSL_version(server);
+ ret.client_protocol = SSL_version(client);
+
+ SSL_free(server);
+ SSL_free(client);
+ return ret;
+}
diff --git a/test/handshake_helper.h b/test/handshake_helper.h
new file mode 100644
index 0000000000..56dfb197e2
--- /dev/null
+++ b/test/handshake_helper.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL licenses, (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * https://www.openssl.org/source/license.html
+ * or in the file LICENSE in the source distribution.
+ */
+
+#ifndef HEADER_HANDSHAKE_HELPER_H
+#define HEADER_HANDSHAKE_HELPER_H
+
+#include "ssl_test_ctx.h"
+
+typedef struct handshake_result {
+ ssl_test_result_t result;
+ /* These alerts are in the 2-byte format returned by the info_callback. */
+ /* Alert sent by the client; 0 if no alert. */
+ int client_alert_sent;
+ /* Alert received by the server; 0 if no alert. */
+ int client_alert_received;
+ /* Alert sent by the server; 0 if no alert. */
+ int server_alert_sent;
+ /* Alert received by the client; 0 if no alert. */
+ int server_alert_received;
+ /* Negotiated protocol. On success, these should always match. */
+ int server_protocol;
+ int client_protocol;
+} HANDSHAKE_RESULT;
+
+/* Do a handshake and report some information about the result. */
+HANDSHAKE_RESULT do_handshake(SSL_CTX *server_ctx, SSL_CTX *client_ctx);
+
+#endif /* HEADER_HANDSHAKE_HELPER_H */
diff --git a/test/recipes/80-test_ssl.t b/test/recipes/80-test_ssl.t
index 45750b4203..8cb33a1f2a 100644
--- a/test/recipes/80-test_ssl.t
+++ b/test/recipes/80-test_ssl.t
@@ -66,10 +66,13 @@ my $P2intermediate="tmp_intP2.ss";
my $server_sess="server.ss";
my $client_sess="client.ss";
+# ssltest.c is deprecated in favour of the new framework in ssl_test.c
+# If you're adding tests here, you probably want to convert them to the
+# new format in ssl_test.c and add recipes to 80-test_ssl_new.t instead.
plan tests =>
1 # For testss
+ 1 # For ssltest -test_cipherlist
- + 15 # For the first testssl
+ + 14 # For the first testssl
+ 16 # For the first testsslproxy
+ 16 # For the second testsslproxy
;
@@ -712,55 +715,6 @@ sub testssl {
}
};
- subtest 'TLS Version min/max tests' => sub {
- my @protos;
- push(@protos, "ssl3") unless $no_ssl3;
- push(@protos, "tls1") unless $no_tls1;
- push(@protos, "tls1.1") unless $no_tls1_1;
- push(@protos, "tls1.2") unless $no_tls1_2;
- my @minprotos = (undef, @protos);
- my @maxprotos = (@protos, undef);
- my @shdprotos = (@protos, $protos[$#protos]);
- my $n = ((@protos+2) * (@protos+3))/2 - 2;
- my $ntests = $n * $n;
- plan tests => $ntests;
- SKIP: {
- skip "TLS disabled", 1 if $ntests == 1;
-
- my $should;
- for (my $smin = 0; $smin < @minprotos; ++$smin) {
- for (my $smax = $smin ? $smin - 1 : 0; $smax < @maxprotos; ++$smax) {
- for (my $cmin = 0; $cmin < @minprotos; ++$cmin) {
- for (my $cmax = $cmin ? $cmin - 1 : 0; $cmax < @maxprotos; ++$cmax) {
- if ($cmax < $smin-1) {
- $should = "fail-server";
- } elsif ($smax < $cmin-1) {
- $should = "fail-client";
- } elsif ($cmax > $smax) {
- $should = $shdprotos[$smax];
- } else {
- $should = $shdprotos[$cmax];
- }
-
- my @args = @ssltest;
- push(@args, "-should_negotiate", $should);
- push(@args, "-server_min_proto", $minprotos[$smin])
- if (defined($minprotos[$smin]));
- push(@args, "-server_max_proto", $maxprotos[$smax])
- if (defined($maxprotos[$smax]));
- push(@args, "-client_min_proto", $minprotos[$cmin])
- if (defined($minprotos[$cmin]));
- push(@args, "-client_max_proto", $maxprotos[$cmax])
- if (defined($maxprotos[$cmax]));
- my $ok = run(test[@args]);
- if (! $ok) {
- print STDERR "\nsmin=$smin, smax=$smax, cmin=$cmin, cmax=$cmax\n";
- print STDERR "\nFailed: @args\n";
- }
- ok($ok);
- }}}}}
- };
-
subtest 'DTLS Version min/max tests' => sub {
my @protos;
push(@protos, "dtls1") unless ($no_dtls1 || $no_dtls);
diff --git a/test/recipes/80-test_ssl_new.t b/test/recipes/80-test_ssl_new.t
new file mode 100644
index 0000000000..da98f18fb6
--- /dev/null
+++ b/test/recipes/80-test_ssl_new.t
@@ -0,0 +1,80 @@
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+
+use File::Basename;
+use File::Compare qw/compare_text/;
+
+use OpenSSL::Test qw/:DEFAULT srctop_dir srctop_file/;
+use OpenSSL::Test::Utils qw/disabled alldisabled available_protocols/;
+
+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;
+
+# 02-protocol-version.conf test results depend on the configuration of enabled
+# protocols. We only verify generated sources in the default configuration.
+my $is_default = (disabled("ssl3") && !disabled("tls1") &&
+ !disabled("tls1_1") && !disabled("tls1_2"));
+
+my %conf_dependent_tests = ("02-protocol-version.conf" => 1);
+
+foreach my $conf (@conf_files) {
+ subtest "Test configuration $conf" => sub {
+ test_conf($conf, $conf_dependent_tests{$conf} ? 0 : 1);
+ }
+}
+
+# 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
+
+sub test_conf {
+ plan tests => 3;
+
+ my ($conf, $check_source) = @_;
+
+ my $conf_file = srctop_file("test", "ssl-tests", $conf);
+ my $tmp_file = "${conf}.$$.tmp";
+ my $run_test = 1;
+
+ SKIP: {
+ # "Test" 1. Generate the source.
+ my $input_file = $conf_file . ".in";
+
+ skip 'failure', 2 unless
+ ok(run(perltest(["generate_ssl_tests.pl", $input_file],
+ stdout => $tmp_file)),
+ "Getting output from generate_ssl_tests.pl.");
+
+ SKIP: {
+ # Test 2. Compare against existing output in test/ssl_tests.conf.
+ skip "Skipping generated source test for $conf", 1
+ if !$check_source;
+
+ $run_test = is(cmp_text($tmp_file, $conf_file), 0,
+ "Comparing generated sources.");
+ }
+
+ # Test 3. Run the test.
+ my $no_tls = alldisabled(available_protocols("tls"));
+ skip "No TLS tests available; skipping tests", 1 if $no_tls;
+ skip "Stale sources; skipping tests", 1 if !$run_test;
+
+ ok(run(test(["ssl_test", $tmp_file])), "running ssl_test $conf");
+ }
+
+ unlink glob $tmp_file;
+}
+
+sub cmp_text {
+ return compare_text(@_, sub {
+ $_[0] =~ s/\R//g;
+ $_[1] =~ s/\R//g;
+ return $_[0] ne $_[1];
+ });
+}
diff --git a/test/recipes/80-test_ssl_test_ctx.t b/test/recipes/80-test_ssl_test_ctx.t
new file mode 100644
index 0000000000..210e4e857f
--- /dev/null
+++ b/test/recipes/80-test_ssl_test_ctx.t
@@ -0,0 +1,12 @@
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+
+use OpenSSL::Test qw/:DEFAULT srctop_file/;
+
+setup("test_ssl_test_ctx");
+
+plan tests => 1;
+ok(run(test(["ssl_test_ctx_test", srctop_file("test", "ssl_test_ctx_test.conf")])),
+ "running ssl_test_ctx_test ssl_test_ctx_test.conf");
diff --git a/test/ssl-tests/01-simple.conf b/test/ssl-tests/01-simple.conf
new file mode 100644
index 0000000000..8c8067dae2
--- /dev/null
+++ b/test/ssl-tests/01-simple.conf
@@ -0,0 +1,56 @@
+# Generated with generate_ssl_tests.pl
+
+num_tests = 2
+
+test-0 = 0-default
+test-1 = 1-verify-cert
+# ===========================================================
+
+[0-default]
+ssl_conf = 0-default-ssl
+
+[0-default-ssl]
+server = 0-default-server