summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2023-08-31 16:18:28 +0100
committerHugo Landau <hlandau@openssl.org>2023-09-02 15:23:55 +0100
commit48724e8a205c732705c3f54a3bd43d7049e77774 (patch)
tree5ce960d7d9b9868790deb46dc92c9738149cb5d0
parent3a0012cb52bef4df54bd46946d7ff783c24b4305 (diff)
Add a test for QUIC non IO retry errors
Test that errors such as SSL_ERROR_WANT_RETRY_VERIFY are properly handled by QUIC connections. Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Hugo Landau <hlandau@openssl.org> (Merged from https://github.com/openssl/openssl/pull/21922)
-rw-r--r--doc/designs/quic-design/quic-fault-injector.md7
-rw-r--r--test/helpers/quictestlib.c39
-rw-r--r--test/helpers/quictestlib.h7
-rw-r--r--test/quicapitest.c59
4 files changed, 106 insertions, 6 deletions
diff --git a/doc/designs/quic-design/quic-fault-injector.md b/doc/designs/quic-design/quic-fault-injector.md
index a60763518f..30db905ee8 100644
--- a/doc/designs/quic-design/quic-fault-injector.md
+++ b/doc/designs/quic-design/quic-fault-injector.md
@@ -229,6 +229,13 @@ void ossl_quic_fault_free(OSSL_QUIC_FAULT *fault);
int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl);
/*
+ * Same as qtest_create_quic_connection but will stop (successfully) if the
+ * clientssl indicates SSL_ERROR_WANT_XXX as specified by |wanterr|
+ */
+int qtest_create_quic_connection_ex(QUIC_TSERVER *qtserv, SSL *clientssl,
+ int wanterr);
+
+/*
* Confirm that the server has received the given transport error code.
*/
int qtest_check_server_transport_err(QUIC_TSERVER *qtserv, uint64_t code);
diff --git a/test/helpers/quictestlib.c b/test/helpers/quictestlib.c
index 2dbbb435bb..2fcb4bdb6f 100644
--- a/test/helpers/quictestlib.c
+++ b/test/helpers/quictestlib.c
@@ -239,6 +239,7 @@ int qtest_supports_blocking(void)
#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
static int globserverret = 0;
+static TSAN_QUALIFIER int abortserverthread = 0;
static QUIC_TSERVER *globtserv;
static const thread_t thread_zero;
@@ -253,7 +254,8 @@ static void run_server_thread(void)
}
#endif
-int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl)
+int qtest_create_quic_connection_ex(QUIC_TSERVER *qtserv, SSL *clientssl,
+ int wanterr)
{
int retc = -1, rets = 0, abortctr = 0, ret = 0;
int clienterr = 0, servererr = 0;
@@ -263,6 +265,9 @@ int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl)
* t uninitialised
*/
thread_t t = thread_zero;
+
+ if (clientssl != NULL)
+ abortserverthread = 0;
#endif
if (!TEST_ptr(qtserv)) {
@@ -295,10 +300,21 @@ int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl)
if (retc <= 0) {
err = SSL_get_error(clientssl, retc);
- if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
- TEST_info("SSL_connect() failed %d, %d", retc, err);
- TEST_openssl_errors();
- clienterr = 1;
+ if (err == wanterr) {
+ retc = 1;
+#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
+ if (qtserv == NULL && rets > 0)
+ tsan_store(&abortserverthread, 1);
+ else
+#endif
+ rets = 1;
+ } else {
+ if (err != SSL_ERROR_WANT_READ
+ && err != SSL_ERROR_WANT_WRITE) {
+ TEST_info("SSL_connect() failed %d, %d", retc, err);
+ TEST_openssl_errors();
+ clienterr = 1;
+ }
}
}
}
@@ -312,6 +328,7 @@ int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl)
*/
if (!clienterr && retc <= 0)
SSL_handle_events(clientssl);
+
if (!servererr && rets <= 0) {
qtest_add_time(1);
ossl_quic_tserver_tick(qtserv);
@@ -327,7 +344,12 @@ int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl)
TEST_info("No progress made");
goto err;
}
- } while ((retc <= 0 && !clienterr) || (rets <= 0 && !servererr));
+ } while ((retc <= 0 && !clienterr)
+ || (rets <= 0 && !servererr
+#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
+ && !tsan_load(&abortserverthread)
+#endif
+ ));
if (qtserv == NULL && rets > 0) {
#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
@@ -345,6 +367,11 @@ int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl)
return ret;
}
+int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl)
+{
+ return qtest_create_quic_connection_ex(qtserv, clientssl, SSL_ERROR_NONE);
+}
+
#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
static TSAN_QUALIFIER int shutdowndone;
diff --git a/test/helpers/quictestlib.h b/test/helpers/quictestlib.h
index cfda1b29b5..fb1c5d88b5 100644
--- a/test/helpers/quictestlib.h
+++ b/test/helpers/quictestlib.h
@@ -63,6 +63,13 @@ int qtest_supports_blocking(void);
int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl);
/*
+ * Same as qtest_create_quic_connection but will stop (successfully) if the
+ * clientssl indicates SSL_ERROR_WANT_XXX as specified by |wanterr|
+ */
+int qtest_create_quic_connection_ex(QUIC_TSERVER *qtserv, SSL *clientssl,
+ int wanterr);
+
+/*
* Shutdown the client SSL object gracefully
*/
int qtest_shutdown(QUIC_TSERVER *qtserv, SSL *clientssl);
diff --git a/test/quicapitest.c b/test/quicapitest.c
index 83a048bc74..5eff924527 100644
--- a/test/quicapitest.c
+++ b/test/quicapitest.c
@@ -1003,6 +1003,64 @@ static int test_multiple_dgrams(void)
return testresult;
}
+static int non_io_retry_cert_verify_cb(X509_STORE_CTX *ctx, void *arg)
+{
+ int idx = SSL_get_ex_data_X509_STORE_CTX_idx();
+ SSL *ssl;
+ int *ctr = (int *)arg;
+
+ /* this should not happen but check anyway */
+ if (idx < 0
+ || (ssl = X509_STORE_CTX_get_ex_data(ctx, idx)) == NULL)
+ return 0;
+
+ /* If this is the first time we've been called then retry */
+ if (((*ctr)++) == 0)
+ return SSL_set_retry_verify(ssl);
+
+ /* Otherwise do nothing - verification succeeds. Continue as normal */
+ return 1;
+}
+
+/* Test that we can handle a non-io related retry error
+ * Test 0: Non-blocking
+ * Test 1: Blocking
+ */
+static int test_non_io_retry(int idx)
+{
+ SSL_CTX *cctx;
+ SSL *clientquic = NULL;
+ QUIC_TSERVER *qtserv = NULL;
+ int testresult = 0;
+ int flags = 0, ctr = 0;
+
+ if (idx >= 1 && !qtest_supports_blocking())
+ return TEST_skip("Blocking tests not supported in this build");
+
+ cctx = SSL_CTX_new_ex(libctx, NULL, OSSL_QUIC_client_method());
+ if (!TEST_ptr(cctx))
+ goto err;
+
+ SSL_CTX_set_cert_verify_callback(cctx, non_io_retry_cert_verify_cb, &ctr);
+
+ flags = (idx >= 1) ? QTEST_FLAG_BLOCK : 0;
+ if (!TEST_true(qtest_create_quic_objects(libctx, cctx, NULL, cert, privkey,
+ flags, &qtserv, &clientquic, NULL))
+ || !TEST_true(qtest_create_quic_connection_ex(qtserv, clientquic,
+ SSL_ERROR_WANT_RETRY_VERIFY))
+ || !TEST_int_eq(SSL_want(clientquic), SSL_RETRY_VERIFY)
+ || !TEST_true(qtest_create_quic_connection(qtserv, clientquic)))
+ goto err;
+
+ testresult = 1;
+ err:
+ SSL_free(clientquic);
+ ossl_quic_tserver_free(qtserv);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+
OPT_TEST_DECLARE_USAGE("provider config certsdir datadir\n")
int setup_tests(void)
@@ -1072,6 +1130,7 @@ int setup_tests(void)
ADD_TEST(test_bio_ssl);
ADD_TEST(test_back_pressure);
ADD_TEST(test_multiple_dgrams);
+ ADD_ALL_TESTS(test_non_io_retry, 2);
return 1;
err:
cleanup_tests();