Add a test for the ticket callbacks
authorMatt Caswell <matt@openssl.org>
Tue, 8 May 2018 15:29:02 +0000 (16:29 +0100)
committerMatt Caswell <matt@openssl.org>
Fri, 11 May 2018 13:51:08 +0000 (14:51 +0100)
Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6198)

test/sslapitest.c

index 7ebd2e9..1db3998 100644 (file)
@@ -16,6 +16,7 @@
 #include <openssl/ocsp.h>
 #include <openssl/srp.h>
 #include <openssl/txt_db.h>
+#include <openssl/aes.h>
 
 #include "ssltestlib.h"
 #include "testutil.h"
@@ -4593,6 +4594,157 @@ static int test_ssl_get_shared_ciphers(int tst)
     return testresult;
 }
 
+static const char *appdata = "Hello World";
+static int gen_tick_called, dec_tick_called;
+
+static int gen_tick_cb(SSL *s, void *arg)
+{
+    gen_tick_called = 1;
+
+    return SSL_SESSION_set1_ticket_appdata(SSL_get_session(s), appdata,
+                                           strlen(appdata));
+}
+
+static SSL_TICKET_RETURN dec_tick_cb(SSL *s, SSL_SESSION *ss,
+                                     const unsigned char *keyname,
+                                     size_t keyname_length,
+                                     SSL_TICKET_RETURN retv, void *arg)
+{
+    void *tickdata;
+    size_t tickdlen;
+
+    dec_tick_called = 1;
+
+    if (!TEST_true(retv == SSL_TICKET_SUCCESS
+                   || retv == SSL_TICKET_SUCCESS_RENEW))
+        return retv;
+
+    if (!TEST_true(SSL_SESSION_get0_ticket_appdata(ss, &tickdata, &tickdlen))
+            || !TEST_size_t_eq(tickdlen, strlen(appdata))
+            || !TEST_int_eq(memcmp(tickdata, appdata, tickdlen), 0))
+        return SSL_TICKET_FATAL_ERR_OTHER;
+
+    return retv;
+}
+
+static int tick_renew = 0;
+
+static int tick_key_cb(SSL *s, unsigned char key_name[16],
+                       unsigned char iv[EVP_MAX_IV_LENGTH], EVP_CIPHER_CTX *ctx,
+                       HMAC_CTX *hctx, int enc)
+{
+    const unsigned char tick_aes_key[16] = "0123456789abcdef";
+    const unsigned char tick_hmac_key[16] = "0123456789abcdef";
+
+    memset(iv, 0, AES_BLOCK_SIZE);
+    memset(key_name, 0, 16);
+    if (!EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, tick_aes_key, iv, enc)
+            || !HMAC_Init_ex(hctx, tick_hmac_key, sizeof(tick_hmac_key),
+                             EVP_sha256(), NULL))
+        return -1;
+
+    return tick_renew ? 2 : 1;
+}
+
+/*
+ * Test the various ticket callbacks
+ * Test 0: TLSv1.2, no ticket key callback (default no ticket renewal)
+ * Test 1: TLSv1.3, no ticket key callback (default ticket renewal)
+ * Test 2: TLSv1.2, ticket key callback, no ticket renewal
+ * Test 3: TLSv1.3, ticket key callback, no ticket renewal
+ * Test 4: TLSv1.2, ticket key callback, ticket renewal
+ * Test 5: TLSv1.3, ticket key callback, ticket renewal
+ */
+static int test_ticket_callbacks(int tst)
+{
+    SSL_CTX *cctx = NULL, *sctx = NULL;
+    SSL *clientssl = NULL, *serverssl = NULL;
+    SSL_SESSION *clntsess = NULL;
+    int testresult = 0;
+
+#ifdef OPENSSL_NO_TLS1_2
+    if (tst % 2 == 0);
+        return 1;
+#endif
+#ifdef OPENSSL_NO_TLS1_3
+    if (tst % 2 == 1);
+        return 1;
+#endif
+
+    gen_tick_called = dec_tick_called = 0;
+
+    /* Which tests the ticket key callback should request renewal for */
+    if (tst == 4 || tst == 5)
+        tick_renew = 1;
+    else
+        tick_renew = 0;
+
+    if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(),
+                                       TLS_client_method(),
+                                       TLS1_VERSION,
+                                       tst == 0 ? TLS1_2_VERSION
+                                                : TLS1_3_VERSION,
+                                       &sctx, &cctx, cert, privkey)))
+        goto end;
+
+    if (!TEST_true(SSL_CTX_set_session_ticket_cb(sctx, gen_tick_cb, dec_tick_cb,
+                                                 NULL)))
+        goto end;
+
+    if (tst >= 2
+            && !TEST_true(SSL_CTX_set_tlsext_ticket_key_cb(sctx, tick_key_cb)))
+        goto end;
+
+    if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                             NULL, NULL))
+            || !TEST_true(create_ssl_connection(serverssl, clientssl,
+                                                SSL_ERROR_NONE)))
+        goto end;
+
+    if (!TEST_int_eq(gen_tick_called, 1)
+            || !TEST_int_eq(dec_tick_called, 0))
+        goto end;
+
+    gen_tick_called = dec_tick_called = 0;
+
+    clntsess = SSL_get1_session(clientssl);
+    SSL_shutdown(clientssl);
+    SSL_shutdown(serverssl);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    serverssl = clientssl = NULL;
+
+    /* Now do a resumption */
+    if (!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;
+
+    /*
+     * In TLSv1.2 we default to not renewing the ticket everytime. In TLSv1.3
+     * we default to renewing. The defaults are overridden if a ticket key
+     * callback is in place.
+     */
+    if (!TEST_int_eq(gen_tick_called,
+                     (tst == 0 || tst == 2 || tst == 3) ? 0 : 1)
+            || !TEST_int_eq(dec_tick_called, 1))
+        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;
+}
+
 int setup_tests(void)
 {
     if (!TEST_ptr(cert = test_get_argument(0))
@@ -4686,6 +4838,7 @@ int setup_tests(void)
     ADD_ALL_TESTS(test_info_callback, 6);
     ADD_ALL_TESTS(test_ssl_pending, 2);
     ADD_ALL_TESTS(test_ssl_get_shared_ciphers, OSSL_NELEM(shared_ciphers_data));
+    ADD_ALL_TESTS(test_ticket_callbacks, 6);
     return 1;
 }