Commit f20e51341d for openssl.org

commit f20e51341d3134bed58e6bb18475b80bfd5712ce
Author: Alexandr Nedvedicky <sashan@openssl.org>
Date:   Thu Jul 23 07:06:28 2026 +0200

    test/quictestlib.c: add functions to create QUIC objects on dgram bio

    Add the following helper functions:
      * create_quic_ctx_pair() - creates pair of SSL_CTX (server, client).
      * create_quic_conn_objects() - creates pair of SSL objects, client
        and listener.  They both are 'connected' by BIO_dgram_pair.
      * create_quic_client() - creates SSL QUIC client object bound to BIO
        object provided by caller.

    Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
    Reviewed-by: Andrew Dinh <andrewd@openssl.org>
    Reviewed-by: Neil Horman <nhorman@openssl.org>
    MergeDate: Wed Aug 12 15:00:27 2026
    (Merged from https://github.com/openssl/openssl/pull/32052)

diff --git a/test/helpers/quictestlib.c b/test/helpers/quictestlib.c
index 29508dcfd6..4e6d3f519e 100644
--- a/test/helpers/quictestlib.c
+++ b/test/helpers/quictestlib.c
@@ -1376,3 +1376,314 @@ int bio_msg_copy(BIO_MSG *dst, BIO_MSG *src)

     return 1;
 }
