]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
curl_ed25519: add GnuTLS support (via nettle, hogweed)
authorViktor Szakats <commit@vsz.me>
Fri, 31 Jul 2026 22:45:57 +0000 (00:45 +0200)
committerViktor Szakats <commit@vsz.me>
Mon, 3 Aug 2026 14:48:08 +0000 (16:48 +0200)
The necessary cryptography API is provided by nettle 3.1+, via its
'hogweed' library. The minimum GnuTLS version required by curl is 3.6.5,
which requires nettle 3.4.1+, so the API is always available.

Also:
- autotools: detect and use nettle's hogweed library.
- cmake/FindNettle: add support for the hogweed library.
- GHA/http3-linux: enable in the autotools/cmake GnuTLS jobs.

Ref: https://github.com/gnutls/gnutls/commit/4353ea025ae032887f3e8cf5aadace25662c6b35

Closes #22456

.github/workflows/http3-linux.yml
CMake/FindNettle.cmake
CMakeLists.txt
configure.ac
docs/INSTALL-CMAKE.md
lib/curl_ed25519.c
m4/curl-gnutls.m4

index 6d107895c1e112f77d4539426cbc47b4c21bbcb1..d880b1688508e83052be9d71b8326eeef215acd4 100644 (file)
@@ -473,7 +473,7 @@ jobs:
             LDFLAGS: -Wl,-rpath,/home/runner/gnutls/build/lib -Wl,-rpath,/home/runner/nettle/build/lib64 -Wl,-rpath,/home/runner/ngtcp2/build/lib
             PKG_CONFIG_PATH: /home/runner/nettle/build/lib64/pkgconfig:/home/runner/gnutls/build/lib/pkgconfig:/home/runner/nghttp3/build/lib/pkgconfig:/home/runner/nghttp2/build/lib/pkgconfig
             configure: >-
-              --with-gnutls=/home/runner/gnutls/build --with-ngtcp2=/home/runner/ngtcp2/build --with-libssh --enable-ssls-export
+              --with-gnutls=/home/runner/gnutls/build --with-ngtcp2=/home/runner/ngtcp2/build --with-libssh --enable-ssls-export --enable-httpsig
 
           - name: 'gnutls'
             install_packages: libp11-kit-dev libssh-dev
@@ -486,7 +486,7 @@ jobs:
               /home/runner/nghttp2/build/lib/pkgconfig"
             generate: >-
               -DCURL_USE_GNUTLS=ON -DUSE_NGTCP2=ON -DCURL_USE_LIBSSH=ON
-              -DCMAKE_UNITY_BUILD=ON
+              -DCMAKE_UNITY_BUILD=ON -DCURL_DISABLE_HTTPSIG=OFF
 
           - name: 'libressl'
             install_steps: skipall
index c963180cba0e62a1ff8cc5500e11c945f5addf3b..f14cf23886ef9e5d3d6d8ffc743e72e2edfb211e 100644 (file)
 #
 # Input variables:
 #
-# - `NETTLE_INCLUDE_DIR`:  Absolute path to nettle include directory.
-# - `NETTLE_LIBRARY`:      Absolute path to `nettle` library.
+# - `NETTLE_INCLUDE_DIR`:      Absolute path to nettle include directory.
+# - `NETTLE_HOGWEED_LIBRARY`:  Absolute path to `hogweed` library.
+# - `NETTLE_LIBRARY`:          Absolute path to `nettle` library.
 #
 # Defines:
 #
-# - `NETTLE_FOUND`:        System has nettle.
-# - `NETTLE_VERSION`:      Version of nettle.
-# - `CURL::nettle`:        nettle library target.
+# - `NETTLE_FOUND`:            System has nettle.
+# - `NETTLE_VERSION`:          Version of nettle.
+# - `CURL::nettle`:            nettle library target.
 
-set(_nettle_pc_requires "nettle")
+set(_nettle_pc_requires "hogweed" "nettle")
 
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED NETTLE_INCLUDE_DIR AND
+   NOT DEFINED NETTLE_HOGWEED_LIBRARY AND
    NOT DEFINED NETTLE_LIBRARY)
   find_package(PkgConfig QUIET)
   pkg_check_modules(_nettle ${_nettle_pc_requires})
@@ -46,10 +48,11 @@ endif()
 if(_nettle_FOUND)
   set(Nettle_FOUND TRUE)
   set(NETTLE_FOUND TRUE)
