]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add an SSL BIO test for QUIC
authorMatt Caswell <matt@openssl.org>
Tue, 4 Jul 2023 15:28:41 +0000 (16:28 +0100)
committerTomas Mraz <tomas@openssl.org>
Tue, 11 Jul 2023 15:51:34 +0000 (17:51 +0200)
We create an SSL BIO using a QUIC based SSL_CTX and then use that BIO
to create a connection and read/write data from streams.

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21367)

test/helpers/quictestlib.c
test/quicapitest.c

index 52cf587c32a51b303695b21001ba1b37f25c42bb..1053a102de651b242e7cb9cd111bc4bcb3040e9d 100644 (file)
@@ -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))))
index a6b7c88eba2623e9ff8e33916dc63f9818697501..780224f07c6c11cf8418359db090ba43507a73fc 100644 (file)
@@ -608,6 +608,139 @@ err:
     return testresult;
 }
 
+#define MAXLOOPS    1000
+
+static int test_bio_ssl(void)
+{
+    /*
+     * We just use OSSL_QUIC_client_method() rather than
+     * OSSL_QUIC_client_thread_method(). We will never leave the connection idle
+     * so we will always be implicitly handling time events anyway via other
+     * IO calls.
+     */
+    SSL_CTX *cctx = SSL_CTX_new_ex(libctx, NULL, OSSL_QUIC_client_method());
+    SSL *clientquic = NULL, *stream = NULL;
+    QUIC_TSERVER *qtserv = NULL;
+    int testresult = 0;
+    BIO *cbio = NULL, *strbio = NULL, *thisbio;
+    const char *msg = "Hello world";
+    int abortctr = 0, err, clienterr = 0, servererr = 0, retc = 0, rets = 0;
+    size_t written, readbytes, msglen;
+    int sid = 0, i;
+    unsigned char buf[80];
+
+    if (!TEST_ptr(cctx))
+        goto err;
+
+    cbio = BIO_new_ssl(cctx, 1);
+    if (!TEST_ptr(cbio))
+        goto err;
+
+    /*
+     * We must configure the ALPN/peer address etc so we get the SSL object in
+     * order to pass it to qtest_create_quic_objects for configuration.
+     */
+    if (!TEST_int_eq(BIO_get_ssl(cbio, &clientquic), 1))
+        goto err;
+
+    if (!TEST_true(qtest_create_quic_objects(libctx, NULL, cert, privkey,
+                                             0, &qtserv, &clientquic, NULL)))
+        goto err;
+
+    msglen = strlen(msg);
+
+    do {
+        err = BIO_FLAGS_WRITE;
+        while (!clienterr && !retc && err == BIO_FLAGS_WRITE) {
+            retc = BIO_write_ex(cbio, msg, msglen, &written);
+            if (!retc) {
+                if (BIO_should_retry(cbio))
+                    err = BIO_retry_type(cbio);
+                else
+                    err = 0;
+            }
+        }
+
+        if (!clienterr && retc <= 0 && err != BIO_FLAGS_READ) {
+            TEST_info("BIO_write_ex() failed %d, %d", retc, err);
+            TEST_openssl_errors();
+            clienterr = 1;
+        }
+
+        if (!servererr && rets <= 0) {
+            ossl_quic_tserver_tick(qtserv);
+            servererr = ossl_quic_tserver_is_term_any(qtserv);
+            if (!servererr)
+                rets = ossl_quic_tserver_is_handshake_confirmed(qtserv);
+        }
+
+        if (clienterr && servererr)
+            goto err;
+
+        if (++abortctr == MAXLOOPS) {
+            TEST_info("No progress made");
+            goto err;
+        }
+    } while ((!retc && !clienterr) || (rets <= 0 && !servererr));
+
+    /*
+     * 2 loops: The first using the default stream, and the second using a new
+     * client initiated bidi stream.
+     */
+    for (i = 0, thisbio = cbio; i < 2; i++) {
+        if (!TEST_true(ossl_quic_tserver_read(qtserv, sid, buf, sizeof(buf),
+                                              &readbytes))
+                || !TEST_mem_eq(msg, msglen, buf, readbytes))
+            goto err;
+
+        if (!TEST_true(ossl_quic_tserver_write(qtserv, sid, (unsigned char *)msg,
+                                               msglen, &written)))
+            goto err;
+        ossl_quic_tserver_tick(qtserv);
+
+        if (!TEST_true(BIO_read_ex(thisbio, buf, sizeof(buf), &readbytes))
+                || !TEST_mem_eq(msg, msglen, buf, readbytes))
+            goto err;
+
+        if (i == 1)
+            break;
+
+        /*
+         * Now create a new stream and repeat. The bottom two bits of the stream
+         * id represents whether the stream is bidi and whether it is client
+         * initiated or not. For client initiated bidi they are both 0. So the
+         * first client initiated bidi stream is 0 and the next one is 4.
+         */
+        sid = 4;
+        stream = SSL_new_stream(clientquic, 0);
+        if (!TEST_ptr(stream))
+            goto err;
+
+        thisbio = strbio = BIO_new(BIO_f_ssl());
+        if (!TEST_ptr(strbio))
+            goto err;
+
+        if (!TEST_int_eq(BIO_set_ssl(thisbio, stream, BIO_CLOSE), 1))
+            goto err;
+        stream = NULL;
+
+        if (!TEST_true(BIO_write_ex(thisbio, msg, msglen, &written)))
+            goto err;
+
+        ossl_quic_tserver_tick(qtserv);
+    }
+
+    testresult = 1;
+ err:
+    BIO_free_all(cbio);
+    BIO_free_all(strbio);
+    SSL_free(stream);
+    ossl_quic_tserver_free(qtserv);
+    SSL_CTX_free(cctx);
+
+    return testresult;
+}
+
 OPT_TEST_DECLARE_USAGE("provider config certsdir datadir\n")
 
 int setup_tests(void)
@@ -673,6 +806,7 @@ int setup_tests(void)
     ADD_TEST(test_quic_forbidden_apis);
     ADD_TEST(test_quic_forbidden_options);
     ADD_ALL_TESTS(test_quic_set_fd, 3);
+    ADD_TEST(test_bio_ssl);
     return 1;
  err:
     cleanup_tests();