Add comments to test_ciphersuite_change()
[openssl.git] / test / sslapitest.c
index a2424cf748e7bebe1ce63faf34ec00d62a6aeb03..a161989a65c348522f33dfc0952f7b9dbc8e88c8 100644 (file)
@@ -18,6 +18,7 @@
 #include "ssltestlib.h"
 #include "testutil.h"
 #include "e_os.h"
+#include "../ssl/ssl_locl.h"
 
 static char *cert = NULL;
 static char *privkey = NULL;
@@ -404,6 +405,7 @@ static int full_early_callback(SSL *s, int *al, void *arg)
 {
     int *ctr = arg;
     const unsigned char *p;
+    int *exts;
     /* We only configure two ciphers, but the SCSV is added automatically. */
 #ifdef OPENSSL_NO_EC
     const unsigned char expected_ciphers[] = {0x00, 0x9d, 0x00, 0xff};
@@ -411,6 +413,11 @@ static int full_early_callback(SSL *s, int *al, void *arg)
     const unsigned char expected_ciphers[] = {0x00, 0x9d, 0xc0,
                                               0x2c, 0x00, 0xff};
 #endif
+    const int expected_extensions[] = {
+#ifndef OPENSSL_NO_EC
+                                       11, 10,
+#endif
+                                       35, 13, 22, 23};
     size_t len;
 
     /* Make sure we can defer processing and get called back. */
@@ -422,6 +429,15 @@ static int full_early_callback(SSL *s, int *al, void *arg)
             || !TEST_size_t_eq(SSL_early_get0_compression_methods(s, &p), 1)
             || !TEST_int_eq(*p, 0))
         return 0;
+    if (!SSL_early_get1_extensions_present(s, &exts, &len))
+        return 0;
+    if (len != OSSL_NELEM(expected_extensions) ||
+        memcmp(exts, expected_extensions, len * sizeof(*exts)) != 0) {
+        printf("Early callback expected ClientHello extensions mismatch\n");
+        OPENSSL_free(exts);
+        return 0;
+    }
+    OPENSSL_free(exts);
     return 1;
 }
 
@@ -1782,8 +1798,136 @@ static int test_early_data_tls1_2(int idx)
 
     return testresult;
 }
