]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add QUIC-TLS server support
authorMatt Caswell <matt@openssl.org>
Tue, 29 Nov 2022 11:26:08 +0000 (11:26 +0000)
committerMatt Caswell <matt@openssl.org>
Tue, 24 Jan 2023 17:16:29 +0000 (17:16 +0000)
Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19748)

include/internal/quic_tserver.h
ssl/quic/quic_impl.c
ssl/quic/quic_tls.c
ssl/quic/quic_tserver.c
test/quic_tserver_test.c
test/recipes/70-test_quic_tserver.t

index 668621032208ccb9608ea02509ec152521287669..4610627b5e166061e9f10106effa6078009e221a 100644 (file)
@@ -36,7 +36,8 @@ typedef struct quic_tserver_args_st {
     BIO *net_rbio, *net_wbio;
 } QUIC_TSERVER_ARGS;
 
-QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args);
+QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args,
+                                    const char *certfile, const char *keyfile);
 
 void ossl_quic_tserver_free(QUIC_TSERVER *srv);
 
index 4331e6412b96bc2ce994ca8a71c9a8d9e00cd71a..5b895cb48a39b6a87b57a46a6d66d192068c548a 100644 (file)
@@ -131,7 +131,7 @@ SSL *ossl_quic_new(SSL_CTX *ctx)
         goto err;
     }
 
-    qc->tls = ossl_ssl_connection_new_int(ctx, TLS_client_method());
+    qc->tls = ossl_ssl_connection_new_int(ctx, TLS_method());
     if (qc->tls == NULL || (sc = SSL_CONNECTION_FROM_SSL(qc->tls)) == NULL)
          goto err;
     /* override the user_ssl of the inner connection */
