]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - test/helpers/quictestlib.c
Copyright year updates
[thirdparty/openssl.git] / test / helpers / quictestlib.c
index 52cf587c32a51b303695b21001ba1b37f25c42bb..f0955559dcac251fdd172771b1f5699502fbea9e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
 # include "../threadstest.h"
 #endif
+#include "internal/quic_ssl.h"
 #include "internal/quic_wire_pkt.h"
 #include "internal/quic_record_tx.h"
 #include "internal/quic_error.h"
 #include "internal/packet.h"
+#include "internal/tsan_assist.h"
 
 #define GROWTH_ALLOWANCE 1024
 
@@ -64,8 +66,6 @@ struct qtest_fault {
 static void packet_plain_finish(void *arg);
 static void handshake_finish(void *arg);
 
-static BIO_METHOD *get_bio_method(void);
-
 static OSSL_TIME fake_now;
 
 static OSSL_TIME fake_now_cb(void *arg)
@@ -74,7 +74,7 @@ static OSSL_TIME fake_now_cb(void *arg)
 }
 
 int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx,
-                              char *certfile, char *keyfile,
+                              SSL_CTX *serverctx, char *certfile, char *keyfile,
                               int flags, QUIC_TSERVER **qtserv, SSL **cssl,
                               QTEST_FAULT **fault)
 {
@@ -88,9 +88,12 @@ int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx,
     *qtserv = NULL;
     if (fault != NULL)
         *fault = NULL;
-    *cssl = SSL_new(clientctx);
-    if (!TEST_ptr(*cssl))
-        return 0;
+
+    if (*cssl == NULL) {
+        *cssl = SSL_new(clientctx);
+        if (!TEST_ptr(*cssl))
+            return 0;
+    }
 
     /* SSL_set_alpn_protos returns 0 for success! */
     if (!TEST_false(SSL_set_alpn_protos(*cssl, alpn, sizeof(alpn))))
@@ -143,7 +146,7 @@ int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx,
                                          (flags & QTEST_FLAG_BLOCK) != 0 ? 1 : 0)))
         goto err;
 
-    if (!TEST_true(SSL_set_initial_peer_addr(*cssl, peeraddr)))
+    if (!TEST_true(SSL_set1_initial_peer_addr(*cssl, peeraddr)))
         goto err;
 
     if (fault != NULL) {
@@ -152,7 +155,7 @@ int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx,
             goto err;
     }
 
-    fisbio = BIO_new(get_bio_method());
+    fisbio = BIO_new(qtest_get_bio_method());
     if (!TEST_ptr(fisbio))
         goto err;
 
@@ -165,9 +168,15 @@ int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx,
     tserver_args.net_rbio = sbio;
     tserver_args.net_wbio = fisbio;
     tserver_args.alpn = NULL;