+
+static const unsigned char alpn[] = {
+    8, 'o', 's', 's', 'l', 't', 'e', 's', 't'
+};
+
+static int select_alpn(SSL *ssl, const unsigned char **out, unsigned char *out_len,
+    const unsigned char *in, unsigned int in_len, void *arg)
+{
+    int e;
+
+    e = SSL_select_next_proto((unsigned char **)out, out_len, alpn, sizeof(alpn),
+        in, in_len);
+    return (e == OPENSSL_NPN_NEGOTIATED) ? SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_ALERT_FATAL;
+}
+
+int create_quic_ctx_pair(OSSL_LIB_CTX *libctx, SSL_CTX **c_sctx_p, SSL_CTX **s_sctx_p,
+    const char *certfile, const char *keyfile)
+{
+    int ok = 0;
+    SSL_CTX *c_sctx, *s_sctx;
+
+    c_sctx = NULL;
+    s_sctx = NULL;
+    c_sctx = SSL_CTX_new_ex(libctx, NULL, OSSL_QUIC_client_method());
+    if (!TEST_ptr(c_sctx)) {
+        TEST_info("%s SSL_CTX_new_ex(OSSL_QUIC_client_method()) failed", __func__);
+        goto done;
+    }
+
+    s_sctx = SSL_CTX_new_ex(libctx, NULL, OSSL_QUIC_server_method());
+    if (!TEST_ptr(s_sctx)) {
+        TEST_info("%s SSL_CTX_new_ex(OSSL_QUIC_server_method()) failed", __func__);
+        goto done;
+    }
+
+    ok = SSL_CTX_use_certificate_file(s_sctx, certfile, SSL_FILETYPE_PEM);
+    if (ok != 1) {
+        TEST_info("%s SSL_CTX_use_certificate_file(%s) failed", __func__, certfile);
+        ok = 0;
+        goto done;
+    }
+
+    ok = SSL_CTX_use_PrivateKey_file(s_sctx, keyfile, SSL_FILETYPE_PEM);
+    if (ok != 1) {
+        TEST_info("%s SSL_CTX_use_PrivateKey_file(%s) failed", __func__, keyfile);
+        ok = 0;
+        goto done;
+    }
+    SSL_CTX_set_alpn_select_cb(s_sctx, select_alpn, NULL);
+
+    *c_sctx_p = c_sctx;
+    c_sctx = NULL;
+    *s_sctx_p = s_sctx;
+    s_sctx = NULL;
+
+done:
+    SSL_CTX_free(c_sctx);
+    SSL_CTX_free(s_sctx);
+
+    return ok;
+}
+
+static int create_dgram_pair(BIO **c_bio_p, BIO **s_bio_p)
+{
+    BIO *c_bio, *s_bio;
+    BIO_ADDR *localaddr = NULL;
+    struct in_addr ina;
+    int bio_flags = 0;
+    int ok;
+
+    ina.s_addr = htonl(0x7f000001);
+    bio_flags |= BIO_DGRAM_CAP_HANDLES_DST_ADDR
+        | BIO_DGRAM_CAP_HANDLES_SRC_ADDR
+        | BIO_DGRAM_CAP_PROVIDES_DST_ADDR
+        | BIO_DGRAM_CAP_PROVIDES_SRC_ADDR;
+
+    c_bio = NULL;
+    s_bio = NULL;
+    ok = BIO_new_bio_dgram_pair(&c_bio, 1500, &s_bio, 1500);
+    if (ok == 0) {
+        TEST_info("%s BIO_new_bio_dgram_pair() error", __func__);
+        goto done;
+    }
+
+    ok = BIO_dgram_set_caps(c_bio, bio_flags);
+    if (ok == 0) {
+        TEST_info("%s BIO_dgram_set_caps(c_bio, bio_flags) failed", __func__);
+        goto done;
+    }
+
+    ok = BIO_dgram_set_caps(s_bio, bio_flags);
+    if (ok == 0) {
+        TEST_info("%s BIO_dgram_set_caps(s_bio, bio_flags) failed", __func__);
+        goto done;
+    }
+
+    ok = BIO_dgram_set_mtu(c_bio, 1500);
+    if (ok == 0) {
+        TEST_info("%s BIO_dgram_set_mtu(c_bio) error", __func__);
+        goto done;
+    }
+
+    ok = BIO_dgram_set_mtu(s_bio, 1500);
+    if (ok == 0) {
+        TEST_info("%s BIO_dgram_set_mtu(s_bio) error", __func__);
+        goto done;
+    }
+
+    localaddr = BIO_ADDR_new();
+    if (!TEST_ptr(localaddr)) {
+        TEST_info("%s BIO_ADDR_new() error", __func__);
+        goto done;
+    }
+    ok = BIO_ADDR_rawmake(localaddr, AF_INET, &ina, sizeof(ina), htons(4080));
+    if (ok == 0) {
+        TEST_info("%s BIO_ADDR_rawmake(4080) error", __func__);
+        goto done;
+    }
+    ok = BIO_dgram_set0_local_addr(c_bio, localaddr);
+    if (ok != 1) {
+        TEST_info("%s BIO_dgram_set0_local_addr(c_bio)", __func__);
+        ok = 0;
+        goto done;
+    }
+
+    localaddr = BIO_ADDR_new();
+    if (!TEST_ptr(localaddr)) {
+        TEST_info("%s BIO_ADDR_new() error", __func__);
+        goto done;
+    }
+    ok = BIO_ADDR_rawmake(localaddr, AF_INET, &ina, sizeof(ina), htons(8040));
+    if (ok == 0) {
+        TEST_info("%s BIO_ADDR_rawmake(8040) error", __func__);
+        goto done;
+    }
+    ok = BIO_dgram_set0_local_addr(s_bio, localaddr);
+    if (ok != 1) {
+        TEST_info("%s BIO_dgram_set0_local_addr(c_bio)", __func__);
+        ok = 0;
+        goto done;
+    }
+    localaddr = NULL;
+
+    ok = BIO_dgram_set_local_addr_enable(c_bio, 1);
+    if (ok == 0) {
+        TEST_info("%s BIO_dgram_set_local_addr_enable(c_bio)", __func__);
+        goto done;
+    }
+
+    ok = BIO_dgram_set_local_addr_enable(s_bio, 1);
+    if (ok == 0) {
+        TEST_info("%s BIO_dgram_set_local_addr_enable(s_bio)", __func__);
+        goto done;
+    }
+
+    *c_bio_p = c_bio;
+    c_bio = NULL;
+    *s_bio_p = s_bio;
+    s_bio = NULL;
+
+done:
+    BIO_free(c_bio);
+    BIO_free(s_bio);
+    BIO_ADDR_free(localaddr);
+
+    return ok;
+}
+
+static int init_client(SSL *c_ssl)
+{
+    BIO_ADDR *peer_addr = NULL;
+    struct in_addr ina;
+    int ok = 0;
+
+    ina.s_addr = htonl(0x7f000001);
+
+    ok = SSL_set_tlsext_host_name(c_ssl, "localhost");
+    if (ok == 0) {
+        TEST_info("%s SSL_set_tlsext_host_name()", __func__);
+        goto done;
+    }
+
+    ok = SSL_set1_dnsname(c_ssl, "localhost");
+    if (ok == 0) {
+        TEST_info("%s SSL_set1_dnsname()", __func__);
+        goto done;
+    }
+
+    ok = SSL_set_alpn_protos(c_ssl, alpn, sizeof(alpn));
+    if (ok != 0) {
+        TEST_info("%s SSL_set_alpn_protos() failed", __func__);
+        ok = 0;
+        goto done;
+    }
+
+    ok = SSL_set_blocking_mode(c_ssl, 0);
+    if (ok == 0) {
+        TEST_info("%s SSL_set_block_mode() failed", __func__);
+        goto done;
+    }
+
+    peer_addr = BIO_ADDR_new();
+    if (!TEST_ptr(peer_addr)) {
+        TEST_info("%s BIO_ADDR_new() failed", __func__);
+        goto done;
+    }
+    ok = BIO_ADDR_rawmake(peer_addr, AF_INET, &ina, sizeof(ina), htons(8040));
+    if (ok == 0) {
+        TEST_info("%s BIO_ADDR_rawmake() failed", __func__);
+        goto done;
+    }
+    ok = SSL_set1_initial_peer_addr(c_ssl, peer_addr);
+    if (ok == 0) {
+        TEST_info("%s SSL_set1_initial_peer_addr() failed", __func__);
+        goto done;
+    }
+
+done:
+    BIO_ADDR_free(peer_addr);
+
+    return ok;
+}
+
+int create_quic_conn_objects(SSL_CTX *c_sctx, SSL_CTX *s_sctx, SSL **c_ssl_p, SSL **s_ssl_p)
+{
+    BIO *c_bio = NULL, *s_bio = NULL;
+    SSL *c_ssl = NULL, *s_ssl = NULL;
+    int ok;
+
+    ok = create_dgram_pair(&c_bio, &s_bio);
+    if (ok == 0)
+        goto done;
+
+    c_ssl = SSL_new(c_sctx);
+    if (!TEST_ptr(c_ssl)) {
+        TEST_info("%s SSL_new(c_sctx) failed", __func__);
+        ok = 0;
+        goto done;
+    }
+
+    ok = init_client(c_ssl);
+    if (ok == 0)
+        goto done;
+
+    s_ssl = SSL_new_listener(s_sctx, 0);
+    if (!TEST_ptr(s_ssl)) {
+        TEST_info("%s SSL_new_listener() failed", __func__);
+        ok = 0;
+        goto done;
+    }
+
+    SSL_set_bio(c_ssl, c_bio, c_bio);
+    SSL_set_bio(s_ssl, s_bio, s_bio);
+    c_bio = NULL;
+    s_bio = NULL;
+
+    ok = SSL_set_blocking_mode(s_ssl, 0);
+    if (ok == 0) {
+        TEST_info("%s SSL_set_blocking_mode() failed", __func__);
+        ok = 0;
+        goto done;
+    }
+
+    *c_ssl_p = c_ssl;
+    c_ssl = NULL;
+    *s_ssl_p = s_ssl;
+    s_ssl = NULL;
+
+done:
+    BIO_free(c_bio);
+    BIO_free(s_bio);
+    SSL_free(c_ssl);
+    SSL_free(s_ssl);
+
+    return ok;
+}
+
+SSL *create_quic_client(SSL_CTX *c_sctx, BIO *c_bio)
+{
+    SSL *c_ssl;
+
+    if (!TEST_ptr(c_bio))
+        return NULL;
+
+    c_ssl = SSL_new(c_sctx);
+    if (!TEST_ptr(c_ssl)) {
+        TEST_info("%s SSL_new(c_sctx) failed", __func__);
+        return NULL;
+    }
+
+    if (BIO_up_ref(c_bio) == 0) {
+        TEST_info("%s BIO_up_ref() failed)", __func__);
+        goto error;
+    }
+    SSL_set_bio(c_ssl, c_bio, c_bio);
+
+    if (init_client(c_ssl) == 0)
+        goto error;
+
+    if (SSL_set_blocking_mode(c_ssl, 0) == 0) {
+        TEST_info("%s SSL_set_blocking_mode() failed", __func__);
+        goto error;
+    }
+
+    return c_ssl;
+
+error:
+    SSL_free(c_ssl);
+
+    return NULL;
+}
diff --git a/test/helpers/quictestlib.h b/test/helpers/quictestlib.h
index 63c77f90b7..a60d40ffe3 100644
--- a/test/helpers/quictestlib.h
+++ b/test/helpers/quictestlib.h
@@ -289,3 +289,7 @@ const BIO_METHOD *bio_f_pkt_split_dgram_filter(void);

 /* Free the BIO filter method object */
 void bio_f_pkt_split_dgram_filter_free(void);
+
+int create_quic_ctx_pair(OSSL_LIB_CTX *libctx, SSL_CTX **c_sctx_p, SSL_CTX **s_sctx_p, const char *certfile, const char *keyfile);
+int create_quic_conn_objects(SSL_CTX *c_sctx, SSL_CTX *s_ctx, SSL **c_ssl_p, SSL **s_ssl_p);
+SSL *create_quic_client(SSL_CTX *c_sctx, BIO *c_bio);