-# endif
-#endif
+# endif /* OPENSSL_NO_TLS1_2 */
+
+static int test_ciphersuite_change(void)
+{
+    SSL_CTX *cctx = NULL, *sctx = NULL;
+    SSL *clientssl = NULL, *serverssl = NULL;
+    SSL_SESSION *clntsess = NULL;
+    int testresult = 0;
+    const SSL_CIPHER *aes_128_gcm_sha256 = NULL;
+
+    /* Create a session based on SHA-256 */
+    if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(),
+                                       TLS_client_method(), &sctx,
+                                       &cctx, cert, privkey))
+            || !TEST_true(SSL_CTX_set_cipher_list(cctx,
+                                                  "TLS13-AES-128-GCM-SHA256"))
+            || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
+                                          &clientssl, NULL, NULL))
+            || !TEST_true(create_ssl_connection(serverssl, clientssl,
+                                                SSL_ERROR_NONE)))
+        goto end;
+
+    clntsess = SSL_get1_session(clientssl);
+    /* Save for later */
+    aes_128_gcm_sha256 = SSL_SESSION_get0_cipher(clntsess);
+    SSL_shutdown(clientssl);
+    SSL_shutdown(serverssl);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    serverssl = clientssl = NULL;
+
+    /* Check we can resume a session with a different SHA-256 ciphersuite */
+    if (!TEST_true(SSL_CTX_set_cipher_list(cctx,
+                                           "TLS13-CHACHA20-POLY1305-SHA256"))
+            || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                             NULL, NULL))
+            || !TEST_true(SSL_set_session(clientssl, clntsess))
+            || !TEST_true(create_ssl_connection(serverssl, clientssl,
+                                                SSL_ERROR_NONE))
+            || !TEST_true(SSL_session_reused(clientssl)))
+        goto end;
+
+    SSL_SESSION_free(clntsess);
+    clntsess = SSL_get1_session(clientssl);
+    SSL_shutdown(clientssl);
+    SSL_shutdown(serverssl);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    serverssl = clientssl = NULL;
+
+    /*
+     * Check attempting to resume a SHA-256 session with no SHA-256 ciphersuites
+     * succeeds but does not resume.
+     */
+    if (!TEST_true(SSL_CTX_set_cipher_list(cctx, "TLS13-AES-256-GCM-SHA384"))
+            || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                             NULL, NULL))
+            || !TEST_true(SSL_set_session(clientssl, clntsess))
+            || !TEST_true(create_ssl_connection(serverssl, clientssl,
+                                                SSL_ERROR_SSL))
+            || !TEST_false(SSL_session_reused(clientssl)))
+        goto end;
+
+    SSL_SESSION_free(clntsess);
+    clntsess = NULL;
+    SSL_shutdown(clientssl);
+    SSL_shutdown(serverssl);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    serverssl = clientssl = NULL;
+
+    /* Create a session based on SHA384 */
+    if (!TEST_true(SSL_CTX_set_cipher_list(cctx, "TLS13-AES-256-GCM-SHA384"))
+            || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
+                                          &clientssl, NULL, NULL))
+            || !TEST_true(create_ssl_connection(serverssl, clientssl,
+                                                SSL_ERROR_NONE)))
+        goto end;
+
+    clntsess = SSL_get1_session(clientssl);
+    SSL_shutdown(clientssl);
+    SSL_shutdown(serverssl);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    serverssl = clientssl = NULL;
+
+    if (!TEST_true(SSL_CTX_set_cipher_list(cctx,
+                   "TLS13-AES-128-GCM-SHA256:TLS13-AES-256-GCM-SHA384"))
+            || !TEST_true(SSL_CTX_set_cipher_list(sctx,
+                                                  "TLS13-AES-256-GCM-SHA384"))
+            || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                             NULL, NULL))
+            || !TEST_true(SSL_set_session(clientssl, clntsess))
+               /*
+                * We use SSL_ERROR_WANT_READ below so that we can pause the
+                * connection after the initial ClientHello has been sent to
+                * enable us to make some session changes.
+                */
+            || !TEST_false(create_ssl_connection(serverssl, clientssl,
+                                                SSL_ERROR_WANT_READ)))
+        goto end;
+
+    /* Trick the client into thinking this session is for a different digest */
+    clntsess->cipher = aes_128_gcm_sha256;
+    clntsess->cipher_id = clntsess->cipher->id;
+
+    /*
+     * Continue the previously started connection. Server has selected a SHA-384
+     * ciphersuite, but client thinks the session is for SHA-256, so it should
+     * bail out.
+     */
+    if (!TEST_false(create_ssl_connection(serverssl, clientssl,
+                                                SSL_ERROR_SSL))
+            || !TEST_int_eq(ERR_GET_REASON(ERR_get_error()),
+                            SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED))
+        goto end;
+
+    testresult = 1;
+
+ end:
+    SSL_SESSION_free(clntsess);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    SSL_CTX_free(sctx);
+    SSL_CTX_free(cctx);
+
+    return testresult;
+}
+
+#endif /* OPENSSL_NO_TLS1_3 */
 
 static int clntaddoldcb = 0;
 static int clntparseoldcb = 0;
@@ -2207,6 +2351,7 @@ int test_main(int argc, char *argv[])
 # endif
 #endif
 #ifndef OPENSSL_NO_TLS1_3
+    ADD_TEST(test_ciphersuite_change);
     ADD_ALL_TESTS(test_custom_exts, 5);
 #else
     ADD_ALL_TESTS(test_custom_exts, 3);