Add an sslapitest for early callback
authorBenjamin Kaduk <bkaduk@akamai.com>
Mon, 13 Feb 2017 18:42:43 +0000 (12:42 -0600)
committerRichard Levitte <levitte@openssl.org>
Thu, 23 Feb 2017 18:40:27 +0000 (19:40 +0100)
Make sure that we can stop handshake processing and resume it later.
Also check that the cipher list and compression methods are sane.
Unfortunately, we don't have the client-side APIs needed to force
a specific (known) session ID to be sent in the ClientHello, so
that accessor cannot be tested here.

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2279)

test/sslapitest.c

index cc852952e7cf45b56653c87c7452e2477a9c6870..f492e0bae4942556c1cf5039a75ea20aac95423e 100644 (file)
@@ -477,6 +477,89 @@ end:
 }
 #endif
 
+static int full_early_callback(SSL *s, int *al, void *arg)
+{
+    int *ctr = arg;
+    const unsigned char *p;
+    /* We only configure two ciphers, but the SCSV is added automatically. */
+#ifdef OPENSSL_NO_EC
+    const unsigned char expected_ciphers[] = {0x00, 0x9d, 0x00, 0xff};
+#else
+    const unsigned char expected_ciphers[] = {0x00, 0x9d, 0xc0,
+                                              0x2c, 0x00, 0xff};
+#endif
+    size_t len;
+
+    /* Make sure we can defer processing and get called back. */
+    if ((*ctr)++ == 0)
+        return -1;
+
+    len = SSL_early_get0_ciphers(s, &p);
+    if (len != sizeof(expected_ciphers) ||
+        memcmp(p, expected_ciphers, len) != 0) {
+        printf("Early callback expected ciphers mismatch\n");
+        return 0;
+    }
+    len = SSL_early_get0_compression_methods(s, &p);
+    if (len != 1 || *p != 0) {
+        printf("Early callback expected comperssion methods mismatch\n");
+        return 0;
+    }
+    return 1;
+}
+
+static int test_early_cb(void) {
+    SSL_CTX *cctx = NULL, *sctx = NULL;
+    SSL *clientssl = NULL, *serverssl = NULL;
+    int testctr = 0, testresult = 0;
+
+    if (!create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(), &sctx,
+                             &cctx, cert, privkey)) {
+        printf("Unable to create SSL_CTX pair\n");
+        goto end;
+    }
+
+    SSL_CTX_set_early_cb(sctx, full_early_callback, &testctr);
+    /* The gimpy cipher list we configure can't do TLS 1.3. */
+    SSL_CTX_set_max_proto_version(cctx, TLS1_2_VERSION);
+    if (!SSL_CTX_set_cipher_list(cctx,
+            "AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384")) {
+        printf("Failed to set cipher list\n");
+        goto end;
+    }
+
+    if (!create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) {
+        printf("Unable to create SSL objects\n");
+        goto end;
+    }
+
+    if (create_ssl_connection(serverssl, clientssl, SSL_ERROR_WANT_EARLY)) {
+        printf("Creating SSL connection succeeded with async early return\n");
+        goto end;
+    }
+
+    /* Passing a -1 literal is a hack since the real value was lost. */
+    if (SSL_get_error(serverssl, -1) != SSL_ERROR_WANT_EARLY) {
+        printf("Early callback failed to make state SSL_ERROR_WANT_EARLY\n");
+        goto end;
+    }
+
+    if (!create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) {
+        printf("Restarting SSL connection failed\n");
+        goto end;
+    }
+
+    testresult = 1;
+
+end:
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    SSL_CTX_free(sctx);
+    SSL_CTX_free(cctx);
+
+    return testresult;
+}
+
 static int execute_test_large_message(const SSL_METHOD *smeth,
                                       const SSL_METHOD *cmeth, int read_ahead)
 {
@@ -1485,6 +1568,7 @@ int test_main(int argc, char *argv[])
 #ifndef OPENSSL_NO_TLS1_3
     ADD_TEST(test_keylog_no_master_key);
 #endif
+    ADD_TEST(test_early_cb);
 
     testresult = run_tests(argv[0]);