SSL test framework: port resumption tests
authorEmilia Kasper <emilia@openssl.org>
Tue, 5 Jul 2016 17:06:23 +0000 (19:06 +0200)
committerEmilia Kasper <emilia@openssl.org>
Wed, 20 Jul 2016 11:55:53 +0000 (13:55 +0200)
Systematically test every server-side version downgrade or upgrade.

Client version upgrade or downgrade could be tested analogously but will
be done in a later change.

Reviewed-by: Rich Salz <rsalz@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
20 files changed:
test/README.ssltest.md
test/generate_ssl_tests.pl
test/handshake_helper.c
test/handshake_helper.h
test/recipes/80-test_ssl_new.t
test/recipes/80-test_ssl_old.t
test/ssl-tests/02-protocol-version.conf.in
test/ssl-tests/05-sni.conf.in
test/ssl-tests/07-dtls-protocol-version.conf.in
test/ssl-tests/10-resumption.conf [new file with mode: 0644]
test/ssl-tests/10-resumption.conf.in [new file with mode: 0644]
test/ssl-tests/11-dtls_resumption.conf [new file with mode: 0644]
test/ssl-tests/11-dtls_resumption.conf.in [new file with mode: 0644]
test/ssl-tests/protocol_version.pm
test/ssl_test.c
test/ssl_test.tmpl
test/ssl_test_ctx.c
test/ssl_test_ctx.h
test/ssl_test_ctx_test.c
test/ssl_test_ctx_test.conf

index 9d828b5..8cd55ed 100644 (file)
@@ -82,7 +82,20 @@ The test section supports the following options:
   - Ignore - do not check for a session ticket (default)
   - Yes - a session ticket is expected
   - No - a session ticket is not expected
-  - Broken - a special test case where the session ticket callback does not initialize crypto
+  - Broken - a special test case where the session ticket callback does not
+    initialize crypto
+
+* HandshakeMode - which handshake flavour to test:
+  - Simple - plain handshake (default)
+  - Resume - test resumption
+  - (Renegotiate - test renegotiation, not yet implemented)
+
+* ResumptionExpected - whether or not resumption is expected (Resume mode only)
+  - Yes - resumed handshake
+  - No - full handshake (default)
+
+When HandshakeMode is Resume or Renegotiate, the original handshake is expected
+to succeed. All configured test expectations are verified against the second handshake.
 
 * ServerNPNProtocols, Server2NPNProtocols, ClientNPNProtocols, ExpectedNPNProtocol,
   ServerALPNProtocols, Server2ALPNProtocols, ClientALPNProtocols, ExpectedALPNProtocol -
