From f92bf647df9409ca197eebb450ac5a9991332898 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 10 Sep 2026 18:45:00 -0700 Subject: [PATCH 01/11] internal: compile Ed25519 host keys without ECDSA The ID_ED25519 arm of SendKexGetSigningKey() sat inside the "#ifndef WOLFSSH_NO_ECDSA" block that precedes it, so a build with ECDSA off never compiled the case that decodes and hashes an Ed25519 host key. Close the ECDSA guard at the end of the ECDSA cases instead. --- src/internal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internal.c b/src/internal.c index 77382f50c..a0ca2ab90 100644 --- a/src/internal.c +++ b/src/internal.c @@ -16049,6 +16049,7 @@ static int SendKexGetSigningKey(WOLFSSH* ssh, sigKeyBlock_ptr->sk.ecc.qSz); } break; + #endif /* WOLFSSH_NO_ECDSA */ #ifndef WOLFSSH_NO_ED25519 case ID_ED25519: @@ -16117,8 +16118,7 @@ static int SendKexGetSigningKey(WOLFSSH* ssh, sigKeyBlock_ptr->sk.ed.q, sigKeyBlock_ptr->sk.ed.qSz); break; - #endif - #endif + #endif /* WOLFSSH_NO_ED25519 */ #ifndef WOLFSSH_NO_MLDSA #ifdef WOLFSSH_CERTS From b92861492c903d3eb13a95827fc111e88a0daf10 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 10 Sep 2026 18:45:00 -0700 Subject: [PATCH 02/11] internal: shift, not divide, in the GEX check mp_div_2() maps to sp_div_2(), which SP math compiles only for ECC, so the safe-prime check in ValidateKexDhGexGroup() fails to link when RSA and ECC are both off. mp_rshb() is unconditional and q is positive here, so the two do the same thing. --- src/internal.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/internal.c b/src/internal.c index a0ca2ab90..a6bfd0fa3 100644 --- a/src/internal.c +++ b/src/internal.c @@ -9228,10 +9228,14 @@ static int ValidateKexDhGexGroup(const byte* primeGroup, word32 primeGroupSz, } } - /* Safe prime check: q = (p - 1) / 2 must also be prime. */ + /* Safe prime check: q = (p - 1) / 2 must also be prime. mp_rshb() rather + * than mp_div_2(): the latter is an ECC-only entry point in SP math, and + * q is positive here, so the shift is the same operation. */ if (ret == WS_SUCCESS) { - if (mp_sub_d(&p, 1, &q) != MP_OKAY || mp_div_2(&q, &q) != MP_OKAY) + if (mp_sub_d(&p, 1, &q) != MP_OKAY) ret = WS_CRYPTO_FAILED; + else + mp_rshb(&q, 1); } if (ret == WS_SUCCESS) { isPrime = MP_NO; From c8b9d09adee2010005d0b7187f64c7505b0f29ee Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 10 Sep 2026 18:45:00 -0700 Subject: [PATCH 03/11] internal, ssh: quiet unused RSA-only locals Three locals feed only RSA and ECDSA code and draw -Werror warnings once both are compiled out. - digestSz in DoUserAuthRequestPublicKey(), read only by the RSA and ECDSA verify arms - heap in SendKexGetSigningKey(), used only where a key is allocated - the id parameter of CurveNameForId(), unread with no curve to name --- src/internal.c | 5 +++++ src/ssh.c | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/internal.c b/src/internal.c index a6bfd0fa3..ec4f21c89 100644 --- a/src/internal.c +++ b/src/internal.c @@ -11648,6 +11648,9 @@ static int DoUserAuthRequestPublicKey(WOLFSSH* ssh, WS_UserAuthData* authData, } } + /* Only the RSA and ECDSA arms above read the digest size; + * with both compiled out the switch is just the default. */ + WOLFSSH_UNUSED(digestSz); WS_FORCEZERO(digest, sizeof(digest)); } @@ -15736,6 +15739,8 @@ static int SendKexGetSigningKey(WOLFSSH* ssh, heap = ssh->ctx->heap; + /* Only the RSA, ECDSA and ML-DSA arms allocate; Ed25519 does not. */ + WOLFSSH_UNUSED(heap); #ifdef WOLFSSH_TPM ssh->handshake->useTpm = ssh->ctx->privateKey[keyIdx].isTpm; diff --git a/src/ssh.c b/src/ssh.c index 2afd0cab4..05e99d372 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -5494,6 +5494,8 @@ static const char* CurveNameForId(byte id) return "Curve25519"; #endif } +#else + WOLFSSH_UNUSED(id); #endif return ""; } From 49a431a34cd898213dd0ba11f9cc65223a127a11 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 10 Sep 2026 18:45:00 -0700 Subject: [PATCH 04/11] examples, tests: drop the WOLFSSH_NO_ECC guard Nothing defines WOLFSSH_NO_ECC, so every "#ifndef WOLFSSH_NO_ECC" block was always compiled and the sample ECC keys behind them reached their "#error" with no curve available. Use WOLFSSH_NO_ECDSA, which wolfssh/internal.h derives. - echoserver builds load_key() and its two default host keys only when RSA or ECDSA is there; the Ed25519 host key still loads - ECC_PATH moves inside that guard, its only reader - peerEcc is now read only by load_key(), so mark it used --- examples/client/common.c | 10 +++++----- examples/echoserver/echoserver.c | 16 +++++++++++----- tests/api.c | 2 +- tests/auth.c | 16 ++++++++-------- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/examples/client/common.c b/examples/client/common.c index c6d471ae1..3fd5305e8 100644 --- a/examples/client/common.c +++ b/examples/client/common.c @@ -222,7 +222,7 @@ static const unsigned int hanselPrivateRsaSz = 1191; #endif -#ifndef WOLFSSH_NO_ECC +#ifndef WOLFSSH_NO_ECDSA #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 static const char* hanselPublicEcc = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAA" @@ -1008,7 +1008,7 @@ int ClientSetPrivateKey(const char* privKeyName, int userEcc, (void)tpmKeyAuth; /* Not used */ if (privKeyName == NULL) { - #if defined(WOLFSSH_NO_RSA) && defined(WOLFSSH_NO_ECC) + #if defined(WOLFSSH_NO_RSA) && defined(WOLFSSH_NO_ECDSA) /* No built-in key to load. Leave the client to authenticate * some other way rather than failing here. */ userPrivateKeySz = 0; @@ -1017,7 +1017,7 @@ int ClientSetPrivateKey(const char* privKeyName, int userEcc, (void)heap; #else if (userEcc) { - #ifndef WOLFSSH_NO_ECC + #ifndef WOLFSSH_NO_ECDSA userPrivateKeySz = sizeof(userPrivateKeyBuf); ret = wolfSSH_ReadKey_buffer(hanselPrivateEcc, hanselPrivateEccSz, WOLFSSH_FORMAT_ASN1, &userPrivateKey, &userPrivateKeySz, @@ -1080,7 +1080,7 @@ int ClientUsePubKey(const char* pubKeyName, int userEcc, void* heap) int ret = 0; if (pubKeyName == NULL) { - #if defined(WOLFSSH_NO_RSA) && defined(WOLFSSH_NO_ECC) + #if defined(WOLFSSH_NO_RSA) && defined(WOLFSSH_NO_ECDSA) /* No built-in key to load. Leave the client to authenticate * some other way rather than failing here. */ userPublicKeySz = 0; @@ -1092,7 +1092,7 @@ int ClientUsePubKey(const char* pubKeyName, int userEcc, void* heap) userPublicKeySz = sizeof(userPublicKeyBuf); if (userEcc) { - #ifndef WOLFSSH_NO_ECC + #ifndef WOLFSSH_NO_ECDSA ret = wolfSSH_ReadKey_buffer((const byte*)hanselPublicEcc, (word32)strlen(hanselPublicEcc), WOLFSSH_FORMAT_SSH, &p, &userPublicKeySz, diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index d3ba00eb3..e40e607da 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -2284,6 +2284,7 @@ static int load_file(const char* fileName, byte* buf, word32* bufSz) } #endif /* NO_FILESYSTEM */ +#if !defined(WOLFSSH_NO_RSA) || !defined(WOLFSSH_NO_ECDSA) #ifdef WOLFSSH_NO_ECDSA_SHA2_NISTP256 #define ECC_PATH "./keys/server-key-ecc-521.der" #else @@ -2319,6 +2320,7 @@ static int load_key(byte isEcc, byte* buf, word32 bufSz) return sz; } +#endif /* !WOLFSSH_NO_RSA || !WOLFSSH_NO_ECDSA */ #ifndef WOLFSSH_NO_ED25519 /* returns buffer size on success */ @@ -2659,7 +2661,7 @@ static const char samplePasswordBuffer[] = "jack:fetchapail\n"; -#ifndef WOLFSSH_NO_ECC +#ifndef WOLFSSH_NO_ECDSA #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 static const char samplePublicKeyEccBuffer[] = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAA" @@ -3882,12 +3884,14 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) userEcc = 1; peerEcc = 1; #endif -#ifdef WOLFSSH_NO_ECC - /* If wolfCrypt isn't built with ECC, force ECC off. */ +#ifdef WOLFSSH_NO_ECDSA + /* If wolfCrypt isn't built with ECDSA, force ECC off. */ userEcc = 0; peerEcc = 0; #endif (void)userEcc; + /* Only load_key() reads it, and that is RSA/ECDSA only. */ + (void)peerEcc; if (wolfSSH_Init() != WS_SUCCESS) { ES_ERROR("Couldn't initialize wolfSSH.\n"); @@ -4130,6 +4134,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) #endif if (loadDefaultHostKeys) { + #if !defined(WOLFSSH_NO_RSA) || !defined(WOLFSSH_NO_ECDSA) bufSz = load_key(peerEcc, keyLoadBuf, bufSz); if (bufSz == 0) { #ifdef WOLFSSH_SMALL_STACK @@ -4147,7 +4152,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) ES_ERROR("Couldn't use first key buffer.\n"); } - #if !defined(WOLFSSH_NO_RSA) && !defined(WOLFSSH_NO_ECC) + #if !defined(WOLFSSH_NO_RSA) && !defined(WOLFSSH_NO_ECDSA) peerEcc = !peerEcc; bufSz = EXAMPLE_KEYLOAD_BUFFER_SZ; @@ -4168,6 +4173,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) ES_ERROR("Couldn't use second key buffer.\n"); } #endif + #endif /* !WOLFSSH_NO_RSA || !WOLFSSH_NO_ECDSA */ #ifndef WOLFSSH_NO_ED25519 bufSz = EXAMPLE_KEYLOAD_BUFFER_SZ; @@ -4301,7 +4307,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) LoadPasswordBuffer(keyLoadBuf, bufSz, &pwMapList); if (userEcc) { - #ifndef WOLFSSH_NO_ECC + #ifndef WOLFSSH_NO_ECDSA bufName = samplePublicKeyEccBuffer; #endif } diff --git a/tests/api.c b/tests/api.c index fa14cf980..c8c1e0d21 100644 --- a/tests/api.c +++ b/tests/api.c @@ -520,7 +520,7 @@ static void test_wolfSSH_CTX_UsePrivateKey_buffer(void) word32 lastKeySz = 0; int i; -#ifndef WOLFSSH_NO_ECC +#ifndef WOLFSSH_NO_ECDSA AssertIntEQ(0, ConvertHexToBin(serverKeyEccDer, &eccKey, &eccKeySz, NULL, NULL, NULL, diff --git a/tests/auth.c b/tests/auth.c index b8b63b7b6..c15490e56 100644 --- a/tests/auth.c +++ b/tests/auth.c @@ -365,7 +365,7 @@ static const unsigned int hanselPrivateRsaSz = (unsigned int)sizeof(hanselPrivat #endif /* WOLFSSH_NO_RSA */ /* Hansel's ECC keypair */ -#ifndef WOLFSSH_NO_ECC +#ifndef WOLFSSH_NO_ECDSA #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 static const char* hanselPublicEcc = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAA" @@ -438,7 +438,7 @@ static const unsigned int hanselPrivateEccSz = (unsigned int)sizeof(hanselPrivat #else #error "Enable nistp256, nistp384, nistp521, or disable ECC." #endif -#endif /* WOLFSSH_NO_ECC */ +#endif /* WOLFSSH_NO_ECDSA */ /* Server context: SHA256 hash of the authorized key/cert, and optional CA * cert for cert-based auth (NULL/0 for plain pubkey tests). */ @@ -1222,7 +1222,7 @@ static void test_pubkey_auth_rsacert_bad_sig(void) #endif /* WOLFSSH_CERTS && !WOLFSSH_NO_RSA && WOLFSSH_NO_SHA1_SOFT_DISABLE && !WOLFSSH_NO_SSH_RSA_SHA1 */ -#ifndef WOLFSSH_NO_ECC +#ifndef WOLFSSH_NO_ECDSA static void test_pubkey_auth_ecc(void) { PubkeyServerCtx sCtx = {0}; @@ -1320,9 +1320,9 @@ static void test_pubkey_auth_ecc_bad_sig(void) run_pubkey_test(&sCtx, &cCtx, WS_FATAL_ERROR); } -#endif /* WOLFSSH_NO_ECC */ +#endif /* WOLFSSH_NO_ECDSA */ -#if !defined(WOLFSSH_NO_RSA) && !defined(WOLFSSH_NO_ECC) +#if !defined(WOLFSSH_NO_RSA) && !defined(WOLFSSH_NO_ECDSA) /* Negative test: server authorises the RSA key but client presents the ECC key. * The unauthorised key must be rejected. */ @@ -1376,7 +1376,7 @@ static void test_pubkey_auth_wrong_key(void) * wrap inner errors as WS_FATAL_ERROR at the API boundary */ run_pubkey_test(&sCtx, &cCtx, WS_FATAL_ERROR); } -#endif /* !WOLFSSH_NO_RSA && !WOLFSSH_NO_ECC */ +#endif /* !WOLFSSH_NO_RSA && !WOLFSSH_NO_ECDSA */ #if !defined(WOLFSSH_NO_MLDSA) && !defined(WOLFSSH_NO_MLDSA44) && \ defined(WOLFSSL_MLDSA_PRIVATE_KEY) && !defined(WOLFSSL_MLDSA_NO_ASN1) && \ @@ -2445,11 +2445,11 @@ int wolfSSH_AuthTest(int argc, char** argv) test_pubkey_auth_rsacert_bad_sig(); #endif #endif -#ifndef WOLFSSH_NO_ECC +#ifndef WOLFSSH_NO_ECDSA test_pubkey_auth_ecc(); test_pubkey_auth_ecc_bad_sig(); #endif -#if !defined(WOLFSSH_NO_RSA) && !defined(WOLFSSH_NO_ECC) +#if !defined(WOLFSSH_NO_RSA) && !defined(WOLFSSH_NO_ECDSA) test_pubkey_auth_wrong_key(); #endif #if !defined(WOLFSSH_NO_ED25519) && defined(HAVE_ED25519) && \ From 767cb86ef6146dfa8ad6be4cda445412678eb70a Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 10 Sep 2026 18:45:00 -0700 Subject: [PATCH 05/11] tests: build the Ed25519 cases without ECDSA The Ed25519 key DER helpers arrive through asn.h, which unit.c includes only for RSA, and the host key that test_wolfSSH_SetAlgoList() installs came only in RSA and ECDSA flavors. - include wolfssl/wolfcrypt/asn_public.h unconditionally in unit.c - add ./keys/server-key-ed25519.der to api.c as the last host key fallback --- tests/api.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ tests/unit.c | 4 +++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/tests/api.c b/tests/api.c index c8c1e0d21..51e291d08 100644 --- a/tests/api.c +++ b/tests/api.c @@ -461,6 +461,14 @@ static const byte serverKeyEccCurveId = ID_ECDSA_SHA2_NISTP521; #endif #endif +/* ./keys/server-key-ed25519.der */ +#ifndef WOLFSSH_NO_ED25519 +static const char serverKeyEd25519Der[] = + "3050020100300506032b6570042204206a67f30e64ea52fef4ad654d45606138" + "58110784f0039493147b7b331abaf61981200f560c9f7d7a6287f026161931e4" + "b21de9bdee4a7f55ae262da125e4ee4a5100"; +#endif + #ifndef WOLFSSH_NO_RSA static const char serverKeyRsaDer[] = "308204a30201000282010100da5dad2514761559f340fd3cb86230b36dc0f9ec" @@ -515,6 +523,11 @@ static void test_wolfSSH_CTX_UsePrivateKey_buffer(void) #ifndef WOLFSSH_NO_RSA byte* rsaKey; word32 rsaKeySz; +#endif +#ifndef WOLFSSH_NO_ED25519 + byte* ed25519Key; + word32 ed25519KeySz; + word32 ed25519Idx; #endif const byte* lastKey = NULL; word32 lastKeySz = 0; @@ -534,6 +547,13 @@ static void test_wolfSSH_CTX_UsePrivateKey_buffer(void) NULL, NULL, NULL, NULL, NULL, NULL)); #endif +#ifndef WOLFSSH_NO_ED25519 + AssertIntEQ(0, + ConvertHexToBin(serverKeyEd25519Der, &ed25519Key, &ed25519KeySz, + NULL, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL)); +#endif AssertNotNull(ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL)); for (i = 0; i < WOLFSSH_MAX_PVT_KEYS; i++) { @@ -618,6 +638,26 @@ static void test_wolfSSH_CTX_UsePrivateKey_buffer(void) AssertIntNE(lastKeySz, ctx->privateKey[0].keySz); #endif +#ifndef WOLFSSH_NO_ED25519 + /* Ed25519 may land in any slot, so track the index rather than + * assuming 0. In an Ed25519-only build this is the only key the test + * loads successfully. */ + ed25519Idx = ctx->privateKeyCount; + lastKey = ctx->privateKey[ed25519Idx].key; + lastKeySz = ctx->privateKey[ed25519Idx].keySz; + + AssertIntEQ(WS_SUCCESS, + wolfSSH_CTX_UsePrivateKey_buffer(ctx, ed25519Key, ed25519KeySz, + TEST_GOOD_FORMAT_ASN1)); + AssertIntEQ(ed25519Idx + 1, ctx->privateKeyCount); + AssertNotNull(ctx->privateKey[ed25519Idx].key); + AssertIntNE(0, ctx->privateKey[ed25519Idx].keySz); + AssertIntEQ(ID_ED25519, ctx->privateKey[ed25519Idx].publicKeyFmt); + + AssertIntEQ(0, (lastKey == ctx->privateKey[ed25519Idx].key)); + AssertIntNE(lastKeySz, ctx->privateKey[ed25519Idx].keySz); +#endif + /* Add the same keys again. This should succeed. */ #if !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) || \ !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) || \ @@ -631,6 +671,11 @@ static void test_wolfSSH_CTX_UsePrivateKey_buffer(void) wolfSSH_CTX_UsePrivateKey_buffer(ctx, rsaKey, rsaKeySz, TEST_GOOD_FORMAT_ASN1)); #endif +#ifndef WOLFSSH_NO_ED25519 + AssertIntEQ(WS_SUCCESS, + wolfSSH_CTX_UsePrivateKey_buffer(ctx, ed25519Key, ed25519KeySz, + TEST_GOOD_FORMAT_ASN1)); +#endif wolfSSH_CTX_free(ctx); #if !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) || \ @@ -641,6 +686,9 @@ static void test_wolfSSH_CTX_UsePrivateKey_buffer(void) #ifndef WOLFSSH_NO_RSA FreeBins(rsaKey, NULL, NULL, NULL); #endif +#ifndef WOLFSSH_NO_ED25519 + FreeBins(ed25519Key, NULL, NULL, NULL); +#endif #endif /* NO_WOLFSSH_SERVER */ } @@ -7489,6 +7537,8 @@ static void test_wolfSSH_SetAlgoList(void) rawKey = serverKeyEccDer; #elif !defined(WOLFSSH_NO_RSA) rawKey = serverKeyRsaDer; +#elif !defined(WOLFSSH_NO_ED25519) + rawKey = serverKeyEd25519Der; #endif AssertNotNull(rawKey); AssertIntEQ(0, diff --git a/tests/unit.c b/tests/unit.c index e8ddc1d2a..29292e1dd 100644 --- a/tests/unit.c +++ b/tests/unit.c @@ -42,6 +42,9 @@ #include #include #endif +/* The Ed25519 key DER helpers arrive with asn.h, but that include is RSA-only + * and the Ed25519 tests do not need RSA. */ +#include #define WOLFSSH_TEST_HEX2BIN #include @@ -56,7 +59,6 @@ defined(WOLFSSL_CERT_GEN) && !defined(WOLFSSH_NO_ECDSA) && \ !defined(NO_FILESYSTEM) #define WOLFSSH_TEST_CERTMAN_PROMOTE - #include #include #endif From 2feab94af4b1899606741a65142ff4bae656b14b Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 15 Sep 2026 15:09:54 -0700 Subject: [PATCH 06/11] internal: guard PrimeNameForId on ECDSA alone PrimeNameForId() is called only from the three ECDSA paths, so it now sits in its own WOLFSSH_NO_ECDSA block. wcPrimeForId() keeps the wider "ECDSA or ECDH" condition that its curve lookups still need. --- src/internal.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/internal.c b/src/internal.c index ec4f21c89..5d95174f4 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6400,7 +6400,10 @@ int wcPrimeForId(byte id) return ECC_CURVE_INVALID; } } +#endif /* !WOLFSSH_NO_ECDSA || !WOLFSSH_NO_ECDH */ + +#ifndef WOLFSSH_NO_ECDSA static INLINE const char *PrimeNameForId(byte id) { switch (id) { From 6ec1e05db7efcf9dfd1765b1771ec201967d64ba Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 15 Sep 2026 15:09:54 -0700 Subject: [PATCH 07/11] internal: decode DER Ed25519 user auth keys PrepareUserAuthRequestEd25519() tries wc_Ed25519PrivateKeyDecode() and falls back to the OpenSSH container only when that decode fails, as the RSA and ECDSA paths do. A private-only DER gets its public key derived the way SendKexGetSigningKey() does, or is rejected when it cannot be. --- src/internal.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/src/internal.c b/src/internal.c index 5d95174f4..b2f7ebd85 100644 --- a/src/internal.c +++ b/src/internal.c @@ -21297,9 +21297,46 @@ static int PrepareUserAuthRequestEd25519(WOLFSSH* ssh, word32* payloadSz, else #endif { - ret = GetOpenSshKey(keySig, - authData->sf.publicKey.privateKey, - authData->sf.publicKey.privateKeySz, &idx); + int derRet; + + /* As in the RSA and ECDSA paths, try DER first and fall back to + * the OpenSSH container. Only a decode failure falls back; a + * derive failure keeps its own error. */ + derRet = wc_Ed25519PrivateKeyDecode( + authData->sf.publicKey.privateKey, &idx, + &keySig->ks.ed25519.key, + authData->sf.publicKey.privateKeySz); + + if (derRet != 0) { + idx = 0; + ret = GetOpenSshKey(keySig, + authData->sf.publicKey.privateKey, + authData->sf.publicKey.privateKeySz, &idx); + } + else { + ret = WS_SUCCESS; + + if (!keySig->ks.ed25519.key.pubKeySet) { + #ifdef HAVE_ED25519_MAKE_KEY + /* Priv-only DER: derive the public key from the seed, + * the way SendKexGetSigningKey() does for a host key. */ + byte q[ED25519_PUB_KEY_SIZE]; + + ret = wc_ed25519_make_public(&keySig->ks.ed25519.key, + q, (word32)sizeof(q)); + if (ret == 0) { + /* trusted=1: q came from this key's own scalar. */ + ret = wc_ed25519_import_public_ex(q, + ED25519_PUB_KEY_SIZE, + &keySig->ks.ed25519.key, 1); + } + #else + /* Nothing to derive it with; reject here rather than + * failing inside wc_ed25519_sign_msg(). */ + ret = WS_KEY_FORMAT_E; + #endif /* HAVE_ED25519_MAKE_KEY */ + } + } } } From a7ede492b8a8769a114d387689efc161c547e05f Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 15 Sep 2026 15:09:54 -0700 Subject: [PATCH 08/11] tests: run the Ed25519 pubkey test without ECDSA test_pubkey_auth_ed25519_privonly_hostkey() authenticates with an Ed25519 user key rather than hansel's ECDSA key, so it covers Ed25519 user auth alongside the host key derive fallback and needs no ECDSA. - load_key() falls back to the Ed25519 host key when neither RSA nor ECDSA is available - guard run_pubkey_test() on RSA or ECDSA, its only callers --- tests/auth.c | 56 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/tests/auth.c b/tests/auth.c index c15490e56..01ee216b7 100644 --- a/tests/auth.c +++ b/tests/auth.c @@ -216,7 +216,21 @@ static int load_key(byte isEcc, byte* buf, word32 bufSz) { word32 sz = 0; +#if defined(WOLFSSH_NO_RSA) && defined(WOLFSSH_NO_ECDSA) && \ + !defined(WOLFSSH_NO_ED25519) + /* Neither key this picks between is compiled in; Ed25519 is what is + * left, and the server threads need some host key to offer. */ + (void)isEcc; #ifndef NO_FILESYSTEM + sz = load_file("./keys/server-key-ed25519.der", buf, &bufSz); +#else + if ((word32)sizeof_ed25519_key_der_ssh > bufSz) { + return 0; + } + WMEMCPY(buf, ed25519_key_der_ssh, sizeof_ed25519_key_der_ssh); + sz = (word32)sizeof_ed25519_key_der_ssh; +#endif +#elif !defined(NO_FILESYSTEM) const char* bufName; bufName = isEcc ? ECC_PATH : "./keys/server-key-rsa.der"; sz = load_file(bufName, buf, &bufSz); @@ -440,6 +454,23 @@ static const unsigned int hanselPrivateEccSz = (unsigned int)sizeof(hanselPrivat #endif #endif /* WOLFSSH_NO_ECDSA */ +#if !defined(WOLFSSH_NO_ED25519) && defined(HAVE_ED25519) && \ + defined(HAVE_ED25519_MAKE_KEY) && defined(HAVE_ED25519_KEY_EXPORT) +static const char* hanselPublicEd25519 = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHTSoBZIJBO2V0Jb2OWyMWNbkD" + "d6ReDfKxnrAPlbPuCe hansel"; +/* PKCS#8 Ed25519 private key with no public key attribute, the pair to + * hanselPublicEd25519. */ +static const byte hanselPrivateEd25519[] = { + 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, + 0x04, 0x22, 0x04, 0x20, 0x28, 0xc6, 0xe9, 0xd8, 0x37, 0x4d, 0x0c, 0x52, + 0x7e, 0x5f, 0xb3, 0x4c, 0x81, 0xe8, 0x68, 0xee, 0xc9, 0x7c, 0xad, 0x00, + 0xad, 0xa0, 0xe3, 0xe2, 0x13, 0x06, 0x55, 0xf1, 0x17, 0xf1, 0x0a, 0xf0 +}; +static const unsigned int hanselPrivateEd25519Sz = + (unsigned int)sizeof(hanselPrivateEd25519); +#endif /* !WOLFSSH_NO_ED25519 && HAVE_ED25519_MAKE_KEY */ + /* Server context: SHA256 hash of the authorized key/cert, and optional CA * cert for cert-based auth (NULL/0 for plain pubkey tests). */ typedef struct PubkeyServerCtx { @@ -677,12 +708,15 @@ static int run_pubkey_test_ex(PubkeyServerCtx* sCtx, PubkeyClientCtx* cCtx, return WS_SUCCESS; } -/* Existing callers all want the default fixture host key. */ +/* Existing callers all want the default fixture host key, and every one of + * them is an RSA or ECDSA test. */ +#if !defined(WOLFSSH_NO_RSA) || !defined(WOLFSSH_NO_ECDSA) static int run_pubkey_test(PubkeyServerCtx* sCtx, PubkeyClientCtx* cCtx, int expect) { return run_pubkey_test_ex(sCtx, cCtx, expect, NULL, 0); } +#endif #ifndef WOLFSSH_NO_RSA static void test_pubkey_auth_rsa(void) @@ -1420,11 +1454,12 @@ static void test_pubkey_load_mldsa_privonly_hostkey(void) * && !WOLFSSL_MLDSA_NO_ASN1 && !WOLFSSL_MLDSA_NO_MAKE_KEY */ #if !defined(WOLFSSH_NO_ED25519) && defined(HAVE_ED25519) && \ - defined(HAVE_ED25519_MAKE_KEY) && defined(HAVE_ED25519_KEY_EXPORT) && \ - !defined(WOLFSSH_NO_ECDSA) + defined(HAVE_ED25519_MAKE_KEY) && defined(HAVE_ED25519_KEY_EXPORT) /* End-to-end regression test for ID_ED25519 derive-fallback in * SendKexGetSigningKey. Tests a real handshake using a private-only - * Ed25519 host key to ensure wolfSSH correctly derives the public key. */ + * Ed25519 host key to ensure wolfSSH correctly derives the public key. + * The user key is Ed25519 as well, so the whole exchange runs on a build + * with neither RSA nor ECDSA compiled in. */ static void test_pubkey_auth_ed25519_privonly_hostkey(void) { PubkeyServerCtx sCtx = {0}; @@ -1457,14 +1492,14 @@ static void test_pubkey_auth_ed25519_privonly_hostkey(void) wc_ed25519_free(&edKey); AssertIntGT(hostKeyDerSz, 0); - AssertIntEQ(wolfSSH_ReadKey_buffer((const byte*)hanselPublicEcc, - (word32)WSTRLEN(hanselPublicEcc), WOLFSSH_FORMAT_SSH, + AssertIntEQ(wolfSSH_ReadKey_buffer((const byte*)hanselPublicEd25519, + (word32)WSTRLEN(hanselPublicEd25519), WOLFSSH_FORMAT_SSH, &p, &pubKeySz, &pubKeyType, &pubKeyTypeSz, NULL), WS_SUCCESS); AssertIntEQ(wc_Sha256Hash(pubKeyBuf, pubKeySz, sCtx.hash), 0); - AssertIntEQ(wolfSSH_ReadKey_buffer(hanselPrivateEcc, hanselPrivateEccSz, - WOLFSSH_FORMAT_ASN1, + AssertIntEQ(wolfSSH_ReadKey_buffer(hanselPrivateEd25519, + hanselPrivateEd25519Sz, WOLFSSH_FORMAT_ASN1, &privKeyPtr, &privKeySz, &privKeyType, &privKeyTypeSz, NULL), WS_SUCCESS); @@ -1478,7 +1513,7 @@ static void test_pubkey_auth_ed25519_privonly_hostkey(void) run_pubkey_test_ex(&sCtx, &cCtx, WS_SUCCESS, hostKeyDer, (word32)hostKeyDerSz); } -#endif /* !WOLFSSH_NO_ED25519 && HAVE_ED25519_MAKE_KEY && !WOLFSSH_NO_ECDSA */ +#endif /* !WOLFSSH_NO_ED25519 && HAVE_ED25519_MAKE_KEY */ #if !defined(WOLFSSH_NO_ECDSA) && !defined(WOLFSSH_NO_RSA) && \ defined(HAVE_ECC_KEY_EXPORT) @@ -2453,8 +2488,7 @@ int wolfSSH_AuthTest(int argc, char** argv) test_pubkey_auth_wrong_key(); #endif #if !defined(WOLFSSH_NO_ED25519) && defined(HAVE_ED25519) && \ - defined(HAVE_ED25519_MAKE_KEY) && defined(HAVE_ED25519_KEY_EXPORT) && \ - !defined(WOLFSSH_NO_ECDSA) + defined(HAVE_ED25519_MAKE_KEY) && defined(HAVE_ED25519_KEY_EXPORT) test_pubkey_auth_ed25519_privonly_hostkey(); #endif #if !defined(WOLFSSH_NO_ECDSA) && !defined(WOLFSSH_NO_RSA) && \ From 53814839bb043f73750de2b678be2035aca83c4a Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 15 Sep 2026 15:09:54 -0700 Subject: [PATCH 09/11] echoserver: add Ed25519 sample public keys The example server loads hansel's and gretel's Ed25519 public keys when neither RSA nor ECDSA is compiled in, so public key auth works there instead of falling back to passwords. That arm is the "#if" and the userEcc choice the "#else", so no empty if/else is left behind. --- examples/echoserver/echoserver.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index e40e607da..76156bd47 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -2705,6 +2705,17 @@ static const char samplePublicKeyEccBuffer[] = #endif /* WOLFSSH_TPM */ #endif /* WOLFSSH_NO_RSA */ +/* Ed25519 is the only signing algorithm left when neither RSA nor ECDSA + * is compiled in, so the server needs sample keys of its own. */ +#if defined(WOLFSSH_NO_RSA) && defined(WOLFSSH_NO_ECDSA) && \ + !defined(WOLFSSH_NO_ED25519) +static const char samplePublicKeyEd25519Buffer[] = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHTSoBZIJBO2V0Jb2OWyMWNbkD" + "d6ReDfKxnrAPlbPuCe hansel\n" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFD8Bwir++gzNJmif9ooAZdaRi" + "sFZjlp9XU2seaec7/m gretel\n"; +#endif + #ifdef WOLFSSH_ALLOW_USERAUTH_NONE static const char sampleNoneBuffer[] = @@ -4306,6 +4317,13 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) keyLoadBuf[bufSz] = 0; LoadPasswordBuffer(keyLoadBuf, bufSz, &pwMapList); + #if defined(WOLFSSH_NO_RSA) && defined(WOLFSSH_NO_ECDSA) + /* Ed25519 is the only sample key left, so -e has nothing to pick + * between and is ignored. */ + #ifndef WOLFSSH_NO_ED25519 + bufName = samplePublicKeyEd25519Buffer; + #endif + #else if (userEcc) { #ifndef WOLFSSH_NO_ECDSA bufName = samplePublicKeyEccBuffer; @@ -4320,6 +4338,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) #endif #endif } + #endif if (bufName != NULL) { bufSz = (word32)WSTRLEN(bufName); WMEMCPY(keyLoadBuf, bufName, bufSz); From 49f07314d685f836ece7611f93a26ad3233b3b89 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 15 Sep 2026 19:56:50 -0700 Subject: [PATCH 10/11] examples, keys: add an Ed25519 user credential The sample clients load hansel's Ed25519 key when neither RSA nor ECDSA is compiled in, so public key auth reaches the echoserver's matching sample keys instead of sending a request carrying no key. - commit keys/{hansel,gretel}-key-ed25519.{der,pem,pub}, the pair to the echoserver's sample authorized keys - ClientUserAuth() fails a publickey request with no key loaded, so the library can offer another method --- examples/client/common.c | 50 ++++++++++++++++++++++++++++++++++-- keys/gretel-key-ed25519.der | Bin 0 -> 48 bytes keys/gretel-key-ed25519.pem | 3 +++ keys/gretel-key-ed25519.pub | 1 + keys/hansel-key-ed25519.der | Bin 0 -> 48 bytes keys/hansel-key-ed25519.pem | 3 +++ keys/hansel-key-ed25519.pub | 1 + keys/include.am | 2 ++ 8 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 keys/gretel-key-ed25519.der create mode 100644 keys/gretel-key-ed25519.pem create mode 100644 keys/gretel-key-ed25519.pub create mode 100644 keys/hansel-key-ed25519.der create mode 100644 keys/hansel-key-ed25519.pem create mode 100644 keys/hansel-key-ed25519.pub diff --git a/examples/client/common.c b/examples/client/common.c index 3fd5305e8..9e8e9d22e 100644 --- a/examples/client/common.c +++ b/examples/client/common.c @@ -275,6 +275,23 @@ static const unsigned int hanselPrivateEccSz = 223; #endif #endif +/* The pair in keys/hansel-key-ed25519.*, the only built-in user key left + * when both RSA and ECDSA are compiled out. */ +#if defined(WOLFSSH_NO_RSA) && defined(WOLFSSH_NO_ECDSA) && \ + !defined(WOLFSSH_NO_ED25519) +static const char* hanselPublicEd25519 = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHTSoBZIJBO2V0Jb2OWyMWNbkD" + "d6ReDfKxnrAPlbPuCe hansel"; +static const byte hanselPrivateEd25519[] = { + 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, + 0x04, 0x22, 0x04, 0x20, 0x28, 0xc6, 0xe9, 0xd8, 0x37, 0x4d, 0x0c, 0x52, + 0x7e, 0x5f, 0xb3, 0x4c, 0x81, 0xe8, 0x68, 0xee, 0xc9, 0x7c, 0xad, 0x00, + 0xad, 0xa0, 0xe3, 0xe2, 0x13, 0x06, 0x55, 0xf1, 0x17, 0xf1, 0x0a, 0xf0 +}; +static const unsigned int hanselPrivateEd25519Sz = + (unsigned int)sizeof(hanselPrivateEd25519); +#endif + #if defined(WOLFSSH_CERTS) @@ -476,6 +493,13 @@ int ClientUserAuth(byte authType, if (authType == WOLFSSH_USERAUTH_PUBLICKEY) { WS_UserAuthData_PublicKey* pk = &authData->sf.publicKey; + if (userPublicKeyType == NULL || userPublicKeySz == 0) { + /* Nothing to sign with. SendUserAuthRequest() turns this + * into WS_FATAL_ERROR rather than putting an untyped + * publickey request on the wire. */ + return WOLFSSH_USERAUTH_FAILURE; + } + pk->publicKeyType = userPublicKeyType; pk->publicKeyTypeSz = userPublicKeyTypeSz; pk->publicKey = userPublicKey; @@ -1009,12 +1033,21 @@ int ClientSetPrivateKey(const char* privKeyName, int userEcc, if (privKeyName == NULL) { #if defined(WOLFSSH_NO_RSA) && defined(WOLFSSH_NO_ECDSA) + (void)userEcc; + #ifndef WOLFSSH_NO_ED25519 + userPrivateKeySz = sizeof(userPrivateKeyBuf); + ret = wolfSSH_ReadKey_buffer(hanselPrivateEd25519, + hanselPrivateEd25519Sz, WOLFSSH_FORMAT_ASN1, + &userPrivateKey, &userPrivateKeySz, + &userPrivateKeyType, &userPrivateKeyTypeSz, heap); + isPrivate = 1; + #else /* No built-in key to load. Leave the client to authenticate * some other way rather than failing here. */ userPrivateKeySz = 0; userPrivateKeyType = NULL; - (void)userEcc; (void)heap; + #endif #else if (userEcc) { #ifndef WOLFSSH_NO_ECDSA @@ -1081,12 +1114,25 @@ int ClientUsePubKey(const char* pubKeyName, int userEcc, void* heap) if (pubKeyName == NULL) { #if defined(WOLFSSH_NO_RSA) && defined(WOLFSSH_NO_ECDSA) + (void)userEcc; + #ifndef WOLFSSH_NO_ED25519 + { + byte* p = userPublicKey; + + userPublicKeySz = sizeof(userPublicKeyBuf); + ret = wolfSSH_ReadKey_buffer((const byte*)hanselPublicEd25519, + (word32)strlen(hanselPublicEd25519), WOLFSSH_FORMAT_SSH, + &p, &userPublicKeySz, + &userPublicKeyType, &userPublicKeyTypeSz, heap); + isPrivate = 1; + } + #else /* No built-in key to load. Leave the client to authenticate * some other way rather than failing here. */ userPublicKeySz = 0; userPublicKeyType = NULL; - (void)userEcc; (void)heap; + #endif #else byte* p = userPublicKey; userPublicKeySz = sizeof(userPublicKeyBuf); diff --git a/keys/gretel-key-ed25519.der b/keys/gretel-key-ed25519.der new file mode 100644 index 0000000000000000000000000000000000000000..4ee73f8bef824be5af6c42388db91524d184b99b GIT binary patch literal 48 zcmXreV`5}5U}a<0PAyaY2{y<7C_Z%IPm`PwO(h{LT1qZ{e=09qT*m^;j%o E0AF_z?EnA( literal 0 HcmV?d00001 diff --git a/keys/gretel-key-ed25519.pem b/keys/gretel-key-ed25519.pem new file mode 100644 index 000000000..b322e776c --- /dev/null +++ b/keys/gretel-key-ed25519.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIEHo0C0B8ZM9j3mX6D3LLQLp+wHhvXG6eriviX8uBDhc +-----END PRIVATE KEY----- diff --git a/keys/gretel-key-ed25519.pub b/keys/gretel-key-ed25519.pub new file mode 100644 index 000000000..b172de693 --- /dev/null +++ b/keys/gretel-key-ed25519.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFD8Bwir++gzNJmif9ooAZdaRisFZjlp9XU2seaec7/m gretel diff --git a/keys/hansel-key-ed25519.der b/keys/hansel-key-ed25519.der new file mode 100644 index 0000000000000000000000000000000000000000..ee8603afb6808f925ad78e388bc89aa634f39ea2 GIT binary patch literal 48 zcmV-00MGw0E&>4nFa-t!D`jv5A_O2P#_8BMO$<_gU$abs=xFZAe60YjpyT2b237GF G@e1%+UlMx& literal 0 HcmV?d00001 diff --git a/keys/hansel-key-ed25519.pem b/keys/hansel-key-ed25519.pem new file mode 100644 index 000000000..2d2a8432f --- /dev/null +++ b/keys/hansel-key-ed25519.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEICjG6dg3TQxSfl+zTIHoaO7JfK0AraDj4hMGVfEX8Qrw +-----END PRIVATE KEY----- diff --git a/keys/hansel-key-ed25519.pub b/keys/hansel-key-ed25519.pub new file mode 100644 index 000000000..825818260 --- /dev/null +++ b/keys/hansel-key-ed25519.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHTSoBZIJBO2V0Jb2OWyMWNbkDd6ReDfKxnrAPlbPuCe hansel diff --git a/keys/include.am b/keys/include.am index e465ee7ec..db10dd306 100644 --- a/keys/include.am +++ b/keys/include.am @@ -16,6 +16,8 @@ EXTRA_DIST+= \ keys/gretel-key-ecc-384.der keys/gretel-key-ecc-384.pem keys/gretel-key-ecc-384.pub \ keys/gretel-key-ecc-521.der keys/gretel-key-ecc-521.pem keys/gretel-key-ecc-521.pub \ keys/gretel-key-rsa.der keys/gretel-key-rsa.pem keys/gretel-key-rsa.pub \ + keys/hansel-key-ed25519.der keys/hansel-key-ed25519.pem keys/hansel-key-ed25519.pub \ + keys/gretel-key-ed25519.der keys/gretel-key-ed25519.pem keys/gretel-key-ed25519.pub \ keys/pubkeys-ecc.txt keys/pubkeys-ecc-384.txt keys/pubkeys-ecc-521.txt \ keys/pubkeys-rsa.txt keys/passwd.txt keys/ca-cert-ecc.der \ keys/ca-cert-ecc.pem keys/ca-key-ecc.der keys/ca-key-ecc.pem \ From 817be0d074a2732a9a9b9de01b5706541004aefe Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 16 Sep 2026 09:48:17 -0700 Subject: [PATCH 11/11] ci: build and test without RSA or ECC os-check builds a wolfSSL with neither, then wolfssh against it, so the Ed25519-only paths are exercised. That wolfSSL line names two things the short option list does not imply: --enable-ed25519-stream, which wolfSSH needs to keep Ed25519, and --enable-base64encode, which the ssh client app needs and which defaults off away from x86_64. --- .github/workflows/os-check.yml | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index 8de9a277b..9d39e60d5 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -142,3 +142,39 @@ jobs: set -o pipefail LD_LIBRARY_PATH=${{ github.workspace }}/build-dir/lib ./tests/unit.test | tee unit-test.log grep "ScpSendCallback_ExactFitBuffer: SUCCESS" unit-test.log + + build_wolfssh_no_rsa_ecc: + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, macos-latest ] + name: Build and test wolfssh without RSA or ECC + runs-on: ${{ matrix.os }} + timeout-minutes: 16 + steps: + # Not the cached --enable-all wolfSSL: this job needs one with no RSA + # and no ECC. Ed25519 is then the only signing algorithm wolfSSH has, + # and wolfssh/internal.h wants WOLFSSL_ED25519_STREAMING_VERIFY with + # it, so --enable-ed25519-stream is required, not optional. The ssh + # client app needs Base64_Encode_NoNl(), which nothing else in this + # short list pulls in, hence --enable-base64encode. + - name: Checkout, build, and install wolfssl + uses: wolfSSL/actions-build-autotools-project@v1 + with: + repository: wolfssl/wolfssl + ref: master + path: wolfssl + configure: >- + --enable-ssh --enable-ed25519 --enable-ed25519-stream + --enable-curve25519 --enable-aesctr --enable-base64encode + --disable-rsa --disable-ecc --disable-dsa --disable-mldsa + check: false + install: true + + - name: Checkout, build, and test wolfssh + uses: wolfSSL/actions-build-autotools-project@v1 + with: + repository: wolfssl/wolfssh + path: wolfssh + configure: --enable-keyboard-interactive --enable-sftp --enable-scp --enable-sshclient LDFLAGS="-L${{ github.workspace }}/build-dir/lib" CPPFLAGS="-I${{ github.workspace }}/build-dir/include" + check: true