+ && (!TEST_int_eq(new_called, numnewsesstick)
+
+ || !TEST_int_eq(remove_called, 0)))
+ goto end;
+
+ new_called = remove_called = 0;
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl2,
+ &clientssl2, NULL, NULL))
+ || !TEST_true(SSL_set_session(clientssl2, sess1))
+ || !TEST_true(create_ssl_connection(serverssl2, clientssl2,
+ SSL_ERROR_NONE))
+ || !TEST_true(SSL_session_reused(clientssl2)))
+ goto end;
+
+ if (maxprot == TLS1_3_VERSION) {
+ /*
+ * In TLSv1.3 we should have created a new session even though we have
+ * resumed. Since we attempted a resume we should also have removed the
+ * old ticket from the cache so that we try to only use tickets once.
+ */
+ if (use_ext_cache
+ && (!TEST_int_eq(new_called, 1)
+ || !TEST_int_eq(remove_called, 1)))
+ goto end;
+ } else {
+ /*
+ * In TLSv1.2 we expect to have resumed so no sessions added or
+ * removed.
+ */
+ if (use_ext_cache
+ && (!TEST_int_eq(new_called, 0)
+ || !TEST_int_eq(remove_called, 0)))
+ goto end;
+ }
+
+ SSL_SESSION_free(sess1);
+ if (!TEST_ptr(sess1 = SSL_get1_session(clientssl2)))
+ goto end;
+ shutdown_ssl_connection(serverssl2, clientssl2);
+ serverssl2 = clientssl2 = NULL;
+
+ new_called = remove_called = 0;
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl2,
+ &clientssl2, NULL, NULL))
+ || !TEST_true(create_ssl_connection(serverssl2, clientssl2,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ if (!TEST_ptr(sess2 = SSL_get1_session(clientssl2)))
+ goto end;
+
+ if (use_ext_cache
+ && (!TEST_int_eq(new_called, numnewsesstick)
+ || !TEST_int_eq(remove_called, 0)))
+ goto end;
+
+ new_called = remove_called = 0;
+ /*
+ * This should clear sess2 from the cache because it is a "bad" session.
+ * See SSL_set_session() documentation.
+ */
+ if (!TEST_true(SSL_set_session(clientssl2, sess1)))
+ goto end;
+ if (use_ext_cache
+ && (!TEST_int_eq(new_called, 0) || !TEST_int_eq(remove_called, 1)))
+ goto end;
+ if (!TEST_ptr_eq(SSL_get_session(clientssl2), sess1))
+ goto end;
+
+ if (use_int_cache) {
+ /* Should succeeded because it should not already be in the cache */
+ if (!TEST_true(SSL_CTX_add_session(cctx, sess2))
+ || !TEST_true(SSL_CTX_remove_session(cctx, sess2)))
+ goto end;
+ }
+
+ new_called = remove_called = 0;
+ /* This shouldn't be in the cache so should fail */
+ if (!TEST_false(SSL_CTX_remove_session(cctx, sess2)))
+ goto end;
+
+ if (use_ext_cache
+ && (!TEST_int_eq(new_called, 0) || !TEST_int_eq(remove_called, 1)))
+ goto end;
+
+# if !defined(OPENSSL_NO_TLS1_1)
+ new_called = remove_called = 0;
+ /* Force a connection failure */
+ SSL_CTX_set_max_proto_version(sctx, TLS1_1_VERSION);
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl3,
+ &clientssl3, NULL, NULL))
+ || !TEST_true(SSL_set_session(clientssl3, sess1))
+ /* This should fail because of the mismatched protocol versions */
+ || !TEST_false(create_ssl_connection(serverssl3, clientssl3,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ /* We should have automatically removed the session from the cache */
+ if (use_ext_cache
+ && (!TEST_int_eq(new_called, 0) || !TEST_int_eq(remove_called, 1)))
+ goto end;
+
+ /* Should succeed because it should not already be in the cache */
+ if (use_int_cache && !TEST_true(SSL_CTX_add_session(cctx, sess2)))
+ goto end;
+# endif
+
+ /* Now do some tests for server side caching */
+ if (use_ext_cache) {
+ SSL_CTX_sess_set_new_cb(cctx, NULL);
+ SSL_CTX_sess_set_remove_cb(cctx, NULL);
+ SSL_CTX_sess_set_new_cb(sctx, new_session_cb);
+ SSL_CTX_sess_set_remove_cb(sctx, remove_session_cb);
+ SSL_CTX_sess_set_get_cb(sctx, get_session_cb);
+ get_sess_val = NULL;
+ }
+
+ SSL_CTX_set_session_cache_mode(cctx, 0);
+ /* Internal caching is the default on the server side */
+ if (!use_int_cache)
+ SSL_CTX_set_session_cache_mode(sctx,
+ SSL_SESS_CACHE_SERVER
+ | SSL_SESS_CACHE_NO_INTERNAL_STORE);
+
+ SSL_free(serverssl1);
+ SSL_free(clientssl1);
+ serverssl1 = clientssl1 = NULL;
+ SSL_free(serverssl2);
+ SSL_free(clientssl2);
+ serverssl2 = clientssl2 = NULL;
+ SSL_SESSION_free(sess1);
+ sess1 = NULL;
+ SSL_SESSION_free(sess2);
+ sess2 = NULL;
+
+ SSL_CTX_set_max_proto_version(sctx, maxprot);
+ if (maxprot == TLS1_2_VERSION)
+ SSL_CTX_set_options(sctx, SSL_OP_NO_TICKET);
+ new_called = remove_called = get_called = 0;
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl1, &clientssl1,
+ NULL, NULL))
+ || !TEST_true(create_ssl_connection(serverssl1, clientssl1,
+ SSL_ERROR_NONE))
+ || !TEST_ptr(sess1 = SSL_get1_session(clientssl1))
+ || !TEST_ptr(sess2 = SSL_get1_session(serverssl1)))
+ goto end;
+
+ if (use_int_cache) {
+ if (maxprot == TLS1_3_VERSION && !use_ext_cache) {
+ /*
+ * In TLSv1.3 it should not have been added to the internal cache,
+ * except in the case where we also have an external cache (in that
+ * case it gets added to the cache in order to generate remove
+ * events after timeout).
+ */
+ if (!TEST_false(SSL_CTX_remove_session(sctx, sess2)))
+ goto end;
+ } else {
+ /* Should fail because it should already be in the cache */
+ if (!TEST_false(SSL_CTX_add_session(sctx, sess2)))
+ goto end;
+ }
+ }
+
+ if (use_ext_cache) {
+ SSL_SESSION *tmp = sess2;
+
+ if (!TEST_int_eq(new_called, numnewsesstick)
+ || !TEST_int_eq(remove_called, 0)
+ || !TEST_int_eq(get_called, 0))
+ goto end;
+ /*
+ * Delete the session from the internal cache to force a lookup from
+ * the external cache. We take a copy first because
+ * SSL_CTX_remove_session() also marks the session as non-resumable.
+ */
+ if (use_int_cache && maxprot != TLS1_3_VERSION) {
+ if (!TEST_ptr(tmp = SSL_SESSION_dup(sess2))
+ || !TEST_true(SSL_CTX_remove_session(sctx, sess2)))
+ goto end;
+ SSL_SESSION_free(sess2);
+ }
+ sess2 = tmp;
+ }
+
+ new_called = remove_called = get_called = 0;
+ get_sess_val = sess2;
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl2,
+ &clientssl2, NULL, NULL))
+ || !TEST_true(SSL_set_session(clientssl2, sess1))
+ || !TEST_true(create_ssl_connection(serverssl2, clientssl2,
+ SSL_ERROR_NONE))
+ || !TEST_true(SSL_session_reused(clientssl2)))
+ goto end;
+
+ if (use_ext_cache) {
+ if (!TEST_int_eq(remove_called, 0))
+ goto end;
+
+ if (maxprot == TLS1_3_VERSION) {
+ if (!TEST_int_eq(new_called, 1)
+ || !TEST_int_eq(get_called, 0))
+ goto end;
+ } else {
+ if (!TEST_int_eq(new_called, 0)
+ || !TEST_int_eq(get_called, 1))
+ goto end;
+ }
+ }
+
+ testresult = 1;
+
+ end:
+ SSL_free(serverssl1);
+ SSL_free(clientssl1);
+ SSL_free(serverssl2);
+ SSL_free(clientssl2);
+# ifndef OPENSSL_NO_TLS1_1
+ SSL_free(serverssl3);
+ SSL_free(clientssl3);
+# endif
+ SSL_SESSION_free(sess1);
+ SSL_SESSION_free(sess2);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+#endif /* !defined(OPENSSL_NO_TLS1_3) || !defined(OPENSSL_NO_TLS1_2) */
+
+static int test_session_with_only_int_cache(void)
+{
+#ifndef OPENSSL_NO_TLS1_3
+ if (!execute_test_session(TLS1_3_VERSION, 1, 0))
+ return 0;
+#endif
+
+#ifndef OPENSSL_NO_TLS1_2
+ return execute_test_session(TLS1_2_VERSION, 1, 0);
+#else
+ return 1;
+#endif
+}
+
+static int test_session_with_only_ext_cache(void)
+{
+#ifndef OPENSSL_NO_TLS1_3
+ if (!execute_test_session(TLS1_3_VERSION, 0, 1))
+ return 0;
+#endif
+
+#ifndef OPENSSL_NO_TLS1_2
+ return execute_test_session(TLS1_2_VERSION, 0, 1);
+#else
+ return 1;
+#endif
+}
+
+static int test_session_with_both_cache(void)
+{
+#ifndef OPENSSL_NO_TLS1_3
+ if (!execute_test_session(TLS1_3_VERSION, 1, 1))
+ return 0;
+#endif
+
+#ifndef OPENSSL_NO_TLS1_2
+ return execute_test_session(TLS1_2_VERSION, 1, 1);
+#else
+ return 1;
+#endif
+}
+
+#ifndef OPENSSL_NO_TLS1_3
+static SSL_SESSION *sesscache[6];
+static int do_cache;
+
+static int new_cachesession_cb(SSL *ssl, SSL_SESSION *sess)
+{
+ if (do_cache) {
+ sesscache[new_called] = sess;
+ } else {
+ /* We don't need the reference to the session, so free it */
+ SSL_SESSION_free(sess);
+ }
+ new_called++;
+
+ return 1;
+}
+
+static int post_handshake_verify(SSL *sssl, SSL *cssl)
+{
+ SSL_set_verify(sssl, SSL_VERIFY_PEER, NULL);
+ if (!TEST_true(SSL_verify_client_post_handshake(sssl)))
+ return 0;
+
+ /* Start handshake on the server and client */
+ if (!TEST_int_eq(SSL_do_handshake(sssl), 1)
+ || !TEST_int_le(SSL_read(cssl, NULL, 0), 0)
+ || !TEST_int_le(SSL_read(sssl, NULL, 0), 0)
+ || !TEST_true(create_ssl_connection(sssl, cssl,
+ SSL_ERROR_NONE)))
+ return 0;
+
+ return 1;
+}
+
+static int setup_ticket_test(int stateful, int idx, SSL_CTX **sctx,
+ SSL_CTX **cctx)
+{
+ int sess_id_ctx = 1;
+
+ if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(),
+ TLS1_VERSION, 0, sctx,
+ cctx, cert, privkey))
+ || !TEST_true(SSL_CTX_set_num_tickets(*sctx, idx))
+ || !TEST_true(SSL_CTX_set_session_id_context(*sctx,
+ (void *)&sess_id_ctx,
+ sizeof(sess_id_ctx))))
+ return 0;
+
+ if (stateful)
+ SSL_CTX_set_options(*sctx, SSL_OP_NO_TICKET);
+
+ SSL_CTX_set_session_cache_mode(*cctx, SSL_SESS_CACHE_CLIENT
+ | SSL_SESS_CACHE_NO_INTERNAL_STORE);
+ SSL_CTX_sess_set_new_cb(*cctx, new_cachesession_cb);
+
+ return 1;
+}
+
+static int check_resumption(int idx, SSL_CTX *sctx, SSL_CTX *cctx, int succ)
+{
+ SSL *serverssl = NULL, *clientssl = NULL;
+ int i;
+
+ /* Test that we can resume with all the tickets we got given */
+ for (i = 0; i < idx * 2; i++) {
+ new_called = 0;
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
+ &clientssl, NULL, NULL))
+ || !TEST_true(SSL_set_session(clientssl, sesscache[i])))
+ goto end;
+
+ SSL_set_post_handshake_auth(clientssl, 1);
+
+ if (!TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ /*
+ * Following a successful resumption we only get 1 ticket. After a
+ * failed one we should get idx tickets.
+ */
+ if (succ) {
+ if (!TEST_true(SSL_session_reused(clientssl))
+ || !TEST_int_eq(new_called, 1))
+ goto end;
+ } else {
+ if (!TEST_false(SSL_session_reused(clientssl))
+ || !TEST_int_eq(new_called, idx))
+ goto end;
+ }
+
+ new_called = 0;
+ /* After a post-handshake authentication we should get 1 new ticket */
+ if (succ
+ && (!post_handshake_verify(serverssl, clientssl)
+ || !TEST_int_eq(new_called, 1)))
+ goto end;
+
+ SSL_shutdown(clientssl);
+ SSL_shutdown(serverssl);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ serverssl = clientssl = NULL;
+ SSL_SESSION_free(sesscache[i]);
+ sesscache[i] = NULL;
+ }
+
+ return 1;
+
+ end:
+ SSL_free(clientssl);
+ SSL_free(serverssl);
+ return 0;
+}
+
+static int test_tickets(int stateful, int idx)
+{
+ SSL_CTX *sctx = NULL, *cctx = NULL;
+ SSL *serverssl = NULL, *clientssl = NULL;
+ int testresult = 0;
+ size_t j;
+
+ /* idx is the test number, but also the number of tickets we want */
+
+ new_called = 0;
+ do_cache = 1;
+
+ if (!setup_ticket_test(stateful, idx, &sctx, &cctx))
+ goto end;
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
+ &clientssl, NULL, NULL)))
+ goto end;
+
+ if (!TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE))
+ /* Check we got the number of tickets we were expecting */
+ || !TEST_int_eq(idx, new_called))
+ goto end;
+
+ SSL_shutdown(clientssl);
+ SSL_shutdown(serverssl);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ clientssl = serverssl = NULL;
+ sctx = cctx = NULL;
+
+ /*
+ * Now we try to resume with the tickets we previously created. The
+ * resumption attempt is expected to fail (because we're now using a new
+ * SSL_CTX). We should see idx number of tickets issued again.
+ */
+
+ /* Stop caching sessions - just count them */
+ do_cache = 0;
+
+ if (!setup_ticket_test(stateful, idx, &sctx, &cctx))
+ goto end;
+
+ if (!check_resumption(idx, sctx, cctx, 0))
+ goto end;
+
+ /* Start again with caching sessions */
+ new_called = 0;
+ do_cache = 1;
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ sctx = cctx = NULL;
+
+ if (!setup_ticket_test(stateful, idx, &sctx, &cctx))
+ goto end;
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
+ &clientssl, NULL, NULL)))
+ goto end;
+
+ SSL_set_post_handshake_auth(clientssl, 1);
+
+ if (!TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE))
+ /* Check we got the number of tickets we were expecting */
+ || !TEST_int_eq(idx, new_called))
+ goto end;
+
+ /* After a post-handshake authentication we should get new tickets issued */
+ if (!post_handshake_verify(serverssl, clientssl)
+ || !TEST_int_eq(idx * 2, new_called))
+ goto end;
+
+ SSL_shutdown(clientssl);
+ SSL_shutdown(serverssl);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ serverssl = clientssl = NULL;
+
+ /* Stop caching sessions - just count them */
+ do_cache = 0;
+
+ /*
+ * Check we can resume with all the tickets we created. This time around the
+ * resumptions should all be successful.
+ */
+ if (!check_resumption(idx, sctx, cctx, 1))
+ goto end;
+
+ testresult = 1;
+
+ end:
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ for (j = 0; j < OSSL_NELEM(sesscache); j++) {
+ SSL_SESSION_free(sesscache[j]);
+ sesscache[j] = NULL;
+ }
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+
+static int test_stateless_tickets(int idx)
+{
+ return test_tickets(0, idx);
+}
+
+static int test_stateful_tickets(int idx)
+{
+ return test_tickets(1, idx);
+}
+
+static int test_psk_tickets(void)
+{
+ SSL_CTX *sctx = NULL, *cctx = NULL;
+ SSL *serverssl = NULL, *clientssl = NULL;
+ int testresult = 0;
+ int sess_id_ctx = 1;
+
+ if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(),
+ TLS1_VERSION, 0, &sctx,
+ &cctx, NULL, NULL))
+ || !TEST_true(SSL_CTX_set_session_id_context(sctx,
+ (void *)&sess_id_ctx,
+ sizeof(sess_id_ctx))))
+ goto end;
+
+ SSL_CTX_set_session_cache_mode(cctx, SSL_SESS_CACHE_CLIENT
+ | SSL_SESS_CACHE_NO_INTERNAL_STORE);
+ SSL_CTX_set_psk_use_session_callback(cctx, use_session_cb);
+ SSL_CTX_set_psk_find_session_callback(sctx, find_session_cb);
+ SSL_CTX_sess_set_new_cb(cctx, new_session_cb);
+ use_session_cb_cnt = 0;
+ find_session_cb_cnt = 0;
+ srvid = pskid;
+ new_called = 0;
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL)))
+ goto end;
+ clientpsk = serverpsk = create_a_psk(clientssl);
+ if (!TEST_ptr(clientpsk))
+ goto end;
+ SSL_SESSION_up_ref(clientpsk);
+
+ if (!TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE))
+ || !TEST_int_eq(1, find_session_cb_cnt)
+ || !TEST_int_eq(1, use_session_cb_cnt)
+ /* We should always get 1 ticket when using external PSK */
+ || !TEST_int_eq(1, new_called))
+ goto end;
+
+ testresult = 1;
+
+ end:
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ SSL_SESSION_free(clientpsk);
+ SSL_SESSION_free(serverpsk);
+ clientpsk = serverpsk = NULL;
+
+ return testresult;
+}
+#endif
+
+#define USE_NULL 0
+#define USE_BIO_1 1
+#define USE_BIO_2 2
+#define USE_DEFAULT 3
+
+#define CONNTYPE_CONNECTION_SUCCESS 0
+#define CONNTYPE_CONNECTION_FAIL 1
+#define CONNTYPE_NO_CONNECTION 2
+
+#define TOTAL_NO_CONN_SSL_SET_BIO_TESTS (3 * 3 * 3 * 3)
+#define TOTAL_CONN_SUCCESS_SSL_SET_BIO_TESTS (2 * 2)
+#if !defined(OPENSSL_NO_TLS1_3) && !defined(OPENSSL_NO_TLS1_2)
+# define TOTAL_CONN_FAIL_SSL_SET_BIO_TESTS (2 * 2)
+#else
+# define TOTAL_CONN_FAIL_SSL_SET_BIO_TESTS 0
+#endif
+
+#define TOTAL_SSL_SET_BIO_TESTS TOTAL_NO_CONN_SSL_SET_BIO_TESTS \
+ + TOTAL_CONN_SUCCESS_SSL_SET_BIO_TESTS \
+ + TOTAL_CONN_FAIL_SSL_SET_BIO_TESTS
+
+static void setupbio(BIO **res, BIO *bio1, BIO *bio2, int type)
+{
+ switch (type) {
+ case USE_NULL:
+ *res = NULL;
+ break;
+ case USE_BIO_1:
+ *res = bio1;
+ break;
+ case USE_BIO_2:
+ *res = bio2;
+ break;
+ }
+}
+
+
+/*
+ * Tests calls to SSL_set_bio() under various conditions.
+ *
+ * For the first 3 * 3 * 3 * 3 = 81 tests we do 2 calls to SSL_set_bio() with
+ * various combinations of valid BIOs or NULL being set for the rbio/wbio. We
+ * then do more tests where we create a successful connection first using our
+ * standard connection setup functions, and then call SSL_set_bio() with
+ * various combinations of valid BIOs or NULL. We then repeat these tests
+ * following a failed connection. In this last case we are looking to check that
+ * SSL_set_bio() functions correctly in the case where s->bbio is not NULL.
+ */
+static int test_ssl_set_bio(int idx)
+{
+ SSL_CTX *sctx = NULL, *cctx = NULL;
+ BIO *bio1 = NULL;
+ BIO *bio2 = NULL;
+ BIO *irbio = NULL, *iwbio = NULL, *nrbio = NULL, *nwbio = NULL;
+ SSL *serverssl = NULL, *clientssl = NULL;
+ int initrbio, initwbio, newrbio, newwbio, conntype;
+ int testresult = 0;
+
+ if (idx < TOTAL_NO_CONN_SSL_SET_BIO_TESTS) {
+ initrbio = idx % 3;
+ idx /= 3;
+ initwbio = idx % 3;
+ idx /= 3;
+ newrbio = idx % 3;
+ idx /= 3;
+ newwbio = idx % 3;
+ conntype = CONNTYPE_NO_CONNECTION;
+ } else {
+ idx -= TOTAL_NO_CONN_SSL_SET_BIO_TESTS;
+ initrbio = initwbio = USE_DEFAULT;
+ newrbio = idx % 2;
+ idx /= 2;
+ newwbio = idx % 2;
+ idx /= 2;
+ conntype = idx % 2;
+ }
+
+ if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(),
+ TLS1_VERSION, 0,
+ &sctx, &cctx, cert, privkey)))
+ goto end;
+
+ if (conntype == CONNTYPE_CONNECTION_FAIL) {
+ /*
+ * We won't ever get here if either TLSv1.3 or TLSv1.2 is disabled
+ * because we reduced the number of tests in the definition of
+ * TOTAL_CONN_FAIL_SSL_SET_BIO_TESTS to avoid this scenario. By setting
+ * mismatched protocol versions we will force a connection failure.
+ */
+ SSL_CTX_set_min_proto_version(sctx, TLS1_3_VERSION);
+ SSL_CTX_set_max_proto_version(cctx, TLS1_2_VERSION);
+ }
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL)))
+ goto end;
+
+ if (initrbio == USE_BIO_1
+ || initwbio == USE_BIO_1
+ || newrbio == USE_BIO_1
+ || newwbio == USE_BIO_1) {
+ if (!TEST_ptr(bio1 = BIO_new(BIO_s_mem())))
+ goto end;
+ }
+
+ if (initrbio == USE_BIO_2
+ || initwbio == USE_BIO_2
+ || newrbio == USE_BIO_2
+ || newwbio == USE_BIO_2) {
+ if (!TEST_ptr(bio2 = BIO_new(BIO_s_mem())))
+ goto end;
+ }
+
+ if (initrbio != USE_DEFAULT) {
+ setupbio(&irbio, bio1, bio2, initrbio);
+ setupbio(&iwbio, bio1, bio2, initwbio);
+ SSL_set_bio(clientssl, irbio, iwbio);
+
+ /*
+ * We want to maintain our own refs to these BIO, so do an up ref for
+ * each BIO that will have ownership transferred in the SSL_set_bio()
+ * call
+ */
+ if (irbio != NULL)
+ BIO_up_ref(irbio);
+ if (iwbio != NULL && iwbio != irbio)
+ BIO_up_ref(iwbio);
+ }
+
+ if (conntype != CONNTYPE_NO_CONNECTION
+ && !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)
+ == (conntype == CONNTYPE_CONNECTION_SUCCESS)))
+ goto end;
+
+ setupbio(&nrbio, bio1, bio2, newrbio);
+ setupbio(&nwbio, bio1, bio2, newwbio);
+
+ /*
+ * We will (maybe) transfer ownership again so do more up refs.
+ * SSL_set_bio() has some really complicated ownership rules where BIOs have
+ * already been set!
+ */
+ if (nrbio != NULL
+ && nrbio != irbio
+ && (nwbio != iwbio || nrbio != nwbio))
+ BIO_up_ref(nrbio);
+ if (nwbio != NULL
+ && nwbio != nrbio
+ && (nwbio != iwbio || (nwbio == iwbio && irbio == iwbio)))
+ BIO_up_ref(nwbio);
+
+ SSL_set_bio(clientssl, nrbio, nwbio);
+
+ testresult = 1;
+
+ end:
+ BIO_free(bio1);
+ BIO_free(bio2);
+
+ /*
+ * This test is checking that the ref counting for SSL_set_bio is correct.
+ * If we get here and we did too many frees then we will fail in the above
+ * functions. If we haven't done enough then this will only be detected in
+ * a crypto-mdebug build
+ */
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ return testresult;
+}
+
+typedef enum { NO_BIO_CHANGE, CHANGE_RBIO, CHANGE_WBIO } bio_change_t;
+
+static int execute_test_ssl_bio(int pop_ssl, bio_change_t change_bio)
+{
+ BIO *sslbio = NULL, *membio1 = NULL, *membio2 = NULL;
+ SSL_CTX *ctx;
+ SSL *ssl = NULL;
+ int testresult = 0;
+
+ if (!TEST_ptr(ctx = SSL_CTX_new(TLS_method()))
+ || !TEST_ptr(ssl = SSL_new(ctx))
+ || !TEST_ptr(sslbio = BIO_new(BIO_f_ssl()))
+ || !TEST_ptr(membio1 = BIO_new(BIO_s_mem())))
+ goto end;
+
+ BIO_set_ssl(sslbio, ssl, BIO_CLOSE);
+
+ /*
+ * If anything goes wrong here then we could leak memory, so this will
+ * be caught in a crypto-mdebug build
+ */
+ BIO_push(sslbio, membio1);
+
+ /* Verify changing the rbio/wbio directly does not cause leaks */
+ if (change_bio != NO_BIO_CHANGE) {
+ if (!TEST_ptr(membio2 = BIO_new(BIO_s_mem())))
+ goto end;
+ if (change_bio == CHANGE_RBIO)
+ SSL_set0_rbio(ssl, membio2);
+ else
+ SSL_set0_wbio(ssl, membio2);
+ }
+ ssl = NULL;
+
+ if (pop_ssl)
+ BIO_pop(sslbio);
+ else
+ BIO_pop(membio1);
+
+ testresult = 1;
+ end:
+ BIO_free(membio1);
+ BIO_free(sslbio);
+ SSL_free(ssl);
+ SSL_CTX_free(ctx);
+
+ return testresult;
+}
+
+static int test_ssl_bio_pop_next_bio(void)
+{
+ return execute_test_ssl_bio(0, NO_BIO_CHANGE);
+}
+
+static int test_ssl_bio_pop_ssl_bio(void)
+{
+ return execute_test_ssl_bio(1, NO_BIO_CHANGE);
+}
+
+static int test_ssl_bio_change_rbio(void)
+{
+ return execute_test_ssl_bio(0, CHANGE_RBIO);
+}
+
+static int test_ssl_bio_change_wbio(void)
+{
+ return execute_test_ssl_bio(0, CHANGE_WBIO);
+}
+
+#if !defined(OPENSSL_NO_TLS1_2) || defined(OPENSSL_NO_TLS1_3)
+typedef struct {
+ /* The list of sig algs */
+ const int *list;
+ /* The length of the list */
+ size_t listlen;
+ /* A sigalgs list in string format */
+ const char *liststr;
+ /* Whether setting the list should succeed */
+ int valid;
+ /* Whether creating a connection with the list should succeed */
+ int connsuccess;
+} sigalgs_list;
+
+static const int validlist1[] = {NID_sha256, EVP_PKEY_RSA};
+# ifndef OPENSSL_NO_EC
+static const int validlist2[] = {NID_sha256, EVP_PKEY_RSA, NID_sha512, EVP_PKEY_EC};
+static const int validlist3[] = {NID_sha512, EVP_PKEY_EC};
+# endif
+static const int invalidlist1[] = {NID_undef, EVP_PKEY_RSA};
+static const int invalidlist2[] = {NID_sha256, NID_undef};
+static const int invalidlist3[] = {NID_sha256, EVP_PKEY_RSA, NID_sha256};
+static const int invalidlist4[] = {NID_sha256};
+static const sigalgs_list testsigalgs[] = {
+ {validlist1, OSSL_NELEM(validlist1), NULL, 1, 1},
+# ifndef OPENSSL_NO_EC
+ {validlist2, OSSL_NELEM(validlist2), NULL, 1, 1},
+ {validlist3, OSSL_NELEM(validlist3), NULL, 1, 0},
+# endif
+ {NULL, 0, "RSA+SHA256", 1, 1},
+# ifndef OPENSSL_NO_EC
+ {NULL, 0, "RSA+SHA256:ECDSA+SHA512", 1, 1},
+ {NULL, 0, "ECDSA+SHA512", 1, 0},
+# endif
+ {invalidlist1, OSSL_NELEM(invalidlist1), NULL, 0, 0},
+ {invalidlist2, OSSL_NELEM(invalidlist2), NULL, 0, 0},
+ {invalidlist3, OSSL_NELEM(invalidlist3), NULL, 0, 0},
+ {invalidlist4, OSSL_NELEM(invalidlist4), NULL, 0, 0},
+ {NULL, 0, "RSA", 0, 0},
+ {NULL, 0, "SHA256", 0, 0},
+ {NULL, 0, "RSA+SHA256:SHA256", 0, 0},
+ {NULL, 0, "Invalid", 0, 0}
+};
+
+static int test_set_sigalgs(int idx)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ const sigalgs_list *curr;
+ int testctx;
+
+ /* Should never happen */
+ if (!TEST_size_t_le((size_t)idx, OSSL_NELEM(testsigalgs) * 2))
+ return 0;
+
+ testctx = ((size_t)idx < OSSL_NELEM(testsigalgs));
+ curr = testctx ? &testsigalgs[idx]
+ : &testsigalgs[idx - OSSL_NELEM(testsigalgs)];
+
+ if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(),
+ TLS1_VERSION, 0,
+ &sctx, &cctx, cert, privkey)))
+ return 0;
+
+ /*
+ * TODO(TLS1.3): These APIs cannot set TLSv1.3 sig algs so we just test it
+ * for TLSv1.2 for now until we add a new API.
+ */
+ SSL_CTX_set_max_proto_version(cctx, TLS1_2_VERSION);
+
+ if (testctx) {
+ int ret;
+
+ if (curr->list != NULL)
+ ret = SSL_CTX_set1_sigalgs(cctx, curr->list, curr->listlen);
+ else
+ ret = SSL_CTX_set1_sigalgs_list(cctx, curr->liststr);
+
+ if (!ret) {
+ if (curr->valid)
+ TEST_info("Failure setting sigalgs in SSL_CTX (%d)\n", idx);
+ else
+ testresult = 1;
+ goto end;
+ }
+ if (!curr->valid) {
+ TEST_info("Not-failed setting sigalgs in SSL_CTX (%d)\n", idx);
+ goto end;
+ }
+ }
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
+ &clientssl, NULL, NULL)))
+ goto end;
+
+ if (!testctx) {
+ int ret;
+
+ if (curr->list != NULL)
+ ret = SSL_set1_sigalgs(clientssl, curr->list, curr->listlen);
+ else
+ ret = SSL_set1_sigalgs_list(clientssl, curr->liststr);
+ if (!ret) {
+ if (curr->valid)
+ TEST_info("Failure setting sigalgs in SSL (%d)\n", idx);
+ else
+ testresult = 1;
+ goto end;
+ }
+ if (!curr->valid)
+ goto end;
+ }
+
+ if (!TEST_int_eq(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE),
+ curr->connsuccess))
+ goto end;
+
+ testresult = 1;
+
+ end:
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+#endif
+
+#ifndef OPENSSL_NO_TLS1_3
+static int psk_client_cb_cnt = 0;
+static int psk_server_cb_cnt = 0;
+
+static int use_session_cb(SSL *ssl, const EVP_MD *md, const unsigned char **id,
+ size_t *idlen, SSL_SESSION **sess)
+{
+ switch (++use_session_cb_cnt) {
+ case 1:
+ /* The first call should always have a NULL md */
+ if (md != NULL)
+ return 0;
+ break;
+
+ case 2:
+ /* The second call should always have an md */
+ if (md == NULL)
+ return 0;
+ break;
+
+ default:
+ /* We should only be called a maximum of twice */
+ return 0;
+ }
+
+ if (clientpsk != NULL)
+ SSL_SESSION_up_ref(clientpsk);
+
+ *sess = clientpsk;
+ *id = (const unsigned char *)pskid;
+ *idlen = strlen(pskid);
+
+ return 1;
+}
+
+#ifndef OPENSSL_NO_PSK
+static unsigned int psk_client_cb(SSL *ssl, const char *hint, char *id,
+ unsigned int max_id_len,
+ unsigned char *psk,
+ unsigned int max_psk_len)
+{
+ unsigned int psklen = 0;
+
+ psk_client_cb_cnt++;
+
+ if (strlen(pskid) + 1 > max_id_len)
+ return 0;
+
+ /* We should only ever be called a maximum of twice per connection */
+ if (psk_client_cb_cnt > 2)
+ return 0;
+
+ if (clientpsk == NULL)
+ return 0;
+
+ /* We'll reuse the PSK we set up for TLSv1.3 */
+ if (SSL_SESSION_get_master_key(clientpsk, NULL, 0) > max_psk_len)
+ return 0;
+ psklen = SSL_SESSION_get_master_key(clientpsk, psk, max_psk_len);
+ strncpy(id, pskid, max_id_len);
+
+ return psklen;
+}
+#endif /* OPENSSL_NO_PSK */
+
+static int find_session_cb(SSL *ssl, const unsigned char *identity,
+ size_t identity_len, SSL_SESSION **sess)
+{
+ find_session_cb_cnt++;
+
+ /* We should only ever be called a maximum of twice per connection */
+ if (find_session_cb_cnt > 2)
+ return 0;
+
+ if (serverpsk == NULL)
+ return 0;
+
+ /* Identity should match that set by the client */
+ if (strlen(srvid) != identity_len
+ || strncmp(srvid, (const char *)identity, identity_len) != 0) {
+ /* No PSK found, continue but without a PSK */
+ *sess = NULL;
+ return 1;
+ }
+
+ SSL_SESSION_up_ref(serverpsk);
+ *sess = serverpsk;
+
+ return 1;
+}
+
+#ifndef OPENSSL_NO_PSK
+static unsigned int psk_server_cb(SSL *ssl, const char *identity,
+ unsigned char *psk, unsigned int max_psk_len)
+{
+ unsigned int psklen = 0;
+
+ psk_server_cb_cnt++;
+
+ /* We should only ever be called a maximum of twice per connection */
+ if (find_session_cb_cnt > 2)
+ return 0;
+
+ if (serverpsk == NULL)
+ return 0;
+
+ /* Identity should match that set by the client */
+ if (strcmp(srvid, identity) != 0) {
+ return 0;
+ }
+
+ /* We'll reuse the PSK we set up for TLSv1.3 */
+ if (SSL_SESSION_get_master_key(serverpsk, NULL, 0) > max_psk_len)
+ return 0;
+ psklen = SSL_SESSION_get_master_key(serverpsk, psk, max_psk_len);
+
+ return psklen;
+}
+#endif /* OPENSSL_NO_PSK */
+
+#define MSG1 "Hello"
+#define MSG2 "World."
+#define MSG3 "This"
+#define MSG4 "is"
+#define MSG5 "a"
+#define MSG6 "test"
+#define MSG7 "message."
+
+#define TLS13_AES_256_GCM_SHA384_BYTES ((const unsigned char *)"\x13\x02")
+#define TLS13_AES_128_GCM_SHA256_BYTES ((const unsigned char *)"\x13\x01")
+
+
+static SSL_SESSION *create_a_psk(SSL *ssl)
+{
+ const SSL_CIPHER *cipher = NULL;
+ const unsigned char key[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+ 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+ 0x2c, 0x2d, 0x2e, 0x2f
+ };
+ SSL_SESSION *sess = NULL;
+
+ cipher = SSL_CIPHER_find(ssl, TLS13_AES_256_GCM_SHA384_BYTES);
+ sess = SSL_SESSION_new();
+ if (!TEST_ptr(sess)
+ || !TEST_ptr(cipher)
+ || !TEST_true(SSL_SESSION_set1_master_key(sess, key,
+ sizeof(key)))
+ || !TEST_true(SSL_SESSION_set_cipher(sess, cipher))
+ || !TEST_true(
+ SSL_SESSION_set_protocol_version(sess,
+ TLS1_3_VERSION))) {
+ SSL_SESSION_free(sess);
+ return NULL;
+ }
+ return sess;
+}
+
+/*
+ * Helper method to setup objects for early data test. Caller frees objects on
+ * error.
+ */
+static int setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx, SSL **clientssl,
+ SSL **serverssl, SSL_SESSION **sess, int idx)
+{
+ if (*sctx == NULL
+ && !TEST_true(create_ssl_ctx_pair(TLS_server_method(),
+ TLS_client_method(),
+ TLS1_VERSION, 0,
+ sctx, cctx, cert, privkey)))
+ return 0;
+
+ if (!TEST_true(SSL_CTX_set_max_early_data(*sctx, SSL3_RT_MAX_PLAIN_LENGTH)))
+ return 0;
+
+ if (idx == 1) {
+ /* When idx == 1 we repeat the tests with read_ahead set */
+ SSL_CTX_set_read_ahead(*cctx, 1);
+ SSL_CTX_set_read_ahead(*sctx, 1);
+ } else if (idx == 2) {
+ /* When idx == 2 we are doing early_data with a PSK. Set up callbacks */
+ SSL_CTX_set_psk_use_session_callback(*cctx, use_session_cb);
+ SSL_CTX_set_psk_find_session_callback(*sctx, find_session_cb);
+ use_session_cb_cnt = 0;
+ find_session_cb_cnt = 0;
+ srvid = pskid;
+ }
+
+ if (!TEST_true(create_ssl_objects(*sctx, *cctx, serverssl, clientssl,
+ NULL, NULL)))
+ return 0;
+
+ /*
+ * For one of the run throughs (doesn't matter which one), we'll try sending
+ * some SNI data in the initial ClientHello. This will be ignored (because
+ * there is no SNI cb set up by the server), so it should not impact
+ * early_data.
+ */
+ if (idx == 1
+ && !TEST_true(SSL_set_tlsext_host_name(*clientssl, "localhost")))
+ return 0;
+
+ if (idx == 2) {
+ clientpsk = create_a_psk(*clientssl);
+ if (!TEST_ptr(clientpsk)
+ /*
+ * We just choose an arbitrary value for max_early_data which
+ * should be big enough for testing purposes.
+ */
+ || !TEST_true(SSL_SESSION_set_max_early_data(clientpsk,
+ 0x100))
+ || !TEST_true(SSL_SESSION_up_ref(clientpsk))) {
+ SSL_SESSION_free(clientpsk);
+ clientpsk = NULL;
+ return 0;
+ }
+ serverpsk = clientpsk;
+
+ if (sess != NULL) {
+ if (!TEST_true(SSL_SESSION_up_ref(clientpsk))) {
+ SSL_SESSION_free(clientpsk);
+ SSL_SESSION_free(serverpsk);
+ clientpsk = serverpsk = NULL;
+ return 0;
+ }
+ *sess = clientpsk;
+ }
+ return 1;
+ }
+
+ if (sess == NULL)
+ return 1;
+
+ if (!TEST_true(create_ssl_connection(*serverssl, *clientssl,
+ SSL_ERROR_NONE)))
+ return 0;
+
+ *sess = SSL_get1_session(*clientssl);
+ SSL_shutdown(*clientssl);
+ SSL_shutdown(*serverssl);
+ SSL_free(*serverssl);
+ SSL_free(*clientssl);
+ *serverssl = *clientssl = NULL;
+
+ if (!TEST_true(create_ssl_objects(*sctx, *cctx, serverssl,
+ clientssl, NULL, NULL))
+ || !TEST_true(SSL_set_session(*clientssl, *sess)))
+ return 0;
+
+ return 1;
+}
+
+static int test_early_data_read_write(int idx)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ SSL_SESSION *sess = NULL;
+ unsigned char buf[20], data[1024];
+ size_t readbytes, written, eoedlen, rawread, rawwritten;
+ BIO *rbio;
+
+ if (!TEST_true(setupearly_data_test(&cctx, &sctx, &clientssl,
+ &serverssl, &sess, idx)))
+ goto end;
+
+ /* Write and read some early data */
+ if (!TEST_true(SSL_write_early_data(clientssl, MSG1, strlen(MSG1),
+ &written))
+ || !TEST_size_t_eq(written, strlen(MSG1))
+ || !TEST_int_eq(SSL_read_early_data(serverssl, buf,
+ sizeof(buf), &readbytes),
+ SSL_READ_EARLY_DATA_SUCCESS)
+ || !TEST_mem_eq(MSG1, readbytes, buf, strlen(MSG1))
+ || !TEST_int_eq(SSL_get_early_data_status(serverssl),
+ SSL_EARLY_DATA_ACCEPTED))
+ goto end;
+
+ /*
+ * Server should be able to write data, and client should be able to
+ * read it.
+ */
+ if (!TEST_true(SSL_write_early_data(serverssl, MSG2, strlen(MSG2),
+ &written))
+ || !TEST_size_t_eq(written, strlen(MSG2))
+ || !TEST_true(SSL_read_ex(clientssl, buf, sizeof(buf), &readbytes))
+ || !TEST_mem_eq(buf, readbytes, MSG2, strlen(MSG2)))
+ goto end;
+
+ /* Even after reading normal data, client should be able write early data */
+ if (!TEST_true(SSL_write_early_data(clientssl, MSG3, strlen(MSG3),
+ &written))
+ || !TEST_size_t_eq(written, strlen(MSG3)))
+ goto end;
+
+ /* Server should still be able read early data after writing data */
+ if (!TEST_int_eq(SSL_read_early_data(serverssl, buf, sizeof(buf),
+ &readbytes),
+ SSL_READ_EARLY_DATA_SUCCESS)
+ || !TEST_mem_eq(buf, readbytes, MSG3, strlen(MSG3)))
+ goto end;
+
+ /* Write more data from server and read it from client */
+ if (!TEST_true(SSL_write_early_data(serverssl, MSG4, strlen(MSG4),
+ &written))
+ || !TEST_size_t_eq(written, strlen(MSG4))
+ || !TEST_true(SSL_read_ex(clientssl, buf, sizeof(buf), &readbytes))
+ || !TEST_mem_eq(buf, readbytes, MSG4, strlen(MSG4)))
+ goto end;
+
+ /*
+ * If client writes normal data it should mean writing early data is no
+ * longer possible.
+ */
+ if (!TEST_true(SSL_write_ex(clientssl, MSG5, strlen(MSG5), &written))
+ || !TEST_size_t_eq(written, strlen(MSG5))
+ || !TEST_int_eq(SSL_get_early_data_status(clientssl),
+ SSL_EARLY_DATA_ACCEPTED))
+ goto end;
+
+ /*
+ * At this point the client has written EndOfEarlyData, ClientFinished and
+ * normal (fully protected) data. We are going to cause a delay between the
+ * arrival of EndOfEarlyData and ClientFinished. We read out all the data
+ * in the read BIO, and then just put back the EndOfEarlyData message.
+ */
+ rbio = SSL_get_rbio(serverssl);
+ if (!TEST_true(BIO_read_ex(rbio, data, sizeof(data), &rawread))
+ || !TEST_size_t_lt(rawread, sizeof(data))
+ || !TEST_size_t_gt(rawread, SSL3_RT_HEADER_LENGTH))
+ goto end;
+
+ /* Record length is in the 4th and 5th bytes of the record header */
+ eoedlen = SSL3_RT_HEADER_LENGTH + (data[3] << 8 | data[4]);
+ if (!TEST_true(BIO_write_ex(rbio, data, eoedlen, &rawwritten))
+ || !TEST_size_t_eq(rawwritten, eoedlen))
+ goto end;
+
+ /* Server should be told that there is no more early data */
+ if (!TEST_int_eq(SSL_read_early_data(serverssl, buf, sizeof(buf),
+ &readbytes),
+ SSL_READ_EARLY_DATA_FINISH)
+ || !TEST_size_t_eq(readbytes, 0))
+ goto end;
+
+ /*
+ * Server has not finished init yet, so should still be able to write early
+ * data.
+ */
+ if (!TEST_true(SSL_write_early_data(serverssl, MSG6, strlen(MSG6),
+ &written))
+ || !TEST_size_t_eq(written, strlen(MSG6)))
+ goto end;
+
+ /* Push the ClientFinished and the normal data back into the server rbio */
+ if (!TEST_true(BIO_write_ex(rbio, data + eoedlen, rawread - eoedlen,
+ &rawwritten))
+ || !TEST_size_t_eq(rawwritten, rawread - eoedlen))