@@ -103,9 +116,16 @@ server => {
 }
 ```
 
-A server2 section may optionally be defined to configure a secondary
-context that is selected via the ServerName test option. If the server2
-section is not configured, then the configuration matches server.
+The following sections may optionally be defined:
+
+* server2 - this section configures a secondary context that is selected via the
+  ServerName test option. This context is used whenever a ServerNameCallback is
+  specified. If the server2 section is not present, then the configuration
+  matches server.
+* resume_server - this section configures the client to resume its session
+  against a different server. This context is used whenever HandshakeMode is
+  Resume. If the resume-server section is not present, then the configuration
+  matches server.
 
 ### Default server and client configurations
 
index 7a016d1..a2f4714 100644 (file)
@@ -43,12 +43,25 @@ sub print_templates {
     # Add the implicit base configuration.
     foreach my $test (@ssltests::tests) {
         $test->{"server"} = { (%ssltests::base_server, %{$test->{"server"}}) };
-       # Do not emit an empty "server2" section.
-       if (defined $test->{"server2"}) {
+        if (defined $test->{"server2"}) {
             $test->{"server2"} = { (%ssltests::base_server, %{$test->{"server2"}}) };
+        } elsif (defined $test->{"test"}->{"ServerNameCallback"}) {
+            # Default is the same as server.
+            $test->{"server2"} = { (%ssltests::base_server, %{$test->{"server"}}) };
         } else {
+            # Do not emit an empty "server2" section.
             $test->{"server2"} = { };
         }
+        if (defined $test->{"resume_server"}) {
+            $test->{"resume_server"} = { (%ssltests::base_server, %{$test->{"resume_server"}}) };
+        } elsif (defined $test->{"test"}->{"HandshakeMode"} &&
+                 $test->{"test"}->{"HandshakeMode"} eq "Resume") {
+            # Default is the same as server.
+            $test->{"resume_server"} = { (%ssltests::base_server, %{$test->{"server"}}) };
+        } else {
+            # Do not emit an empty "resume-server" section.
+            $test->{"resume_server"} = { };
+        }
         $test->{"client"} = { (%ssltests::base_client, %{$test->{"client"}}) };
     }
 
index 77852ad..c4f298e 100644 (file)
@@ -273,6 +273,9 @@ static void configure_handshake_ctx(SSL_CTX *server_ctx, SSL_CTX *server2_ctx,
                                     CTX_DATA *server2_ctx_data,
                                     CTX_DATA *client_ctx_data)
 {
+    unsigned char *ticket_keys;
+    size_t ticket_key_len;
+
     switch (test_ctx->client_verify_callback) {
     case SSL_TEST_VERIFY_ACCEPT_ALL:
         SSL_CTX_set_cert_verify_callback(client_ctx, &verify_accept_cb,
@@ -312,7 +315,6 @@ static void configure_handshake_ctx(SSL_CTX *server_ctx, SSL_CTX *server2_ctx,
     if (test_ctx->session_ticket_expected == SSL_TEST_SESSION_TICKET_BROKEN) {
         SSL_CTX_set_tlsext_ticket_key_cb(server_ctx, broken_session_ticket_cb);
     }
-
     if (test_ctx->server_npn_protocols != NULL) {
         parse_protos(test_ctx->server_npn_protocols,
                      &server_ctx_data->npn_protocols,
@@ -358,6 +360,16 @@ static void configure_handshake_ctx(SSL_CTX *server_ctx, SSL_CTX *server2_ctx,
                                                alpn_protos_len) == 0);
         OPENSSL_free(alpn_protos);
     }
+    /*
+     * Use fixed session ticket keys so that we can decrypt a ticket created with
+     * one CTX in another CTX. Don't address server2 for the moment.
+     */
+    ticket_key_len = SSL_CTX_set_tlsext_ticket_keys(server_ctx, NULL, 0);
+    ticket_keys = OPENSSL_zalloc(ticket_key_len);
+    OPENSSL_assert(ticket_keys != NULL);
+    OPENSSL_assert(SSL_CTX_set_tlsext_ticket_keys(server_ctx, ticket_keys,
+                                                  ticket_key_len) == 1);
+    OPENSSL_free(ticket_keys);
 }
 
 /* Configure per-SSL callbacks and other properties. */
@@ -376,16 +388,31 @@ typedef enum {
     PEER_ERROR
 } peer_status_t;
 
-static peer_status_t do_handshake_step(SSL *ssl)
+/*
+ * RFC 5246 says:
+ *
+ * Note that as of TLS 1.1,
+ *     failure to properly close a connection no longer requires that a
+ *     session not be resumed.  This is a change from TLS 1.0 to conform
+ *     with widespread implementation practice.
+ *
+ * However,
+ * (a) OpenSSL requires that a connection be shutdown for all protocol versions.
+ * (b) We test lower versions, too.
+ * So we just implement shutdown. We do a full bidirectional shutdown so that we
+ * can compare sent and received close_notify alerts and get some test coverage
+ * for SSL_shutdown as a bonus.
+ */
+static peer_status_t do_handshake_step(SSL *ssl, int shutdown)
 {
     int ret;
 
-    ret = SSL_do_handshake(ssl);
+    ret = shutdown ? SSL_shutdown(ssl) : SSL_do_handshake(ssl);
 
     if (ret == 1) {
         return PEER_SUCCESS;
     } else if (ret == 0) {
-        return PEER_ERROR;
+        return shutdown ? PEER_RETRY : PEER_ERROR;
     } else {
         int error = SSL_get_error(ssl, ret);
         /* Memory bios should never block with SSL_ERROR_WANT_WRITE. */
@@ -484,15 +511,17 @@ static char *dup_str(const unsigned char *in, size_t len)
     return ret;
 }
 
-HANDSHAKE_RESULT *do_handshake(SSL_CTX *server_ctx, SSL_CTX *server2_ctx,
-                               SSL_CTX *client_ctx, const SSL_TEST_CTX *test_ctx)
+static HANDSHAKE_RESULT *do_handshake_internal(
+    SSL_CTX *server_ctx, SSL_CTX *server2_ctx, SSL_CTX *client_ctx,
+    const SSL_TEST_CTX *test_ctx, SSL_SESSION *session_in,
+    SSL_SESSION **session_out)
 {
     SSL *server, *client;
     BIO *client_to_server, *server_to_client;
     HANDSHAKE_EX_DATA server_ex_data, client_ex_data;
     CTX_DATA client_ctx_data, server_ctx_data, server2_ctx_data;
     HANDSHAKE_RESULT *ret = HANDSHAKE_RESULT_new();
-    int client_turn = 1;
+    int client_turn = 1, shutdown = 0;
     peer_status_t client_status = PEER_RETRY, server_status = PEER_RETRY;
     handshake_status_t status = HANDSHAKE_RETRY;
     unsigned char* tick = NULL;
@@ -514,6 +543,11 @@ HANDSHAKE_RESULT *do_handshake(SSL_CTX *server_ctx, SSL_CTX *server2_ctx,
     OPENSSL_assert(server != NULL && client != NULL);
 
     configure_handshake_ssl(server, client, test_ctx);
+    if (session_in != NULL) {
+        /* In case we're testing resumption without tickets. */
+        OPENSSL_assert(SSL_CTX_add_session(server_ctx, session_in));
+        OPENSSL_assert(SSL_set_session(client, session_in));
+    }
 
     memset(&server_ex_data, 0, sizeof(server_ex_data));
     memset(&client_ex_data, 0, sizeof(client_ex_data));
@@ -559,19 +593,26 @@ HANDSHAKE_RESULT *do_handshake(SSL_CTX *server_ctx, SSL_CTX *server2_ctx,
      */
     for(;;) {
         if (client_turn) {
-            client_status = do_handshake_step(client);
+            client_status = do_handshake_step(client, shutdown);
             status = handshake_status(client_status, server_status,
                                       1 /* client went last */);
         } else {
-            server_status = do_handshake_step(server);
+            server_status = do_handshake_step(server, shutdown);
             status = handshake_status(server_status, client_status,
                                       0 /* server went last */);
         }
 
         switch (status) {
         case HANDSHAKE_SUCCESS:
-            ret->result = SSL_TEST_SUCCESS;
-            goto err;
+            if (shutdown) {
+                ret->result = SSL_TEST_SUCCESS;
+                goto err;
+            } else {
+                client_status = server_status = PEER_RETRY;
+                shutdown = 1;
+                client_turn = 1;
+                break;
+            }
         case CLIENT_ERROR:
             ret->result = SSL_TEST_CLIENT_FAIL;
             goto err;
@@ -615,10 +656,45 @@ HANDSHAKE_RESULT *do_handshake(SSL_CTX *server_ctx, SSL_CTX *server2_ctx,
     SSL_get0_alpn_selected(server, &proto, &proto_len);
     ret->server_alpn_negotiated = dup_str(proto, proto_len);
 
+    ret->client_resumed = SSL_session_reused(client);
+    ret->server_resumed = SSL_session_reused(server);
+
+    if (session_out != NULL)
+        *session_out = SSL_get1_session(client);
+
     ctx_data_free_data(&server_ctx_data);
     ctx_data_free_data(&server2_ctx_data);
     ctx_data_free_data(&client_ctx_data);
+
     SSL_free(server);
     SSL_free(client);
     return ret;
 }
+
+HANDSHAKE_RESULT *do_handshake(SSL_CTX *server_ctx, SSL_CTX *server2_ctx,
+                               SSL_CTX *client_ctx, SSL_CTX *resume_server_ctx,
+                               const SSL_TEST_CTX *test_ctx)
+{
+    HANDSHAKE_RESULT *result;
+    SSL_SESSION *session = NULL;
+
+    result = do_handshake_internal(server_ctx, server2_ctx, client_ctx,
+                                   test_ctx, NULL, &session);
+    if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_SIMPLE)
+        goto end;
+
+    OPENSSL_assert(test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RESUME);
+
+    if (result->result != SSL_TEST_SUCCESS) {
+        result->result = SSL_TEST_FIRST_HANDSHAKE_FAILED;
+        return result;
+    }
+
+    HANDSHAKE_RESULT_free(result);
+    /* We don't support SNI on second handshake yet, so server2_ctx is NULL. */
+    result = do_handshake_internal(resume_server_ctx, NULL, client_ctx, test_ctx,
+                                   session, NULL);
+ end:
+    SSL_SESSION_free(session);
+    return result;
+}
index 56c0aac..5027bef 100644 (file)
@@ -36,6 +36,9 @@ typedef struct handshake_result {
     char *server_npn_negotiated;
     char *client_alpn_negotiated;
     char *server_alpn_negotiated;
+    /* Was the handshake resumed? */
+    int client_resumed;
+    int server_resumed;
 } HANDSHAKE_RESULT;
 
 HANDSHAKE_RESULT *HANDSHAKE_RESULT_new(void);
@@ -43,6 +46,7 @@ void HANDSHAKE_RESULT_free(HANDSHAKE_RESULT *result);
 
 /* Do a handshake and report some information about the result. */
 HANDSHAKE_RESULT *do_handshake(SSL_CTX *server_ctx, SSL_CTX *server2_ctx,
-                               SSL_CTX *client_ctx, const SSL_TEST_CTX *test_ctx);
+                               SSL_CTX *client_ctx, SSL_CTX *resume_server_ctx,
+                               const SSL_TEST_CTX *test_ctx);
 
 #endif  /* HEADER_HANDSHAKE_HELPER_H */
index 56afb64..6867cc3 100644 (file)
@@ -42,12 +42,15 @@ my %conf_dependent_tests = (
   "02-protocol-version.conf" => !$is_default_tls,
   "04-client_auth.conf" => !$is_default_tls,
   "05-dtls-protocol-version.conf" => !$is_default_dtls,
+  "10-resumption.conf" => !$is_default_tls,
+  "11-dtls_resumption.conf" => !$is_default_dtls,
 );
 
 # Default is $no_tls but some tests have different skip conditions.
 my %skip = (
   "05-dtls-protocol-version.conf" => $no_dtls,
   "08-npn.conf" => $no_tls || $no_npn,
+  "11-dtls_resumption.conf" => $no_dtls,
 );
 
 foreach my $conf (@conf_files) {
@@ -60,7 +63,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 => 9;  # = scalar @conf_srcs
+plan tests => 11;  # = scalar @conf_srcs
 
 sub test_conf {
     plan tests => 3;
index 5228112..8f43d6b 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
-    + 11                       # For the first testssl
+    +9                         # For the first testssl
     ;
 
 subtest 'test_ss' => sub {
@@ -618,52 +618,6 @@ sub testssl {
        }
     };
 
-    subtest 'TLS session reuse' => sub {
-        plan tests => 12;
-
-        SKIP: {
-            skip "TLS1.1 or TLS1.2 disabled", 12 if $no_tls1_1 || $no_tls1_2;
-            ok(run(test([@ssltest, "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
-            ok(run(test([@ssltest, "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "tls1.2"])));
-            ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "tls1.1"])));
-
-            ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
-            ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "tls1.1"])));
-            ok(run(test([@ssltest, "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "tls1.2"])));
-
-            ok(run(test([@ssltest, "-no_ticket", "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
-            ok(run(test([@ssltest, "-no_ticket", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "tls1.2"])));
-            ok(run(test([@ssltest, "-no_ticket", "-server_max_proto", "tls1.1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "tls1.1"])));
-
-            ok(run(test([@ssltest, "-no_ticket", "-server_max_proto", "tls1.1", "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
-            ok(run(test([@ssltest, "-no_ticket", "-server_max_proto", "tls1.1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "tls1.1"])));
-            ok(run(test([@ssltest, "-no_ticket", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "tls1.2"])));
-        }
-    };
-
-    subtest 'DTLS session reuse' => sub {
-        plan tests => 12;
-      SKIP: {
-        skip "DTLS1.0 or DTLS1.2 disabled", 12 if $no_dtls1 || $no_dtls1_2;
-
-        ok(run(test([@ssltest, "-dtls", "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
-        ok(run(test([@ssltest, "-dtls", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "dtls1.2"])));
-        ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "dtls1"])));
-
-        ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1", "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
-        ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "dtls1"])));
-        ok(run(test([@ssltest, "-dtls", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "dtls1.2"])));
-
-        ok(run(test([@ssltest, "-dtls", "-no_ticket", "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
-        ok(run(test([@ssltest, "-dtls", "-no_ticket", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "dtls1.2"])));
-        ok(run(test([@ssltest, "-dtls", "-no_ticket", "-server_max_proto", "dtls1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "dtls1"])));
-
-        ok(run(test([@ssltest, "-dtls", "-no_ticket", "-server_max_proto", "dtls1", "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
-        ok(run(test([@ssltest, "-dtls", "-no_ticket", "-server_max_proto", "dtls1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "dtls1"])));
-        ok(run(test([@ssltest, "-dtls", "-no_ticket", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "dtls1.2"])));
-       }
-    };
-
     subtest 'Certificate Transparency tests' => sub {
        ######################################################################
 
index 46851c9..26d64b5 100644 (file)
@@ -16,4 +16,4 @@ use warnings;
 
 use protocol_version;
 
-our @tests = generate_tests("TLS");
+our @tests = generate_version_tests("TLS");
index 635ce9a..0a8378e 100644 (file)
@@ -18,7 +18,6 @@ our @tests = (
     {
         name => "SNI-switch-context",
         server => { },
-        server2 => { },
         client => { },
         test   => { "ServerName" => "server2",
                     "ExpectedServerName" => "server2",
@@ -28,7 +27,6 @@ our @tests = (
     {
         name => "SNI-keep-context",
         server => { },
-        server2 => { },
         client => { },
         test   => { "ServerName" => "server1",
                     "ExpectedServerName" => "server1",
@@ -45,7 +43,6 @@ our @tests = (
     {
         name => "SNI-no-client-support",
         server => { },
-        server2 => { },
         client => { },
         test   => {
             # We expect that the callback is still called
@@ -59,7 +56,6 @@ our @tests = (
     {
         name => "SNI-bad-sni-ignore-mismatch",
         server => { },
-        server2 => { },
         client => { },
         test   => { "ServerName" => "invalid",
                     "ExpectedServerName" => "server1",
@@ -69,7 +65,6 @@ our @tests = (
     {
         name => "SNI-bad-sni-reject-mismatch",
         server => { },
-        server2 => { },
         client => { },
         test   => { "ServerName" => "invalid",
                     "ServerNameCallback" => "RejectMismatch",
index 965ed3e..fb3c44a 100644 (file)
@@ -16,4 +16,4 @@ use warnings;
 
 use protocol_version;
 
-our @tests = generate_tests("DTLS");
+our @tests = generate_version_tests("DTLS");
diff --git a/test/ssl-tests/10-resumption.conf b/test/ssl-tests/10-resumption.conf
new file mode 100644 (file)
index 0000000..899f321
--- /dev/null
@@ -0,0 +1,652 @@
+# Generated with generate_ssl_tests.pl
+
+num_tests = 18
+
+test-0 = 0-resumption
+test-1 = 1-resumption
+test-2 = 2-resumption
+test-3 = 3-resumption
+test-4 = 4-resumption
+test-5 = 5-resumption
+test-6 = 6-resumption
+test-7 = 7-resumption
+test-8 = 8-resumption
+test-9 = 9-resumption
+test-10 = 10-resumption
+test-11 = 11-resumption
+test-12 = 12-resumption
+test-13 = 13-resumption
+test-14 = 14-resumption
+test-15 = 15-resumption
+test-16 = 16-resumption
+test-17 = 17-resumption
+# ===========================================================
+
+[0-resumption]
+ssl_conf = 0-resumption-ssl
+
+[0-resumption-ssl]
+server = 0-resumption-server
+resume-server = 0-resumption-resume-server
+client = 0-resumption-client
+
+[0-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1
+MinProtocol = TLSv1
+Options = SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[0-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[0-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-0]
+HandshakeMode = Resume
+Protocol = TLSv1
+ResumptionExpected = Yes
+
+
+# ===========================================================
+
+[1-resumption]
+ssl_conf = 1-resumption-ssl
+
+[1-resumption-ssl]
+server = 1-resumption-server
+resume-server = 1-resumption-resume-server
+client = 1-resumption-client
+
+[1-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1
+MinProtocol = TLSv1
+Options = -SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[1-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[1-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-1]
+HandshakeMode = Resume
+Protocol = TLSv1
+ResumptionExpected = Yes
+
+
+# ===========================================================
+
+[2-resumption]
+ssl_conf = 2-resumption-ssl
+
+[2-resumption-ssl]
+server = 2-resumption-server
+resume-server = 2-resumption-resume-server
+client = 2-resumption-client
+
+[2-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1
+MinProtocol = TLSv1
+Options = SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[2-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[2-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-2]
+HandshakeMode = Resume
+Protocol = TLSv1.1
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[3-resumption]
+ssl_conf = 3-resumption-ssl
+
+[3-resumption-ssl]
+server = 3-resumption-server
+resume-server = 3-resumption-resume-server
+client = 3-resumption-client
+
+[3-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1
+MinProtocol = TLSv1
+Options = -SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[3-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[3-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-3]
+HandshakeMode = Resume
+Protocol = TLSv1.1
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[4-resumption]
+ssl_conf = 4-resumption-ssl
+
+[4-resumption-ssl]
+server = 4-resumption-server
+resume-server = 4-resumption-resume-server
+client = 4-resumption-client
+
+[4-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1
+MinProtocol = TLSv1
+Options = SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[4-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[4-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-4]
+HandshakeMode = Resume
+Protocol = TLSv1.2
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[5-resumption]
+ssl_conf = 5-resumption-ssl
+
+[5-resumption-ssl]
+server = 5-resumption-server
+resume-server = 5-resumption-resume-server
+client = 5-resumption-client
+
+[5-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1
+MinProtocol = TLSv1
+Options = -SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[5-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[5-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-5]
+HandshakeMode = Resume
+Protocol = TLSv1.2
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[6-resumption]
+ssl_conf = 6-resumption-ssl
+
+[6-resumption-ssl]
+server = 6-resumption-server
+resume-server = 6-resumption-resume-server
+client = 6-resumption-client
+
+[6-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.1
+MinProtocol = TLSv1.1
+Options = SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[6-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[6-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-6]
+HandshakeMode = Resume
+Protocol = TLSv1
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[7-resumption]
+ssl_conf = 7-resumption-ssl
+
+[7-resumption-ssl]
+server = 7-resumption-server
+resume-server = 7-resumption-resume-server
+client = 7-resumption-client
+
+[7-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.1
+MinProtocol = TLSv1.1
+Options = -SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[7-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[7-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-7]
+HandshakeMode = Resume
+Protocol = TLSv1
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[8-resumption]
+ssl_conf = 8-resumption-ssl
+
+[8-resumption-ssl]
+server = 8-resumption-server
+resume-server = 8-resumption-resume-server
+client = 8-resumption-client
+
+[8-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.1
+MinProtocol = TLSv1.1
+Options = SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[8-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[8-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-8]
+HandshakeMode = Resume
+Protocol = TLSv1.1
+ResumptionExpected = Yes
+
+
+# ===========================================================
+
+[9-resumption]
+ssl_conf = 9-resumption-ssl
+
+[9-resumption-ssl]
+server = 9-resumption-server
+resume-server = 9-resumption-resume-server
+client = 9-resumption-client
+
+[9-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.1
+MinProtocol = TLSv1.1
+Options = -SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[9-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[9-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-9]
+HandshakeMode = Resume
+Protocol = TLSv1.1
+ResumptionExpected = Yes
+
+
+# ===========================================================
+
+[10-resumption]
+ssl_conf = 10-resumption-ssl
+
+[10-resumption-ssl]
+server = 10-resumption-server
+resume-server = 10-resumption-resume-server
+client = 10-resumption-client
+
+[10-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.1
+MinProtocol = TLSv1.1
+Options = SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[10-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[10-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-10]
+HandshakeMode = Resume
+Protocol = TLSv1.2
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[11-resumption]
+ssl_conf = 11-resumption-ssl
+
+[11-resumption-ssl]
+server = 11-resumption-server
+resume-server = 11-resumption-resume-server
+client = 11-resumption-client
+
+[11-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.1
+MinProtocol = TLSv1.1
+Options = -SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[11-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[11-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-11]
+HandshakeMode = Resume
+Protocol = TLSv1.2
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[12-resumption]
+ssl_conf = 12-resumption-ssl
+
+[12-resumption-ssl]
+server = 12-resumption-server
+resume-server = 12-resumption-resume-server
+client = 12-resumption-client
+
+[12-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+MinProtocol = TLSv1.2
+Options = SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[12-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[12-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-12]
+HandshakeMode = Resume
+Protocol = TLSv1
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[13-resumption]
+ssl_conf = 13-resumption-ssl
+
+[13-resumption-ssl]
+server = 13-resumption-server
+resume-server = 13-resumption-resume-server
+client = 13-resumption-client
+
+[13-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+MinProtocol = TLSv1.2
+Options = -SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[13-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[13-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-13]
+HandshakeMode = Resume
+Protocol = TLSv1
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[14-resumption]
+ssl_conf = 14-resumption-ssl
+
+[14-resumption-ssl]
+server = 14-resumption-server
+resume-server = 14-resumption-resume-server
+client = 14-resumption-client
+
+[14-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+MinProtocol = TLSv1.2
+Options = SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[14-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[14-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-14]
+HandshakeMode = Resume
+Protocol = TLSv1.1
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[15-resumption]
+ssl_conf = 15-resumption-ssl
+
+[15-resumption-ssl]
+server = 15-resumption-server
+resume-server = 15-resumption-resume-server
+client = 15-resumption-client
+
+[15-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+MinProtocol = TLSv1.2
+Options = -SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[15-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[15-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-15]
+HandshakeMode = Resume
+Protocol = TLSv1.1
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[16-resumption]
+ssl_conf = 16-resumption-ssl
+
+[16-resumption-ssl]
+server = 16-resumption-server
+resume-server = 16-resumption-resume-server
+client = 16-resumption-client
+
+[16-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+MinProtocol = TLSv1.2
+Options = SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[16-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[16-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-16]
+HandshakeMode = Resume
+Protocol = TLSv1.2
+ResumptionExpected = Yes
+
+
+# ===========================================================
+
+[17-resumption]
+ssl_conf = 17-resumption-ssl
+
+[17-resumption-ssl]
+server = 17-resumption-server
+resume-server = 17-resumption-resume-server
+client = 17-resumption-client
+
+[17-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+MinProtocol = TLSv1.2
+Options = -SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[17-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.2
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[17-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-17]
+HandshakeMode = Resume
+Protocol = TLSv1.2
+ResumptionExpected = Yes
+
+
diff --git a/test/ssl-tests/10-resumption.conf.in b/test/ssl-tests/10-resumption.conf.in
new file mode 100644 (file)
index 0000000..989135f
--- /dev/null
@@ -0,0 +1,19 @@
+# -*- 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 upon resumption.
+
+use strict;
+use warnings;
+
+package ssltests;
+
+use protocol_version;
+
+our @tests = generate_resumption_tests("TLS");
diff --git a/test/ssl-tests/11-dtls_resumption.conf b/test/ssl-tests/11-dtls_resumption.conf
new file mode 100644 (file)
index 0000000..3433944
--- /dev/null
@@ -0,0 +1,300 @@
+# Generated with generate_ssl_tests.pl
+
+num_tests = 8
+
+test-0 = 0-resumption
+test-1 = 1-resumption
+test-2 = 2-resumption
+test-3 = 3-resumption
+test-4 = 4-resumption
+test-5 = 5-resumption
+test-6 = 6-resumption
+test-7 = 7-resumption
+# ===========================================================
+
+[0-resumption]
+ssl_conf = 0-resumption-ssl
+
+[0-resumption-ssl]
+server = 0-resumption-server
+resume-server = 0-resumption-resume-server
+client = 0-resumption-client
+
+[0-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1
+MinProtocol = DTLSv1
+Options = SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[0-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[0-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-0]
+HandshakeMode = Resume
+Method = DTLS
+Protocol = DTLSv1
+ResumptionExpected = Yes
+
+
+# ===========================================================
+
+[1-resumption]
+ssl_conf = 1-resumption-ssl
+
+[1-resumption-ssl]
+server = 1-resumption-server
+resume-server = 1-resumption-resume-server
+client = 1-resumption-client
+
+[1-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1
+MinProtocol = DTLSv1
+Options = -SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[1-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[1-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-1]
+HandshakeMode = Resume
+Method = DTLS
+Protocol = DTLSv1
+ResumptionExpected = Yes
+
+
+# ===========================================================
+
+[2-resumption]
+ssl_conf = 2-resumption-ssl
+
+[2-resumption-ssl]
+server = 2-resumption-server
+resume-server = 2-resumption-resume-server
+client = 2-resumption-client
+
+[2-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1
+MinProtocol = DTLSv1
+Options = SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[2-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1.2
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[2-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-2]
+HandshakeMode = Resume
+Method = DTLS
+Protocol = DTLSv1.2
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[3-resumption]
+ssl_conf = 3-resumption-ssl
+
+[3-resumption-ssl]
+server = 3-resumption-server
+resume-server = 3-resumption-resume-server
+client = 3-resumption-client
+
+[3-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1
+MinProtocol = DTLSv1
+Options = -SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[3-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1.2
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[3-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-3]
+HandshakeMode = Resume
+Method = DTLS
+Protocol = DTLSv1.2
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[4-resumption]
+ssl_conf = 4-resumption-ssl
+
+[4-resumption-ssl]
+server = 4-resumption-server
+resume-server = 4-resumption-resume-server
+client = 4-resumption-client
+
+[4-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1.2
+MinProtocol = DTLSv1.2
+Options = SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[4-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[4-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-4]
+HandshakeMode = Resume
+Method = DTLS
+Protocol = DTLSv1
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[5-resumption]
+ssl_conf = 5-resumption-ssl
+
+[5-resumption-ssl]
+server = 5-resumption-server
+resume-server = 5-resumption-resume-server
+client = 5-resumption-client
+
+[5-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1.2
+MinProtocol = DTLSv1.2
+Options = -SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[5-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[5-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-5]
+HandshakeMode = Resume
+Method = DTLS
+Protocol = DTLSv1
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[6-resumption]
+ssl_conf = 6-resumption-ssl
+
+[6-resumption-ssl]
+server = 6-resumption-server
+resume-server = 6-resumption-resume-server
+client = 6-resumption-client
+
+[6-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1.2
+MinProtocol = DTLSv1.2
+Options = SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[6-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1.2
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[6-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-6]
+HandshakeMode = Resume
+Method = DTLS
+Protocol = DTLSv1.2
+ResumptionExpected = Yes
+
+
+# ===========================================================
+
+[7-resumption]
+ssl_conf = 7-resumption-ssl
+
+[7-resumption-ssl]
+server = 7-resumption-server
+resume-server = 7-resumption-resume-server
+client = 7-resumption-client
+
+[7-resumption-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1.2
+MinProtocol = DTLSv1.2
+Options = -SessionTicket
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[7-resumption-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = DTLSv1.2
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[7-resumption-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-7]
+HandshakeMode = Resume
+Method = DTLS
+Protocol = DTLSv1.2
+ResumptionExpected = Yes
+
+
diff --git a/test/ssl-tests/11-dtls_resumption.conf.in b/test/ssl-tests/11-dtls_resumption.conf.in
new file mode 100644 (file)
index 0000000..16dec1d
--- /dev/null
@@ -0,0 +1,19 @@
+# -*- 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 upon resumption.
+
+use strict;
+use warnings;
+
+package ssltests;
+
+use protocol_version;
+
+our @tests = generate_resumption_tests("DTLS");
index cb99756..276adfd 100644 (file)
@@ -71,12 +71,18 @@ foreach my $i (0..$#dtls_protocols) {
     }
 }
 
-sub generate_tests {
+sub no_tests {
+    my ($dtls) = @_;
+    return $dtls ? alldisabled("dtls1", "dtls1_2") :
+      alldisabled("ssl3", "tls1", "tls1_1", "tls1_2");
+}
+
+sub generate_version_tests {
     my ($method) = @_;
 
     my $dtls = $method eq "DTLS";
     # Don't write the redundant "Method = TLS" into the configuration.
-    undef $method if !$dtls; 
+    undef $method if !$dtls;
 
     my @protocols = $dtls ? @dtls_protocols : @tls_protocols;
     my @min_protocols = $dtls ? @min_dtls_protocols : @min_tls_protocols;
@@ -84,9 +90,7 @@ sub generate_tests {
     my $min_enabled  = $dtls ? $min_dtls_enabled : $min_tls_enabled;
     my $max_enabled  = $dtls ? $max_dtls_enabled : $max_tls_enabled;
 
-    my $no_tests = $dtls ? alldisabled("dtls1", "dtls1_2") :
-      alldisabled("ssl3", "tls1", "tls1_1", "tls1_2");
-    if ($no_tests) {
+    if (no_tests($dtls)) {
         return;
     }
 
@@ -124,6 +128,61 @@ sub generate_tests {
     return @tests;
 }
 
+sub generate_resumption_tests {
+    my ($method) = @_;
+
+    my $dtls = $method eq "DTLS";
+    # Don't write the redundant "Method = TLS" into the configuration.
+    undef $method if !$dtls;
+
+    my @protocols = $dtls ? @dtls_protocols : @tls_protocols;
+    my $min_enabled  = $dtls ? $min_dtls_enabled : $min_tls_enabled;
+
+    if (no_tests($dtls)) {
+        return;
+    }
+
+    my @tests = ();
+
+    # Obtain the first session against a fixed-version server.
+    foreach my $original_protocol($min_enabled..$#protocols) {
+        # Upgrade or downgrade the server max version support and test
+        # that it upgrades, downgrades or resumes the session as well.
+        foreach my $resume_protocol($min_enabled..$#protocols) {
+            my $resumption_expected;
+            # We should only resume on exact version match.
+            if ($original_protocol eq $resume_protocol) {
+                $resumption_expected = "Yes";
+            } else {
+                $resumption_expected = "No";
+            }
+
+            foreach my $ticket ("SessionTicket", "-SessionTicket") {
+                push @tests, {
+                    "name" => "resumption",
+                    "client" => { },
+                    "server" => {
+                        "MinProtocol" => $protocols[$original_protocol],
+                        "MaxProtocol" => $protocols[$original_protocol],
+                        "Options" => $ticket,
+                    },
+                    "resume_server" => {
+                        "MaxProtocol" => $protocols[$resume_protocol],
+                    },
+                    "test" => {
+                        "Protocol" => $protocols[$resume_protocol],
+                        "Method" => $method,
+                        "HandshakeMode" => "Resume",
+                        "ResumptionExpected" => $resumption_expected,
+                    }
+                };
+            }
+        }
+    }
+
+    return @tests;
+}
+
 sub expected_result {
     my ($c_min, $c_max, $s_min, $s_max, $min_enabled, $max_enabled,
         $protocols) = @_;
index 5a3aaa8..c5deeb2 100644 (file)
@@ -174,6 +174,21 @@ static int check_alpn(HANDSHAKE_RESULT *result, SSL_TEST_CTX *test_ctx)
     return ret;
 }
 
+static int check_resumption(HANDSHAKE_RESULT *result, SSL_TEST_CTX *test_ctx)
+{
+    if (result->client_resumed != result->server_resumed) {
+        fprintf(stderr, "Resumption mismatch (client vs server): %d vs %d\n",
+                result->client_resumed, result->server_resumed);
+        return 0;
+    }
+    if (result->client_resumed != test_ctx->resumption_expected) {
+        fprintf(stderr, "ResumptionExpected mismatch: %d vs %d\n",
+                test_ctx->resumption_expected, result->client_resumed);
+        return 0;
+    }
+    return 1;
+}
+
 /*
  * This could be further simplified by constructing an expected
  * HANDSHAKE_RESULT, and implementing comparison methods for
@@ -191,6 +206,7 @@ static int check_test(HANDSHAKE_RESULT *result, SSL_TEST_CTX *test_ctx)
         ret &= (result->session_ticket_do_not_call == 0);
         ret &= check_npn(result, test_ctx);
         ret &= check_alpn(result, test_ctx);
+        ret &= check_resumption(result, test_ctx);
     }
     return ret;
 }
@@ -198,7 +214,8 @@ static int check_test(HANDSHAKE_RESULT *result, SSL_TEST_CTX *test_ctx)
 static int execute_test(SSL_TEST_FIXTURE fixture)
 {
     int ret = 0;
-    SSL_CTX *server_ctx = NULL, *server2_ctx = NULL, *client_ctx = NULL;
+    SSL_CTX *server_ctx = NULL, *server2_ctx = NULL, *client_ctx = NULL,
+        *resume_server_ctx = NULL;
     SSL_TEST_CTX *test_ctx = NULL;
     HANDSHAKE_RESULT *result = NULL;
 
@@ -214,6 +231,10 @@ static int execute_test(SSL_TEST_FIXTURE fixture)
             OPENSSL_assert(server2_ctx != NULL);
         }
         client_ctx = SSL_CTX_new(DTLS_client_method());
+        if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RESUME) {
+            resume_server_ctx = SSL_CTX_new(DTLS_server_method());
+            OPENSSL_assert(resume_server_ctx != NULL);
+        }
     }
 #endif
     if (test_ctx->method == SSL_TEST_METHOD_TLS) {
@@ -223,6 +244,11 @@ static int execute_test(SSL_TEST_FIXTURE fixture)
             OPENSSL_assert(server2_ctx != NULL);
         }
         client_ctx = SSL_CTX_new(TLS_client_method());
+
+        if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RESUME) {
+            resume_server_ctx = SSL_CTX_new(TLS_server_method());
+            OPENSSL_assert(resume_server_ctx != NULL);
+        }
     }
 
     OPENSSL_assert(server_ctx != NULL && client_ctx != NULL);
@@ -236,8 +262,12 @@ static int execute_test(SSL_TEST_FIXTURE fixture)
 
     if (server2_ctx != NULL && !SSL_CTX_config(server2_ctx, "server2"))
         goto err;
+    if (resume_server_ctx != NULL
+        && !SSL_CTX_config(resume_server_ctx, "resume-server"))
+        goto err;
 
-    result = do_handshake(server_ctx, server2_ctx, client_ctx, test_ctx);
+    result = do_handshake(server_ctx, server2_ctx, client_ctx,
+                          resume_server_ctx, test_ctx);
 
     ret = check_test(result, test_ctx);
 
@@ -246,6 +276,7 @@ err:
     SSL_CTX_free(server_ctx);
     SSL_CTX_free(server2_ctx);
     SSL_CTX_free(client_ctx);
+    SSL_CTX_free(resume_server_ctx);
     SSL_TEST_CTX_free(test_ctx);
     if (ret != 1)
         ERR_print_errors_fp(stderr);
index 6a5333e..3169918 100644 (file)
@@ -3,11 +3,14 @@ ssl_conf = {-$testname-}-ssl
 
 [{-$testname-}-ssl]
 server = {-$testname-}-server{-
-    # The server2 section is optional.
+    # The following sections are optional.
     $OUT = "";
     if (%server2) {
         $OUT .= "\nserver2 = $testname-server2";
     }
+    if (%resume_server) {
+        $OUT .= "\nresume-server = $testname-resume-server";
+    }
 -}
 client = {-$testname-}-client
 
@@ -22,6 +25,12 @@ client = {-$testname-}-client
             $OUT .= qq{$key} . " = " . qq{$server2{$key}\n} if defined $server2{$key};
         }
     }
+    if (%resume_server) {
+        $OUT .= "\n[$testname-resume-server]\n";
+        foreach my $key (sort keys %resume_server) {
+            $OUT .= qq{$key} . " = " . qq{$resume_server{$key}\n} if defined $resume_server{$key};
+        }
+    }
 -}
 [{-$testname-}-client]
 {-
index 090e1a3..8dd63ae 100644 (file)
@@ -304,6 +304,54 @@ IMPLEMENT_SSL_TEST_CTX_STRING_OPTION(server_alpn_protocols)
 IMPLEMENT_SSL_TEST_CTX_STRING_OPTION(server2_alpn_protocols)
 IMPLEMENT_SSL_TEST_CTX_STRING_OPTION(expected_alpn_protocol)
 
+/***********************/
+/* Handshake mode      */
+/***********************/
+
+static const test_enum ssl_handshake_modes[] = {
+    {"Simple", SSL_TEST_HANDSHAKE_SIMPLE},
+    {"Resume", SSL_TEST_HANDSHAKE_RESUME},
+    {"Renegotiate", SSL_TEST_HANDSHAKE_RENEGOTIATE},
+};
+
+__owur static int parse_handshake_mode(SSL_TEST_CTX *test_ctx, const char *value)
+{
+    int ret_value;
+    if (!parse_enum(ssl_handshake_modes, OSSL_NELEM(ssl_handshake_modes),
+                    &ret_value, value)) {
+        return 0;
+    }
+    test_ctx->handshake_mode = ret_value;
+    return 1;
+}
+
+const char *ssl_handshake_mode_name(ssl_handshake_mode_t mode)
+{
+    return enum_name(ssl_handshake_modes, OSSL_NELEM(ssl_handshake_modes),
+                     mode);
+}
+
+static int parse_boolean(const char *value, int *result)
+{
+    if (strcmp(value, "Yes") == 0) {
+        *result = 1;
+        return 1;
+    }
+    else if (strcmp(value, "No") == 0) {
+        *result = 0;
+        return 1;
+    }
+    return 0;
+}
+
+#define IMPLEMENT_SSL_TEST_CTX_BOOL_OPTION(field)                       \
+    static int parse_##field(SSL_TEST_CTX *test_ctx, const char *value) \
+    {                                                                   \
+        return parse_boolean(value, &test_ctx->field);                  \
+    }
+
+IMPLEMENT_SSL_TEST_CTX_BOOL_OPTION(resumption_expected)
+
 /*************************************************************/
 /* Known test options and their corresponding parse methods. */
 /*************************************************************/
@@ -332,6 +380,8 @@ static const ssl_test_ctx_option ssl_test_ctx_options[] = {
     { "ServerALPNProtocols", &parse_server_alpn_protocols },
     { "Server2ALPNProtocols", &parse_server2_alpn_protocols },
     { "ExpectedALPNProtocol", &parse_expected_alpn_protocol },
+    { "HandshakeMode", &parse_handshake_mode },
+    { "ResumptionExpected", &parse_resumption_expected },
 };
 
 /*
@@ -377,7 +427,7 @@ SSL_TEST_CTX *SSL_TEST_CTX_create(const CONF *conf, const char *test_section)
         int found = 0;
         const CONF_VALUE *option = sk_CONF_VALUE_value(sk_conf, i);
         for (j = 0; j < OSSL_NELEM(ssl_test_ctx_options); j++) {
-            if (strcmp(option->name, ssl_test_ctx_options[j].name) == 0) {
+            if (strcasecmp(option->name, ssl_test_ctx_options[j].name) == 0) {
                 if (!ssl_test_ctx_options[j].parse(ctx, option->value)) {
                     fprintf(stderr, "Bad value %s for option %s\n",
                             option->value, option->name);
index a96245e..d3d86e7 100644 (file)
@@ -17,7 +17,9 @@ typedef enum {
     SSL_TEST_SUCCESS = 0,  /* Default */
     SSL_TEST_SERVER_FAIL,
     SSL_TEST_CLIENT_FAIL,
-    SSL_TEST_INTERNAL_ERROR
+    SSL_TEST_INTERNAL_ERROR,
+    /* Couldn't test resumption/renegotiation: original handshake failed. */
+    SSL_TEST_FIRST_HANDSHAKE_FAILED
 } ssl_test_result_t;
 
 typedef enum {
@@ -39,7 +41,6 @@ typedef enum {
     SSL_TEST_SERVERNAME_REJECT_MISMATCH
 } ssl_servername_callback_t;
 
-
 typedef enum {
     SSL_TEST_SESSION_TICKET_IGNORE = 0, /* Default */
     SSL_TEST_SESSION_TICKET_YES,
@@ -52,6 +53,13 @@ typedef enum {
     SSL_TEST_METHOD_DTLS
 } ssl_test_method_t;
 
+typedef enum {
+    SSL_TEST_HANDSHAKE_SIMPLE = 0, /* Default */
+    SSL_TEST_HANDSHAKE_RESUME,
+    /* Not yet implemented */
+    SSL_TEST_HANDSHAKE_RENEGOTIATE
+} ssl_handshake_mode_t;
+
 typedef struct ssl_test_ctx {
     /* Test expectations. */
     /* Defaults to SUCCESS. */
@@ -96,6 +104,10 @@ typedef struct ssl_test_ctx {
     char *server_alpn_protocols;
     char *server2_alpn_protocols;
     char *expected_alpn_protocol;
+    /* Whether to test a resumed/renegotiated handshake. */
+    ssl_handshake_mode_t handshake_mode;
+    /* Whether the second handshake is resumed or a full handshake (boolean). */
+    int resumption_expected;
 } SSL_TEST_CTX;
 
 const char *ssl_test_result_name(ssl_test_result_t result);
@@ -107,6 +119,7 @@ const char *ssl_servername_callback_name(ssl_servername_callback_t
                                          servername_callback);
 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);
 
 /*
  * Load the test case context from |conf|.
index b3e2e70..6366e0a 100644 (file)
@@ -92,7 +92,12 @@ static int SSL_TEST_CTX_equal(SSL_TEST_CTX *ctx, SSL_TEST_CTX *ctx2)
     if (!strings_equal("ClientNPNProtocols", ctx->client_npn_protocols,
                        ctx2->client_npn_protocols))
         return 0;
-
+    if (ctx->method != ctx2->method) {
+        fprintf(stderr, "Method mismatch: %s vs %s.\n",
+                ssl_test_method_name(ctx->method),
+                ssl_test_method_name(ctx2->method));
+        return 0;
+    }
     if (!strings_equal("ServerNPNProtocols", ctx->server_npn_protocols,
                        ctx2->server_npn_protocols))
         return 0;
@@ -115,6 +120,17 @@ static int SSL_TEST_CTX_equal(SSL_TEST_CTX *ctx, SSL_TEST_CTX *ctx2)
     if (!strings_equal("ExpectedALPNProtocol", ctx->expected_alpn_protocol,
                        ctx2->expected_alpn_protocol))
         return 0;
+    if (ctx->handshake_mode != ctx2->handshake_mode) {
+        fprintf(stderr, "HandshakeMode mismatch: %s vs %s.\n",
+                ssl_handshake_mode_name(ctx->handshake_mode),
+                ssl_handshake_mode_name(ctx2->handshake_mode));
+        return 0;
+    }
+    if (ctx->resumption_expected != ctx2->resumption_expected) {
+        fprintf(stderr, "ResumptionExpected mismatch: %d vs %d.\n",
+                ctx->resumption_expected, ctx2->resumption_expected);
+        return 0;
+    }
     return 1;
 }
 
@@ -202,6 +218,8 @@ static int test_good_configuration()
     fixture.expected_ctx->server2_alpn_protocols = OPENSSL_strdup("baz");
     OPENSSL_assert(fixture.expected_ctx->client_npn_protocols != NULL);
     OPENSSL_assert(fixture.expected_ctx->server2_alpn_protocols != NULL);
+    fixture.expected_ctx->handshake_mode = SSL_TEST_HANDSHAKE_RESUME;
+    fixture.expected_ctx->resumption_expected = 1;
     EXECUTE_SSL_TEST_CTX_TEST();
 }
 
@@ -215,6 +233,8 @@ static const char *bad_configurations[] = {
     "ssltest_unknown_servername_callback",
     "ssltest_unknown_session_ticket_expected",
     "ssltest_unknown_method",
+    "ssltest_unknown_handshake_mode",
+    "ssltest_unknown_resumption_expected",
 };
 
 static int test_bad_configuration(int idx)
index 17925b5..1f76155 100644 (file)
@@ -12,6 +12,8 @@ SessionTicketExpected = Yes
 Method = DTLS
 ClientNPNProtocols = foo,bar
 Server2ALPNProtocols = baz
+HandshakeMode = Resume
+ResumptionExpected = Yes
 
 [ssltest_unknown_option]
 UnknownOption = Foo
@@ -39,3 +41,9 @@ SessionTicketExpected = Foo
 
 [ssltest_unknown_method]
 Method = TLS2
+
+[ssltest_unknown_handshake_mode]
+HandshakeMode = Foo
+
+[ssltest_unknown_resumption_expected]
+ResumptionExpected = Foo