gnutls/gnutls-3.8.6-liboqs-x25519-kyber768d00.patch
Daiki Ueno 0ad408d5bc liboqs: check whether Kyber768 is compiled in
Related: RHEL-50011
Signed-off-by: Daiki Ueno <dueno@redhat.com>
2024-07-29 09:13:24 +09:00

3247 lines
96 KiB
Diff

From 39dad633e6acb18c3853b7cb182324ccd250ba46 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Fri, 31 May 2024 09:18:27 +0900
Subject: [PATCH 1/2] build: plumb liboqs as an optional dependency
This exposes OQS functions necessary to implement Kyber768 through
dlopen with stub implementation for lower-level cryptographic
primitives, such as SHA3 and DRBG.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
.gitignore | 1 +
cfg.mk | 2 +-
configure.ac | 37 ++++
devel/dlwrap/oqs.syms | 9 +
devel/generate-dlwrap.sh | 3 +
devel/indent-gnutls | 2 +-
lib/Makefile.am | 14 ++
lib/dlwrap/oqs.c | 182 ++++++++++++++++
lib/dlwrap/oqs.h | 53 +++++
lib/dlwrap/oqsfuncs.h | 14 ++
lib/global.c | 8 +
lib/liboqs/Makefile.am | 43 ++++
lib/liboqs/backport/sha3_ops.h | 256 ++++++++++++++++++++++
lib/liboqs/liboqs.c | 41 ++++
lib/liboqs/liboqs.h | 27 +++
lib/liboqs/rand.c | 43 ++++
lib/liboqs/rand.h | 27 +++
lib/liboqs/sha3.c | 373 +++++++++++++++++++++++++++++++++
lib/liboqs/sha3.h | 27 +++
19 files changed, 1160 insertions(+), 2 deletions(-)
create mode 100644 devel/dlwrap/oqs.syms
create mode 100644 lib/dlwrap/oqs.c
create mode 100644 lib/dlwrap/oqs.h
create mode 100644 lib/dlwrap/oqsfuncs.h
create mode 100644 lib/liboqs/Makefile.am
create mode 100644 lib/liboqs/backport/sha3_ops.h
create mode 100644 lib/liboqs/liboqs.c
create mode 100644 lib/liboqs/liboqs.h
create mode 100644 lib/liboqs/rand.c
create mode 100644 lib/liboqs/rand.h
create mode 100644 lib/liboqs/sha3.c
create mode 100644 lib/liboqs/sha3.h
diff --git a/cfg.mk b/cfg.mk
index 1b94279633..88f6df480d 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -24,7 +24,7 @@ PACKAGE ?= gnutls
.PHONY: config glimport
-INDENT_SOURCES = `find . -name \*.[ch] -o -name gnutls.h.in | grep -v -e ^./build-aux/ -e ^./config.h -e ^./devel/ -e ^./gnulib -e ^./lib/minitasn1/ -e ^./lib/includes/gnutls/gnutls.h -e ^./lib/nettle/backport/ -e ^./lib/priority_options.h -e ^./lib/unistring/ -e ^./lib/x509/supported_exts.h -e ^./lib/build-aux/ -e ^./lib/dlwrap/ -e ^./gl/ -e ^./src/gl/ -e ^./src/.*-options.[ch] -e -args.[ch] -e asn1_tab.c -e ^./tests/suite/`
+INDENT_SOURCES = `find . -name \*.[ch] -o -name gnutls.h.in | grep -v -e ^./build-aux/ -e ^./config.h -e ^./devel/ -e ^./gnulib -e ^./lib/minitasn1/ -e ^./lib/includes/gnutls/gnutls.h -e ^./lib/nettle/backport/ -e ^./lib/priority_options.h -e ^./lib/unistring/ -e ^./lib/x509/supported_exts.h -e ^./lib/build-aux/ -e ^./lib/dlwrap/ -e ^./lib/liboqs/backport/ -e ^./gl/ -e ^./src/gl/ -e ^./src/.*-options.[ch] -e -args.[ch] -e asn1_tab.c -e ^./tests/suite/`
ifeq ($(.DEFAULT_GOAL),abort-due-to-no-makefile)
.DEFAULT_GOAL := bootstrap
diff --git a/configure.ac b/configure.ac
index fb0aefe1f4..145eada690 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1185,6 +1185,41 @@ AS_IF([test "$ac_cv_dlopen_soname_works" = yes], [
CFLAGS="$save_CFLAGS"
])
+AC_ARG_WITH(liboqs,
+ AS_HELP_STRING([--with-liboqs],
+ [Enable liboqs support.]),
+ [with_liboqs=$withval], [with_liboqs=no])
+AS_IF([test "$with_liboqs" != "no"], [PKG_CHECK_MODULES(LIBOQS, [liboqs >= 0.10.1], [have_liboqs=yes], [have_liboqs=no])])
+AS_IF([test "$have_liboqs" = "yes"], [AC_DEFINE([HAVE_LIBOQS], 1, [Have liboqs])],
+ [test "$with_liboqs" = "yes"], [AC_MSG_ERROR([[
+***
+*** liboqs support was requested but the required libraries were not found.
+*** ]])])
+
+save_CFLAGS=$CFLAGS
+CFLAGS="$CFLAGS $LIBOQS_CFLAGS"
+AC_CHECK_DECLS([OQS_SHA3_set_callbacks])
+CFLAGS="$save_CFLAGS"
+
+# liboqs 0.10.1 didn't expose OQS_SHA3_set_callbacks from the header
+# file, so extra treatment is needed:
+# https://github.com/open-quantum-safe/liboqs/pull/1832
+AM_CONDITIONAL(NEED_LIBOQS_SHA3_OPS_H, test "$ac_cv_have_decl_OQS_SHA3_set_callbacks" != yes)
+
+AM_CONDITIONAL(ENABLE_LIBOQS, test "$have_liboqs" = "yes")
+
+AS_IF([test "$ac_cv_dlopen_soname_works" = yes], [
+ save_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS $LIBOQS_CFLAGS"
+ save_LIBS=$LIBS
+ LIBS="$LIBS $LIBOQS_LIBS"
+ LIBGNUTLS_CHECK_SONAME([oqs], [AC_LANG_PROGRAM([
+ #include <oqs/oqs.h>],[
+ OQS_version ();])])
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+])
+
AM_CONDITIONAL(NEED_LTLIBDL, test "$need_ltlibdl" = yes)
# export for use in scripts
@@ -1382,6 +1417,7 @@ AC_CONFIG_FILES([
lib/gnutls.pc
lib/includes/Makefile
lib/includes/gnutls/gnutls.h
+ lib/liboqs/Makefile
lib/minitasn1/Makefile
lib/nettle/Makefile
lib/x509/Makefile
@@ -1463,6 +1499,7 @@ if features are disabled)
Non-SuiteB curves: $enable_non_suiteb
FIPS140 mode: $enable_fips
Strict DER time: $ac_strict_der_time
+ liboqs: $have_liboqs
])
AC_MSG_NOTICE([Optional libraries:
diff --git a/devel/dlwrap/oqs.syms b/devel/dlwrap/oqs.syms
new file mode 100644
index 0000000000..8f067b2dd3
--- /dev/null
+++ b/devel/dlwrap/oqs.syms
@@ -0,0 +1,9 @@
+OQS_SHA3_set_callbacks
+OQS_init
+OQS_destroy
+OQS_KEM_new
+OQS_KEM_encaps
+OQS_KEM_decaps
+OQS_KEM_keypair
+OQS_KEM_free
+OQS_randombytes_custom_algorithm
\ No newline at end of file
diff --git a/devel/generate-dlwrap.sh b/devel/generate-dlwrap.sh
index dbcf870612..3e253d9228 100755
--- a/devel/generate-dlwrap.sh
+++ b/devel/generate-dlwrap.sh
@@ -35,3 +35,6 @@ echo "Generating $DST/brotlidec.h"
"$DLWRAP" --input /usr/include/brotli/decode.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/brotlidec.syms" --license-file "$SRC/brotli.license" --soname BROTLIDEC_LIBRARY_SONAME --prefix gnutls_brotlidec --loader-basename brotlidec --header-guard GNUTLS_LIB_DLWRAP_BROTLIDEC_H_ --include "<brotli/decode.h>"
+echo "Generating $DST/oqs.h"
+
+"$DLWRAP" --input /usr/include/oqs/oqs.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/oqs.syms" --license "SPDX-License-Identifier: MIT" --soname OQS_LIBRARY_SONAME --prefix gnutls_oqs --header-guard GNUTLS_LIB_DLWRAP_OQS_H_ --include "<oqs/oqs.h>"
diff --git a/lib/Makefile.am b/lib/Makefile.am
index d1bd07248e..067772c322 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -29,6 +29,10 @@ if ENABLE_MINITASN1
SUBDIRS += minitasn1
endif
+if ENABLE_LIBOQS
+SUBDIRS += liboqs
+endif
+
localedir = $(datadir)/locale
include $(top_srcdir)/lib/common.mk
@@ -119,6 +123,16 @@ thirdparty_libadd += $(LIBBROTLIDEC_LIBS)
endif
endif
+if ENABLE_LIBOQS
+COBJECTS += dlwrap/oqs.c dlwrap/oqsfuncs.h dlwrap/oqs.h
+
+if ENABLE_DLOPEN
+AM_CPPFLAGS += $(LIBOQS_CFLAGS) -DGNUTLS_OQS_ENABLE_DLOPEN=1
+else
+thirdparty_libadd += $(LIBOQS_LIBS)
+endif
+endif
+
if ENABLE_GOST
COBJECTS += vko.c
endif
diff --git a/lib/dlwrap/oqs.c b/lib/dlwrap/oqs.c
new file mode 100644
index 0000000000..d7fcc9c80c
--- /dev/null
+++ b/lib/dlwrap/oqs.c
@@ -0,0 +1,182 @@
+/*
+ * Copying and distribution of this file, with or without modification,
+ * are permitted in any medium without royalty provided the copyright
+ * notice and this notice are preserved. This file is offered as-is,
+ * without any warranty.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "oqs.h"
+
+#if defined(GNUTLS_OQS_ENABLE_DLOPEN) && GNUTLS_OQS_ENABLE_DLOPEN
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* If OQS_LIBRARY_SONAME is defined, dlopen handle can be automatically
+ * set; otherwise, the caller needs to call
+ * gnutls_oqs_ensure_library with soname determined at run time.
+ */
+#ifdef OQS_LIBRARY_SONAME
+
+static void
+ensure_library (void)
+{
+ if (gnutls_oqs_ensure_library (OQS_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0)
+ abort ();
+}
+
+#if defined(GNUTLS_OQS_ENABLE_PTHREAD) && GNUTLS_OQS_ENABLE_PTHREAD
+#include <pthread.h>
+
+static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT;
+
+#define ENSURE_LIBRARY pthread_once(&dlopen_once, ensure_library)
+
+#else /* GNUTLS_OQS_ENABLE_PTHREAD */
+
+#define ENSURE_LIBRARY do { \
+ if (!gnutls_oqs_dlhandle) \
+ ensure_library(); \
+ } while (0)
+
+#endif /* !GNUTLS_OQS_ENABLE_PTHREAD */
+
+#else /* OQS_LIBRARY_SONAME */
+
+#define ENSURE_LIBRARY do {} while (0)
+
+#endif /* !OQS_LIBRARY_SONAME */
+
+static void *gnutls_oqs_dlhandle;
+
+/* Define redirection symbols */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-macros"
+
+#if (2 <= __GNUC__ || (4 <= __clang_major__))
+#define FUNC(ret, name, args, cargs) \
+ static __typeof__(name)(*gnutls_oqs_sym_##name);
+#else
+#define FUNC(ret, name, args, cargs) \
+ static ret(*gnutls_oqs_sym_##name)args;
+#endif
+#define VOID_FUNC FUNC
+#include "oqsfuncs.h"
+#undef VOID_FUNC
+#undef FUNC
+
+#pragma GCC diagnostic pop
+
+/* Define redirection wrapper functions */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-macros"
+
+#define FUNC(ret, name, args, cargs) \
+ret gnutls_oqs_func_##name args \
+{ \
+ ENSURE_LIBRARY; \
+ assert (gnutls_oqs_sym_##name); \
+ return gnutls_oqs_sym_##name cargs; \
+}
+#define VOID_FUNC(ret, name, args, cargs) \
+ret gnutls_oqs_func_##name args \
+{ \
+ ENSURE_LIBRARY; \
+ assert (gnutls_oqs_sym_##name); \
+ gnutls_oqs_sym_##name cargs; \
+}
+#include "oqsfuncs.h"
+#undef VOID_FUNC
+#undef FUNC
+
+#pragma GCC diagnostic pop
+
+static int
+ensure_symbol (const char *name, void **symp)
+{
+ if (!*symp)
+ {
+ void *sym = dlsym (gnutls_oqs_dlhandle, name);
+ if (!sym)
+ return -errno;
+ *symp = sym;
+ }
+ return 0;
+}
+
+int
+gnutls_oqs_ensure_library (const char *soname, int flags)
+{
+ int err;
+
+ if (!gnutls_oqs_dlhandle)
+ {
+ gnutls_oqs_dlhandle = dlopen (soname, flags);
+ if (!gnutls_oqs_dlhandle)
+ return -errno;
+ }
+
+#define ENSURE_SYMBOL(name) \
+ ensure_symbol(#name, (void **)&gnutls_oqs_sym_##name)
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-macros"
+
+#define FUNC(ret, name, args, cargs) \
+ err = ENSURE_SYMBOL(name); \
+ if (err < 0) \
+ return err;
+#define VOID_FUNC FUNC
+#include "oqsfuncs.h"
+#undef VOID_FUNC
+#undef FUNC
+
+#pragma GCC diagnostic pop
+
+#undef ENSURE_SYMBOL
+ return 0;
+}
+
+void
+gnutls_oqs_unload_library (void)
+{
+ if (gnutls_oqs_dlhandle)
+ dlclose (gnutls_oqs_dlhandle);
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-macros"
+
+#define FUNC(ret, name, args, cargs) \
+ gnutls_oqs_sym_##name = NULL;
+#define VOID_FUNC FUNC
+#include "oqsfuncs.h"
+#undef VOID_FUNC
+#undef FUNC
+
+#pragma GCC diagnostic pop
+
+#undef RESET_SYMBOL
+}
+
+#else /* GNUTLS_OQS_ENABLE_DLOPEN */
+
+int
+gnutls_oqs_ensure_library (const char *soname, int flags)
+{
+ (void) soname;
+ (void) flags;
+ return 0;
+}
+
+void
+gnutls_oqs_unload_library (void)
+{
+}
+
+#endif /* !GNUTLS_OQS_ENABLE_DLOPEN */
diff --git a/lib/dlwrap/oqs.h b/lib/dlwrap/oqs.h
new file mode 100644
index 0000000000..6a1d8e0766
--- /dev/null
+++ b/lib/dlwrap/oqs.h
@@ -0,0 +1,53 @@
+/*
+ * Copying and distribution of this file, with or without modification,
+ * are permitted in any medium without royalty provided the copyright
+ * notice and this notice are preserved. This file is offered as-is,
+ * without any warranty.
+ */
+
+#ifndef GNUTLS_LIB_DLWRAP_OQS_H_
+#define GNUTLS_LIB_DLWRAP_OQS_H_
+
+/* Local modification: remove this once liboqs 0.10.2 is released */
+#include "config.h"
+#if !HAVE_DECL_OQS_SHA3_SET_CALLBACKS
+#include "liboqs/backport/sha3_ops.h"
+#endif
+
+#include <oqs/oqs.h>
+
+#if defined(GNUTLS_OQS_ENABLE_DLOPEN) && GNUTLS_OQS_ENABLE_DLOPEN
+
+#define FUNC(ret, name, args, cargs) \
+ ret gnutls_oqs_func_##name args;
+#define VOID_FUNC FUNC
+#include "oqsfuncs.h"
+#undef VOID_FUNC
+#undef FUNC
+
+#define GNUTLS_OQS_FUNC(name) gnutls_oqs_func_##name
+
+#else
+
+#define GNUTLS_OQS_FUNC(name) name
+
+#endif /* GNUTLS_OQS_ENABLE_DLOPEN */
+
+/* Ensure SONAME to be loaded with dlopen FLAGS, and all the necessary
+ * symbols are resolved.
+ *
+ * Returns 0 on success; negative error code otherwise.
+ *
+ * Note that this function is NOT thread-safe; when calling it from
+ * multi-threaded programs, protect it with a locking mechanism.
+ */
+int gnutls_oqs_ensure_library (const char *soname, int flags);
+
+/* Unload library and reset symbols.
+ *
+ * Note that this function is NOT thread-safe; when calling it from
+ * multi-threaded programs, protect it with a locking mechanism.
+ */
+void gnutls_oqs_unload_library (void);
+
+#endif /* GNUTLS_LIB_DLWRAP_OQS_H_ */
diff --git a/lib/dlwrap/oqsfuncs.h b/lib/dlwrap/oqsfuncs.h
new file mode 100644
index 0000000000..95c1b083dc
--- /dev/null
+++ b/lib/dlwrap/oqsfuncs.h
@@ -0,0 +1,14 @@
+/*
+ * This file was automatically generated from oqs.h,
+ * which is covered by the following license:
+ * SPDX-License-Identifier: MIT
+ */
+VOID_FUNC(void, OQS_init, (void), ())
+VOID_FUNC(void, OQS_destroy, (void), ())
+VOID_FUNC(void, OQS_SHA3_set_callbacks, (struct OQS_SHA3_callbacks *new_callbacks), (new_callbacks))
+VOID_FUNC(void, OQS_randombytes_custom_algorithm, (void (*algorithm_ptr)(uint8_t *, size_t)), (algorithm_ptr))
+FUNC(OQS_KEM *, OQS_KEM_new, (const char *method_name), (method_name))
+FUNC(OQS_STATUS, OQS_KEM_keypair, (const OQS_KEM *kem, uint8_t *public_key, uint8_t *secret_key), (kem, public_key, secret_key))
+FUNC(OQS_STATUS, OQS_KEM_encaps, (const OQS_KEM *kem, uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key), (kem, ciphertext, shared_secret, public_key))
+FUNC(OQS_STATUS, OQS_KEM_decaps, (const OQS_KEM *kem, uint8_t *shared_secret, const uint8_t *ciphertext, const uint8_t *secret_key), (kem, shared_secret, ciphertext, secret_key))
+VOID_FUNC(void, OQS_KEM_free, (OQS_KEM *kem), (kem))
diff --git a/lib/global.c b/lib/global.c
index b434140bbf..ae2f7f54dc 100644
--- a/lib/global.c
+++ b/lib/global.c
@@ -41,6 +41,7 @@
#include "system-keys.h"
#include "str.h"
#include "global.h"
+#include "liboqs/liboqs.h"
/* Minimum library versions we accept. */
#define GNUTLS_MIN_LIBTASN1_VERSION "0.3.4"
@@ -328,6 +329,10 @@ static int _gnutls_global_init(unsigned constructor)
goto out;
}
+#ifdef HAVE_LIBOQS
+ _gnutls_liboqs_init();
+#endif
+
#ifndef _WIN32
ret = _gnutls_register_fork_handler();
if (ret < 0) {
@@ -444,6 +449,9 @@ static void _gnutls_global_deinit(unsigned destructor)
#ifdef HAVE_TPM2
_gnutls_tpm2_deinit();
#endif
+#ifdef HAVE_LIBOQS
+ _gnutls_liboqs_deinit();
+#endif
_gnutls_nss_keylog_deinit();
} else {
diff --git a/lib/liboqs/Makefile.am b/lib/liboqs/Makefile.am
new file mode 100644
index 0000000000..a20e7cbdf9
--- /dev/null
+++ b/lib/liboqs/Makefile.am
@@ -0,0 +1,43 @@
+## Process this file with automake to produce Makefile.in
+# Copyright (C) 2004-2012 Free Software Foundation, Inc.
+# Copyright (C) 2024 Red Hat, Inc.
+#
+# Author: Daiki Ueno
+#
+# This file is part of GNUTLS.
+#
+# The GNUTLS library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 3 of
+# the License, or (at your option) any later version.
+#
+# The GNUTLS library is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>
+
+include $(top_srcdir)/lib/common.mk
+
+AM_CFLAGS += $(LIBOQS_CFLAGS)
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../../gl \
+ -I$(builddir)/../../gl \
+ -I$(srcdir)/../includes \
+ -I$(builddir)/../includes \
+ -I$(srcdir)/..
+
+if ENABLE_DLOPEN
+AM_CPPFLAGS += $(LIBOQS_CFLAGS) -DGNUTLS_OQS_ENABLE_DLOPEN=1
+endif
+
+noinst_LTLIBRARIES = libcrypto.la
+
+libcrypto_la_SOURCES = liboqs.h liboqs.c rand.h rand.c sha3.h sha3.c
+
+if NEED_LIBOQS_SHA3_OPS_H
+libcrypto_la_SOURCES += backport/sha3_ops.h
+endif
diff --git a/lib/liboqs/backport/sha3_ops.h b/lib/liboqs/backport/sha3_ops.h
new file mode 100644
index 0000000000..694fc21873
--- /dev/null
+++ b/lib/liboqs/backport/sha3_ops.h
@@ -0,0 +1,256 @@
+/**
+ * \file sha3_ops.h
+ * \brief Header defining the callback API for OQS SHA3 and SHAKE
+ *
+ * \author John Underhill, Douglas Stebila
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef OQS_SHA3_OPS_H
+#define OQS_SHA3_OPS_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <oqs/common.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/** Data structure for the state of the incremental SHA3-256 API. */
+typedef struct {
+ /** Internal state. */
+ void *ctx;
+} OQS_SHA3_sha3_256_inc_ctx;
+
+/** Data structure for the state of the incremental SHA3-384 API. */
+typedef struct {
+ /** Internal state. */
+ void *ctx;
+} OQS_SHA3_sha3_384_inc_ctx;
+
+/** Data structure for the state of the incremental SHA3-512 API. */
+typedef struct {
+ /** Internal state. */
+ void *ctx;
+} OQS_SHA3_sha3_512_inc_ctx;
+
+/** Data structure for the state of the incremental SHAKE-128 API. */
+typedef struct {
+ /** Internal state. */
+ void *ctx;
+} OQS_SHA3_shake128_inc_ctx;
+
+/** Data structure for the state of the incremental SHAKE-256 API. */
+typedef struct {
+ /** Internal state. */
+ void *ctx;
+} OQS_SHA3_shake256_inc_ctx;
+
+/** Data structure implemented by cryptographic provider for SHA-3 operations.
+ */
+struct OQS_SHA3_callbacks {
+ /**
+ * Implementation of function OQS_SHA3_sha3_256.
+ */
+ void (*SHA3_sha3_256)(uint8_t *output, const uint8_t *input, size_t inplen);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_256_inc_init.
+ */
+ void (*SHA3_sha3_256_inc_init)(OQS_SHA3_sha3_256_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_256_inc_absorb.
+ */
+ void (*SHA3_sha3_256_inc_absorb)(OQS_SHA3_sha3_256_inc_ctx *state, const uint8_t *input, size_t inlen);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_256_inc_finalize.
+ */
+ void (*SHA3_sha3_256_inc_finalize)(uint8_t *output, OQS_SHA3_sha3_256_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_256_inc_ctx_release.
+ */
+ void (*SHA3_sha3_256_inc_ctx_release)(OQS_SHA3_sha3_256_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_256_inc_ctx_reset.
+ */
+ void (*SHA3_sha3_256_inc_ctx_reset)(OQS_SHA3_sha3_256_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_256_inc_ctx_clone.
+ */
+ void (*SHA3_sha3_256_inc_ctx_clone)(OQS_SHA3_sha3_256_inc_ctx *dest, const OQS_SHA3_sha3_256_inc_ctx *src);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_384.
+ */
+ void (*SHA3_sha3_384)(uint8_t *output, const uint8_t *input, size_t inplen);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_384_inc_init.
+ */
+ void (*SHA3_sha3_384_inc_init)(OQS_SHA3_sha3_384_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_384_inc_absorb.
+ */
+ void (*SHA3_sha3_384_inc_absorb)(OQS_SHA3_sha3_384_inc_ctx *state, const uint8_t *input, size_t inlen);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_384_inc_finalize.
+ */
+ void (*SHA3_sha3_384_inc_finalize)(uint8_t *output, OQS_SHA3_sha3_384_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_384_inc_ctx_release.
+ */
+ void (*SHA3_sha3_384_inc_ctx_release)(OQS_SHA3_sha3_384_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_384_inc_ctx_reset.
+ */
+ void (*SHA3_sha3_384_inc_ctx_reset)(OQS_SHA3_sha3_384_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_384_inc_ctx_clone.
+ */
+ void (*SHA3_sha3_384_inc_ctx_clone)(OQS_SHA3_sha3_384_inc_ctx *dest, const OQS_SHA3_sha3_384_inc_ctx *src);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_512.
+ */
+ void (*SHA3_sha3_512)(uint8_t *output, const uint8_t *input, size_t inplen);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_512_inc_init.
+ */
+ void (*SHA3_sha3_512_inc_init)(OQS_SHA3_sha3_512_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_512_inc_absorb.
+ */
+ void (*SHA3_sha3_512_inc_absorb)(OQS_SHA3_sha3_512_inc_ctx *state, const uint8_t *input, size_t inlen);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_512_inc_finalize.
+ */
+ void (*SHA3_sha3_512_inc_finalize)(uint8_t *output, OQS_SHA3_sha3_512_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_512_inc_ctx_release.
+ */
+ void (*SHA3_sha3_512_inc_ctx_release)(OQS_SHA3_sha3_512_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_512_inc_ctx_reset.
+ */
+ void (*SHA3_sha3_512_inc_ctx_reset)(OQS_SHA3_sha3_512_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_sha3_512_inc_ctx_clone.
+ */
+ void (*SHA3_sha3_512_inc_ctx_clone)(OQS_SHA3_sha3_512_inc_ctx *dest, const OQS_SHA3_sha3_512_inc_ctx *src);
+
+ /**
+ * Implementation of function OQS_SHA3_shake128.
+ */
+ void (*SHA3_shake128)(uint8_t *output, size_t outlen, const uint8_t *input, size_t inplen);
+
+ /**
+ * Implementation of function OQS_SHA3_shake128_inc_init.
+ */
+ void (*SHA3_shake128_inc_init)(OQS_SHA3_shake128_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_shake128_inc_absorb.
+ */
+ void (*SHA3_shake128_inc_absorb)(OQS_SHA3_shake128_inc_ctx *state, const uint8_t *input, size_t inlen);
+
+ /**
+ * Implementation of function OQS_SHA3_shake128_inc_finalize.
+ */
+ void (*SHA3_shake128_inc_finalize)(OQS_SHA3_shake128_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_shake128_inc_squeeze.
+ */
+ void (*SHA3_shake128_inc_squeeze)(uint8_t *output, size_t outlen, OQS_SHA3_shake128_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_shake128_inc_ctx_release.
+ */
+ void (*SHA3_shake128_inc_ctx_release)(OQS_SHA3_shake128_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_shake128_inc_ctx_clone.
+ */
+ void (*SHA3_shake128_inc_ctx_clone)(OQS_SHA3_shake128_inc_ctx *dest, const OQS_SHA3_shake128_inc_ctx *src);
+
+ /**
+ * Implementation of function OQS_SHA3_shake128_inc_ctx_reset.
+ */
+ void (*SHA3_shake128_inc_ctx_reset)(OQS_SHA3_shake128_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_shake256.
+ */
+ void (*SHA3_shake256)(uint8_t *output, size_t outlen, const uint8_t *input, size_t inplen);
+
+ /**
+ * Implementation of function OQS_SHA3_shake256_inc_init.
+ */
+ void (*SHA3_shake256_inc_init)(OQS_SHA3_shake256_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_shake256_inc_absorb.
+ */
+ void (*SHA3_shake256_inc_absorb)(OQS_SHA3_shake256_inc_ctx *state, const uint8_t *input, size_t inlen);
+
+ /**
+ * Implementation of function OQS_SHA3_shake256_inc_finalize.
+ */
+ void (*SHA3_shake256_inc_finalize)(OQS_SHA3_shake256_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_shake256_inc_squeeze.
+ */
+ void (*SHA3_shake256_inc_squeeze)(uint8_t *output, size_t outlen, OQS_SHA3_shake256_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_shake256_inc_ctx_release.
+ */
+ void (*SHA3_shake256_inc_ctx_release)(OQS_SHA3_shake256_inc_ctx *state);
+
+ /**
+ * Implementation of function OQS_SHA3_shake256_inc_ctx_clone.
+ */
+ void (*SHA3_shake256_inc_ctx_clone)(OQS_SHA3_shake256_inc_ctx *dest, const OQS_SHA3_shake256_inc_ctx *src);
+
+ /**
+ * Implementation of function OQS_SHA3_shake256_inc_ctx_reset.
+ */
+ void (*SHA3_shake256_inc_ctx_reset)(OQS_SHA3_shake256_inc_ctx *state);
+};
+
+/**
+ * Set callback functions for SHA3 operations.
+ *
+ * This function may be called before OQS_init to switch the
+ * cryptographic provider for SHA3 operations. If it is not called,
+ * the default provider determined at build time will be used.
+ *
+ * @param new_callbacks Callback functions defined in OQS_SHA3_callbacks struct
+ */
+OQS_API void OQS_SHA3_set_callbacks(struct OQS_SHA3_callbacks *new_callbacks);
+
+#if defined(__cplusplus)
+} // extern "C"
+#endif
+
+#endif // OQS_SHA3_OPS_H
diff --git a/lib/liboqs/liboqs.c b/lib/liboqs/liboqs.c
new file mode 100644
index 0000000000..88f2369719
--- /dev/null
+++ b/lib/liboqs/liboqs.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "config.h"
+
+#include "liboqs/liboqs.h"
+
+#include "dlwrap/oqs.h"
+#include "liboqs/rand.h"
+#include "liboqs/sha3.h"
+
+void _gnutls_liboqs_init(void)
+{
+ _gnutls_liboqs_sha3_init();
+ GNUTLS_OQS_FUNC(OQS_init)();
+ _gnutls_liboqs_rand_init();
+}
+
+void _gnutls_liboqs_deinit(void)
+{
+ _gnutls_liboqs_rand_deinit();
+ _gnutls_liboqs_sha3_deinit();
+ GNUTLS_OQS_FUNC(OQS_destroy)();
+}
diff --git a/lib/liboqs/liboqs.h b/lib/liboqs/liboqs.h
new file mode 100644
index 0000000000..b6c1659212
--- /dev/null
+++ b/lib/liboqs/liboqs.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_LIBOQS_LIBOQS_H
+#define GNUTLS_LIB_LIBOQS_LIBOQS_H
+
+void _gnutls_liboqs_init(void);
+void _gnutls_liboqs_deinit(void);
+
+#endif /* GNUTLS_LIB_LIBOQS_LIBOQS_H */
diff --git a/lib/liboqs/rand.c b/lib/liboqs/rand.c
new file mode 100644
index 0000000000..40496800ad
--- /dev/null
+++ b/lib/liboqs/rand.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "config.h"
+
+#include "liboqs/rand.h"
+
+#include "dlwrap/oqs.h"
+#include "fips.h"
+#include <gnutls/crypto.h>
+#include <stdint.h>
+
+static void rand_bytes(uint8_t *data, size_t size)
+{
+ if (gnutls_rnd(GNUTLS_RND_RANDOM, data, size) < 0)
+ _gnutls_switch_lib_state(LIB_STATE_ERROR);
+}
+
+void _gnutls_liboqs_rand_init(void)
+{
+ GNUTLS_OQS_FUNC(OQS_randombytes_custom_algorithm)(rand_bytes);
+}
+
+void _gnutls_liboqs_rand_deinit(void)
+{
+}
diff --git a/lib/liboqs/rand.h b/lib/liboqs/rand.h
new file mode 100644
index 0000000000..b27ac23362
--- /dev/null
+++ b/lib/liboqs/rand.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_LIBOQS_RAND_H
+#define GNUTLS_LIB_LIBOQS_RAND_H
+
+void _gnutls_liboqs_rand_init(void);
+void _gnutls_liboqs_rand_deinit(void);
+
+#endif /* GNUTLS_LIB_LIBOQS_RAND_H */
diff --git a/lib/liboqs/sha3.c b/lib/liboqs/sha3.c
new file mode 100644
index 0000000000..9f5977e425
--- /dev/null
+++ b/lib/liboqs/sha3.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "config.h"
+
+#include "liboqs/sha3.h"
+
+#include "dlwrap/oqs.h"
+#include <assert.h>
+#include <gnutls/crypto.h>
+#include <string.h>
+
+/* SHA3-256 */
+
+static void SHA3_sha3_256(uint8_t *output, const uint8_t *input, size_t inplen)
+{
+ gnutls_hash_fast(GNUTLS_DIG_SHA3_256, input, inplen, output);
+}
+
+/* SHA3-256 incremental */
+
+static void SHA3_sha3_256_inc_init(OQS_SHA3_sha3_256_inc_ctx *state)
+{
+ gnutls_hash_hd_t hd;
+ int ret;
+
+ ret = gnutls_hash_init(&hd, GNUTLS_DIG_SHA3_256);
+ assert(ret == 0);
+ state->ctx = hd;
+}
+
+static void SHA3_sha3_256_inc_absorb(OQS_SHA3_sha3_256_inc_ctx *state,
+ const uint8_t *input, size_t inplen)
+{
+ int ret;
+
+ ret = gnutls_hash((gnutls_hash_hd_t)state->ctx, input, inplen);
+ assert(ret == 0);
+}
+
+static void SHA3_sha3_256_inc_finalize(uint8_t *output,
+ OQS_SHA3_sha3_256_inc_ctx *state)
+{
+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, output);
+}
+
+static void SHA3_sha3_256_inc_ctx_release(OQS_SHA3_sha3_256_inc_ctx *state)
+{
+ gnutls_hash_deinit((gnutls_hash_hd_t)state->ctx, NULL);
+}
+
+static void SHA3_sha3_256_inc_ctx_clone(OQS_SHA3_sha3_256_inc_ctx *dest,
+ const OQS_SHA3_sha3_256_inc_ctx *src)
+{
+ dest->ctx = gnutls_hash_copy((gnutls_hash_hd_t)src->ctx);
+}
+
+static void SHA3_sha3_256_inc_ctx_reset(OQS_SHA3_sha3_256_inc_ctx *state)
+{
+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, NULL);
+}
+
+/* SHA3-384 */
+
+static void SHA3_sha3_384(uint8_t *output, const uint8_t *input, size_t inplen)
+{
+ gnutls_hash_fast(GNUTLS_DIG_SHA3_384, input, inplen, output);
+}
+
+/* SHA3-384 incremental */
+static void SHA3_sha3_384_inc_init(OQS_SHA3_sha3_384_inc_ctx *state)
+{
+ gnutls_hash_hd_t hd;
+ int ret;
+
+ ret = gnutls_hash_init(&hd, GNUTLS_DIG_SHA3_384);
+ assert(ret == 0);
+ state->ctx = hd;
+}
+
+static void SHA3_sha3_384_inc_absorb(OQS_SHA3_sha3_384_inc_ctx *state,
+ const uint8_t *input, size_t inplen)
+{
+ int ret;
+
+ ret = gnutls_hash((gnutls_hash_hd_t)state->ctx, input, inplen);
+ assert(ret == 0);
+}
+
+static void SHA3_sha3_384_inc_finalize(uint8_t *output,
+ OQS_SHA3_sha3_384_inc_ctx *state)
+{
+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, output);
+}
+
+static void SHA3_sha3_384_inc_ctx_release(OQS_SHA3_sha3_384_inc_ctx *state)
+{
+ gnutls_hash_deinit((gnutls_hash_hd_t)state->ctx, NULL);
+}
+
+static void SHA3_sha3_384_inc_ctx_clone(OQS_SHA3_sha3_384_inc_ctx *dest,
+ const OQS_SHA3_sha3_384_inc_ctx *src)
+{
+ dest->ctx = gnutls_hash_copy((gnutls_hash_hd_t)src->ctx);
+}
+
+static void SHA3_sha3_384_inc_ctx_reset(OQS_SHA3_sha3_384_inc_ctx *state)
+{
+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, NULL);
+}
+
+/* SHA3-512 */
+
+static void SHA3_sha3_512(uint8_t *output, const uint8_t *input, size_t inplen)
+{
+ gnutls_hash_fast(GNUTLS_DIG_SHA3_512, input, inplen, output);
+}
+
+/* SHA3-512 incremental */
+
+static void SHA3_sha3_512_inc_init(OQS_SHA3_sha3_512_inc_ctx *state)
+{
+ gnutls_hash_hd_t hd;
+ int ret;
+
+ ret = gnutls_hash_init(&hd, GNUTLS_DIG_SHA3_512);
+ assert(ret == 0);
+ state->ctx = hd;
+}
+
+static void SHA3_sha3_512_inc_absorb(OQS_SHA3_sha3_512_inc_ctx *state,
+ const uint8_t *input, size_t inplen)
+{
+ int ret;
+
+ ret = gnutls_hash((gnutls_hash_hd_t)state->ctx, input, inplen);
+ assert(ret == 0);
+}
+
+static void SHA3_sha3_512_inc_finalize(uint8_t *output,
+ OQS_SHA3_sha3_512_inc_ctx *state)
+{
+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, output);
+}
+
+static void SHA3_sha3_512_inc_ctx_release(OQS_SHA3_sha3_512_inc_ctx *state)
+{
+ gnutls_hash_deinit((gnutls_hash_hd_t)state->ctx, NULL);
+}
+
+static void SHA3_sha3_512_inc_ctx_clone(OQS_SHA3_sha3_512_inc_ctx *dest,
+ const OQS_SHA3_sha3_512_inc_ctx *src)
+{
+ dest->ctx = gnutls_hash_copy((gnutls_hash_hd_t)src->ctx);
+}
+
+static void SHA3_sha3_512_inc_ctx_reset(OQS_SHA3_sha3_512_inc_ctx *state)
+{
+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, NULL);
+}
+
+/* SHAKE-128 */
+
+static void SHA3_shake128(uint8_t *output, size_t outlen, const uint8_t *input,
+ size_t inplen)
+{
+ gnutls_hash_hd_t hd;
+ int ret;
+
+ ret = gnutls_hash_init(&hd, GNUTLS_DIG_SHAKE_128);
+ assert(ret == 0);
+
+ ret = gnutls_hash(hd, input, inplen);
+ assert(ret == 0);
+
+ ret = gnutls_hash_squeeze(hd, output, outlen);
+ assert(ret == 0);
+
+ gnutls_hash_deinit(hd, NULL);
+}
+
+/* SHAKE-128 incremental
+ */
+
+static void SHA3_shake128_inc_init(OQS_SHA3_shake128_inc_ctx *state)
+{
+ gnutls_hash_hd_t hd;
+ int ret;
+
+ ret = gnutls_hash_init(&hd, GNUTLS_DIG_SHAKE_128);
+ assert(ret == 0);
+
+ state->ctx = hd;
+}
+
+static void SHA3_shake128_inc_absorb(OQS_SHA3_shake128_inc_ctx *state,
+ const uint8_t *input, size_t inplen)
+{
+ int ret;
+
+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, NULL);
+ ret = gnutls_hash((gnutls_hash_hd_t)state->ctx, input, inplen);
+ assert(ret == 0);
+}
+
+static void SHA3_shake128_inc_finalize(OQS_SHA3_shake128_inc_ctx *state)
+{
+ (void)state;
+}
+
+static void SHA3_shake128_inc_squeeze(uint8_t *output, size_t outlen,
+ OQS_SHA3_shake128_inc_ctx *state)
+{
+ int ret;
+
+ ret = gnutls_hash_squeeze((gnutls_hash_hd_t)state->ctx, output, outlen);
+ assert(ret == 0);
+}
+
+static void SHA3_shake128_inc_ctx_release(OQS_SHA3_shake128_inc_ctx *state)
+{
+ gnutls_hash_deinit((gnutls_hash_hd_t)state->ctx, NULL);
+}
+
+static void SHA3_shake128_inc_ctx_clone(OQS_SHA3_shake128_inc_ctx *dest,
+ const OQS_SHA3_shake128_inc_ctx *src)
+{
+ dest->ctx = gnutls_hash_copy((gnutls_hash_hd_t)src->ctx);
+}
+
+static void SHA3_shake128_inc_ctx_reset(OQS_SHA3_shake128_inc_ctx *state)
+{
+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, NULL);
+}
+
+/* SHAKE-256 */
+
+static void SHA3_shake256(uint8_t *output, size_t outlen, const uint8_t *input,
+ size_t inplen)
+{
+ gnutls_hash_hd_t hd;
+ int ret;
+
+ ret = gnutls_hash_init(&hd, GNUTLS_DIG_SHAKE_256);
+ assert(ret == 0);
+
+ ret = gnutls_hash(hd, input, inplen);
+ assert(ret == 0);
+
+ ret = gnutls_hash_squeeze(hd, output, outlen);
+ assert(ret == 0);
+
+ gnutls_hash_deinit(hd, NULL);
+}
+
+/* SHAKE-256 incremental */
+
+static void SHA3_shake256_inc_init(OQS_SHA3_shake256_inc_ctx *state)
+{
+ gnutls_hash_hd_t hd;
+ int ret;
+
+ ret = gnutls_hash_init(&hd, GNUTLS_DIG_SHAKE_256);
+ assert(ret == 0);
+
+ state->ctx = hd;
+}
+
+static void SHA3_shake256_inc_absorb(OQS_SHA3_shake256_inc_ctx *state,
+ const uint8_t *input, size_t inplen)
+{
+ int ret;
+
+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, NULL);
+ ret = gnutls_hash((gnutls_hash_hd_t)state->ctx, input, inplen);
+ assert(ret == 0);
+}
+
+static void SHA3_shake256_inc_finalize(OQS_SHA3_shake256_inc_ctx *state)
+{
+ (void)state;
+}
+
+static void SHA3_shake256_inc_squeeze(uint8_t *output, size_t outlen,
+ OQS_SHA3_shake256_inc_ctx *state)
+{
+ int ret;
+
+ ret = gnutls_hash_squeeze((gnutls_hash_hd_t)state->ctx, output, outlen);
+ assert(ret == 0);
+}
+
+static void SHA3_shake256_inc_ctx_release(OQS_SHA3_shake256_inc_ctx *state)
+{
+ gnutls_hash_deinit((gnutls_hash_hd_t)state->ctx, NULL);
+}
+
+static void SHA3_shake256_inc_ctx_clone(OQS_SHA3_shake256_inc_ctx *dest,
+ const OQS_SHA3_shake256_inc_ctx *src)
+{
+ dest->ctx = gnutls_hash_copy((gnutls_hash_hd_t)src->ctx);
+}
+
+static void SHA3_shake256_inc_ctx_reset(OQS_SHA3_shake256_inc_ctx *state)
+{
+ gnutls_hash_output((gnutls_hash_hd_t)state->ctx, NULL);
+}
+
+static struct OQS_SHA3_callbacks sha3_callbacks = {
+ SHA3_sha3_256,
+ SHA3_sha3_256_inc_init,
+ SHA3_sha3_256_inc_absorb,
+ SHA3_sha3_256_inc_finalize,
+ SHA3_sha3_256_inc_ctx_release,
+ SHA3_sha3_256_inc_ctx_reset,
+ SHA3_sha3_256_inc_ctx_clone,
+ SHA3_sha3_384,
+ SHA3_sha3_384_inc_init,
+ SHA3_sha3_384_inc_absorb,
+ SHA3_sha3_384_inc_finalize,
+ SHA3_sha3_384_inc_ctx_release,
+ SHA3_sha3_384_inc_ctx_reset,
+ SHA3_sha3_384_inc_ctx_clone,
+ SHA3_sha3_512,
+ SHA3_sha3_512_inc_init,
+ SHA3_sha3_512_inc_absorb,
+ SHA3_sha3_512_inc_finalize,
+ SHA3_sha3_512_inc_ctx_release,
+ SHA3_sha3_512_inc_ctx_reset,
+ SHA3_sha3_512_inc_ctx_clone,
+ SHA3_shake128,
+ SHA3_shake128_inc_init,
+ SHA3_shake128_inc_absorb,
+ SHA3_shake128_inc_finalize,
+ SHA3_shake128_inc_squeeze,
+ SHA3_shake128_inc_ctx_release,
+ SHA3_shake128_inc_ctx_clone,
+ SHA3_shake128_inc_ctx_reset,
+ SHA3_shake256,
+ SHA3_shake256_inc_init,
+ SHA3_shake256_inc_absorb,
+ SHA3_shake256_inc_finalize,
+ SHA3_shake256_inc_squeeze,
+ SHA3_shake256_inc_ctx_release,
+ SHA3_shake256_inc_ctx_clone,
+ SHA3_shake256_inc_ctx_reset,
+};
+
+void _gnutls_liboqs_sha3_init(void)
+{
+ GNUTLS_OQS_FUNC(OQS_SHA3_set_callbacks)(&sha3_callbacks);
+}
+
+void _gnutls_liboqs_sha3_deinit(void)
+{
+}
diff --git a/lib/liboqs/sha3.h b/lib/liboqs/sha3.h
new file mode 100644
index 0000000000..8b9058aa0d
--- /dev/null
+++ b/lib/liboqs/sha3.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_LIBOQS_SHA3_H
+#define GNUTLS_LIB_LIBOQS_SHA3_H
+
+void _gnutls_liboqs_sha3_init(void);
+void _gnutls_liboqs_sha3_deinit(void);
+
+#endif /* GNUTLS_LIB_LIBOQS_SHA3_H */
--
2.45.2
From 1bc78c387a9796e8248ffb644576074f8de4e6ad Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Sun, 2 Jun 2024 07:19:14 +0900
Subject: [PATCH 2/2] key_share: support X25519Kyber768Draft00
This implements X25519Kyber768Draft00 hybrid post-quantum key exchange
in TLS 1.3, based on the draft:
https://datatracker.ietf.org/doc/draft-tls-westerbaan-xyber768d00/
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/Makefile.am | 4 +
lib/algorithms/groups.c | 8 ++
lib/algorithms/publickey.c | 6 ++
lib/crypto-backend.h | 7 ++
lib/ext/key_share.c | 148 ++++++++++++++++++++++++++--
lib/gnutls_int.h | 2 +
lib/includes/gnutls/gnutls.h.in | 12 ++-
lib/nettle/Makefile.am | 4 +
lib/nettle/pk.c | 164 ++++++++++++++++++++++++++++++++
lib/pk.h | 4 +
lib/state.c | 1 +
tests/Makefile.am | 4 +
tests/pqc-hybrid-kx.sh | 54 +++++++++++
13 files changed, 409 insertions(+), 9 deletions(-)
create mode 100644 tests/pqc-hybrid-kx.sh
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 067772c322..0e89fdf184 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -273,6 +273,10 @@ thirdparty_libadd += $(NETTLE_LIBS) $(HOGWEED_LIBS) $(GMP_LIBS)
libgnutls_la_LIBADD += nettle/libcrypto.la
endif
+if ENABLE_LIBOQS
+libgnutls_la_LIBADD += liboqs/libcrypto.la
+endif
+
if HAVE_LD_OUTPUT_DEF
libgnutls_la_LDFLAGS += -Wl,--output-def,libgnutls-$(DLL_VERSION).def
libgnutls-$(DLL_VERSION).def: libgnutls.la
diff --git a/lib/algorithms/groups.c b/lib/algorithms/groups.c
index 9093de6eb2..a329c746e9 100644
--- a/lib/algorithms/groups.c
+++ b/lib/algorithms/groups.c
@@ -169,6 +169,14 @@ static const gnutls_group_entry_st supported_groups[] = {
.q_bits = &gnutls_ffdhe_8192_key_bits,
.pk = GNUTLS_PK_DH,
.tls_id = 0x104 },
+#endif
+#ifdef HAVE_LIBOQS
+ { .name = "X25519-KYBER768",
+ .id = GNUTLS_GROUP_EXP_X25519_KYBER768,
+ .curve = GNUTLS_ECC_CURVE_X25519,
+ .pk = GNUTLS_PK_ECDH_X25519,
+ .pk2 = GNUTLS_PK_EXP_KYBER768,
+ .tls_id = 0x6399 },
#endif
{ 0, 0, 0 }
};
diff --git a/lib/algorithms/publickey.c b/lib/algorithms/publickey.c
index 0ef0834933..10938bce0e 100644
--- a/lib/algorithms/publickey.c
+++ b/lib/algorithms/publickey.c
@@ -202,6 +202,12 @@ static const gnutls_pk_entry pk_algorithms[] = {
.oid = ECDH_X448_OID,
.id = GNUTLS_PK_ECDH_X448,
.curve = GNUTLS_ECC_CURVE_X448 },
+#ifdef HAVE_LIBOQS
+ { .name = "KYBER768",
+ .oid = NULL,
+ .id = GNUTLS_PK_EXP_KYBER768,
+ .curve = GNUTLS_ECC_CURVE_INVALID },
+#endif
{ .name = "UNKNOWN",
.oid = NULL,
.id = GNUTLS_PK_UNKNOWN,
diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h
index fd8ee0c728..5c0630adaa 100644
--- a/lib/crypto-backend.h
+++ b/lib/crypto-backend.h
@@ -411,6 +411,13 @@ typedef struct gnutls_crypto_pk {
const gnutls_pk_params_st *pub,
const gnutls_datum_t *nonce, unsigned int flags);
+ int (*encaps)(gnutls_pk_algorithm_t, gnutls_datum_t *ciphertext,
+ gnutls_datum_t *shared_secret, const gnutls_datum_t *pub);
+
+ int (*decaps)(gnutls_pk_algorithm_t, gnutls_datum_t *shared_secret,
+ const gnutls_datum_t *ciphertext,
+ const gnutls_datum_t *priv);
+
int (*curve_exists)(gnutls_ecc_curve_t); /* true/false */
int (*pk_exists)(gnutls_pk_algorithm_t); /* true/false */
int (*sign_exists)(gnutls_sign_algorithm_t); /* true/false */
diff --git a/lib/ext/key_share.c b/lib/ext/key_share.c
index 575ffaf8f2..6926cdd00e 100644
--- a/lib/ext/key_share.c
+++ b/lib/ext/key_share.c
@@ -120,6 +120,8 @@ static int client_gen_key_share(gnutls_session_t session,
} else if (group->pk == GNUTLS_PK_ECDH_X25519 ||
group->pk == GNUTLS_PK_ECDH_X448) {
+ unsigned int length_pos;
+
gnutls_pk_params_release(&session->key.kshare.ecdhx_params);
gnutls_pk_params_init(&session->key.kshare.ecdhx_params);
@@ -129,6 +131,8 @@ static int client_gen_key_share(gnutls_session_t session,
if (ret < 0)
return gnutls_assert_val(ret);
+ length_pos = extdata->length;
+
ret = _gnutls_buffer_append_data_prefix(
extdata, 16,
session->key.kshare.ecdhx_params.raw_pub.data,
@@ -141,6 +145,33 @@ static int client_gen_key_share(gnutls_session_t session,
session->key.kshare.ecdhx_params.algo = group->pk;
session->key.kshare.ecdhx_params.curve = group->curve;
+ if (group->pk2 != GNUTLS_PK_UNKNOWN) {
+ gnutls_pk_params_release(
+ &session->key.kshare.kem_params);
+ gnutls_pk_params_init(&session->key.kshare.kem_params);
+
+ ret = _gnutls_pk_generate_keys(
+ group->pk2, 0, &session->key.kshare.kem_params,
+ 1);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_buffer_append_data(
+ extdata,
+ session->key.kshare.kem_params.raw_pub.data,
+ session->key.kshare.kem_params.raw_pub.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ /* copy actual length */
+ _gnutls_write_uint16(extdata->length - length_pos - 2,
+ &extdata->data[length_pos]);
+ }
+
ret = 0;
} else if (group->pk == GNUTLS_PK_DH) {
@@ -243,6 +274,10 @@ static int server_gen_key_share(gnutls_session_t session,
} else if (group->pk == GNUTLS_PK_ECDH_X25519 ||
group->pk == GNUTLS_PK_ECDH_X448) {
+ unsigned int length_pos;
+
+ length_pos = extdata->length;
+
ret = _gnutls_buffer_append_data_prefix(
extdata, 16,
session->key.kshare.ecdhx_params.raw_pub.data,
@@ -250,8 +285,22 @@ static int server_gen_key_share(gnutls_session_t session,
if (ret < 0)
return gnutls_assert_val(ret);
- ret = 0;
+ if (group->pk2 != GNUTLS_PK_UNKNOWN) {
+ ret = _gnutls_buffer_append_data(
+ extdata,
+ session->key.kshare.kem_params.raw_pub.data,
+ session->key.kshare.kem_params.raw_pub.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ /* copy actual length */
+ _gnutls_write_uint16(extdata->length - length_pos - 2,
+ &extdata->data[length_pos]);
+ }
+
+ ret = 0;
} else if (group->pk == GNUTLS_PK_DH) {
ret = _gnutls_buffer_append_prefix(extdata, 16,
group->prime->size);
@@ -333,9 +382,15 @@ static int server_use_key_share(gnutls_session_t session,
curve = _gnutls_ecc_curve_get_params(group->curve);
- if (curve->size != data_size)
- return gnutls_assert_val(
- GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ if (group->pk2 != GNUTLS_PK_UNKNOWN) {
+ if (curve->size > data_size)
+ return gnutls_assert_val(
+ GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ } else {
+ if (curve->size != data_size)
+ return gnutls_assert_val(
+ GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ }
/* generate our key */
ret = _gnutls_pk_generate_keys(
@@ -351,7 +406,7 @@ static int server_use_key_share(gnutls_session_t session,
pub.curve = curve->id;
pub.raw_pub.data = (void *)data;
- pub.raw_pub.size = data_size;
+ pub.raw_pub.size = curve->size;
/* We don't mask the MSB in the final byte as required
* by RFC7748. This will be done internally by nettle 3.3 or later.
@@ -363,6 +418,50 @@ static int server_use_key_share(gnutls_session_t session,
return gnutls_assert_val(ret);
}
+ if (group->pk2 != GNUTLS_PK_UNKNOWN) {
+ gnutls_datum_t key;
+ gnutls_datum_t peer_pub;
+
+ gnutls_pk_params_release(
+ &session->key.kshare.kem_params);
+ gnutls_pk_params_init(&session->key.kshare.kem_params);
+
+ /* generate our key */
+ ret = _gnutls_pk_generate_keys(
+ group->pk2, 0, &session->key.kshare.kem_params,
+ 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ /* server's public key is unused, but the raw_pub field
+ * is used to store ciphertext */
+ gnutls_free(
+ session->key.kshare.kem_params.raw_pub.data);
+
+ peer_pub.data = (uint8_t *)data + curve->size;
+ peer_pub.size = data_size - curve->size;
+
+ ret = _gnutls_pk_encaps(
+ group->pk2,
+ &session->key.kshare.kem_params.raw_pub, &key,
+ &peer_pub);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ session->key.key.data = gnutls_realloc_fast(
+ session->key.key.data,
+ session->key.key.size + key.size);
+ if (!session->key.key.data) {
+ _gnutls_free_datum(&key);
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ }
+
+ memcpy(session->key.key.data + session->key.key.size,
+ key.data, key.size);
+ session->key.key.size += key.size;
+ _gnutls_free_datum(&key);
+ }
+
ret = 0;
} else if (group->pk == GNUTLS_PK_DH) {
@@ -496,9 +595,15 @@ static int client_use_key_share(gnutls_session_t session,
return gnutls_assert_val(
GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
- if (curve->size != data_size)
- return gnutls_assert_val(
- GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ if (group->pk2 != GNUTLS_PK_UNKNOWN) {
+ if (curve->size > data_size)
+ return gnutls_assert_val(
+ GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ } else {
+ if (curve->size != data_size)
+ return gnutls_assert_val(
+ GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ }
/* read the public key and generate shared */
gnutls_pk_params_init(&pub);
@@ -519,6 +624,33 @@ static int client_use_key_share(gnutls_session_t session,
return gnutls_assert_val(ret);
}
+ if (group->pk2 != GNUTLS_PK_UNKNOWN) {
+ gnutls_datum_t key;
+ gnutls_datum_t ciphertext;
+
+ ciphertext.data = (uint8_t *)data + curve->size;
+ ciphertext.size = data_size - curve->size;
+
+ ret = _gnutls_pk_decaps(
+ group->pk2, &key, &ciphertext,
+ &session->key.kshare.kem_params.raw_priv);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ session->key.key.data = gnutls_realloc_fast(
+ session->key.key.data,
+ session->key.key.size + key.size);
+ if (!session->key.key.data) {
+ _gnutls_free_datum(&key);
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ }
+
+ memcpy(session->key.key.data + session->key.key.size,
+ key.data, key.size);
+ session->key.key.size += key.size;
+ _gnutls_free_datum(&key);
+ }
+
ret = 0;
} else if (group->pk == GNUTLS_PK_DH) {
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 258a08c842..5727739bdc 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -594,6 +594,7 @@ struct gnutls_key_st {
gnutls_pk_params_st ecdh_params;
gnutls_pk_params_st ecdhx_params;
gnutls_pk_params_st dh_params;
+ gnutls_pk_params_st kem_params;
} kshare;
/* The union contents depend on the negotiated protocol.
@@ -764,6 +765,7 @@ typedef struct gnutls_group_entry_st {
const unsigned *q_bits;
gnutls_ecc_curve_t curve;
gnutls_pk_algorithm_t pk;
+ gnutls_pk_algorithm_t pk2;
unsigned tls_id; /* The RFC4492 namedCurve ID or TLS 1.3 group ID */
} gnutls_group_entry_st;
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 6b87610c44..790406e4df 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -908,7 +908,12 @@ typedef enum {
GNUTLS_PK_ECDH_X448 = 11,
GNUTLS_PK_EDDSA_ED448 = 12,
GNUTLS_PK_RSA_OAEP = 13,
- GNUTLS_PK_MAX = GNUTLS_PK_RSA_OAEP
+ GNUTLS_PK_MAX = GNUTLS_PK_RSA_OAEP,
+
+ /* Experimental algorithms */
+ GNUTLS_PK_EXP_MIN = 256,
+ GNUTLS_PK_EXP_KYBER768 = GNUTLS_PK_EXP_MIN,
+ GNUTLS_PK_EXP_MAX = GNUTLS_PK_EXP_KYBER768
} gnutls_pk_algorithm_t;
const char *gnutls_pk_algorithm_get_name(gnutls_pk_algorithm_t algorithm);
@@ -1136,6 +1141,11 @@ typedef enum {
GNUTLS_GROUP_FFDHE8192,
GNUTLS_GROUP_FFDHE6144,
GNUTLS_GROUP_MAX = GNUTLS_GROUP_FFDHE6144,
+
+ /* Experimental algorithms */
+ GNUTLS_GROUP_EXP_MIN = 512,
+ GNUTLS_GROUP_EXP_X25519_KYBER768 = GNUTLS_GROUP_EXP_MIN,
+ GNUTLS_GROUP_EXP_MAX = GNUTLS_GROUP_EXP_X25519_KYBER768
} gnutls_group_t;
/* macros to allow specifying a specific curve in gnutls_privkey_generate()
diff --git a/lib/nettle/Makefile.am b/lib/nettle/Makefile.am
index b855c8c193..0f21823cb4 100644
--- a/lib/nettle/Makefile.am
+++ b/lib/nettle/Makefile.am
@@ -36,6 +36,10 @@ if ENABLE_MINITASN1
AM_CPPFLAGS += -I$(srcdir)/../minitasn1
endif
+if ENABLE_DLOPEN
+AM_CPPFLAGS += $(LIBOQS_CFLAGS) -DGNUTLS_OQS_ENABLE_DLOPEN=1
+endif
+
noinst_LTLIBRARIES = libcrypto.la
libcrypto_la_SOURCES = pk.c mpi.c mac.c cipher.c init.c \
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
index b317b790d7..4155a540ed 100644
--- a/lib/nettle/pk.c
+++ b/lib/nettle/pk.c
@@ -70,6 +70,9 @@
#include "gnettle.h"
#include "fips.h"
#include "dh.h"
+#ifdef HAVE_LIBOQS
+#include "dlwrap/oqs.h"
+#endif
static inline const struct ecc_curve *get_supported_nist_curve(int curve);
static inline const struct ecc_curve *get_supported_gost_curve(int curve);
@@ -687,6 +690,111 @@ cleanup:
return ret;
}
+static int _wrap_nettle_pk_encaps(gnutls_pk_algorithm_t algo,
+ gnutls_datum_t *ciphertext,
+ gnutls_datum_t *shared_secret,
+ const gnutls_datum_t *pub)
+{
+ int ret;
+
+ switch (algo) {
+#ifdef HAVE_LIBOQS
+ case GNUTLS_PK_EXP_KYBER768: {
+ OQS_KEM *kem = NULL;
+ OQS_STATUS rc;
+
+ kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768);
+ if (kem == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ ciphertext->data = gnutls_malloc(kem->length_ciphertext);
+ if (ciphertext->data == NULL) {
+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem);
+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ goto cleanup;
+ }
+ ciphertext->size = kem->length_ciphertext;
+
+ shared_secret->data = gnutls_malloc(kem->length_shared_secret);
+ if (shared_secret->data == NULL) {
+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem);
+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ goto cleanup;
+ }
+ shared_secret->size = kem->length_shared_secret;
+
+ rc = GNUTLS_OQS_FUNC(OQS_KEM_encaps)(
+ kem, ciphertext->data, shared_secret->data, pub->data);
+ if (rc != OQS_SUCCESS) {
+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem);
+ ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ goto cleanup;
+ }
+
+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem);
+ ret = 0;
+ } break;
+#endif
+ default:
+ ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_ALGORITHM);
+ goto cleanup;
+ }
+
+cleanup:
+ if (ret < 0) {
+ gnutls_free(ciphertext->data);
+ gnutls_free(shared_secret->data);
+ }
+ return ret;
+}
+
+static int _wrap_nettle_pk_decaps(gnutls_pk_algorithm_t algo,
+ gnutls_datum_t *shared_secret,
+ const gnutls_datum_t *ciphertext,
+ const gnutls_datum_t *priv)
+{
+ int ret;
+
+ switch (algo) {
+#ifdef HAVE_LIBOQS
+ case GNUTLS_PK_EXP_KYBER768: {
+ OQS_KEM *kem = NULL;
+ OQS_STATUS rc;
+
+ kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768);
+ if (kem == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ shared_secret->data = gnutls_malloc(kem->length_shared_secret);
+ if (shared_secret->data == NULL) {
+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem);
+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ goto cleanup;
+ }
+ shared_secret->size = kem->length_shared_secret;
+
+ rc = GNUTLS_OQS_FUNC(OQS_KEM_decaps)(
+ kem, shared_secret->data, ciphertext->data, priv->data);
+ if (rc != OQS_SUCCESS) {
+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem);
+ ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ goto cleanup;
+ }
+
+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem);
+ ret = 0;
+ } break;
+#endif
+ default:
+ ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_ALGORITHM);
+ goto cleanup;
+ }
+cleanup:
+ if (ret < 0)
+ gnutls_free(shared_secret->data);
+ return ret;
+}
+
/* This wraps nettle_rsa_encrypt so it returns ciphertext as a byte
* array instead of a mpz_t value. Returns 1 on success; 0 otherwise.
*/
@@ -2234,6 +2342,9 @@ static int _wrap_nettle_pk_exists(gnutls_pk_algorithm_t pk)
case GNUTLS_PK_RSA_PSS:
case GNUTLS_PK_RSA_OAEP:
case GNUTLS_PK_EDDSA_ED25519:
+#ifdef HAVE_LIBOQS
+ case GNUTLS_PK_EXP_KYBER768:
+#endif
#if ENABLE_GOST
case GNUTLS_PK_GOST_01:
case GNUTLS_PK_GOST_12_256:
@@ -2875,6 +2986,9 @@ static int pct_test(gnutls_pk_algorithm_t algo,
}
case GNUTLS_PK_ECDH_X25519:
case GNUTLS_PK_ECDH_X448:
+#ifdef HAVE_LIBOQS
+ case GNUTLS_PK_EXP_KYBER768:
+#endif
ret = 0;
goto cleanup;
default:
@@ -3605,6 +3719,49 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
goto cleanup;
break;
}
+#ifdef HAVE_LIBOQS
+ case GNUTLS_PK_EXP_KYBER768: {
+ OQS_KEM *kem = NULL;
+ OQS_STATUS rc;
+
+ not_approved = true;
+
+ kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768);
+ if (kem == NULL) {
+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ goto cleanup;
+ }
+
+ params->raw_priv.size = kem->length_secret_key;
+ params->raw_priv.data = gnutls_malloc(params->raw_priv.size);
+ if (params->raw_priv.data == NULL) {
+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem);
+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ goto cleanup;
+ }
+
+ params->raw_pub.size = kem->length_public_key;
+ params->raw_pub.data = gnutls_malloc(params->raw_pub.size);
+ if (params->raw_pub.data == NULL) {
+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem);
+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ goto cleanup;
+ }
+
+ rc = GNUTLS_OQS_FUNC(OQS_KEM_keypair)(kem, params->raw_pub.data,
+ params->raw_priv.data);
+ if (rc != OQS_SUCCESS) {
+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem);
+ ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+ goto cleanup;
+ }
+
+ GNUTLS_OQS_FUNC(OQS_KEM_free)(kem);
+
+ ret = 0;
+ break;
+ }
+#endif
default:
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
@@ -3858,6 +4015,11 @@ static int wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo,
ret = 0;
break;
}
+#ifdef HAVE_LIBOQS
+ case GNUTLS_PK_EXP_KYBER768:
+ ret = 0;
+ break;
+#endif
#if ENABLE_GOST
case GNUTLS_PK_GOST_01:
case GNUTLS_PK_GOST_12_256:
@@ -4307,6 +4469,8 @@ gnutls_crypto_pk_st _gnutls_pk_ops = {
.generate_keys = wrap_nettle_pk_generate_keys,
.pk_fixup_private_params = wrap_nettle_pk_fixup,
.derive = _wrap_nettle_pk_derive,
+ .encaps = _wrap_nettle_pk_encaps,
+ .decaps = _wrap_nettle_pk_decaps,
.curve_exists = _wrap_nettle_pk_curve_exists,
.pk_exists = _wrap_nettle_pk_exists,
.sign_exists = _wrap_nettle_pk_sign_exists
diff --git a/lib/pk.h b/lib/pk.h
index 20fe314f94..eca4e02d73 100644
--- a/lib/pk.h
+++ b/lib/pk.h
@@ -46,6 +46,10 @@ extern gnutls_crypto_pk_st _gnutls_pk_ops;
_gnutls_pk_ops.derive(algo, out, pub, priv, nonce, 0)
#define _gnutls_pk_derive_tls13(algo, out, pub, priv) \
_gnutls_pk_ops.derive(algo, out, pub, priv, NULL, PK_DERIVE_TLS13)
+#define _gnutls_pk_encaps(algo, ciphertext, shared_secret, pub) \
+ _gnutls_pk_ops.encaps(algo, ciphertext, shared_secret, pub)
+#define _gnutls_pk_decaps(algo, shared_secret, ciphertext, priv) \
+ _gnutls_pk_ops.decaps(algo, shared_secret, ciphertext, priv)
#define _gnutls_pk_generate_keys(algo, bits, params, temporal) \
_gnutls_pk_ops.generate_keys(algo, bits, params, temporal)
#define _gnutls_pk_generate_params(algo, bits, priv) \
diff --git a/lib/state.c b/lib/state.c
index ec514c0cd2..f2c74d97d0 100644
--- a/lib/state.c
+++ b/lib/state.c
@@ -459,6 +459,7 @@ static void deinit_keys(gnutls_session_t session)
gnutls_pk_params_release(&session->key.kshare.ecdhx_params);
gnutls_pk_params_release(&session->key.kshare.ecdh_params);
gnutls_pk_params_release(&session->key.kshare.dh_params);
+ gnutls_pk_params_release(&session->key.kshare.kem_params);
if (!vers->tls13_sem && session->key.binders[0].prf == NULL) {
gnutls_pk_params_release(&session->key.proto.tls12.ecdh.params);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index c674835c1f..ca76736d2e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -600,6 +600,10 @@ ctests += win32-certopenstore
endif
+if ENABLE_LIBOQS
+dist_check_SCRIPTS += pqc-hybrid-kx.sh
+endif
+
cpptests =
if ENABLE_CXX
if HAVE_CMOCKA
diff --git a/tests/pqc-hybrid-kx.sh b/tests/pqc-hybrid-kx.sh
new file mode 100644
index 0000000000..b9302b43b1
--- /dev/null
+++ b/tests/pqc-hybrid-kx.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+# Copyright (C) 2022 Red Hat, Inc.
+#
+# Author: Daiki Ueno
+#
+# This file is part of GnuTLS.
+#
+# GnuTLS is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# GnuTLS is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GnuTLS. If not, see <https://www.gnu.org/licenses/>.
+
+: ${srcdir=.}
+: ${SERV=../src/gnutls-serv${EXEEXT}}
+: ${CLI=../src/gnutls-cli${EXEEXT}}
+
+if ! test -x "${SERV}"; then
+ exit 77
+fi
+
+if ! test -x "${CLI}"; then
+ exit 77
+fi
+
+. "${srcdir}/scripts/common.sh"
+testdir=`create_testdir pqc-hybrid-kx`
+
+KEY="$srcdir/../doc/credentials/x509/key-ed25519.pem"
+CERT="$srcdir/../doc/credentials/x509/cert-ed25519.pem"
+CACERT="$srcdir/../doc/credentials/x509/ca.pem"
+
+eval "${GETPORT}"
+launch_server --echo --priority NORMAL:-GROUP-ALL:+GROUP-X25519-KYBER768 --x509keyfile="$KEY" --x509certfile="$CERT"
+PID=$!
+wait_server ${PID}
+
+${VALGRIND} "${CLI}" -p "${PORT}" 127.0.0.1 --priority NORMAL:-GROUP-ALL:+GROUP-X25519-KYBER768 --x509cafile="$CACERT" --logfile="$testdir/cli.log" </dev/null
+
+kill ${PID}
+wait
+
+grep -- '- Description: (TLS1.3-X.509)-(ECDHE-X25519-KYBER768)-(EdDSA-Ed25519)-(AES-256-GCM)' "$testdir/cli.log" || { echo "unexpected handshake description"; exit 1; }
+
+rm -rf "$testdir"
+exit 0
--
2.45.2
From baae5fca41567297ef3550bcbce6ac4c18984006 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Tue, 23 Jul 2024 11:25:18 +0900
Subject: [PATCH 1/3] dlwrap: use different macro for library soname in
generated code
As GnuTLS opt in for manual initialization of dlopen'ed libraries,
config.h shouldn't define the SONAME macro used in the generated code.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
devel/generate-dlwrap.sh | 18 +++++++++++++-----
lib/dlwrap/brotlidec.c | 17 +++++++++--------
lib/dlwrap/brotlienc.c | 17 +++++++++--------
lib/dlwrap/oqs.c | 17 +++++++++--------
lib/dlwrap/zlib.c | 17 +++++++++--------
lib/dlwrap/zstd.c | 17 +++++++++--------
6 files changed, 58 insertions(+), 45 deletions(-)
diff --git a/devel/generate-dlwrap.sh b/devel/generate-dlwrap.sh
index 3e253d9228..0394655bbf 100755
--- a/devel/generate-dlwrap.sh
+++ b/devel/generate-dlwrap.sh
@@ -21,20 +21,28 @@ DST="$srcdir/lib/$DLWRAP"
echo "Generating $DST/zlib.h"
-"$DLWRAP" --input /usr/include/zlib.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/z.syms" --license-file "$SRC/z.license" --soname Z_LIBRARY_SONAME --prefix gnutls_zlib --header-guard GNUTLS_LIB_DLWRAP_ZLIB_H_ --include "<zlib.h>"
+"$DLWRAP" --input /usr/include/zlib.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/z.syms" --license-file "$SRC/z.license" --soname Z_LIBRARY_SONAME_UNUSED --prefix gnutls_zlib --header-guard GNUTLS_LIB_DLWRAP_ZLIB_H_ --include "<zlib.h>"
echo "Generating $DST/zstd.h"
-"$DLWRAP" --input /usr/include/zstd.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/zstd.syms" --license-file "$SRC/zstd.license" --soname ZSTD_LIBRARY_SONAME --prefix gnutls_zstd --header-guard GNUTLS_LIB_DLWRAP_ZSTD_H_ --include "<zstd.h>"
+"$DLWRAP" --input /usr/include/zstd.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/zstd.syms" --license-file "$SRC/zstd.license" --soname ZSTD_LIBRARY_SONAME_UNUSED --prefix gnutls_zstd --header-guard GNUTLS_LIB_DLWRAP_ZSTD_H_ --include "<zstd.h>"
echo "Generating $DST/brotlienc.h"
-"$DLWRAP" --input /usr/include/brotli/encode.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/brotlienc.syms" --license-file "$SRC/brotli.license" --soname BROTLIENC_LIBRARY_SONAME --prefix gnutls_brotlienc --loader-basename brotlienc --header-guard GNUTLS_LIB_DLWRAP_BROTLIENC_H_ --include "<brotli/encode.h>"
+"$DLWRAP" --input /usr/include/brotli/encode.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/brotlienc.syms" --license-file "$SRC/brotli.license" --soname BROTLIENC_LIBRARY_SONAME_UNUSED --prefix gnutls_brotlienc --loader-basename brotlienc --header-guard GNUTLS_LIB_DLWRAP_BROTLIENC_H_ --include "<brotli/encode.h>"
echo "Generating $DST/brotlidec.h"
-"$DLWRAP" --input /usr/include/brotli/decode.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/brotlidec.syms" --license-file "$SRC/brotli.license" --soname BROTLIDEC_LIBRARY_SONAME --prefix gnutls_brotlidec --loader-basename brotlidec --header-guard GNUTLS_LIB_DLWRAP_BROTLIDEC_H_ --include "<brotli/decode.h>"
+"$DLWRAP" --input /usr/include/brotli/decode.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/brotlidec.syms" --license-file "$SRC/brotli.license" --soname BROTLIDEC_LIBRARY_SONAME_UNUSED --prefix gnutls_brotlidec --loader-basename brotlidec --header-guard GNUTLS_LIB_DLWRAP_BROTLIDEC_H_ --include "<brotli/decode.h>"
echo "Generating $DST/oqs.h"
-"$DLWRAP" --input /usr/include/oqs/oqs.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/oqs.syms" --license "SPDX-License-Identifier: MIT" --soname OQS_LIBRARY_SONAME --prefix gnutls_oqs --header-guard GNUTLS_LIB_DLWRAP_OQS_H_ --include "<oqs/oqs.h>"
+"$DLWRAP" --input /usr/include/oqs/oqs.h -o "$DST" --clang-resource-dir $(clang -print-resource-dir) --symbol-file "$SRC/oqs.syms" --license "SPDX-License-Identifier: MIT" --soname OQS_LIBRARY_SONAME_UNUSED --prefix gnutls_oqs --header-guard GNUTLS_LIB_DLWRAP_OQS_H_ --include "<oqs/oqs.h>"
+
+sed -i '/^#include <oqs\/oqs.h>/i\
+/* Local modification: remove this once liboqs 0.10.2 is released */\
+#include "config.h"\
+#if !HAVE_DECL_OQS_SHA3_SET_CALLBACKS\
+#include "liboqs/backport/sha3_ops.h"\
+#endif\
+' "$DST/oqs.h"
diff --git a/lib/dlwrap/brotlidec.c b/lib/dlwrap/brotlidec.c
index 45c9b4b259..15cee63bd6 100644
--- a/lib/dlwrap/brotlidec.c
+++ b/lib/dlwrap/brotlidec.c
@@ -18,16 +18,16 @@
#include <errno.h>
#include <stdlib.h>
-/* If BROTLIDEC_LIBRARY_SONAME is defined, dlopen handle can be automatically
+/* If BROTLIDEC_LIBRARY_SONAME_UNUSED is defined, dlopen handle can be automatically
* set; otherwise, the caller needs to call
* gnutls_brotlidec_ensure_library with soname determined at run time.
*/
-#ifdef BROTLIDEC_LIBRARY_SONAME
+#ifdef BROTLIDEC_LIBRARY_SONAME_UNUSED
static void
ensure_library (void)
{
- if (gnutls_brotlidec_ensure_library (BROTLIDEC_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0)
+ if (gnutls_brotlidec_ensure_library (BROTLIDEC_LIBRARY_SONAME_UNUSED, RTLD_LAZY | RTLD_LOCAL) < 0)
abort ();
}
@@ -47,11 +47,11 @@ static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT;
#endif /* !GNUTLS_BROTLIDEC_ENABLE_PTHREAD */
-#else /* BROTLIDEC_LIBRARY_SONAME */
+#else /* BROTLIDEC_LIBRARY_SONAME_UNUSED */
#define ENSURE_LIBRARY do {} while (0)
-#endif /* !BROTLIDEC_LIBRARY_SONAME */
+#endif /* !BROTLIDEC_LIBRARY_SONAME_UNUSED */
static void *gnutls_brotlidec_dlhandle;
@@ -147,7 +147,10 @@ void
gnutls_brotlidec_unload_library (void)
{
if (gnutls_brotlidec_dlhandle)
- dlclose (gnutls_brotlidec_dlhandle);
+ {
+ dlclose (gnutls_brotlidec_dlhandle);
+ gnutls_brotlidec_dlhandle = NULL;
+ }
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
@@ -160,8 +163,6 @@ gnutls_brotlidec_unload_library (void)
#undef FUNC
#pragma GCC diagnostic pop
-
-#undef RESET_SYMBOL
}
#else /* GNUTLS_BROTLIDEC_ENABLE_DLOPEN */
diff --git a/lib/dlwrap/brotlienc.c b/lib/dlwrap/brotlienc.c
index 9dd8ff37c6..1deff747e2 100644
--- a/lib/dlwrap/brotlienc.c
+++ b/lib/dlwrap/brotlienc.c
@@ -18,16 +18,16 @@
#include <errno.h>
#include <stdlib.h>
-/* If BROTLIENC_LIBRARY_SONAME is defined, dlopen handle can be automatically
+/* If BROTLIENC_LIBRARY_SONAME_UNUSED is defined, dlopen handle can be automatically
* set; otherwise, the caller needs to call
* gnutls_brotlienc_ensure_library with soname determined at run time.
*/
-#ifdef BROTLIENC_LIBRARY_SONAME
+#ifdef BROTLIENC_LIBRARY_SONAME_UNUSED
static void
ensure_library (void)
{
- if (gnutls_brotlienc_ensure_library (BROTLIENC_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0)
+ if (gnutls_brotlienc_ensure_library (BROTLIENC_LIBRARY_SONAME_UNUSED, RTLD_LAZY | RTLD_LOCAL) < 0)
abort ();
}
@@ -47,11 +47,11 @@ static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT;
#endif /* !GNUTLS_BROTLIENC_ENABLE_PTHREAD */
-#else /* BROTLIENC_LIBRARY_SONAME */
+#else /* BROTLIENC_LIBRARY_SONAME_UNUSED */
#define ENSURE_LIBRARY do {} while (0)
-#endif /* !BROTLIENC_LIBRARY_SONAME */
+#endif /* !BROTLIENC_LIBRARY_SONAME_UNUSED */
static void *gnutls_brotlienc_dlhandle;
@@ -147,7 +147,10 @@ void
gnutls_brotlienc_unload_library (void)
{
if (gnutls_brotlienc_dlhandle)
- dlclose (gnutls_brotlienc_dlhandle);
+ {
+ dlclose (gnutls_brotlienc_dlhandle);
+ gnutls_brotlienc_dlhandle = NULL;
+ }
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
@@ -160,8 +163,6 @@ gnutls_brotlienc_unload_library (void)
#undef FUNC
#pragma GCC diagnostic pop
-
-#undef RESET_SYMBOL
}
#else /* GNUTLS_BROTLIENC_ENABLE_DLOPEN */
diff --git a/lib/dlwrap/oqs.c b/lib/dlwrap/oqs.c
index d7fcc9c80c..c05f883127 100644
--- a/lib/dlwrap/oqs.c
+++ b/lib/dlwrap/oqs.c
@@ -18,16 +18,16 @@
#include <errno.h>
#include <stdlib.h>
-/* If OQS_LIBRARY_SONAME is defined, dlopen handle can be automatically
+/* If OQS_LIBRARY_SONAME_UNUSED is defined, dlopen handle can be automatically
* set; otherwise, the caller needs to call
* gnutls_oqs_ensure_library with soname determined at run time.
*/
-#ifdef OQS_LIBRARY_SONAME
+#ifdef OQS_LIBRARY_SONAME_UNUSED
static void
ensure_library (void)
{
- if (gnutls_oqs_ensure_library (OQS_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0)
+ if (gnutls_oqs_ensure_library (OQS_LIBRARY_SONAME_UNUSED, RTLD_LAZY | RTLD_LOCAL) < 0)
abort ();
}
@@ -47,11 +47,11 @@ static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT;
#endif /* !GNUTLS_OQS_ENABLE_PTHREAD */
-#else /* OQS_LIBRARY_SONAME */
+#else /* OQS_LIBRARY_SONAME_UNUSED */
#define ENSURE_LIBRARY do {} while (0)
-#endif /* !OQS_LIBRARY_SONAME */
+#endif /* !OQS_LIBRARY_SONAME_UNUSED */
static void *gnutls_oqs_dlhandle;
@@ -147,7 +147,10 @@ void
gnutls_oqs_unload_library (void)
{
if (gnutls_oqs_dlhandle)
- dlclose (gnutls_oqs_dlhandle);
+ {
+ dlclose (gnutls_oqs_dlhandle);
+ gnutls_oqs_dlhandle = NULL;
+ }
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
@@ -160,8 +163,6 @@ gnutls_oqs_unload_library (void)
#undef FUNC
#pragma GCC diagnostic pop
-
-#undef RESET_SYMBOL
}
#else /* GNUTLS_OQS_ENABLE_DLOPEN */
diff --git a/lib/dlwrap/zlib.c b/lib/dlwrap/zlib.c
index 455485c63f..878070c0a4 100644
--- a/lib/dlwrap/zlib.c
+++ b/lib/dlwrap/zlib.c
@@ -18,16 +18,16 @@
#include <errno.h>
#include <stdlib.h>
-/* If Z_LIBRARY_SONAME is defined, dlopen handle can be automatically
+/* If Z_LIBRARY_SONAME_UNUSED is defined, dlopen handle can be automatically
* set; otherwise, the caller needs to call
* gnutls_zlib_ensure_library with soname determined at run time.
*/
-#ifdef Z_LIBRARY_SONAME
+#ifdef Z_LIBRARY_SONAME_UNUSED
static void
ensure_library (void)
{
- if (gnutls_zlib_ensure_library (Z_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0)
+ if (gnutls_zlib_ensure_library (Z_LIBRARY_SONAME_UNUSED, RTLD_LAZY | RTLD_LOCAL) < 0)
abort ();
}
@@ -47,11 +47,11 @@ static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT;
#endif /* !GNUTLS_ZLIB_ENABLE_PTHREAD */
-#else /* Z_LIBRARY_SONAME */
+#else /* Z_LIBRARY_SONAME_UNUSED */
#define ENSURE_LIBRARY do {} while (0)
-#endif /* !Z_LIBRARY_SONAME */
+#endif /* !Z_LIBRARY_SONAME_UNUSED */
static void *gnutls_zlib_dlhandle;
@@ -147,7 +147,10 @@ void
gnutls_zlib_unload_library (void)
{
if (gnutls_zlib_dlhandle)
- dlclose (gnutls_zlib_dlhandle);
+ {
+ dlclose (gnutls_zlib_dlhandle);
+ gnutls_zlib_dlhandle = NULL;
+ }
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
@@ -160,8 +163,6 @@ gnutls_zlib_unload_library (void)
#undef FUNC
#pragma GCC diagnostic pop
-
-#undef RESET_SYMBOL
}
#else /* GNUTLS_ZLIB_ENABLE_DLOPEN */
diff --git a/lib/dlwrap/zstd.c b/lib/dlwrap/zstd.c
index 2ea7252975..532c80b610 100644
--- a/lib/dlwrap/zstd.c
+++ b/lib/dlwrap/zstd.c
@@ -18,16 +18,16 @@
#include <errno.h>
#include <stdlib.h>
-/* If ZSTD_LIBRARY_SONAME is defined, dlopen handle can be automatically
+/* If ZSTD_LIBRARY_SONAME_UNUSED is defined, dlopen handle can be automatically
* set; otherwise, the caller needs to call
* gnutls_zstd_ensure_library with soname determined at run time.
*/
-#ifdef ZSTD_LIBRARY_SONAME
+#ifdef ZSTD_LIBRARY_SONAME_UNUSED
static void
ensure_library (void)
{
- if (gnutls_zstd_ensure_library (ZSTD_LIBRARY_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0)
+ if (gnutls_zstd_ensure_library (ZSTD_LIBRARY_SONAME_UNUSED, RTLD_LAZY | RTLD_LOCAL) < 0)
abort ();
}
@@ -47,11 +47,11 @@ static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT;
#endif /* !GNUTLS_ZSTD_ENABLE_PTHREAD */
-#else /* ZSTD_LIBRARY_SONAME */
+#else /* ZSTD_LIBRARY_SONAME_UNUSED */
#define ENSURE_LIBRARY do {} while (0)
-#endif /* !ZSTD_LIBRARY_SONAME */
+#endif /* !ZSTD_LIBRARY_SONAME_UNUSED */
static void *gnutls_zstd_dlhandle;
@@ -147,7 +147,10 @@ void
gnutls_zstd_unload_library (void)
{
if (gnutls_zstd_dlhandle)
- dlclose (gnutls_zstd_dlhandle);
+ {
+ dlclose (gnutls_zstd_dlhandle);
+ gnutls_zstd_dlhandle = NULL;
+ }
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
@@ -160,8 +163,6 @@ gnutls_zstd_unload_library (void)
#undef FUNC
#pragma GCC diagnostic pop
-
-#undef RESET_SYMBOL
}
#else /* GNUTLS_ZSTD_ENABLE_DLOPEN */
--
2.45.2
From ec65c64e6c904d5a408e2afb31ecacc2b52ed7dc Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Tue, 23 Jul 2024 15:12:11 +0900
Subject: [PATCH 2/3] liboqs: manually load liboqs.so at startup
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/global.c | 6 +++++-
lib/liboqs/liboqs.c | 21 ++++++++++++++++++++-
lib/liboqs/liboqs.h | 2 +-
3 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/lib/global.c b/lib/global.c
index ae2f7f54dc..4aaf79a768 100644
--- a/lib/global.c
+++ b/lib/global.c
@@ -330,7 +330,11 @@ static int _gnutls_global_init(unsigned constructor)
}
#ifdef HAVE_LIBOQS
- _gnutls_liboqs_init();
+ ret = _gnutls_liboqs_init();
+ if (ret < 0) {
+ gnutls_assert();
+ goto out;
+ }
#endif
#ifndef _WIN32
diff --git a/lib/liboqs/liboqs.c b/lib/liboqs/liboqs.c
index 88f2369719..c5531d4796 100644
--- a/lib/liboqs/liboqs.c
+++ b/lib/liboqs/liboqs.c
@@ -22,15 +22,33 @@
#include "liboqs/liboqs.h"
+#ifdef _WIN32
+#define RTLD_NOW 0
+#define RTLD_GLOBAL 0
+#else
+#include <dlfcn.h>
+#endif
+
+#ifndef OQS_LIBRARY_SONAME
+#define OQS_LIBRARY_SONAME "none"
+#endif
+
+#include "errors.h"
+
#include "dlwrap/oqs.h"
#include "liboqs/rand.h"
#include "liboqs/sha3.h"
-void _gnutls_liboqs_init(void)
+int _gnutls_liboqs_init(void)
{
+ if (gnutls_oqs_ensure_library(OQS_LIBRARY_SONAME,
+ RTLD_NOW | RTLD_GLOBAL) < 0)
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
_gnutls_liboqs_sha3_init();
GNUTLS_OQS_FUNC(OQS_init)();
_gnutls_liboqs_rand_init();
+ return 0;
}
void _gnutls_liboqs_deinit(void)
@@ -38,4 +56,5 @@ void _gnutls_liboqs_deinit(void)
_gnutls_liboqs_rand_deinit();
_gnutls_liboqs_sha3_deinit();
GNUTLS_OQS_FUNC(OQS_destroy)();
+ gnutls_oqs_unload_library();
}
diff --git a/lib/liboqs/liboqs.h b/lib/liboqs/liboqs.h
index b6c1659212..50206fa77c 100644
--- a/lib/liboqs/liboqs.h
+++ b/lib/liboqs/liboqs.h
@@ -21,7 +21,7 @@
#ifndef GNUTLS_LIB_LIBOQS_LIBOQS_H
#define GNUTLS_LIB_LIBOQS_LIBOQS_H
-void _gnutls_liboqs_init(void);
+int _gnutls_liboqs_init(void);
void _gnutls_liboqs_deinit(void);
#endif /* GNUTLS_LIB_LIBOQS_LIBOQS_H */
--
2.45.2
From ecc41197f2233494d066114e2747b17b24d24543 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Tue, 23 Jul 2024 09:50:04 +0900
Subject: [PATCH 3/3] tests: pqc-hybrid-kx: use key and certificate in
distribution
The Ed25519 key and certificate in doc/credentials/x509/ are currently
not included in the distribution. Use the ECDSA ones in the test to
make the test work.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
tests/pqc-hybrid-kx.sh | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tests/pqc-hybrid-kx.sh b/tests/pqc-hybrid-kx.sh
index b9302b43b1..b587587bd2 100644
--- a/tests/pqc-hybrid-kx.sh
+++ b/tests/pqc-hybrid-kx.sh
@@ -34,8 +34,8 @@ fi
. "${srcdir}/scripts/common.sh"
testdir=`create_testdir pqc-hybrid-kx`
-KEY="$srcdir/../doc/credentials/x509/key-ed25519.pem"
-CERT="$srcdir/../doc/credentials/x509/cert-ed25519.pem"
+KEY="$srcdir/../doc/credentials/x509/key-ecc.pem"
+CERT="$srcdir/../doc/credentials/x509/cert-ecc.pem"
CACERT="$srcdir/../doc/credentials/x509/ca.pem"
eval "${GETPORT}"
@@ -43,12 +43,12 @@ launch_server --echo --priority NORMAL:-GROUP-ALL:+GROUP-X25519-KYBER768 --x509k
PID=$!
wait_server ${PID}
-${VALGRIND} "${CLI}" -p "${PORT}" 127.0.0.1 --priority NORMAL:-GROUP-ALL:+GROUP-X25519-KYBER768 --x509cafile="$CACERT" --logfile="$testdir/cli.log" </dev/null
+${VALGRIND} "${CLI}" -p "${PORT}" localhost --priority NORMAL:-GROUP-ALL:+GROUP-X25519-KYBER768 --x509cafile="$CACERT" --logfile="$testdir/cli.log" </dev/null
kill ${PID}
wait
-grep -- '- Description: (TLS1.3-X.509)-(ECDHE-X25519-KYBER768)-(EdDSA-Ed25519)-(AES-256-GCM)' "$testdir/cli.log" || { echo "unexpected handshake description"; exit 1; }
+grep -- '- Description: (TLS1.3-X.509)-(ECDHE-X25519-KYBER768)-(ECDSA-SECP256R1-SHA256)-(AES-256-GCM)' "$testdir/cli.log" || { echo "unexpected handshake description"; exit 1; }
rm -rf "$testdir"
exit 0
--
2.45.2
From acba7357c7274c3783dd9b70e054f062e937da93 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Tue, 23 Jul 2024 20:48:26 +0900
Subject: [PATCH] liboqs: defer loading of liboqs at run-time
Instead of loading liboqs at startup, this defers it until the liboqs
functions are actually used.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/dlwrap/brotlidec.c | 24 ++++++++++++++++++----
lib/dlwrap/brotlidec.h | 7 +++++++
lib/dlwrap/brotlienc.c | 24 ++++++++++++++++++----
lib/dlwrap/brotlienc.h | 7 +++++++
lib/dlwrap/oqs.c | 24 ++++++++++++++++++----
lib/dlwrap/oqs.h | 7 +++++++
lib/dlwrap/zlib.c | 24 ++++++++++++++++++----
lib/dlwrap/zlib.h | 7 +++++++
lib/dlwrap/zstd.c | 24 ++++++++++++++++++----
lib/dlwrap/zstd.h | 7 +++++++
lib/global.c | 8 --------
lib/liboqs/liboqs.c | 46 +++++++++++++++++++++++++++++++++++-------
lib/liboqs/liboqs.h | 2 +-
lib/nettle/pk.c | 33 ++++++++++++++++++++++++------
14 files changed, 202 insertions(+), 42 deletions(-)
diff --git a/lib/dlwrap/brotlidec.c b/lib/dlwrap/brotlidec.c
index 15cee63bd6..7e4546a8e7 100644
--- a/lib/dlwrap/brotlidec.c
+++ b/lib/dlwrap/brotlidec.c
@@ -128,10 +128,13 @@ gnutls_brotlidec_ensure_library (const char *soname, int flags)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
-#define FUNC(ret, name, args, cargs) \
- err = ENSURE_SYMBOL(name); \
- if (err < 0) \
- return err;
+#define FUNC(ret, name, args, cargs) \
+ err = ENSURE_SYMBOL(name); \
+ if (err < 0) \
+ { \
+ gnutls_brotlidec_dlhandle = NULL; \
+ return err; \
+ }
#define VOID_FUNC FUNC
#include "brotlidecfuncs.h"
#undef VOID_FUNC
@@ -165,6 +168,12 @@ gnutls_brotlidec_unload_library (void)
#pragma GCC diagnostic pop
}
+unsigned
+gnutls_brotlidec_is_usable (void)
+{
+ return gnutls_brotlidec_dlhandle != NULL;
+}
+
#else /* GNUTLS_BROTLIDEC_ENABLE_DLOPEN */
int
@@ -180,4 +189,11 @@ gnutls_brotlidec_unload_library (void)
{
}
+unsigned
+gnutls_brotlidec_is_usable (void)
+{
+ /* The library is linked at build time, thus always usable */
+ return 1;
+}
+
#endif /* !GNUTLS_BROTLIDEC_ENABLE_DLOPEN */
diff --git a/lib/dlwrap/brotlidec.h b/lib/dlwrap/brotlidec.h
index 31397f24cf..f7d97eed35 100644
--- a/lib/dlwrap/brotlidec.h
+++ b/lib/dlwrap/brotlidec.h
@@ -44,4 +44,11 @@ int gnutls_brotlidec_ensure_library (const char *soname, int flags);
*/
void gnutls_brotlidec_unload_library (void);
+/* Return 1 if the library is loaded and usable.
+ *
+ * Note that this function is NOT thread-safe; when calling it from
+ * multi-threaded programs, protect it with a locking mechanism.
+ */
+unsigned gnutls_brotlidec_is_usable (void);
+
#endif /* GNUTLS_LIB_DLWRAP_BROTLIDEC_H_ */
diff --git a/lib/dlwrap/brotlienc.c b/lib/dlwrap/brotlienc.c
index 1deff747e2..fae13ed313 100644
--- a/lib/dlwrap/brotlienc.c
+++ b/lib/dlwrap/brotlienc.c
@@ -128,10 +128,13 @@ gnutls_brotlienc_ensure_library (const char *soname, int flags)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
-#define FUNC(ret, name, args, cargs) \
- err = ENSURE_SYMBOL(name); \
- if (err < 0) \
- return err;
+#define FUNC(ret, name, args, cargs) \
+ err = ENSURE_SYMBOL(name); \
+ if (err < 0) \
+ { \
+ gnutls_brotlienc_dlhandle = NULL; \
+ return err; \
+ }
#define VOID_FUNC FUNC
#include "brotliencfuncs.h"
#undef VOID_FUNC
@@ -165,6 +168,12 @@ gnutls_brotlienc_unload_library (void)
#pragma GCC diagnostic pop
}
+unsigned
+gnutls_brotlienc_is_usable (void)
+{
+ return gnutls_brotlienc_dlhandle != NULL;
+}
+
#else /* GNUTLS_BROTLIENC_ENABLE_DLOPEN */
int
@@ -180,4 +189,11 @@ gnutls_brotlienc_unload_library (void)
{
}
+unsigned
+gnutls_brotlienc_is_usable (void)
+{
+ /* The library is linked at build time, thus always usable */
+ return 1;
+}
+
#endif /* !GNUTLS_BROTLIENC_ENABLE_DLOPEN */
diff --git a/lib/dlwrap/brotlienc.h b/lib/dlwrap/brotlienc.h
index ed1af45e04..4dfbf3b838 100644
--- a/lib/dlwrap/brotlienc.h
+++ b/lib/dlwrap/brotlienc.h
@@ -44,4 +44,11 @@ int gnutls_brotlienc_ensure_library (const char *soname, int flags);
*/
void gnutls_brotlienc_unload_library (void);
+/* Return 1 if the library is loaded and usable.
+ *
+ * Note that this function is NOT thread-safe; when calling it from
+ * multi-threaded programs, protect it with a locking mechanism.
+ */
+unsigned gnutls_brotlienc_is_usable (void);
+
#endif /* GNUTLS_LIB_DLWRAP_BROTLIENC_H_ */
diff --git a/lib/dlwrap/oqs.c b/lib/dlwrap/oqs.c
index c05f883127..f9ae269faa 100644
--- a/lib/dlwrap/oqs.c
+++ b/lib/dlwrap/oqs.c
@@ -128,10 +128,13 @@ gnutls_oqs_ensure_library (const char *soname, int flags)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
-#define FUNC(ret, name, args, cargs) \
- err = ENSURE_SYMBOL(name); \
- if (err < 0) \
- return err;
+#define FUNC(ret, name, args, cargs) \
+ err = ENSURE_SYMBOL(name); \
+ if (err < 0) \
+ { \
+ gnutls_oqs_dlhandle = NULL; \
+ return err; \
+ }
#define VOID_FUNC FUNC
#include "oqsfuncs.h"
#undef VOID_FUNC
@@ -165,6 +168,12 @@ gnutls_oqs_unload_library (void)
#pragma GCC diagnostic pop
}
+unsigned
+gnutls_oqs_is_usable (void)
+{
+ return gnutls_oqs_dlhandle != NULL;
+}
+
#else /* GNUTLS_OQS_ENABLE_DLOPEN */
int
@@ -180,4 +189,11 @@ gnutls_oqs_unload_library (void)
{
}
+unsigned
+gnutls_oqs_is_usable (void)
+{
+ /* The library is linked at build time, thus always usable */
+ return 1;
+}
+
#endif /* !GNUTLS_OQS_ENABLE_DLOPEN */
diff --git a/lib/dlwrap/oqs.h b/lib/dlwrap/oqs.h
index 6a1d8e0766..1cf5d015a5 100644
--- a/lib/dlwrap/oqs.h
+++ b/lib/dlwrap/oqs.h
@@ -50,4 +50,11 @@ int gnutls_oqs_ensure_library (const char *soname, int flags);
*/
void gnutls_oqs_unload_library (void);
+/* Return 1 if the library is loaded and usable.
+ *
+ * Note that this function is NOT thread-safe; when calling it from
+ * multi-threaded programs, protect it with a locking mechanism.
+ */
+unsigned gnutls_oqs_is_usable (void);
+
#endif /* GNUTLS_LIB_DLWRAP_OQS_H_ */
diff --git a/lib/dlwrap/zlib.c b/lib/dlwrap/zlib.c
index 878070c0a4..19851513a9 100644
--- a/lib/dlwrap/zlib.c
+++ b/lib/dlwrap/zlib.c
@@ -128,10 +128,13 @@ gnutls_zlib_ensure_library (const char *soname, int flags)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
-#define FUNC(ret, name, args, cargs) \
- err = ENSURE_SYMBOL(name); \
- if (err < 0) \
- return err;
+#define FUNC(ret, name, args, cargs) \
+ err = ENSURE_SYMBOL(name); \
+ if (err < 0) \
+ { \
+ gnutls_zlib_dlhandle = NULL; \
+ return err; \
+ }
#define VOID_FUNC FUNC
#include "zlibfuncs.h"
#undef VOID_FUNC
@@ -165,6 +168,12 @@ gnutls_zlib_unload_library (void)
#pragma GCC diagnostic pop
}
+unsigned
+gnutls_zlib_is_usable (void)
+{
+ return gnutls_zlib_dlhandle != NULL;
+}
+
#else /* GNUTLS_ZLIB_ENABLE_DLOPEN */
int
@@ -180,4 +189,11 @@ gnutls_zlib_unload_library (void)
{
}
+unsigned
+gnutls_zlib_is_usable (void)
+{
+ /* The library is linked at build time, thus always usable */
+ return 1;
+}
+
#endif /* !GNUTLS_ZLIB_ENABLE_DLOPEN */
diff --git a/lib/dlwrap/zlib.h b/lib/dlwrap/zlib.h
index a9666d27f5..0d7113febf 100644
--- a/lib/dlwrap/zlib.h
+++ b/lib/dlwrap/zlib.h
@@ -44,4 +44,11 @@ int gnutls_zlib_ensure_library (const char *soname, int flags);
*/
void gnutls_zlib_unload_library (void);
+/* Return 1 if the library is loaded and usable.
+ *
+ * Note that this function is NOT thread-safe; when calling it from
+ * multi-threaded programs, protect it with a locking mechanism.
+ */
+unsigned gnutls_zlib_is_usable (void);
+
#endif /* GNUTLS_LIB_DLWRAP_ZLIB_H_ */
diff --git a/lib/dlwrap/zstd.c b/lib/dlwrap/zstd.c
index 532c80b610..bd5153e464 100644
--- a/lib/dlwrap/zstd.c
+++ b/lib/dlwrap/zstd.c
@@ -128,10 +128,13 @@ gnutls_zstd_ensure_library (const char *soname, int flags)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
-#define FUNC(ret, name, args, cargs) \
- err = ENSURE_SYMBOL(name); \
- if (err < 0) \
- return err;
+#define FUNC(ret, name, args, cargs) \
+ err = ENSURE_SYMBOL(name); \
+ if (err < 0) \
+ { \
+ gnutls_zstd_dlhandle = NULL; \
+ return err; \
+ }
#define VOID_FUNC FUNC
#include "zstdfuncs.h"
#undef VOID_FUNC
@@ -165,6 +168,12 @@ gnutls_zstd_unload_library (void)
#pragma GCC diagnostic pop
}
+unsigned
+gnutls_zstd_is_usable (void)
+{
+ return gnutls_zstd_dlhandle != NULL;
+}
+
#else /* GNUTLS_ZSTD_ENABLE_DLOPEN */
int
@@ -180,4 +189,11 @@ gnutls_zstd_unload_library (void)
{
}
+unsigned
+gnutls_zstd_is_usable (void)
+{
+ /* The library is linked at build time, thus always usable */
+ return 1;
+}
+
#endif /* !GNUTLS_ZSTD_ENABLE_DLOPEN */
diff --git a/lib/dlwrap/zstd.h b/lib/dlwrap/zstd.h
index 80ac2fbd46..4a68a45e37 100644
--- a/lib/dlwrap/zstd.h
+++ b/lib/dlwrap/zstd.h
@@ -44,4 +44,11 @@ int gnutls_zstd_ensure_library (const char *soname, int flags);
*/
void gnutls_zstd_unload_library (void);
+/* Return 1 if the library is loaded and usable.
+ *
+ * Note that this function is NOT thread-safe; when calling it from
+ * multi-threaded programs, protect it with a locking mechanism.
+ */
+unsigned gnutls_zstd_is_usable (void);
+
#endif /* GNUTLS_LIB_DLWRAP_ZSTD_H_ */
diff --git a/lib/global.c b/lib/global.c
index 4aaf79a768..42d90ee9d5 100644
--- a/lib/global.c
+++ b/lib/global.c
@@ -329,14 +329,6 @@ static int _gnutls_global_init(unsigned constructor)
goto out;
}
-#ifdef HAVE_LIBOQS
- ret = _gnutls_liboqs_init();
- if (ret < 0) {
- gnutls_assert();
- goto out;
- }
-#endif
-
#ifndef _WIN32
ret = _gnutls_register_fork_handler();
if (ret < 0) {
diff --git a/lib/liboqs/liboqs.c b/lib/liboqs/liboqs.c
index c5531d4796..3c0df56644 100644
--- a/lib/liboqs/liboqs.c
+++ b/lib/liboqs/liboqs.c
@@ -34,27 +34,59 @@
#endif
#include "errors.h"
+#include "locks.h"
#include "dlwrap/oqs.h"
#include "liboqs/rand.h"
#include "liboqs/sha3.h"
-int _gnutls_liboqs_init(void)
+/* We can't use GNUTLS_ONCE here, as it wouldn't allow manual unloading */
+GNUTLS_STATIC_MUTEX(liboqs_init_mutex);
+static int _liboqs_init = 0;
+
+int _gnutls_liboqs_ensure(void)
{
+ int ret;
+
+ if (_liboqs_init)
+ return GNUTLS_E_SUCCESS;
+
+ ret = gnutls_static_mutex_lock(&liboqs_init_mutex);
+ if (unlikely(ret < 0))
+ return gnutls_assert_val(ret);
+
if (gnutls_oqs_ensure_library(OQS_LIBRARY_SONAME,
- RTLD_NOW | RTLD_GLOBAL) < 0)
- return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+ RTLD_NOW | RTLD_GLOBAL) < 0) {
+ _gnutls_debug_log(
+ "liboqs: unable to initialize liboqs functions\n");
+ ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+ goto out;
+ }
_gnutls_liboqs_sha3_init();
GNUTLS_OQS_FUNC(OQS_init)();
_gnutls_liboqs_rand_init();
- return 0;
+
+ _liboqs_init = 1;
+ ret = GNUTLS_E_SUCCESS;
+
+out:
+ (void)gnutls_static_mutex_unlock(&liboqs_init_mutex);
+
+ return ret;
}
+/* This is not thread-safe: call this function only from
+ * gnutls_global_deinit, which has a proper protection.
+ */
void _gnutls_liboqs_deinit(void)
{
- _gnutls_liboqs_rand_deinit();
- _gnutls_liboqs_sha3_deinit();
- GNUTLS_OQS_FUNC(OQS_destroy)();
+ if (_liboqs_init) {
+ _gnutls_liboqs_rand_deinit();
+ _gnutls_liboqs_sha3_deinit();
+ GNUTLS_OQS_FUNC(OQS_destroy)();
+ }
+
gnutls_oqs_unload_library();
+ _liboqs_init = 0;
}
diff --git a/lib/liboqs/liboqs.h b/lib/liboqs/liboqs.h
index 50206fa77c..3717454275 100644
--- a/lib/liboqs/liboqs.h
+++ b/lib/liboqs/liboqs.h
@@ -21,7 +21,7 @@
#ifndef GNUTLS_LIB_LIBOQS_LIBOQS_H
#define GNUTLS_LIB_LIBOQS_LIBOQS_H
-int _gnutls_liboqs_init(void);
+int _gnutls_liboqs_ensure(void);
void _gnutls_liboqs_deinit(void);
#endif /* GNUTLS_LIB_LIBOQS_LIBOQS_H */
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
index 4155a540ed..79f7988d50 100644
--- a/lib/nettle/pk.c
+++ b/lib/nettle/pk.c
@@ -72,6 +72,7 @@
#include "dh.h"
#ifdef HAVE_LIBOQS
#include "dlwrap/oqs.h"
+#include "liboqs/liboqs.h"
#endif
static inline const struct ecc_curve *get_supported_nist_curve(int curve);
@@ -703,6 +704,9 @@ static int _wrap_nettle_pk_encaps(gnutls_pk_algorithm_t algo,
OQS_KEM *kem = NULL;
OQS_STATUS rc;
+ if (_gnutls_liboqs_ensure() < 0)
+ return gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM);
+
kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768);
if (kem == NULL)
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
@@ -761,6 +765,9 @@ static int _wrap_nettle_pk_decaps(gnutls_pk_algorithm_t algo,
OQS_KEM *kem = NULL;
OQS_STATUS rc;
+ if (_gnutls_liboqs_ensure() < 0)
+ return gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM);
+
kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768);
if (kem == NULL)
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
@@ -2342,9 +2349,6 @@ static int _wrap_nettle_pk_exists(gnutls_pk_algorithm_t pk)
case GNUTLS_PK_RSA_PSS:
case GNUTLS_PK_RSA_OAEP:
case GNUTLS_PK_EDDSA_ED25519:
-#ifdef HAVE_LIBOQS
- case GNUTLS_PK_EXP_KYBER768:
-#endif
#if ENABLE_GOST
case GNUTLS_PK_GOST_01:
case GNUTLS_PK_GOST_12_256:
@@ -2353,6 +2357,10 @@ static int _wrap_nettle_pk_exists(gnutls_pk_algorithm_t pk)
case GNUTLS_PK_ECDH_X448:
case GNUTLS_PK_EDDSA_ED448:
return 1;
+#ifdef HAVE_LIBOQS
+ case GNUTLS_PK_EXP_KYBER768:
+ return _gnutls_liboqs_ensure() == 0;
+#endif
default:
return 0;
}
@@ -2986,11 +2994,15 @@ static int pct_test(gnutls_pk_algorithm_t algo,
}
case GNUTLS_PK_ECDH_X25519:
case GNUTLS_PK_ECDH_X448:
+ break;
#ifdef HAVE_LIBOQS
case GNUTLS_PK_EXP_KYBER768:
+ if (_gnutls_liboqs_ensure() < 0) {
+ ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM);
+ goto cleanup;
+ }
#endif
- ret = 0;
- goto cleanup;
+ break;
default:
ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM);
goto cleanup;
@@ -3724,6 +3736,13 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
OQS_KEM *kem = NULL;
OQS_STATUS rc;
+#ifdef HAVE_LIBOQS
+ if (_gnutls_liboqs_ensure() < 0) {
+ ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM);
+ goto cleanup;
+ }
+#endif
+
not_approved = true;
kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768);
@@ -4017,7 +4036,9 @@ static int wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo,
}
#ifdef HAVE_LIBOQS
case GNUTLS_PK_EXP_KYBER768:
- ret = 0;
+ ret = _gnutls_liboqs_ensure();
+ if (ret < 0)
+ ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM);
break;
#endif
#if ENABLE_GOST
--
2.45.2
From dfac4bb0d96507a409e3c3434c04bd8f79ac479f Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Mon, 29 Jul 2024 08:40:34 +0900
Subject: [PATCH 1/2] liboqs: check whether Kyber768 is compiled in
In the default build configuration of liboqs 0.10.1, Kyber768 is
disabled. This adds a guard against it and skip tests if not
available.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
devel/dlwrap/oqs.syms | 1 +
lib/dlwrap/oqsfuncs.h | 1 +
lib/nettle/pk.c | 27 ++++++++++++++++++---------
tests/pqc-hybrid-kx.sh | 4 ++++
4 files changed, 24 insertions(+), 9 deletions(-)
diff --git a/devel/dlwrap/oqs.syms b/devel/dlwrap/oqs.syms
index 8f067b2dd3..413f887598 100644
--- a/devel/dlwrap/oqs.syms
+++ b/devel/dlwrap/oqs.syms
@@ -1,6 +1,7 @@
OQS_SHA3_set_callbacks
OQS_init
OQS_destroy
+OQS_KEM_alg_is_enabled
OQS_KEM_new
OQS_KEM_encaps
OQS_KEM_decaps
diff --git a/lib/dlwrap/oqsfuncs.h b/lib/dlwrap/oqsfuncs.h
index 95c1b083dc..4aa0ba4ab4 100644
--- a/lib/dlwrap/oqsfuncs.h
+++ b/lib/dlwrap/oqsfuncs.h
@@ -7,6 +7,7 @@ VOID_FUNC(void, OQS_init, (void), ())
VOID_FUNC(void, OQS_destroy, (void), ())
VOID_FUNC(void, OQS_SHA3_set_callbacks, (struct OQS_SHA3_callbacks *new_callbacks), (new_callbacks))
VOID_FUNC(void, OQS_randombytes_custom_algorithm, (void (*algorithm_ptr)(uint8_t *, size_t)), (algorithm_ptr))
+FUNC(int, OQS_KEM_alg_is_enabled, (const char *method_name), (method_name))
FUNC(OQS_KEM *, OQS_KEM_new, (const char *method_name), (method_name))
FUNC(OQS_STATUS, OQS_KEM_keypair, (const OQS_KEM *kem, uint8_t *public_key, uint8_t *secret_key), (kem, public_key, secret_key))
FUNC(OQS_STATUS, OQS_KEM_encaps, (const OQS_KEM *kem, uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key), (kem, ciphertext, shared_secret, public_key))
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
index eb8c44459d..8a987ed121 100644
--- a/lib/nettle/pk.c
+++ b/lib/nettle/pk.c
@@ -704,7 +704,9 @@ static int _wrap_nettle_pk_encaps(gnutls_pk_algorithm_t algo,
OQS_KEM *kem = NULL;
OQS_STATUS rc;
- if (_gnutls_liboqs_ensure() < 0)
+ if (_gnutls_liboqs_ensure() < 0 ||
+ !GNUTLS_OQS_FUNC(OQS_KEM_alg_is_enabled)(
+ OQS_KEM_alg_kyber_768))
return gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM);
kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768);
@@ -765,7 +767,9 @@ static int _wrap_nettle_pk_decaps(gnutls_pk_algorithm_t algo,
OQS_KEM *kem = NULL;
OQS_STATUS rc;
- if (_gnutls_liboqs_ensure() < 0)
+ if (_gnutls_liboqs_ensure() < 0 ||
+ !GNUTLS_OQS_FUNC(OQS_KEM_alg_is_enabled)(
+ OQS_KEM_alg_kyber_768))
return gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM);
kem = GNUTLS_OQS_FUNC(OQS_KEM_new)(OQS_KEM_alg_kyber_768);
@@ -2359,7 +2363,9 @@ static int _wrap_nettle_pk_exists(gnutls_pk_algorithm_t pk)
return 1;
#ifdef HAVE_LIBOQS
case GNUTLS_PK_EXP_KYBER768:
- return _gnutls_liboqs_ensure() == 0;
+ return _gnutls_liboqs_ensure() == 0 &&
+ GNUTLS_OQS_FUNC(OQS_KEM_alg_is_enabled)(
+ OQS_KEM_alg_kyber_768);
#endif
default:
return 0;
@@ -2997,7 +3003,9 @@ static int pct_test(gnutls_pk_algorithm_t algo,
break;
#ifdef HAVE_LIBOQS
case GNUTLS_PK_EXP_KYBER768:
- if (_gnutls_liboqs_ensure() < 0) {
+ if (_gnutls_liboqs_ensure() < 0 ||
+ !GNUTLS_OQS_FUNC(OQS_KEM_alg_is_enabled)(
+ OQS_KEM_alg_kyber_768)) {
ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM);
goto cleanup;
}
@@ -3736,12 +3744,12 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
OQS_KEM *kem = NULL;
OQS_STATUS rc;
-#ifdef HAVE_LIBOQS
- if (_gnutls_liboqs_ensure() < 0) {
+ if (_gnutls_liboqs_ensure() < 0 ||
+ !GNUTLS_OQS_FUNC(OQS_KEM_alg_is_enabled)(
+ OQS_KEM_alg_kyber_768)) {
ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM);
goto cleanup;
}
-#endif
not_approved = true;
@@ -4038,8 +4046,9 @@ static int wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo,
}
#ifdef HAVE_LIBOQS
case GNUTLS_PK_EXP_KYBER768:
- ret = _gnutls_liboqs_ensure();
- if (ret < 0)
+ if (_gnutls_liboqs_ensure() < 0 ||
+ !GNUTLS_OQS_FUNC(OQS_KEM_alg_is_enabled)(
+ OQS_KEM_alg_kyber_768))
ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM);
break;
#endif
diff --git a/tests/pqc-hybrid-kx.sh b/tests/pqc-hybrid-kx.sh
index b587587bd2..6d47105fa0 100644
--- a/tests/pqc-hybrid-kx.sh
+++ b/tests/pqc-hybrid-kx.sh
@@ -31,6 +31,10 @@ if ! test -x "${CLI}"; then
exit 77
fi
+if ! "${CLI}" --list | grep '^Public Key Systems: .*Kyber768.*' >/dev/null; then
+ exit 77
+fi
+
. "${srcdir}/scripts/common.sh"
testdir=`create_testdir pqc-hybrid-kx`
--
2.45.2