diff --git a/openssh-patches/openssh-10.5p1.patch b/openssh-patches/openssh-10.5p1.patch new file mode 100644 index 00000000..46b2d8e7 --- /dev/null +++ b/openssh-patches/openssh-10.5p1.patch @@ -0,0 +1,467 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Juliusz Sosinowicz +Date: Tue, 1 Sep 2026 12:48:07 +0000 +Subject: [PATCH] 10.5p1 patch for wolfSSL + +This patch was implemented and tested on OpenSSH version 10.5p1. + +Compile wolfSSL with: + ./configure --enable-openssh + make + make install + +Compile OpenSSH with + patch -p1 < + autoreconf + ./configure --with-wolfssl + make + +Running the OpenSSH tests requires wolfSSL to be configured using + ./configure --enable-openssh --enable-dsa --with-max-rsa-bits=8192 +and it is recommended to configure OpenSSH with + ./configure --with-wolfssl --with-rpath='-Wl,-rpath=' +to resolve issues with missing library paths. With the above modifications +OpenSSH should pass all tests run with: +``` +make tests +``` +--- + Makefile.in | 1 + + cipher-aesctr.h | 4 + + cipher.c | 3 +- + configure.ac | 171 +++++++++++++++++++++++++++- + includes.h | 12 ++ + log.c | 54 +++++++++ + openbsd-compat/openssl-compat.c | 4 + + regress/unittests/test_helper/test_helper.c | 6 + + sshkey.c | 8 ++ + 9 files changed, 260 insertions(+), 3 deletions(-) + +diff --git a/Makefile.in b/Makefile.in +index e9503e7..3a469cd 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -835,6 +835,7 @@ interop-tests t-exec file-tests extra-tests: regress-prep regress-binaries $(TAR + .CURDIR="$(abs_top_srcdir)/regress" \ + .OBJDIR="$(BUILDDIR)/regress" \ + BUILDDIR="$(BUILDDIR)" \ ++ ENABLE_WOLFSSL="@ENABLE_WOLFSSL@" \ + OBJ="$(BUILDDIR)/regress" \ + PATH="$(BUILDDIR):$${PATH}" \ + TEST_ENV=MALLOC_OPTIONS="@TEST_MALLOC_OPTIONS@" \ +diff --git a/cipher-aesctr.h b/cipher-aesctr.h +index 85d55bb..9776fb3 100644 +--- a/cipher-aesctr.h ++++ b/cipher-aesctr.h +@@ -20,7 +20,11 @@ + + #include "rijndael.h" + ++/* wolfSSL and OpenSSL both define this, and neither guards it. Only supply ++ * it when building against neither. */ ++#ifndef AES_BLOCK_SIZE + #define AES_BLOCK_SIZE 16 ++#endif + + typedef struct aesctr_ctx { + int rounds; /* keylen-dependent #rounds */ +diff --git a/cipher.c b/cipher.c +index 0697e55..4401c72 100644 +--- a/cipher.c ++++ b/cipher.c +@@ -386,7 +386,8 @@ cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest, + return SSH_ERR_INVALID_ARGUMENT; + if (EVP_Cipher(cc->evp, dest + aadlen, (u_char *)src + aadlen, + len) < 0) +- return SSH_ERR_LIBCRYPTO_ERROR; ++ return cc->encrypt ? ++ SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID; + if (authlen) { + /* compute tag (on encrypt) or verify tag (on decrypt) */ + if (EVP_Cipher(cc->evp, NULL, NULL, 0) < 0) +diff --git a/configure.ac b/configure.ac +index cb1711f..64ac43e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -690,6 +690,7 @@ SHLIBEXT=".so" + need_pledge_inet="" + + # Check for some target-specific stuff ++WOLFSSL_ADD_LIBPTHREAD_SSHD=0 + case "$host" in + *-*-aix*) + # Some versions of VAC won't allow macro redefinitions at +@@ -970,6 +971,7 @@ int main(void) { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) + no_dev_ptmx=1 + use_pie=auto + check_for_openpty_ctty_bug=1 ++ WOLFSSL_ADD_LIBPTHREAD_SSHD=1 + dnl Target SUSv3/POSIX.1-2001 plus BSD specifics. + dnl _DEFAULT_SOURCE is the new name for _BSD_SOURCE + dnl _GNU_SOURCE is needed for setres*id prototypes. +@@ -2943,6 +2945,145 @@ AC_CHECK_FUNCS([getpgrp],[ + ) + ]) + ++WOLFSSL_URL="https://www.wolfssl.com/download/" ++ENABLE_WOLFSSL="no" ++AC_ARG_WITH(wolfssl, ++ [ --with-wolfssl=PATH PATH to wolfssl install (default /usr/local) ], ++ [ ++ # --without-wolfssl reaches here too, with withval=no. Leave wolfSSL ++ # off in that case and let the OpenSSL checks below run. ++ if test "x${withval}" != "xno" ; then ++ ++ wolfssl_install_dir=/usr/local ++ ++ if test "x${withval}" != "xyes" ; then ++ wolfssl_install_dir=${withval} ++ fi ++ ++ if test -d "${wolfssl_install_dir}/lib"; then ++ if test -n "${rpath_opt}"; then ++ LDFLAGS="-L${wolfssl_install_dir}/lib ${rpath_opt}${wolfssl_install_dir}/lib ${LDFLAGS}" ++ else ++ LDFLAGS="-L${wolfssl_install_dir}/lib ${LDFLAGS}" ++ fi ++ else ++ AC_MSG_ERROR([wolfSSL: lib directory not found at ${wolfssl_install_dir}]) ++ fi ++ if test -d "${wolfssl_install_dir}/include"; then ++ if test -d "${wolfssl_install_dir}/include/wolfssl"; then ++ CPPFLAGS="$CPPFLAGS -I${wolfssl_install_dir}/include -I${wolfssl_install_dir}/include/wolfssl" ++ else ++ AC_MSG_ERROR([wolfSSL: include/wolfssl directory not found at ${wolfssl_install_dir}]) ++ fi ++ else ++ AC_MSG_ERROR([wolfSSL: include directory not found at ${wolfssl_install_dir}]) ++ fi ++ ++ AC_MSG_CHECKING([for wolfSSL]) ++ LIBS="$LIBS -lwolfssl" ++ ++ AC_TRY_LINK_FUNC([wolfSSL_Init], , ++ [ ++ AC_MSG_ERROR([wolfSSL isn't found. You can get it from $WOLFSSL_URL ++ ++ If it's already installed, specify its path using --with-wolfssl=/dir/]) ++ ] ++ ) ++ ++ AC_MSG_RESULT([yes]) ++ ENABLE_WOLFSSL="yes" ++ RAND_MSG="WolfSSL Internal" ++ AC_DEFINE([USING_WOLFSSL], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([WOLFSSL_USE_OPTIONS_H], [1], ++ [Let wolfSSL headers pull in options.h themselves]) ++ AC_DEFINE([WITH_OPENSSL], [1], ++ [Build the OpenSSL-compatible crypto paths. Named for OpenSSL, ++ but satisfied here by wolfSSL's compatibility layer.]) ++ AC_DEFINE([UNSUPPORTED_POSIX_THREADS_HACK], [1], [Defined if using WolfSSL]) ++ # OpenSSL tests for these. Just assume these are present for wolfSSL. ++ AC_DEFINE([HAVE_BN_IS_PRIME_EX], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_SHA256_UPDATE], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_CRYPT], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_DES_CRYPT], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_DSA_GENERATE_PARAMETERS_EX], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_EVP_DIGESTFINAL_EX], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_EVP_DIGESTINIT_EX], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_EVP_MD_CTX_CLEANUP], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_EVP_MD_CTX_INIT], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_EVP_SHA256], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_HMAC_CTX_INIT], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_RSA_GENERATE_KEY_EX], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_RSA_GET_DEFAULT_METHOD], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_OPENSSL_VERSION], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_EVP_CIPHER_CTX_CTRL], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_EVP_CIPHER_CTX_SET_IV], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_EVP_RIPEMD160], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_EVP_SHA384], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_EVP_SHA512], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_OPENSSL_VERSION_NUM], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_EVP_CIPHER_CTX_GET_IV], [1], [Defined if using WolfSSL]) ++ ++ # Dummy RSA method functions ++ AC_DEFINE([HAVE_RSA_METH_SET_PRIV_ENC], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_RSA_METH_SET_PRIV_DEC], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_RSA_METH_SET_PUB_ENC], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_RSA_METH_SET_PUB_DEC], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_RSA_METH_SET_FINISH], [1], [Defined if using WolfSSL]) ++ AC_DEFINE([HAVE_EVP_PKEY_GET0_RSA], [1], [Defined if using WolfSSL]) ++ ++ AC_MSG_CHECKING([is wolfSSL FIPS]) ++ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ ++ #include ++ #ifndef HAVE_FIPS ++ # error macro not defined ++ #endif ++ ]])], [ wolfssl_fips=yes ], [ wolfssl_fips=no ]) ++ if test "x$wolfssl_fips" = "xyes" ; then ++ AC_DEFINE([USING_WOLFSSL_FIPS], [1], [Defined if using wolfSSL FIPS]) ++ AC_MSG_RESULT([yes]) ++ else ++ AC_MSG_RESULT([no]) ++ fi ++ ++ # Leave in place in case we use this in the future, AC_COMPILE_IFELSE works ++ # for now. ++ #AC_CHECK_LIB([wolfssl], [wc_wolfHasAesni], [ wolf_has_aesni=yes ], [ wolf_has_aesni=no ]) ++ AC_MSG_CHECKING([is wolfssl configured with aesni]) ++ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ ++ #include ++ #ifndef WOLFSSL_AESNI ++ # error macro not defined ++ #endif ++ ]])], [ wolf_has_aesni=yes ], [ wolf_has_aesni=no ]) ++ ++ if test "x$wolf_has_aesni" = "xyes" ; then ++ AC_MSG_RESULT([yes]) ++ AC_MSG_CHECKING([is gcc compiler detected]) ++ if test "$GCC" = "yes" ++ then ++ AC_MSG_RESULT([yes]) ++ AC_MSG_CHECKING([is compiler set to icc]) ++ if test "$CC" != "icc" ++ then ++ AC_MSG_RESULT([not icc, add flags -maes and -msse4]) ++ CFLAGS="$CFLAGS -maes -msse4" ++ else ++ AC_MSG_RESULT([using icc compiler. Do not add -maes and -msse4]) ++ fi ++ else ++ AC_MSG_RESULT([no gcc]) ++ fi ++ else ++ AC_MSG_RESULT([no]) ++ fi ++ ++ fi ++]) ++ ++AC_SUBST([ENABLE_WOLFSSL]) ++ ++if test "x$ENABLE_WOLFSSL" = "xno"; then ++ + # Search for OpenSSL + saved_CPPFLAGS="$CPPFLAGS" + saved_LDFLAGS="$LDFLAGS" +@@ -3367,6 +3508,12 @@ if test "x$openssl" = "xyes" ; then + + fi + ++else ++ AC_CHECK_LIB([crypt], [crypt], [LIBS="$LIBS -lcrypt"]) ++ AC_CHECK_FUNCS([crypt]) ++fi # ENABLE_WOLFSSL endif ++ ++ + # PKCS11/U2F depend on OpenSSL and dlopen(). + enable_pkcs11=yes + enable_sk=yes +@@ -3374,6 +3521,15 @@ enable_sk=yes + if test "x$openssl_impl" = "xaws-lc"; then + enable_pkcs11="disabled; PKCS#11 not supported with AWS-LC" + fi ++if test "x$ENABLE_WOLFSSL" = "xyes" && test "x$wolfssl_fips" = "xyes" ; then ++ enable_sk="disabled; wolfSSL FIPS doesn't support all needed OpenSSL functions" ++fi ++if test "x$openssl" != "xyes" && test "x$ENABLE_WOLFSSL" != "xyes" ; then ++ enable_pkcs11="disabled; missing libcrypto" ++fi ++if test "x$ENABLE_WOLFSSL" = "xyes" ; then ++ enable_pkcs11="disabled; wolfSSL doesn't support the METH API used to implement PKCS#11" ++fi + if test "x$ac_cv_func_dlopen" != "xyes" ; then + enable_pkcs11="disabled; missing dlopen(3)" + enable_sk="disabled; missing dlopen(3)" +@@ -3592,12 +3748,19 @@ elif test ! -z "$OPENSSL_SEEDS_ITSELF" ; then + AC_DEFINE([OPENSSL_PRNG_ONLY], [1], + [Define if you want the OpenSSL internally seeded PRNG only]) + RAND_MSG="OpenSSL internal ONLY" +-elif test "x$openssl" = "xno" ; then ++elif test "x$ENABLE_WOLFSSL" = "xyes"; then ++ AC_MSG_WARN([OpenSSH will use /dev/urandom or /dev/random as a source of random numbers. It will fail if both devices are not supported or accessible]) ++elif test "x$openssl" = "xno"; then + AC_MSG_WARN([OpenSSH will use /dev/urandom as a source of random numbers. It will fail if this device is not supported or accessible]) + else + AC_MSG_ERROR([OpenSSH has no source of random numbers. Please configure OpenSSL with an entropy source or re-run configure using one of the --with-prngd-port or --with-prngd-socket options]) + fi +-LIBS="$nocrypto_saved_LIBS" ++ ++# Upstream restores here, after the entropy probes above have used -lcrypto. ++# wolfSSL builds keep theirs, since -lwolfssl has to stay on the link line. ++if test "x$ENABLE_WOLFSSL" != "xyes" ; then ++ LIBS="$nocrypto_saved_LIBS" ++fi + + saved_LIBS="$LIBS" + AC_CHECK_LIB([iaf], [ia_openinfo], [ +@@ -3639,6 +3802,9 @@ AC_ARG_WITH([pam], + PAM_MSG="yes" + + SSHDLIBS="$SSHDLIBS -lpam" ++ if test "x$WOLFSSL_ADD_LIBPTHREAD_SSHD" = "x1" ; then ++ SSHDLIBS="$SSHDLIBS -lpthread" ++ fi + AC_DEFINE([USE_PAM], [1], + [Define if you want to enable PAM support]) + +@@ -5883,6 +6049,7 @@ echo " Solaris privilege support: $SPP_MSG" + echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" + echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" + echo " BSD Auth support: $BSD_AUTH_MSG" ++echo " WolfSSL support: $ENABLE_WOLFSSL" + echo " Random number source: $RAND_MSG" + echo " Privsep sandbox style: $SANDBOX_STYLE" + echo " PKCS#11 support: $enable_pkcs11" +diff --git a/includes.h b/includes.h +index 96cddbc..1fdbe63 100644 +--- a/includes.h ++++ b/includes.h +@@ -169,6 +169,18 @@ + # endif + #endif + ++#ifdef USING_WOLFSSL ++#include ++#include ++/* OpenSSH's sandbox blocks /dev/urandom. Make sure wolfSSL can seed its DRBG ++ * without it. */ ++#if !defined(HAVE_INTEL_RDSEED) && !defined(HAVE_AMD_RDSEED) && \ ++ !defined(WOLFSSL_GETRANDOM) && !defined(HAVE_GETRANDOM) && \ ++ !defined(WOLFSSL_SEED_SOURCE_IS_SANDBOX_SAFE) ++#error "No sandbox-safe RNG seed source. Build wolfSSL with rdseed or getrandom(2) support, or define WOLFSSL_SEED_SOURCE_IS_SANDBOX_SAFE if your seed source works inside OpenSSH's sandbox." ++#endif ++#endif ++ + #ifdef WITH_OPENSSL + #include /* For OPENSSL_VERSION_NUMBER */ + #endif +diff --git a/log.c b/log.c +index 2903871..fcea66a 100644 +--- a/log.c ++++ b/log.c +@@ -186,6 +186,43 @@ log_verbose_reset(void) + nlog_verbose = 0; + } + ++static void Logging_cb(const int logLevel, const char *const logMessage) { ++ (void)logLevel; ++ debug("wolfSSL: %s", logMessage); ++} ++ ++/* getrandom(2) is the only seed source that survives the sandbox the ++ * privsep child runs under. Without it, leave wolfSSL on its default. */ ++#if defined(WC_RNG_SEED_CB) && defined(HAVE_GETRANDOM) ++#include ++static int wolf_seed(OS_Seed* os, byte* output, word32 sz) ++{ ++ int ret = 0; ++ (void)os; ++ ++ while (sz) { ++ int len; ++ ++ errno = 0; ++ len = (int)getrandom(output, sz, 0); ++ if (len == -1) { ++ if (errno == EINTR) { ++ /* interrupted, call getrandom again */ ++ continue; ++ } ++ else { ++ ret = READ_RAN_E; ++ } ++ break; ++ } ++ ++ sz -= len; ++ output += len; ++ } ++ return ret; ++} ++#endif ++ + /* + * Initialize the log. + */ +@@ -200,6 +237,23 @@ log_init(const char *av0, LogLevel level, SyslogFacility facility, + + argv0 = av0; + ++ /* hijack log init callback since every ssh program calls it ++ * to make sure wolfssl is inited and has a seed callback registered */ ++#ifdef USING_WOLFSSL ++ /* Follow the level the caller asked for rather than logging ++ * unconditionally. No-op unless wolfSSL was built with DEBUG_WOLFSSL. */ ++ if (level >= SYSLOG_LEVEL_DEBUG1) ++ wolfSSL_Debugging_ON(); ++ wolfSSL_SetLoggingCb(Logging_cb); ++ wolfSSL_Init(); ++#ifndef WC_RNG_SEED_CB ++#error wolfSSL needs to be built with WC_RNG_SEED_CB ++#endif ++#ifdef HAVE_GETRANDOM ++ wc_SetSeed_Cb(wolf_seed); ++#endif ++#endif ++ + if (log_change_level(level) != 0) { + fprintf(stderr, "Unrecognized internal syslog level code %d\n", + (int) level); +diff --git a/openbsd-compat/openssl-compat.c b/openbsd-compat/openssl-compat.c +index e0cd472..17ebe32 100644 +--- a/openbsd-compat/openssl-compat.c ++++ b/openbsd-compat/openssl-compat.c +@@ -75,6 +75,10 @@ ssh_libcrypto_init(void) + uint64_t opts = OPENSSL_INIT_ADD_ALL_CIPHERS | + OPENSSL_INIT_ADD_ALL_DIGESTS; + ++#ifdef USING_WOLFSSL ++ wolfSSL_Init(); ++#endif ++ + #ifdef USE_OPENSSL_ENGINE + /* Enable use of crypto hardware */ + ENGINE_load_builtin_engines(); +diff --git a/regress/unittests/test_helper/test_helper.c b/regress/unittests/test_helper/test_helper.c +index 898732d..83ca769 100644 +--- a/regress/unittests/test_helper/test_helper.c ++++ b/regress/unittests/test_helper/test_helper.c +@@ -202,6 +202,12 @@ main(int argc, char **argv) + exit(1); + } + } ++#ifdef USING_WOLFSSL ++ /* After getopt so it follows -v/-q. */ ++ if (verbose_mode) ++ wolfSSL_Debugging_ON(); ++#endif ++ + setvbuf(stdout, NULL, _IONBF, 0); + if (!quiet_mode) + printf("%s: ", __progname); +diff --git a/sshkey.c b/sshkey.c +index a590529..b0fc010 100644 +--- a/sshkey.c ++++ b/sshkey.c +@@ -2696,8 +2696,16 @@ sshkey_ec_validate_public(const EC_GROUP *group, const EC_POINT *public) + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } ++#ifdef USING_WOLFSSL ++ /* wolfSSL does not expose EC_GROUP_get_cofactor. It only supports ++ * NIST P-256/P-384/P-521, all of which have cofactor 1; per ++ * NIST SP 800-56A 5.6.2.3 the cofactor check below becomes a no-op. */ ++ if (!BN_one(cofactor)) ++ goto out; ++#else + if (EC_GROUP_get_cofactor(group, cofactor, NULL) != 1) + goto out; ++#endif + + /* + * Verify nQ == infinity (n == order of subgroup) +-- +2.43.0 +