Add support for testing renegotiation
authorMatt Caswell <matt@openssl.org>
Mon, 26 Sep 2016 16:25:43 +0000 (17:25 +0100)
committerMatt Caswell <matt@openssl.org>
Wed, 28 Sep 2016 08:15:07 +0000 (09:15 +0100)
Reviewed-by: Rich Salz <rsalz@openssl.org>
test/handshake_helper.c
test/recipes/80-test_ssl_new.t
test/ssl-tests/17-renegotiate.conf [new file with mode: 0644]
test/ssl-tests/17-renegotiate.conf.in [new file with mode: 0644]
test/ssl_test_ctx.h

index 3cfee16..1c6ad48 100644 (file)
@@ -583,6 +583,54 @@ static void do_app_data_step(PEER *peer)
     }
 }
 
+static void do_reneg_setup_step(PEER *peer)
+{
+    int ret;
+    char buf;
+
+    TEST_check(peer->status == PEER_RETRY);
+    /* We only support client initiated reneg at the moment */
+    /* TODO: server side */
+    if (!SSL_is_server(peer->ssl)) {
+        ret = SSL_renegotiate(peer->ssl);
+        if (!ret) {
+            peer->status = PEER_ERROR;
+            return;
+        }
+        do_handshake_step(peer);
+        /*
+         * If status is PEER_RETRY it means we're waiting on the server to
+         * continue the handshake. As far as setting up the renegotiation is
+         * concerned that is a success. The next step will continue the
+         * handshake to its conclusion.
+         */
+        if (peer->status == PEER_RETRY)
+            peer->status = PEER_SUCCESS;
+        return;
+    }
+
+    /*
+     * The SSL object is still expecting app data, even though it's going to
+     * get a handshake message. We try to read, and it should fail - after which
+     * we should be in a handshake
+     */
+    ret = SSL_read(peer->ssl, &buf, sizeof(buf));
+    if (ret >= 0) {
+        /* We're not actually expecting data - we're expect a reneg to start */
+        peer->status = PEER_ERROR;
+        return;
+    } else {
+        int error = SSL_get_error(peer->ssl, ret);
+        if (error != SSL_ERROR_WANT_READ || !SSL_in_init(peer->ssl)) {
+            peer->status = PEER_ERROR;
+            return;
+        }
+    }
+
+    peer->status = PEER_SUCCESS;
+}
+
+
 /*
  * RFC 5246 says:
  *
@@ -617,15 +665,27 @@ static void do_shutdown_step(PEER *peer)
 
 typedef enum {
     HANDSHAKE,
+    RENEG_APPLICATION_DATA,
+    RENEG_SETUP,
+    RENEG_HANDSHAKE,
     APPLICATION_DATA,
     SHUTDOWN,
     CONNECTION_DONE
 } connect_phase_t;
 
-static connect_phase_t next_phase(connect_phase_t phase)
+static connect_phase_t next_phase(const SSL_TEST_CTX *test_ctx,
+                                  connect_phase_t phase)
 {
     switch (phase) {
     case HANDSHAKE:
+        if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEGOTIATE)
+            return RENEG_APPLICATION_DATA;
+        return APPLICATION_DATA;
+    case RENEG_APPLICATION_DATA:
+        return RENEG_SETUP;
+    case RENEG_SETUP:
+        return RENEG_HANDSHAKE;
+    case RENEG_HANDSHAKE:
         return APPLICATION_DATA;
     case APPLICATION_DATA:
         return SHUTDOWN;
@@ -644,6 +704,15 @@ static void do_connect_step(PEER *peer, connect_phase_t phase)
     case HANDSHAKE:
         do_handshake_step(peer);
         break;
+    case RENEG_APPLICATION_DATA:
+        do_app_data_step(peer);
+        break;
+    case RENEG_SETUP:
+        do_reneg_setup_step(peer);
+        break;
+    case RENEG_HANDSHAKE:
+        do_handshake_step(peer);
+        break;
     case APPLICATION_DATA:
         do_app_data_step(peer);
         break;
@@ -857,7 +926,7 @@ static HANDSHAKE_RESULT *do_handshake_internal(
 
         switch (status) {
         case HANDSHAKE_SUCCESS:
-            phase = next_phase(phase);
+            phase = next_phase(test_ctx, phase);
             if (phase == CONNECTION_DONE) {
                 ret->result = SSL_TEST_SUCCESS;
                 goto err;
@@ -945,11 +1014,9 @@ HANDSHAKE_RESULT *do_handshake(SSL_CTX *server_ctx, SSL_CTX *server2_ctx,
     result = do_handshake_internal(server_ctx, server2_ctx, client_ctx,
                                    test_ctx, &test_ctx->extra,
                                    NULL, &session);
-    if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_SIMPLE)
+    if (test_ctx->handshake_mode != SSL_TEST_HANDSHAKE_RESUME)
         goto end;
 
-    TEST_check(test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RESUME);
-
     if (result->result != SSL_TEST_SUCCESS) {
         result->result = SSL_TEST_FIRST_HANDSHAKE_FAILED;
         goto end;
index 47eab18..d496f21 100644 (file)
@@ -29,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 => 16;  # = scalar @conf_srcs
+plan tests => 17;  # = scalar @conf_srcs
 
 # Some test results depend on the configuration of enabled protocols. We only
 # verify generated sources in the default configuration.
diff --git a/test/ssl-tests/17-renegotiate.conf b/test/ssl-tests/17-renegotiate.conf
new file mode 100644 (file)
index 0000000..5ef4b0a
--- /dev/null
@@ -0,0 +1,30 @@
+# Generated with generate_ssl_tests.pl
+
+num_tests = 1
+
+test-0 = 0-renegotiate
+# ===========================================================
+
+[0-renegotiate]
+ssl_conf = 0-renegotiate-ssl
+
+[0-renegotiate-ssl]
+server = 0-renegotiate-server
+client = 0-renegotiate-client
+
+[0-renegotiate-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[0-renegotiate-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-0]
+ExpectedResult = Success
+HandshakeMode = Renegotiate
+Method = TLS
+
+
diff --git a/test/ssl-tests/17-renegotiate.conf.in b/test/ssl-tests/17-renegotiate.conf.in
new file mode 100644 (file)
index 0000000..6cecd7e
--- /dev/null
@@ -0,0 +1,29 @@
+# -*- 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 Renegotiation
+
+use strict;
+use warnings;
+
+package ssltests;
+
+
+our @tests = (
+    {
+        name => "renegotiate",
+        server => {},
+        client => {},
+        test => {
+            "Method" => "TLS",
+            "HandshakeMode" => "Renegotiate",
+            "ExpectedResult" => "Success"
+        }
+    },
+);
index c8c66d6..73e223a 100644 (file)
@@ -56,7 +56,6 @@ typedef enum {
 typedef enum {
     SSL_TEST_HANDSHAKE_SIMPLE = 0, /* Default */
     SSL_TEST_HANDSHAKE_RESUME,
-    /* Not yet implemented */
     SSL_TEST_HANDSHAKE_RENEGOTIATE
 } ssl_handshake_mode_t;