]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
QUIC SRT GEN: Add SRT generator
authorHugo Landau <hlandau@openssl.org>
Thu, 2 Nov 2023 15:41:23 +0000 (15:41 +0000)
committerHugo Landau <hlandau@openssl.org>
Sat, 25 Nov 2023 09:14:05 +0000 (09:14 +0000)
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/22599)

include/internal/quic_srt_gen.h [new file with mode: 0644]
ssl/quic/build.info
ssl/quic/quic_srt_gen.c [new file with mode: 0644]
test/build.info
test/quic_srt_gen_test.c [new file with mode: 0644]
test/recipes/75-test_quic_srt_gen.t [new file with mode: 0644]

diff --git a/include/internal/quic_srt_gen.h b/include/internal/quic_srt_gen.h
new file mode 100644 (file)
index 0000000..a25e71a
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+* Copyright 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
+* in the file LICENSE in the source distribution or at
+* https://www.openssl.org/source/license.html
+*/
+
+#ifndef OSSL_INTERNAL_QUIC_SRT_GEN_H
+# define OSSL_INTERNAL_QUIC_SRT_GEN_H
+# pragma once
+
+# include "internal/e_os.h"
+# include "internal/time.h"
+# include "internal/quic_types.h"
+# include "internal/quic_wire.h"
+
+# ifndef OPENSSL_NO_QUIC
+
+/*
+ * QUIC Stateless Reset Token Generator
+ * ====================================
+ *
+ * This generates 16-byte QUIC Stateless Reset Tokens given a secret symmetric
+ * key and a DCID. Because the output is deterministic with regards to these
+ * inputs, assuming the same key is used between invocations of a process, we
+ * are able to generate the same stateless reset token in a subsequent process,
+ * thereby allowing us to achieve stateless reset of a peer which still thinks
+ * it is connected to a past process at the same UDP address.
+ */
+typedef struct quic_srt_gen_st QUIC_SRT_GEN;
+
+/*
+ * Create a new stateless reset token generator using the given key as input.
+ * The key may be of arbitrary length.
+ *
+ * The caller is responsible for performing domain separation with regards to
+ * the key; i.e., the caller is responsible for ensuring the key is never used
+ * in any other context.
+ */
+QUIC_SRT_GEN *ossl_quic_srt_gen_new(OSSL_LIB_CTX *libctx, const char *propq,
+                                    const unsigned char *key, size_t key_len);
+
+/* Free the stateless reset token generator. No-op if srt_gen is NULL. */
+void ossl_quic_srt_gen_free(QUIC_SRT_GEN *srt_gen);
+
+/*
+ * Calculates a token using the given DCID and writes it to *token. Returns 0 on
+ * failure.
+ */
+int ossl_quic_srt_gen_calculate_token(QUIC_SRT_GEN *srt_gen,
+                                      const QUIC_CONN_ID *dcid,
+                                      QUIC_STATELESS_RESET_TOKEN *token);
+
+# endif
+#endif
index 866f581fa9113d2c81cf77d825fb17cdcb760634..b8d871848c106f0ac829051eca50548b1b5dbad1 100644 (file)
@@ -14,4 +14,4 @@ SOURCE[$LIBSSL]=quic_tserver.c
 SOURCE[$LIBSSL]=quic_tls.c
 SOURCE[$LIBSSL]=quic_thread_assist.c
 SOURCE[$LIBSSL]=quic_trace.c
-SOURCE[$LIBSSL]=quic_srtm.c
+SOURCE[$LIBSSL]=quic_srtm.c quic_srt_gen.c
diff --git a/ssl/quic/quic_srt_gen.c b/ssl/quic/quic_srt_gen.c
new file mode 100644 (file)
index 0000000..e43a55b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+#include "internal/quic_srt_gen.h"
+#include <openssl/core_names.h>
+#include <openssl/evp.h>
+
+struct quic_srt_gen_st {
+    EVP_MAC         *mac;
+    EVP_MAC_CTX     *mac_ctx;
+};
+
+/*
+ * Simple HMAC-SHA256-based stateless reset token generator.
+ */
+
+QUIC_SRT_GEN *ossl_quic_srt_gen_new(OSSL_LIB_CTX *libctx, const char *propq,
+                                    const unsigned char *key, size_t key_len)
+{
+    QUIC_SRT_GEN *srt_gen;
+    OSSL_PARAM params[3], *p = params;
+
+    if ((srt_gen = OPENSSL_zalloc(sizeof(*srt_gen))) == NULL)
+        return NULL;
+
+    if ((srt_gen->mac = EVP_MAC_fetch(libctx, "HMAC", propq)) == NULL)
+        goto err;
+
+    if ((srt_gen->mac_ctx = EVP_MAC_CTX_new(srt_gen->mac)) == NULL)
+        goto err;
+
+    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, "SHA256", 7);
+    if (propq != NULL)
+        *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_PROPERTIES,
+                                                (char *)propq, 0);
+    *p++ = OSSL_PARAM_construct_end();
+
+    if (!EVP_MAC_init(srt_gen->mac_ctx, key, key_len, params))
+        goto err;
+
+    return srt_gen;
+
+err:
+    ossl_quic_srt_gen_free(srt_gen);
+    return NULL;
+}
+
+void ossl_quic_srt_gen_free(QUIC_SRT_GEN *srt_gen)
+{
+    if (srt_gen == NULL)
+        return;
+
+    EVP_MAC_CTX_free(srt_gen->mac_ctx);
+    EVP_MAC_free(srt_gen->mac);
+    OPENSSL_free(srt_gen);
+}
+
+int ossl_quic_srt_gen_calculate_token(QUIC_SRT_GEN *srt_gen,
+                                      const QUIC_CONN_ID *dcid,
+                                      QUIC_STATELESS_RESET_TOKEN *token)
+{
+    size_t outl = 0;
+    unsigned char mac[32];
+
+    if (!EVP_MAC_init(srt_gen->mac_ctx, NULL, 0, NULL))
+        return 0;
+
+    if (!EVP_MAC_update(srt_gen->mac_ctx, (const unsigned char *)dcid->id,
+                        dcid->id_len))
+        return 0;
+
+    if (!EVP_MAC_final(srt_gen->mac_ctx, mac, &outl, sizeof(mac))
+        || outl != sizeof(mac))
+        return 0;
+
+    memcpy(token, mac, sizeof(*token));
+    return 1;
+}
index cba48e6db00de2571e9a114cad7867b29b83c167..a71ee13d1f12457994ca0ecf689234b03ca44641 100644 (file)
@@ -75,7 +75,7 @@ IF[{- !$disabled{tests} -}]
 
   IF[{- !$disabled{quic} -}]
     PROGRAMS{noinst}=priority_queue_test event_queue_test quicfaultstest quicapitest \
