curl_ed25519: add GnuTLS support (via nettle, hogweed)

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: 4353ea025a

Closes #22456
This commit is contained in:
Viktor Szakats 2026-08-01 00:45:57 +02:00
parent 56457f838c
commit a368fbe968
No known key found for this signature in database
7 changed files with 101 additions and 15 deletions

View 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

View file

@ -25,19 +25,21 @@
#
# 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)

View 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()

View 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

View 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.

View 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,

View 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
])