]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
build: plumb liboqs as an optional dependency
authorDaiki Ueno <ueno@gnu.org>
Fri, 31 May 2024 00:18:27 +0000 (09:18 +0900)
committerDaiki Ueno <ueno@gnu.org>
Sat, 20 Jul 2024 23:30:14 +0000 (08:30 +0900)
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>
19 files changed:
.gitignore
cfg.mk
configure.ac
devel/dlwrap/oqs.syms [new file with mode: 0644]
devel/generate-dlwrap.sh
devel/indent-gnutls
lib/Makefile.am
lib/dlwrap/oqs.c [new file with mode: 0644]
lib/dlwrap/oqs.h [new file with mode: 0644]
lib/dlwrap/oqsfuncs.h [new file with mode: 0644]
lib/global.c
lib/liboqs/Makefile.am [new file with mode: 0644]
lib/liboqs/backport/sha3_ops.h [new file with mode: 0644]
lib/liboqs/liboqs.c [new file with mode: 0644]
lib/liboqs/liboqs.h [new file with mode: 0644]
lib/liboqs/rand.c [new file with mode: 0644]
lib/liboqs/rand.h [new file with mode: 0644]
lib/liboqs/sha3.c [new file with mode: 0644]
lib/liboqs/sha3.h [new file with mode: 0644]

index 5a66fa4e6a2d890a30d73be08374b9f222715c85..85dad0f8721f25886b5fef09c4e5e6b59643f05e 100644 (file)
@@ -222,6 +222,7 @@ lib/libgnutls-xssl.la
 lib/libgnutlsxx.la
 lib/Makefile
 lib/Makefile.in
+lib/liboqs/libcrypto.la
 lib/minitasn1/libminitasn1.la
 lib/minitasn1/Makefile
 lib/minitasn1/Makefile.in
diff --git a/cfg.mk b/cfg.mk
index 1b94279633ca28dcca977dc85530a7be7c4a1ef7..88f6df480da649156b54800d51d05f50d31d3508 100644 (file)
--- 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
index fb0aefe1f49bed16363b356199e5fa4616b9a3ea..145eada6908bf4ea99c2fd282d25075b229a6f50 100644 (file)
@@ -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 (file)
index 0000000..8f067b2
--- /dev/null
@@ -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
index dbcf870612e882eb9a16f4bf4d5608bd26447887..3e253d92281a075ce7b4227bfc259009eb2ca48e 100755 (executable)
@@ -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>"
index 39d3985eba6decc26720f0d4c036ea7d2c1d5419..6ddb5c30b71f5c354c922e159972307fce72e997 100755 (executable)
@@ -44,6 +44,6 @@ case $mode in
        ;;
 esac
 
-git ls-files -z | grep -z '\.[ch]\(.in\)\?$' | grep -z -v '^devel/' | grep -z -v '^lib/dlwrap/' | xargs -P "$parallel" -0 -n1 "$CLANG_FORMAT" $CLANG_FORMAT_ARGS
+git ls-files -z | grep -z '\.[ch]\(.in\)\?$' | grep -z -v '^devel/' | grep -z -v '^lib/dlwrap/' | grep -z -v '^lib/liboqs/backport/' | xargs -P "$parallel" -0 -n1 "$CLANG_FORMAT" $CLANG_FORMAT_ARGS
 
 exit $?
index d1bd07248ebd7b235bdd580aedc41ea57c4dafad..067772c322c51f50469fa197e0083d0420e916f6 100644 (file)
@@ -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 (file)
index 0000000..d7fcc9c
--- /dev/null
@@ -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 (file)
index 0000000..6a1d8e0
--- /dev/null
@@ -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 (file)
index 0000000..95c1b08
--- /dev/null
@@ -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))
index b434140bbfeaddb895a2152f97381feccbb2bb83..ae2f7f54dc5d9d42381471bfc490fa102a507cc6 100644 (file)
@@ -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 (file)
index 0000000..a20e7cb
--- /dev/null
@@ -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 (file)
index 0000000..694fc21
--- /dev/null
@@ -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 (file)
index 0000000..88f2369
--- /dev/null
@@ -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 (file)
index 0000000..b6c1659
--- /dev/null
@@ -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 (file)
index 0000000..4049680
--- /dev/null
@@ -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 (file)
index 0000000..b27ac23
--- /dev/null
@@ -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 (file)
index 0000000..9f5977e
--- /dev/null
@@ -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 (file)
index 0000000..8b9058a
--- /dev/null
@@ -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 */