index d7e3dd4acdcab26159cab1c879fc1dd9e6ccda83..5ce71a2e4fdad0bd359796aa10a73ec7d2f88af7 100644 (file)
@@ -641,6 +641,7 @@ int ossl_quic_tls_tick(QUIC_TLS *qtls)
 
     if (!qtls->configured) {
         SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(qtls->args.s);
+        SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(sc);
         BIO *nullbio;
 
         /*
@@ -649,9 +650,16 @@ int ossl_quic_tls_tick(QUIC_TLS *qtls)
          */
 
         /* ALPN is a requirement for QUIC and must be set */
-        if (sc->ext.alpn == NULL || sc->ext.alpn_len == 0) {
-            qtls->inerror = 1;
-            return 0;
+        if (qtls->args.is_server) {
+            if (sctx->ext.alpn_select_cb == NULL) {
+                qtls->inerror = 1;
+                return 0;
+            }
+        } else {
+            if (sc->ext.alpn == NULL || sc->ext.alpn_len == 0) {
+                qtls->inerror = 1;
+                return 0;
+            }
         }
         if (!SSL_set_min_proto_version(qtls->args.s, TLS1_3_VERSION)) {
             qtls->inerror = 1;
@@ -661,7 +669,8 @@ int ossl_quic_tls_tick(QUIC_TLS *qtls)
         ossl_ssl_set_custom_record_layer(sc, &quic_tls_record_method, qtls);
 
         if (!ossl_tls_add_custom_ext_intern(NULL, &sc->cert->custext,
-                                            ENDPOINT_CLIENT,
+                                            qtls->args.is_server ? ENDPOINT_SERVER
+                                                                 : ENDPOINT_CLIENT,
                                             TLSEXT_TYPE_quic_transport_parameters,
                                             SSL_EXT_TLS1_3_ONLY
                                             | SSL_EXT_CLIENT_HELLO
@@ -685,9 +694,14 @@ int ossl_quic_tls_tick(QUIC_TLS *qtls)
          */
         SSL_set_bio(qtls->args.s, nullbio, nullbio);
 
+        if (qtls->args.is_server)
+            SSL_set_accept_state(qtls->args.s);
+        else
+            SSL_set_connect_state(qtls->args.s);
+
         qtls->configured = 1;
     }
-    ret = SSL_connect(qtls->args.s);
+    ret = SSL_do_handshake(qtls->args.s);
     if (ret <= 0) {
         switch (SSL_get_error(qtls->args.s, ret)) {
         case SSL_ERROR_WANT_READ:
@@ -713,12 +727,6 @@ int ossl_quic_tls_set_transport_params(QUIC_TLS *qtls,
                                        const unsigned char *transport_params,
                                        size_t transport_params_len)
 {
-    if (!ossl_assert(!qtls->args.is_server)) {
-        ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
-        qtls->inerror = 1;
-        return 0;
-    }
-
     qtls->local_transport_params       = transport_params;
     qtls->local_transport_params_len   = transport_params_len;
     return 1;
index 96fb668b241eba651d32db9e52334d30bf45d176..6795d4ec4659d42814ac5396f2aceb4b3b9930a9 100644 (file)
@@ -24,6 +24,12 @@ struct quic_tserver_st {
      */
     QUIC_CHANNEL    *ch;
 
+    /* SSL_CTX for creating the underlying TLS connection */
+    SSL_CTX *ctx;
+
+    /* SSL for the underlying TLS connection */
+    SSL *tls;
+
     /* Our single bidirectional application data stream. */
     QUIC_STREAM     *stream0;
 
@@ -34,7 +40,21 @@ struct quic_tserver_st {
     unsigned int    connected       : 1;
 };
 
-QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args)
+static int alpn_select_cb(SSL *ssl, const unsigned char **out,
+                          unsigned char *outlen, const unsigned char *in,
+                          unsigned int inlen, void *arg)
+{
+    unsigned char alpn[] = { 8, 'o', 's', 's', 'l', 't', 'e', 's', 't' };
+
+    if (SSL_select_next_proto((unsigned char **)out, outlen, alpn, sizeof(alpn),
+                              in, inlen) != OPENSSL_NPN_NEGOTIATED)
+        return SSL_TLSEXT_ERR_ALERT_FATAL;
+
+    return SSL_TLSEXT_ERR_OK;
+}
+
+QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args,
+                                    const char *certfile, const char *keyfile)
 {
     QUIC_TSERVER *srv = NULL;
     QUIC_CHANNEL_ARGS ch_args = {0};
@@ -47,8 +67,25 @@ QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args)
 
     srv->args = *args;
 
+    srv->ctx = SSL_CTX_new_ex(srv->args.libctx, srv->args.propq, TLS_method());
+    if (srv->ctx == NULL)
+        goto err;
+
+    if (SSL_CTX_use_certificate_file(srv->ctx, certfile, SSL_FILETYPE_PEM) <= 0)
+        goto err;
+
+    if (SSL_CTX_use_PrivateKey_file(srv->ctx, keyfile, SSL_FILETYPE_PEM) <= 0)
+        goto err;
+
+    SSL_CTX_set_alpn_select_cb(srv->ctx, alpn_select_cb, srv);
+
+    srv->tls = SSL_new(srv->ctx);
+    if (srv->tls == NULL)
+        goto err;
+
     ch_args.libctx      = srv->args.libctx;
     ch_args.propq       = srv->args.propq;
+    ch_args.tls         = srv->tls;
     ch_args.is_server   = 1;
 
     if ((srv->ch = ossl_quic_channel_new(&ch_args)) == NULL)
@@ -80,6 +117,8 @@ void ossl_quic_tserver_free(QUIC_TSERVER *srv)
     ossl_quic_channel_free(srv->ch);
     BIO_free(srv->args.net_rbio);
     BIO_free(srv->args.net_wbio);
+    SSL_free(srv->tls);
+    SSL_CTX_free(srv->ctx);
     OPENSSL_free(srv);
 }
 
index 0e070cb1f29c6ec8701af2bd8000e0553e20dd17..c2a831c89c4494233122c28c9430ec4401dae570 100644 (file)
@@ -18,6 +18,8 @@
 static const char msg1[] = "The quick brown fox jumped over the lazy dogs.";
 static char msg2[1024], msg3[1024];
 
+static const char *certfile, *keyfile;
+
 static int is_want(SSL *s, int ret)
 {
     int ec = SSL_get_error(s, ret);
@@ -43,6 +45,7 @@ static int test_tserver(void)
     size_t l = 0, s_total_read = 0, s_total_written = 0, c_total_read = 0;
     int s_begin_write = 0;
     OSSL_TIME start_time;
+    unsigned char alpn[] = { 8, 'o', 's', 's', 'l', 't', 'e', 's', 't' };
 
     ina.s_addr = htonl(0x7f000001UL);
 
@@ -80,7 +83,8 @@ static int test_tserver(void)
     tserver_args.net_rbio = s_net_bio;
     tserver_args.net_wbio = s_net_bio;
 
-    if (!TEST_ptr(tserver = ossl_quic_tserver_new(&tserver_args))) {
+    if (!TEST_ptr(tserver = ossl_quic_tserver_new(&tserver_args, certfile,
+                                                  keyfile))) {
         BIO_free(s_net_bio);
         goto err;
     }
@@ -107,6 +111,10 @@ static int test_tserver(void)
     if (!TEST_ptr(c_ssl = SSL_new(c_ctx)))
         goto err;
 
+    /* 0 is a success for SSL_set_alpn_protos() */
+    if (!TEST_false(SSL_set_alpn_protos(c_ssl, alpn, sizeof(alpn))))
+        goto err;
+
     /* Takes ownership of our reference to the BIO. */
     SSL_set0_rbio(c_ssl, c_net_bio);
 
@@ -215,8 +223,19 @@ err:
     return testresult;
 }
 
+OPT_TEST_DECLARE_USAGE("certfile privkeyfile\n")
+
 int setup_tests(void)
 {
+    if (!test_skip_common_options()) {
+        TEST_error("Error parsing test options\n");
+        return 0;
+    }
+
+    if (!TEST_ptr(certfile = test_get_argument(0))
+            || !TEST_ptr(keyfile = test_get_argument(1)))
+        return 0;
+
     ADD_TEST(test_tserver);
     return 1;
 }
index 76c24c36c536670a30d6bcfd1e782a278a12c6a8..4ff2d208b657679d86c4ebc9d0c366e9b8fc5d16 100644 (file)
@@ -6,14 +6,16 @@
 # in the file LICENSE in the source distribution or at
 # https://www.openssl.org/source/license.html
 
-use OpenSSL::Test;
+use OpenSSL::Test qw/:DEFAULT srctop_file/;
 use OpenSSL::Test::Utils;
 
-setup("test_quic_txp");
+setup("test_quic_tserver");
 
 plan skip_all => "QUIC protocol is not supported by this OpenSSL build"
     if disabled('quic');
 
 plan tests => 1;
 
-ok(run(test(["quic_tserver_test"])));
+ok(run(test(["quic_tserver_test",
+             srctop_file("test", "certs", "servercert.pem"),
+             srctop_file("test", "certs", "serverkey.pem")])));