-  set(NETTLE_VERSION ${_nettle_VERSION})
+  set(NETTLE_VERSION ${_nettle_nettle_VERSION})
   message(STATUS "Found Nettle (via pkg-config): ${_nettle_INCLUDE_DIRS} (found version \"${NETTLE_VERSION}\")")
 else()
   find_path(NETTLE_INCLUDE_DIR NAMES "nettle/sha2.h")
+  find_library(NETTLE_HOGWEED_LIBRARY NAMES "hogweed")
   find_library(NETTLE_LIBRARY NAMES "nettle")
 
   unset(NETTLE_VERSION CACHE)
@@ -71,6 +74,7 @@ else()
   find_package_handle_standard_args(Nettle
     REQUIRED_VARS
       NETTLE_INCLUDE_DIR
+      NETTLE_HOGWEED_LIBRARY
       NETTLE_LIBRARY
     VERSION_VAR
       NETTLE_VERSION
@@ -78,10 +82,10 @@ else()
 
   if(NETTLE_FOUND)
     set(_nettle_INCLUDE_DIRS ${NETTLE_INCLUDE_DIR})
-    set(_nettle_LIBRARIES    ${NETTLE_LIBRARY})
+    set(_nettle_LIBRARIES    ${NETTLE_HOGWEED_LIBRARY} ${NETTLE_LIBRARY})
   endif()
 
-  mark_as_advanced(NETTLE_INCLUDE_DIR NETTLE_LIBRARY)
+  mark_as_advanced(NETTLE_INCLUDE_DIR NETTLE_HOGWEED_LIBRARY NETTLE_LIBRARY)
 endif()
 
 if(NETTLE_FOUND)
index ae1152c9b3f9ddbb2202bfbe5fefc939b5dbce83..868234926516926774b4dcc21223d7e0c5eb6e06 100644 (file)
@@ -1106,8 +1106,8 @@ if(USE_ECH)
   endif()
 endif()
 
-if(NOT CURL_DISABLE_HTTPSIG AND (NOT USE_OPENSSL AND NOT USE_WOLFSSL))
-  message(WARNING "HTTPSIG requires OpenSSL or wolfSSL. HTTPSIG support disabled.")
+if(NOT CURL_DISABLE_HTTPSIG AND NOT USE_GNUTLS AND NOT USE_OPENSSL AND NOT USE_WOLFSSL)
+  message(WARNING "HTTPSIG requires GnuTLS, OpenSSL or wolfSSL. HTTPSIG support disabled.")
   set(CURL_DISABLE_HTTPSIG ON)
 endif()
 
index a00a2f8aa65c153f53354cfe948c69fd977b219d..6ae2e7b57ead4097885069d6d40b0acaca544a14 100644 (file)
@@ -4608,8 +4608,8 @@ AS_HELP_STRING([--disable-httpsig],[Disable HTTP Message Signatures support (exp
     want_httpsig="no"
 )
 
-if test "$want_httpsig" = "yes" && test "$OPENSSL_ENABLED" != "1" && test "$WOLFSSL_ENABLED" != "1"; then
-  AC_MSG_WARN([HTTPSIG requires OpenSSL or wolfSSL. HTTPSIG support disabled.])
+if test "$want_httpsig" = "yes" && test "$GNUTLS_ENABLED" != "1" && test "$OPENSSL_ENABLED" != "1" && test "$WOLFSSL_ENABLED" != "1"; then
+  AC_MSG_WARN([HTTPSIG requires GnuTLS, OpenSSL or wolfSSL. HTTPSIG support disabled.])
   want_httpsig="no"
 fi
 if test "$want_httpsig" != "yes"; then
index 1e7b1639e951a757c81d4c418117bfeba3c6fbe5..f240d9c52e9d62fc9b4ff3b8f28d9e416eb6d319 100644 (file)
@@ -456,6 +456,7 @@ Details via CMake
 - `NGTCP2_CRYPTO_WOLFSSL_LIBRARY`:          Absolute path to `ngtcp2_crypto_wolfssl` library.
 - `NGTCP2_USE_STATIC_LIBS`:                 Configure for static ngtcp2 libraries. (experimental)
 - `NETTLE_INCLUDE_DIR`:                     Absolute path to nettle include directory.
+- `NETTLE_HOGWEED_LIBRARY`:                 Absolute path to `hogweed` library.
 - `NETTLE_LIBRARY`:                         Absolute path to `nettle` library.
 - `PTHREAD_LIBRARY`:                        Absolute path to `pthread` library. (for Rustls)
 - `QUICHE_INCLUDE_DIR`:                     Absolute path to quiche include directory.
index cc95a7d526cca79faf30d740d1a72e7f6ec88006..44311ec54e4ce8f3bbbbf9d1ad1426cf145dddaa 100644 (file)
@@ -135,6 +135,26 @@ fail:
   return CURLE_AUTH_ERROR;
 }
 
+#elif defined(USE_GNUTLS)
+#include <nettle/eddsa.h>
+
+CURLcode Curl_ed25519_sign(const unsigned char *key, size_t keylen,
+                           const unsigned char *msg, size_t msglen,
+                           unsigned char *sig, size_t *siglen)
+{
+  uint8_t pubkey[ED25519_KEY_SIZE];
+
+  if(keylen != ED25519_KEY_SIZE)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  nettle_ed25519_sha512_public_key(pubkey, key);
+
+  nettle_ed25519_sha512_sign(pubkey, key, msglen, msg, sig);
+  *siglen = CURL_ED25519_SIGLEN;
+
+  return CURLE_OK;
+}
+
 #else /* no Ed25519-capable backend */
 
 CURLcode Curl_ed25519_sign(const unsigned char *key, size_t keylen,
index 9da5cf6bd5c631145514ed87d74772e1e43a05b0..59012a1ab5d982617c1cfb7cb4959e17004a9f80 100644 (file)
@@ -199,5 +199,66 @@ if test "$GNUTLS_ENABLED" = "1"; then
   if test "$USE_GNUTLS_NETTLE" = "1"; then
     LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE nettle"
   fi
+
+  USE_GNUTLS_HOGWEED=
+  dnl First check if we can detect either crypto library via transitive linking
+  AC_CHECK_LIB(gnutls, nettle_ed25519_sha512_sign, [ USE_GNUTLS_HOGWEED=1 ])
+
+  dnl If not, try linking directly to both of them to see if they are available
+  if test -z "$USE_GNUTLS_HOGWEED"; then
+
+    dnl this is with no particular path given
+    CURL_CHECK_PKGCONFIG(hogweed)
+
+    if test "$PKGCONFIG" != "no"; then
+      addlib=`$PKGCONFIG --libs-only-l hogweed`
+      addld=`$PKGCONFIG --libs-only-L hogweed`
+      addcflags=`$PKGCONFIG --cflags-only-I hogweed`
+      version=`$PKGCONFIG --modversion hogweed`
+      gtlslib=`echo $addld | $SED -e 's/^-L//'`
+
+      if test -n "$addlib"; then
+
+        CLEANLIBS="$LIBS"
+        CLEANCPPFLAGS="$CPPFLAGS"
+        CLEANLDFLAGS="$LDFLAGS"
+        CLEANLDFLAGSPC="$LDFLAGSPC"
+
+        LIBS="$addlib $LIBS"
+        LDFLAGS="$LDFLAGS $addld"
+        LDFLAGSPC="$LDFLAGSPC $addld"
+        if test "$addcflags" != "-I/usr/include"; then
+          CPPFLAGS="$CPPFLAGS $addcflags"
+        fi
+
+        AC_CHECK_LIB(hogweed, nettle_ed25519_sha512_sign,
+        [
+          USE_GNUTLS_HOGWEED=1
+        ],
+        [
+          LIBS="$CLEANLIBS"
+          CPPFLAGS="$CLEANCPPFLAGS"
+          LDFLAGS="$CLEANLDFLAGS"
+          LDFLAGSPC="$CLEANLDFLAGSPC"
+        ])
+
+        if test "$USE_GNUTLS_HOGWEED" = "1"; then
+          if test -z "$version"; then
+            version="unknown"
+          fi
+          AC_MSG_NOTICE([detected hogweed version $version])
+        fi
+      fi
+    fi
+    if test -z "$USE_GNUTLS_HOGWEED"; then
+      AC_MSG_ERROR([GnuTLS found, but hogweed was not found])
+    fi
+  else
+    LIBS="-lhogweed $LIBS"
+  fi
+
+  if test "$USE_GNUTLS_HOGWEED" = "1"; then
+    LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE hogweed"
+  fi
 fi
 ])