SSL tests: port CT tests, add a few more
authorEmilia Kasper <emilia@openssl.org>
Tue, 9 Aug 2016 14:47:26 +0000 (16:47 +0200)
committerEmilia Kasper <emilia@openssl.org>
Wed, 10 Aug 2016 12:41:21 +0000 (14:41 +0200)
This commit only ports existing tests, and adds some coverage for
resumption. We don't appear to have any handshake tests that cover SCT
validation success, and this commit doesn't change that.

Reviewed-by: Rich Salz <rsalz@openssl.org>
test/README.ssltest.md
test/handshake_helper.c
test/recipes/80-test_ssl_new.t
test/recipes/80-test_ssl_old.t
test/ssl-tests/12-ct.conf [new file with mode: 0644]
test/ssl-tests/12-ct.conf.in [new file with mode: 0644]
test/ssl_test_ctx.c
test/ssl_test_ctx.h
test/ssl_test_ctx_test.c
test/ssl_test_ctx_test.conf

index 53ee0b433c50f819b4dbf868a1812b03131a86dd..d6b020d01ab6e42963160c0f7cd550585b48e262 100644 (file)
@@ -143,6 +143,11 @@ client => {
   - server2 - the secondary context
   - invalid - an unknown context
 
+* CTValidation - Certificate Transparency validation strategy. One of
+  - None - no validation (default)
+  - Permissive - SSL_CT_VALIDATION_PERMISSIVE
+  - Strict - SSL_CT_VALIDATION_STRICT
+
 #### Supported server-side options
 
 * ServerNameCallback - the SNI switching callback to use
@@ -212,6 +217,10 @@ $ TEST_CERTS_DIR=test/certs util/shlib_wrap.sh test/ssl_test \
   test/ssl-tests/01-simple.conf
 ```
 
+Some tests also need additional environment variables; for example, Certificate
+Transparency tests need a `CTLOG_FILE`. See `test/recipes/80-test_ssl_new.t` for
+details.
+
 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
index be689dc240f2a1d4ef643cf623507df7cd174128..9fa6019824a7bf58daf1f47112ebc9747970c40c 100644 (file)
@@ -374,6 +374,22 @@ static void configure_handshake_ctx(SSL_CTX *server_ctx, SSL_CTX *server2_ctx,
     OPENSSL_assert(SSL_CTX_set_tlsext_ticket_keys(server_ctx, ticket_keys,
                                                   ticket_key_len) == 1);
     OPENSSL_free(ticket_keys);
+
+#ifndef OPENSSL_NO_CT
+    OPENSSL_assert(SSL_CTX_set_default_ctlog_list_file(client_ctx));
+    switch (extra->client.ct_validation) {
+    case SSL_TEST_CT_VALIDATION_PERMISSIVE:
+        OPENSSL_assert(SSL_CTX_enable_ct(client_ctx,
+                                         SSL_CT_VALIDATION_PERMISSIVE));
+        break;
+    case SSL_TEST_CT_VALIDATION_STRICT:
+        OPENSSL_assert(SSL_CTX_enable_ct(client_ctx,
+                                         SSL_CT_VALIDATION_STRICT));
+        break;
+    case SSL_TEST_CT_VALIDATION_NONE:
+        break;
+    }
+#endif
 }
 
 /* Configure per-SSL callbacks and other properties. */
index 877a087e8ac2ab90651e0ac6ad0688d708759c2a..1530bc2f3d49e5870b7de9cb621644fc3f51fa79 100644 (file)
@@ -20,6 +20,7 @@ use OpenSSL::Test::Utils qw/disabled alldisabled available_protocols/;
 setup("test_ssl_new");
 
 $ENV{TEST_CERTS_DIR} = srctop_dir("test", "certs");
+$ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf");
 
 my @conf_srcs =  glob(srctop_file("test", "ssl-tests", "*.conf.in"));
 map { s/;.*// } @conf_srcs if $^O eq "VMS";
@@ -28,7 +29,7 @@ map { s/\.in// } @conf_files;
 
 # We hard-code the number of tests to double-check that the globbing above
 # finds all files as expected.
-plan tests => 11;  # = scalar @conf_srcs
+plan tests => 12;  # = scalar @conf_srcs
 
 # Some test results depend on the configuration of enabled protocols. We only
 # verify generated sources in the default configuration.
@@ -40,6 +41,7 @@ my $is_default_dtls = (!disabled("dtls1") && !disabled("dtls1_2"));
 my $no_tls = alldisabled(available_protocols("tls"));
 my $no_dtls = alldisabled(available_protocols("dtls"));
 my $no_npn = disabled("nextprotoneg");
+my $no_ct = disabled("ct");
 
 my %conf_dependent_tests = (
   "02-protocol-version.conf" => !$is_default_tls,
@@ -55,6 +57,7 @@ my %skip = (
   "08-npn.conf" => $no_tls || $no_npn,
   "10-resumption.conf" => disabled("tls1_1") || disabled("tls1_2"),
   "11-dtls_resumption.conf" => disabled("dtls1") || disabled("dtls1_2"),
+  "12-ct.conf" => $no_tls || $no_ct,
 );
 
 foreach my $conf (@conf_files) {
index 631adbf7eb674d96b4de1b687fa092c80453cf8a..22bb2264701b8df0e9593840077ac07587101cf2 100644 (file)
@@ -79,7 +79,7 @@ my $client_sess="client.ss";
 # new format in ssl_test.c and add recipes to 80-test_ssl_new.t instead.
 plan tests =>
     1                          # For testss
-    +8                         # For the first testssl
+    +7                         # For the first testssl
     ;
 
 subtest 'test_ss' => sub {
@@ -601,28 +601,6 @@ sub testssl {
          ok(run(test([@ssltest, "-cipher", "AES128-SHA256", "-bytes", "8m"])));
        }
     };
-
-    subtest 'Certificate Transparency tests' => sub {
-       ######################################################################
-
-       plan tests => 3;
-
-      SKIP: {
-        skip "Certificate Transparency is not supported by this OpenSSL build", 3
-            if $no_ct;
-        skip "TLSv1.0 is not supported by this OpenSSL build", 3
-            if $no_tls1;
-
-        $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf");
-        my @ca = qw(-CAfile certCA.ss);
-        ok(run(test([@ssltest, @ca, "-bio_pair", "-tls1", "-noct"])));
-        # No SCTs provided, so this should fail.
-        ok(run(test([@ssltest, @ca, "-bio_pair", "-tls1", "-ct",
-                     "-should_negotiate", "fail-client"])));
-        # No SCTs provided, unverified chains still succeed.
-        ok(run(test([@ssltest, "-bio_pair", "-tls1", "-ct"])));
-        }
-    };
 }
 
 unlink $CAkey;
diff --git a/test/ssl-tests/12-ct.conf b/test/ssl-tests/12-ct.conf
new file mode 100644 (file)
index 0000000..22fa18d
--- /dev/null
@@ -0,0 +1,135 @@
+# Generated with generate_ssl_tests.pl
+
+num_tests = 4
+
+test-0 = 0-ct-permissive
+test-1 = 1-ct-strict
+test-2 = 2-ct-permissive-resumption
+test-3 = 3-ct-strict-resumption
+# ===========================================================
+
+[0-ct-permissive]
+ssl_conf = 0-ct-permissive-ssl
+
+[0-ct-permissive-ssl]
+server = 0-ct-permissive-server
+client = 0-ct-permissive-client
+
+[0-ct-permissive-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[0-ct-permissive-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-0]
+ExpectedResult = Success
+client = 0-ct-permissive-client-extra
+
+[0-ct-permissive-client-extra]
+CTValidation = Permissive
+
+
+# ===========================================================
+
+[1-ct-strict]
+ssl_conf = 1-ct-strict-ssl
+
+[1-ct-strict-ssl]
+server = 1-ct-strict-server
+client = 1-ct-strict-client
+
+[1-ct-strict-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[1-ct-strict-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-1]
+ExpectedClientAlert = HandshakeFailure
+ExpectedResult = ClientFail
+client = 1-ct-strict-client-extra
+
+[1-ct-strict-client-extra]
+CTValidation = Strict
+
+
+# ===========================================================
+
+[2-ct-permissive-resumption]
+ssl_conf = 2-ct-permissive-resumption-ssl
+
+[2-ct-permissive-resumption-ssl]
+server = 2-ct-permissive-resumption-server
+client = 2-ct-permissive-resumption-client
+resume-server = 2-ct-permissive-resumption-server
+resume-client = 2-ct-permissive-resumption-client
+
+[2-ct-permissive-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[2-ct-permissive-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-2]
+ExpectedResult = Success
+HandshakeMode = Resume
+ResumptionExpected = Yes
+client = 2-ct-permissive-resumption-client-extra
+resume-client = 2-ct-permissive-resumption-client-extra
+
+[2-ct-permissive-resumption-client-extra]
+CTValidation = Permissive
+
+
+# ===========================================================
+
+[3-ct-strict-resumption]
+ssl_conf = 3-ct-strict-resumption-ssl
+
+[3-ct-strict-resumption-ssl]
+server = 3-ct-strict-resumption-server
+client = 3-ct-strict-resumption-client
+resume-server = 3-ct-strict-resumption-server
+resume-client = 3-ct-strict-resumption-resume-client
+
+[3-ct-strict-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[3-ct-strict-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[3-ct-strict-resumption-resume-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-3]
+ExpectedResult = Success
+HandshakeMode = Resume
+ResumptionExpected = Yes
+client = 3-ct-strict-resumption-client-extra
+resume-client = 3-ct-strict-resumption-resume-client-extra
+
+[3-ct-strict-resumption-client-extra]
+CTValidation = Permissive
+
+[3-ct-strict-resumption-resume-client-extra]
+CTValidation = Strict
+
+
diff --git a/test/ssl-tests/12-ct.conf.in b/test/ssl-tests/12-ct.conf.in
new file mode 100644 (file)
index 0000000..9964d01
--- /dev/null
@@ -0,0 +1,80 @@
+# -*- mode: perl; -*-
+# Copyright 2016-2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+
+## Test version negotiation
+
+use strict;
+use warnings;
+
+package ssltests;
+
+
+our @tests = (
+    # Currently only have tests for certs without SCTs.
+    {
+       name => "ct-permissive",
+       server => { },
+       client => {
+           extra => {
+               "CTValidation" => "Permissive",
+           },
+       },
+       test => {
+           "ExpectedResult" => "Success",
+       },
+    }, 
+    {
+       name => "ct-strict",
+       server => { },
+       client => {
+           extra => {
+               "CTValidation" => "Strict",
+           },
+       },
+       test => {
+           "ExpectedResult" => "ClientFail",
+           "ExpectedClientAlert" => "HandshakeFailure",
+       },
+    },
+    {
+       name => "ct-permissive-resumption",
+       server => { },
+       client => {
+           extra => {
+               "CTValidation" => "Permissive",
+           },
+       },
+       test => {
+           "HandshakeMode" => "Resume",
+           "ResumptionExpected" => "Yes",
+           "ExpectedResult" => "Success",
+       },
+    }, 
+    {
+       name => "ct-strict-resumption",
+       server => { },
+       client => {
+           extra => {
+               "CTValidation" => "Permissive",
+           },
+       },
+       # SCTs are not present during resumption, so the resumption
+       # should succeed.
+       resume_client => {
+           extra => {
+               "CTValidation" => "Strict",
+           },
+       },
+       test => {
+           "HandshakeMode" => "Resume",
+           "ResumptionExpected" => "Yes",
+           "ExpectedResult" => "Success",
+       },
+    },
+);
index d4a7c8ba59d48746f11f6964684323e70edb4024..e95c1f2f66fb100a166004e647880b9fdb425628 100644 (file)
@@ -142,7 +142,7 @@ static const test_enum ssl_verify_callbacks[] = {
 };
 
 __owur static int parse_client_verify_callback(SSL_TEST_CLIENT_CONF *client_conf,
-                                              const char *value)
+                                               const char *value)
 {
     int ret_value;
     if (!parse_enum(ssl_verify_callbacks, OSSL_NELEM(ssl_verify_callbacks),
@@ -328,6 +328,34 @@ const char *ssl_handshake_mode_name(ssl_handshake_mode_t mode)
                      mode);
 }
 
+/***********************/
+/* CT Validation       */
+/***********************/
+
+static const test_enum ssl_ct_validation_modes[] = {
+    {"None", SSL_TEST_CT_VALIDATION_NONE},
+    {"Permissive", SSL_TEST_CT_VALIDATION_PERMISSIVE},
+    {"Strict", SSL_TEST_CT_VALIDATION_STRICT},
+};
+
+__owur static int parse_ct_validation(SSL_TEST_CLIENT_CONF *client_conf,
+                                      const char *value)
+{
+    int ret_value;
+    if (!parse_enum(ssl_ct_validation_modes, OSSL_NELEM(ssl_ct_validation_modes),
+                    &ret_value, value)) {
+        return 0;
+    }
+    client_conf->ct_validation = ret_value;
+    return 1;
+}
+
+const char *ssl_ct_validation_name(ssl_ct_validation_t mode)
+{
+    return enum_name(ssl_ct_validation_modes, OSSL_NELEM(ssl_ct_validation_modes),
+                     mode);
+}
+
 static int parse_boolean(const char *value, int *result)
 {
     if (strcasecmp(value, "Yes") == 0) {
@@ -385,6 +413,7 @@ static const ssl_test_client_option ssl_test_client_options[] = {
     { "ServerName", &parse_servername },
     { "NPNProtocols", &parse_client_npn_protocols },
     { "ALPNProtocols", &parse_client_alpn_protocols },
+    { "CTValidation", &parse_ct_validation },
 };
 
 /* Nested server options. */
index a939f3d560eb0cc9d950c609cdacc0384b3e057f..916b31aa89acdfa20f15197af5ee6d91a1ca5ff1 100644 (file)
@@ -60,6 +60,11 @@ typedef enum {
     SSL_TEST_HANDSHAKE_RENEGOTIATE
 } ssl_handshake_mode_t;
 
+typedef enum {
+    SSL_TEST_CT_VALIDATION_NONE = 0, /* Default */
+    SSL_TEST_CT_VALIDATION_PERMISSIVE,
+    SSL_TEST_CT_VALIDATION_STRICT
+} ssl_ct_validation_t;
 /*
  * Server/client settings that aren't supported by the SSL CONF library,
  * such as callbacks.
@@ -72,6 +77,7 @@ typedef struct {
     /* Supported NPN and ALPN protocols. A comma-separated list. */
     char *npn_protocols;
     char *alpn_protocols;
+    ssl_ct_validation_t ct_validation;
 } SSL_TEST_CLIENT_CONF;
 
 typedef struct {
@@ -150,6 +156,7 @@ const char *ssl_servername_callback_name(ssl_servername_callback_t
 const char *ssl_session_ticket_name(ssl_session_ticket_t server);
 const char *ssl_test_method_name(ssl_test_method_t method);
 const char *ssl_handshake_mode_name(ssl_handshake_mode_t mode);
+const char *ssl_ct_validation_name(ssl_ct_validation_t mode);
 
 /*
  * Load the test case context from |conf|.
index b7f888a4186ce4eaf8addc73010d5682002a275e..479bda4d587a82a092be160ff6294ed11e8380d2 100644 (file)
@@ -54,6 +54,12 @@ static int SSL_TEST_CLIENT_CONF_equal(SSL_TEST_CLIENT_CONF *client,
     if (!strings_equal("Client ALPNProtocols", client->alpn_protocols,
                        client2->alpn_protocols))
         return 0;
+    if (client->ct_validation != client2->ct_validation) {
+        fprintf(stderr, "CTValidation mismatch: %s vs %s.\n",
+                ssl_ct_validation_name(client->ct_validation),
+                ssl_ct_validation_name(client2->ct_validation));
+        return 0;
+    }
     return 1;
 }
 
@@ -259,6 +265,9 @@ static int test_good_configuration()
     OPENSSL_assert(
         fixture.expected_ctx->resume_extra.server2.alpn_protocols != NULL);
 
+    fixture.expected_ctx->resume_extra.client.ct_validation =
+        SSL_TEST_CT_VALIDATION_STRICT;
+
     EXECUTE_SSL_TEST_CTX_TEST();
 }
 
@@ -275,6 +284,7 @@ static const char *bad_configurations[] = {
     "ssltest_unknown_method",
     "ssltest_unknown_handshake_mode",
     "ssltest_unknown_resumption_expected",
+    "ssltest_unknown_ct_validation",
 };
 
 static int test_bad_configuration(int idx)
index 20ae5d3068243305b228a539be2589159f756317..3c46d9673839d9b5baa28b286b3a9ac7e708653a 100644 (file)
@@ -4,6 +4,7 @@
 client = ssltest_good_client_extra
 server = ssltest_good_server_extra
 resume-server2 = ssltest_good_resume_server2_extra
+resume-client = ssltest_good_resume_client_extra
 
 Method = DTLS
 HandshakeMode = Resume
@@ -20,6 +21,9 @@ VerifyCallback = RejectAll
 ServerName = server2
 NPNProtocols = foo,bar
 
+[ssltest_good_resume_client_extra]
+CTValidation = Strict
+
 [ssltest_good_server_extra]
 ServerNameCallback = IgnoreMismatch
 BrokenSessionTicket = Yes
@@ -74,3 +78,9 @@ HandshakeMode = Foo
 
 [ssltest_unknown_resumption_expected]
 ResumptionExpected = Foo
+
+[ssltest_unknown_ct_validation]
+client = ssltest_unknown_ct_validation_client
+
+[ssltest_unknown_ct_validation_client]
+CTCallback = Foo