Extend the renegotiation tests
authorMatt Caswell <matt@openssl.org>
Tue, 27 Sep 2016 10:50:43 +0000 (11:50 +0100)
committerMatt Caswell <matt@openssl.org>
Wed, 28 Sep 2016 08:15:07 +0000 (09:15 +0100)
Add the ability to test both server initiated and client initiated reneg.

Reviewed-by: Rich Salz <rsalz@openssl.org>
test/README.ssltest.md
test/handshake_helper.c
test/ssl-tests/17-renegotiate.conf
test/ssl-tests/17-renegotiate.conf.in
test/ssl_test_ctx.c
test/ssl_test_ctx.h

index ca6edf5..e28d4b0 100644 (file)
@@ -38,7 +38,8 @@ The test section supports the following options
 * HandshakeMode - which handshake flavour to test:
   - Simple - plain handshake (default)
   - Resume - test resumption
-  - Renegotiate - test renegotiation
+  - RenegotiateServer - test server initiated renegotiation
+  - RenegotiateClient - test client initiated renegotiation
 
 When HandshakeMode is Resume or Renegotiate, the original handshake is expected
 to succeed. All configured test expectations are verified against the second
index 1c6ad48..9004489 100644 (file)
@@ -583,30 +583,55 @@ static void do_app_data_step(PEER *peer)
     }
 }
 