-                     quic_newcid_test
+                     quic_newcid_test quic_srt_gen_test
   ENDIF
 
   IF[{- !$disabled{comp} && (!$disabled{brotli} || !$disabled{zstd} || !$disabled{zlib}) -}]
@@ -850,6 +850,10 @@ IF[{- !$disabled{tests} -}]
       SOURCE[quic_newcid_test]=quic_newcid_test.c helpers/ssltestlib.c $QUICTESTHELPERS
       INCLUDE[quic_newcid_test]=../include ../apps/include ..
       DEPEND[quic_newcid_test]=../libcrypto.a ../libssl.a libtestutil.a
+
+      SOURCE[quic_srt_gen_test]=quic_srt_gen_test.c helpers/ssltestlib.c $QUICTESTHELPERS
+      INCLUDE[quic_srt_gen_test]=../include ../apps/include ..
+      DEPEND[quic_srt_gen_test]=../libcrypto.a ../libssl.a libtestutil.a
     ENDIF
 
     SOURCE[dhtest]=dhtest.c
diff --git a/test/quic_srt_gen_test.c b/test/quic_srt_gen_test.c
new file mode 100644 (file)
index 0000000..6982f59
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/opensslconf.h>
+#include "internal/quic_srt_gen.h"
+
+#include "testutil.h"
+#include "testutil/output.h"
+
+struct test_case {
+    const unsigned char         *key;
+    size_t                      key_len;
+    QUIC_CONN_ID                dcid;
+    QUIC_STATELESS_RESET_TOKEN  expected;
+};
+
+static const unsigned char key_1[] = { 0x01, 0x02, 0x03 };
+
+static const unsigned char key_2[] = {
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
+};
+
+static const struct test_case tests[] = {
+    {
+      key_1, sizeof(key_1), { 2, { 0x55, 0x66 } },
+      {{ 0x02,0x9e,0x8f,0x3d,0x1e,0xa9,0x06,0x23,0xb2,0x43,0xd2,0x19,0x59,0x8a,0xa1,0x66 }}
+    },
+    {
+      key_2, sizeof(key_2), { 0, { 0 } },
+      {{ 0x93,0x10,0x2f,0xc7,0xaf,0x9d,0x9b,0x28,0x3f,0x84,0x95,0x6b,0xa3,0xdc,0x07,0x6b }}
+    },
+    {
+      key_2, sizeof(key_2),
+      { 20, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } },
+      {{ 0x9a,0x98,0x98,0x61,0xbe,0xfd,0xe3,0x05,0x45,0xac,0x66,0xcf,0x3b,0x58,0xfb,0xab }}
+    }
+};
+
+static int test_srt_gen(int idx)
+{
+    int testresult = 0;
+    const struct test_case *t = &tests[idx];
+    QUIC_SRT_GEN *srt_gen = NULL;
+    QUIC_STATELESS_RESET_TOKEN token;
+    size_t i;
+
+    if (!TEST_ptr(srt_gen = ossl_quic_srt_gen_new(NULL, NULL,
+                                                  t->key, t->key_len)))
+        goto err;
+
+    for (i = 0; i < 2; ++i) {
+        memset(&token, 0xff, sizeof(token));
+
+        if (!TEST_true(ossl_quic_srt_gen_calculate_token(srt_gen, &t->dcid,
+                                                         &token)))
+            goto err;
+
+        if (!TEST_mem_eq(&token, sizeof(token),
+                         &t->expected, sizeof(t->expected)))
+            goto err;
+    }
+
+    testresult = 1;
+err:
+    ossl_quic_srt_gen_free(srt_gen);
+    return testresult;
+}
+
+int setup_tests(void)
+{
+    ADD_ALL_TESTS(test_srt_gen, OSSL_NELEM(tests));
+    return 1;
+}
diff --git a/test/recipes/75-test_quic_srt_gen.t b/test/recipes/75-test_quic_srt_gen.t
new file mode 100644 (file)
index 0000000..64c2cae
--- /dev/null
@@ -0,0 +1,19 @@
+#! /usr/bin/env perl
+# 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
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use OpenSSL::Test qw/:DEFAULT/;
+use OpenSSL::Test::Utils;
+
+setup("test_quic_srt_gen");
+
+plan skip_all => "QUIC protocol is not supported by this OpenSSL build"
+    if disabled('quic');
+
+plan tests => 1;
+
+ok(run(test(["quic_srt_gen_test"])));