+    if (serverctx != NULL && !TEST_true(SSL_CTX_up_ref(serverctx)))
+        goto err;
+    tserver_args.ctx = serverctx;
     if ((flags & QTEST_FLAG_FAKE_TIME) != 0) {
         fake_now = ossl_time_zero();
+        /* zero time can have a special meaning, bump it */
+        qtest_add_time(1);
         tserver_args.now_cb = fake_now_cb;
+        (void)ossl_quic_conn_set_override_now_cb(*cssl, fake_now_cb, NULL);
     }
 
     if (!TEST_ptr(*qtserv = ossl_quic_tserver_new(&tserver_args, certfile,
@@ -185,6 +194,7 @@ int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx,
 
     return 1;
  err:
+    SSL_CTX_free(tserver_args.ctx);
     BIO_ADDR_free(peeraddr);
     BIO_free(cbio);
     BIO_free(fisbio);
@@ -203,6 +213,19 @@ void qtest_add_time(uint64_t millis)
     fake_now = ossl_time_add(fake_now, ossl_ms2time(millis));
 }
 
+QTEST_FAULT *qtest_create_injector(QUIC_TSERVER *ts)
+{
+    QTEST_FAULT *f;
+
+    f = OPENSSL_zalloc(sizeof(*f));
+    if (f == NULL)
+        return NULL;
+
+    f->qtserv = ts;
+    return f;
+
+}
+
 int qtest_supports_blocking(void)
 {
 #if !defined(OPENSSL_NO_POSIX_IO) && defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
@@ -216,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;
 
@@ -230,9 +254,10 @@ 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, err, abortctr = 0, ret = 0;
+    int retc = -1, rets = 0, abortctr = 0, ret = 0;
     int clienterr = 0, servererr = 0;
 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
     /*
@@ -240,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)) {
@@ -265,17 +293,30 @@ int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl)
     }
 
     do {
-        err = SSL_ERROR_WANT_WRITE;
-        while (!clienterr && retc <= 0 && err == SSL_ERROR_WANT_WRITE) {
+        if (!clienterr && retc <= 0) {
+            int err;
+
             retc = SSL_connect(clientssl);
-            if (retc <= 0)
+            if (retc <= 0) {
                 err = SSL_get_error(clientssl, retc);
-        }
 
-        if (!clienterr && retc <= 0 && err != SSL_ERROR_WANT_READ) {
-            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;
+                    }
+                }
+            }
         }
 
         /*
@@ -287,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);
@@ -302,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)
@@ -320,13 +367,82 @@ 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;
+
+static void run_server_shutdown_thread(void)
+{
+    /*
+     * This will operate in a busy loop because the server does not block,
+     * but should be acceptable because it is local and we expect this to be
+     * fast
+     */
+    do {
+        ossl_quic_tserver_tick(globtserv);
+    } while(!tsan_load(&shutdowndone));
+}
+#endif
+
 int qtest_shutdown(QUIC_TSERVER *qtserv, SSL *clientssl)
 {
+    int tickserver = 1;
+    int ret = 0;
+#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
+    /*
+     * Pointless initialisation to avoid bogus compiler warnings about using
+     * t uninitialised
+     */
+    thread_t t = thread_zero;
+#endif
+
+    if (SSL_get_blocking_mode(clientssl) > 0) {
+#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
+        /*
+         * clientssl is blocking. We will need a thread to complete the
+         * connection
+         */
+        globtserv = qtserv;
+        shutdowndone = 0;
+        if (!TEST_true(run_thread(&t, run_server_shutdown_thread)))
+            return 0;
+
+        tickserver = 0;
+#else
+        TEST_error("No thread support in this build");
+        return 0;
+#endif
+    }
+
     /* Busy loop in non-blocking mode. It should be quick because its local */
-    while (SSL_shutdown(clientssl) != 1)
-        ossl_quic_tserver_tick(qtserv);
+    for (;;) {
+        int rc = SSL_shutdown(clientssl);
 
-    return 1;
+        if (rc == 1) {
+            ret = 1;
+            break;
+        }
+
+        if (rc < 0)
+            break;
+
+        if (tickserver)
+            ossl_quic_tserver_tick(qtserv);
+    }
+
+#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
+    tsan_store(&shutdowndone, 1);
+    if (!tickserver) {
+        if (!TEST_true(wait_for_thread(t)))
+            ret = 0;
+    }
+#endif
+
+    return ret;
 }
 
 int qtest_check_server_transport_err(QUIC_TSERVER *qtserv, uint64_t code)
@@ -344,6 +460,7 @@ int qtest_check_server_transport_err(QUIC_TSERVER *qtserv, uint64_t code)
     cause = ossl_quic_tserver_get_terminate_cause(qtserv);
     if  (!TEST_ptr(cause)
             || !TEST_true(cause->remote)
+            || !TEST_false(cause->app)
             || !TEST_uint64_t_eq(cause->error_code, code))
         return 0;
 
@@ -355,6 +472,11 @@ int qtest_check_server_protocol_err(QUIC_TSERVER *qtserv)
     return qtest_check_server_transport_err(qtserv, QUIC_ERR_PROTOCOL_VIOLATION);
 }
 
+int qtest_check_server_frame_encoding_err(QUIC_TSERVER *qtserv)
+{
+    return qtest_check_server_transport_err(qtserv, QUIC_ERR_FRAME_ENCODING_ERROR);
+}
+
 void qtest_fault_free(QTEST_FAULT *fault)
 {
     if (fault == NULL)
@@ -478,7 +600,7 @@ int qtest_fault_resize_plain_packet(QTEST_FAULT *fault, size_t newlen)
  * Prepend frame data into a packet. To be called from a packet_plain_listener
  * callback
  */
-int qtest_fault_prepend_frame(QTEST_FAULT *fault, unsigned char *frame,
+int qtest_fault_prepend_frame(QTEST_FAULT *fault, const unsigned char *frame,
                               size_t frame_len)
 {
     unsigned char *buf;
@@ -755,7 +877,13 @@ static int pcipher_sendmmsg(BIO *b, BIO_MSG *msg, size_t stride,
 
             do {
                 if (!ossl_quic_wire_decode_pkt_hdr(&pkt,
-                        0 /* TODO(QUIC): Not sure how this should be set*/, 1,
+                        /*
+                         * TODO(QUIC SERVER):
+                         * Needs to be set to the actual short header CID length
+                         * when testing the server implementation.
+                         */
+                        0,
+                        1,
                         0, &hdr, NULL))
                     goto out;
 
@@ -768,7 +896,7 @@ static int pcipher_sendmmsg(BIO *b, BIO_MSG *msg, size_t stride,
                     goto out;
 
                 /*
-                 * TODO(QUIC): At the moment modifications to hdr by the callback
+                 * At the moment modifications to hdr by the callback
                  * are ignored. We might need to rewrite the QUIC header to
                  * enable tests to change this. We also don't yet have a
                  * mechanism for the callback to change the encrypted data
@@ -810,7 +938,7 @@ static long pcipher_ctrl(BIO *b, int cmd, long larg, void *parg)
     return BIO_ctrl(next, cmd, larg, parg);
 }
 
-static BIO_METHOD *get_bio_method(void)
+BIO_METHOD *qtest_get_bio_method(void)
 {
     BIO_METHOD *tmp;