-static void do_reneg_setup_step(PEER *peer)
+static void do_reneg_setup_step(const SSL_TEST_CTX *test_ctx, 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);
+    TEST_check(test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_SERVER
+                || test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT);
+
+    /* Check if we are the peer that is going to initiate */
+    if ((test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_SERVER
+                && SSL_is_server(peer->ssl))
+            || (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT
+                && !SSL_is_server(peer->ssl))) {
         /*
-         * 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 we already asked for a renegotiation then fall through to the
+         * SSL_read() below.
          */
-        if (peer->status == PEER_RETRY)
-            peer->status = PEER_SUCCESS;
-        return;
+        if (!SSL_renegotiate_pending(peer->ssl)) {
+            /*
+             * If we are the client we will always attempt to resume the
+             * session. The server may or may not resume dependant on the
+             * setting of SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+             */
+            if (SSL_is_server(peer->ssl))
+                ret = SSL_renegotiate(peer->ssl);
+            else
+                ret = SSL_renegotiate_abbreviated(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 peer 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 status is PEER_SUCCESS then we are the server and we have
+             * successfully sent the HelloRequest. We need to continue to wait
+             * until the handshake arrives from the client.
+             */
+            if (peer->status == PEER_RETRY)
+                peer->status = PEER_SUCCESS;
+            else if (peer->status == PEER_SUCCESS)
+                peer->status = PEER_RETRY;
+            return;
+        }
     }
 
     /*
@@ -616,15 +641,21 @@ static void do_reneg_setup_step(PEER *peer)
      */
     ret = SSL_read(peer->ssl, &buf, sizeof(buf));
     if (ret >= 0) {
-        /* We're not actually expecting data - we're expect a reneg to start */
+        /*
+         * We're not actually expecting data - we're expecting 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)) {
+        if (error != SSL_ERROR_WANT_READ) {
             peer->status = PEER_ERROR;
             return;
         }
+        /* If we're no in init yet then we're not done with setup yet */
+        if (!SSL_in_init(peer->ssl))
+            return;
     }
 
     peer->status = PEER_SUCCESS;
@@ -678,7 +709,8 @@ static connect_phase_t next_phase(const SSL_TEST_CTX *test_ctx,
 {
     switch (phase) {
     case HANDSHAKE:
-        if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEGOTIATE)
+        if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_SERVER
+                || test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT)
             return RENEG_APPLICATION_DATA;
         return APPLICATION_DATA;
     case RENEG_APPLICATION_DATA:
@@ -698,7 +730,8 @@ static connect_phase_t next_phase(const SSL_TEST_CTX *test_ctx,
     return -1;
 }
 
-static void do_connect_step(PEER *peer, connect_phase_t phase)
+static void do_connect_step(const SSL_TEST_CTX *test_ctx, PEER *peer,
+                            connect_phase_t phase)
 {
     switch (phase) {
     case HANDSHAKE:
@@ -708,7 +741,7 @@ static void do_connect_step(PEER *peer, connect_phase_t phase)
         do_app_data_step(peer);
         break;
     case RENEG_SETUP:
-        do_reneg_setup_step(peer);
+        do_reneg_setup_step(test_ctx, peer);
         break;
     case RENEG_HANDSHAKE:
         do_handshake_step(peer);
@@ -915,11 +948,11 @@ static HANDSHAKE_RESULT *do_handshake_internal(
      */
     for(;;) {
         if (client_turn) {
-            do_connect_step(&client, phase);
+            do_connect_step(test_ctx, &client, phase);
             status = handshake_status(client.status, server.status,
                                       1 /* client went last */);
         } else {
-            do_connect_step(&server, phase);
+            do_connect_step(test_ctx, &server, phase);
             status = handshake_status(server.status, client.status,
                                       0 /* server went last */);
         }
index 5ef4b0a..c47a956 100644 (file)
 # Generated with generate_ssl_tests.pl
 
-num_tests = 1
+num_tests = 4
 
-test-0 = 0-renegotiate
+test-0 = 0-renegotiate-client-no-resume
+test-1 = 1-renegotiate-client-resume
+test-2 = 2-renegotiate-server-no-resume
+test-3 = 3-renegotiate-server-resume
 # ===========================================================
 
-[0-renegotiate]
-ssl_conf = 0-renegotiate-ssl
+[0-renegotiate-client-no-resume]
+ssl_conf = 0-renegotiate-client-no-resume-ssl
 
-[0-renegotiate-ssl]
-server = 0-renegotiate-server
-client = 0-renegotiate-client
+[0-renegotiate-client-no-resume-ssl]
+server = 0-renegotiate-client-no-resume-server
+client = 0-renegotiate-client-no-resume-client
 
-[0-renegotiate-server]
+[0-renegotiate-client-no-resume-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = DEFAULT
+Options = NoResumptionOnRenegotiation
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
-[0-renegotiate-client]
+[0-renegotiate-client-no-resume-client]
 CipherString = DEFAULT
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-0]
 ExpectedResult = Success
-HandshakeMode = Renegotiate
+HandshakeMode = RenegotiateClient
 Method = TLS
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[1-renegotiate-client-resume]
+ssl_conf = 1-renegotiate-client-resume-ssl
+
+[1-renegotiate-client-resume-ssl]
+server = 1-renegotiate-client-resume-server
+client = 1-renegotiate-client-resume-client
+
+[1-renegotiate-client-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[1-renegotiate-client-resume-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-1]
+ExpectedResult = Success
+HandshakeMode = RenegotiateClient
+Method = TLS
+ResumptionExpected = Yes
+
+
+# ===========================================================
+
+[2-renegotiate-server-no-resume]
+ssl_conf = 2-renegotiate-server-no-resume-ssl
+
+[2-renegotiate-server-no-resume-ssl]
+server = 2-renegotiate-server-no-resume-server
+client = 2-renegotiate-server-no-resume-client
+
+[2-renegotiate-server-no-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+Options = NoResumptionOnRenegotiation
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[2-renegotiate-server-no-resume-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-2]
+ExpectedResult = Success
+HandshakeMode = RenegotiateServer
+Method = TLS
+ResumptionExpected = No
+
+
+# ===========================================================
+
+[3-renegotiate-server-resume]
+ssl_conf = 3-renegotiate-server-resume-ssl
+
+[3-renegotiate-server-resume-ssl]
+server = 3-renegotiate-server-resume-server
+client = 3-renegotiate-server-resume-client
+
+[3-renegotiate-server-resume-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[3-renegotiate-server-resume-client]
+CipherString = DEFAULT
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-3]
+ExpectedResult = Success
+HandshakeMode = RenegotiateServer
+Method = TLS
+ResumptionExpected = Yes
 
 
index 6cecd7e..a081617 100644 (file)
@@ -17,12 +17,50 @@ package ssltests;
 
 our @tests = (
     {
-        name => "renegotiate",
+        name => "renegotiate-client-no-resume",
+        server => {
+            "Options" => "NoResumptionOnRenegotiation"
+        },
+        client => {},
+        test => {
+            "Method" => "TLS",
+            "HandshakeMode" => "RenegotiateClient",
+            "ResumptionExpected" => "No",
+            "ExpectedResult" => "Success"
+        }
+    },
+    {
+        name => "renegotiate-client-resume",
+        server => {},
+        client => {},
+        test => {
+            "Method" => "TLS",
+            "HandshakeMode" => "RenegotiateClient",
+            "ResumptionExpected" => "Yes",
+            "ExpectedResult" => "Success"
+        }
+    },
+    {
+        name => "renegotiate-server-no-resume",
+        server => {
+            "Options" => "NoResumptionOnRenegotiation"
+        },
+        client => {},
+        test => {
+            "Method" => "TLS",
+            "HandshakeMode" => "RenegotiateServer",
+            "ResumptionExpected" => "No",
+            "ExpectedResult" => "Success"
+        }
+    },
+    {
+        name => "renegotiate-server-resume",
         server => {},
         client => {},
         test => {
             "Method" => "TLS",
-            "HandshakeMode" => "Renegotiate",
+            "HandshakeMode" => "RenegotiateServer",
+            "ResumptionExpected" => "Yes",
             "ExpectedResult" => "Success"
         }
     },
index ee2e8a1..0a528d8 100644 (file)
@@ -339,7 +339,8 @@ IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_CTX, test, expected_alpn_protocol)
 static const test_enum ssl_handshake_modes[] = {
     {"Simple", SSL_TEST_HANDSHAKE_SIMPLE},
     {"Resume", SSL_TEST_HANDSHAKE_RESUME},
-    {"Renegotiate", SSL_TEST_HANDSHAKE_RENEGOTIATE},
+    {"RenegotiateServer", SSL_TEST_HANDSHAKE_RENEG_SERVER},
+    {"RenegotiateClient", SSL_TEST_HANDSHAKE_RENEG_CLIENT},
 };
 
 __owur static int parse_handshake_mode(SSL_TEST_CTX *test_ctx, const char *value)
index 73e223a..14acaff 100644 (file)
@@ -56,7 +56,8 @@ typedef enum {
 typedef enum {
     SSL_TEST_HANDSHAKE_SIMPLE = 0, /* Default */
     SSL_TEST_HANDSHAKE_RESUME,
-    SSL_TEST_HANDSHAKE_RENEGOTIATE
+    SSL_TEST_HANDSHAKE_RENEG_SERVER,
+    SSL_TEST_HANDSHAKE_RENEG_CLIENT
 } ssl_handshake_mode_t;
 
 typedef enum {