diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index 97d3accfa..5c1c4fddd 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -2315,7 +2315,10 @@ static void ShowUsage(void) #ifdef WOLFSSH_CERTS printf(" -a load in a root CA certificate file\n"); #endif - printf(" -k set the list of key algos to use\n"); + printf(" -k set the comma separated list of key algos to use\n"); + printf(" -x set the comma separated list of key exchange algos " + "to use\n"); + printf(" -m set the comma separated list of mac algos to use\n"); printf(" -b test user auth would block\n"); } @@ -2356,6 +2359,8 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) word32 defaultHighwater = EXAMPLE_HIGHWATER_MARK; word32 threadCount = 0; const char* keyList = NULL; + const char* kexList = NULL; + const char* macList = NULL; ES_HEAP_HINT* heap = NULL; int multipleConnections = 1; int userEcc = 0; @@ -2378,7 +2383,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) serverArgs->return_code = EXIT_SUCCESS; if (argc > 0) { - const char* optlist = "?1a:d:efEp:R:Ni:j:I:J:K:P:k:b:"; + const char* optlist = "?1a:d:efEp:R:Ni:j:I:J:K:P:k:b:x:m:"; myoptind = 0; while ((ch = mygetopt(argc, argv, optlist)) != -1) { switch (ch) { @@ -2466,6 +2471,14 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) userAuthWouldBlock = atoi(myoptarg); break; + case 'x': + kexList = myoptarg; + break; + + case 'm': + macList = myoptarg; + break; + default: ShowUsage(); serverArgs->return_code = MY_EX_USAGE; @@ -2524,6 +2537,18 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) } } + if (kexList) { + if (wolfSSH_CTX_SetAlgoListKex(ctx, kexList) != WS_SUCCESS) { + ES_ERROR("Error setting kex list.\n"); + } + } + + if (macList) { + if (wolfSSH_CTX_SetAlgoListMac(ctx, macList) != WS_SUCCESS) { + ES_ERROR("Error setting mac list.\n"); + } + } + WMEMSET(&pwMapList, 0, sizeof(pwMapList)); if (serverArgs->user_auth == NULL) wolfSSH_SetUserAuth(ctx, wsUserAuth); diff --git a/src/internal.c b/src/internal.c index 7b2a78e61..d0ed0879b 100644 --- a/src/internal.c +++ b/src/internal.c @@ -93,6 +93,9 @@ WOLFSSH_NO_HMAC_SHA2_256 Set when HMAC or SHA2-256 are disabled. Set to disable HMAC-SHA2-256 support. + WOLFSSH_NO_HMAC_SHA2_512 + Set when HMAC or SHA2-512 are disabled. Set to disable HMAC-SHA2-512 + support. WOLFSSH_NO_DH_GROUP1_SHA1 Set when DH or SHA1 are disabled. Set to disable use of DH (Oakley 1) and SHA1 support. @@ -102,6 +105,9 @@ WOLFSSH_NO_DH_GROUP14_SHA256 Set when DH or SHA256 are disabled. Set to disable use of DH (Oakley 14) and SHA256 support. + WOLFSSH_NO_DH_GROUP16_SHA512 + Set when DH or SHA512 are disabled. Set to disable use of DH (Oakley 16) + and SHA512 support. WOLFSSH_NO_DH_GEX_SHA256 Set when DH or SHA2-256 are disabled. Set to disable use of DH group exchange and SHA2-256 support. @@ -690,6 +696,9 @@ static const char cannedKexAlgoNames[] = #if !defined(WOLFSSH_NO_DH_GROUP14_SHA256) "diffie-hellman-group14-sha256," #endif +#if !defined(WOLFSSH_NO_DH_GROUP16_SHA512) + "diffie-hellman-group16-sha512," +#endif #if !defined(WOLFSSH_NO_DH_GEX_SHA256) "diffie-hellman-group-exchange-sha256," #endif @@ -797,6 +806,9 @@ static const char cannedMacAlgoNames[] = #if !defined(WOLFSSH_NO_HMAC_SHA2_256) "hmac-sha2-256," #endif +#if !defined(WOLFSSH_NO_HMAC_SHA2_512) + "hmac-sha2-512," +#endif #if defined(WOLFSSH_NO_SHA1_SOFT_DISABLE) #if !defined(WOLFSSH_NO_HMAC_SHA1_96) "hmac-sha1-96," @@ -2445,6 +2457,9 @@ static const NameIdPair NameIdMap[] = { #ifndef WOLFSSH_NO_HMAC_SHA2_256 { ID_HMAC_SHA2_256, TYPE_MAC, "hmac-sha2-256" }, #endif +#ifndef WOLFSSH_NO_HMAC_SHA2_512 + { ID_HMAC_SHA2_512, TYPE_MAC, "hmac-sha2-512" }, +#endif /* Key Exchange IDs */ #ifndef WOLFSSH_NO_DH_GROUP1_SHA1 @@ -2456,6 +2471,9 @@ static const NameIdPair NameIdMap[] = { #ifndef WOLFSSH_NO_DH_GROUP14_SHA256 { ID_DH_GROUP14_SHA256, TYPE_KEX, "diffie-hellman-group14-sha256" }, #endif +#ifndef WOLFSSH_NO_DH_GROUP16_SHA512 + { ID_DH_GROUP16_SHA512, TYPE_KEX, "diffie-hellman-group16-sha512" }, +#endif #ifndef WOLFSSH_NO_DH_GEX_SHA256 { ID_DH_GEX_SHA256, TYPE_KEX, "diffie-hellman-group-exchange-sha256" }, #endif @@ -3625,6 +3643,10 @@ static INLINE byte MacSzForId(byte id) #ifndef WOLFSSH_NO_HMAC_SHA2_256 case ID_HMAC_SHA2_256: return WC_SHA256_DIGEST_SIZE; +#endif +#ifndef WOLFSSH_NO_HMAC_SHA2_512 + case ID_HMAC_SHA2_512: + return WC_SHA512_DIGEST_SIZE; #endif default: return 0; @@ -3647,6 +3669,10 @@ static INLINE byte KeySzForId(byte id) case ID_HMAC_SHA2_256: return WC_SHA256_DIGEST_SIZE; #endif +#ifndef WOLFSSH_NO_HMAC_SHA2_512 + case ID_HMAC_SHA2_512: + return WC_SHA512_DIGEST_SIZE; +#endif #ifndef WOLFSSH_NO_AES_CBC case ID_AES128_CBC: return AES_128_KEY_SIZE; @@ -3759,6 +3785,10 @@ enum wc_HashType HashForId(byte id) #endif return WC_HASH_TYPE_SHA512; #endif +#ifndef WOLFSSH_NO_DH_GROUP16_SHA512 + case ID_DH_GROUP16_SHA512: + return WC_HASH_TYPE_SHA512; +#endif #ifndef WOLFSSH_NO_RSA_SHA2_512 case ID_RSA_SHA2_512: return WC_HASH_TYPE_SHA512; @@ -4349,6 +4379,76 @@ static const byte dhPrimeGroup14[] = { static const word32 dhPrimeGroup14Sz = (word32)sizeof(dhPrimeGroup14); #endif +#ifndef WOLFSSH_NO_DH_GROUP16_SHA512 +static const byte dhPrimeGroup16[] = { + /* SSH DH Group 16 (Oakley Group 16, 4096-bit MODP Group, RFC 3526) */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, + 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, + 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, + 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, + 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, + 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, + 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, + 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, + 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, + 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, + 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, + 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, + 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, + 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, + 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, + 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, + 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, + 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, + 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, + 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, + 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, + 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, + 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, + 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, + 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, + 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, + 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, + 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, + 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, + 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, + 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, + 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, + 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, + 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, + 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, + 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, + 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, + 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; +static const word32 dhPrimeGroup16Sz = (word32)sizeof(dhPrimeGroup16); +#endif static int DoKexDhInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) { @@ -9249,6 +9349,27 @@ static INLINE int CreateMac(WOLFSSH* ssh, const byte* in, word32 inSz, } break; +#ifndef WOLFSSH_NO_HMAC_SHA2_512 + case ID_HMAC_SHA2_512: + { + Hmac hmac; + + ret = wc_HmacInit(&hmac, ssh->ctx->heap, INVALID_DEVID); + if (ret == WS_SUCCESS) + ret = wc_HmacSetKey(&hmac, WC_SHA512, + ssh->keys.macKey, + ssh->keys.macKeySz); + if (ret == WS_SUCCESS) + ret = wc_HmacUpdate(&hmac, flatSeq, sizeof(flatSeq)); + if (ret == WS_SUCCESS) + ret = wc_HmacUpdate(&hmac, in, inSz); + if (ret == WS_SUCCESS) + ret = wc_HmacFinal(&hmac, mac); + wc_HmacFree(&hmac); + } + break; +#endif + default: WLOG(WS_LOG_DEBUG, "Invalid Mac ID"); ret = WS_FATAL_ERROR; @@ -9311,6 +9432,19 @@ static INLINE int VerifyMac(WOLFSSH* ssh, const byte* in, word32 inSz, ret = WS_VERIFY_MAC_E; break; + case ID_HMAC_SHA2_512: + ret = wc_HmacSetKey(&hmac, WC_SHA512, ssh->peerKeys.macKey, + ssh->peerKeys.macKeySz); + if (ret == WS_SUCCESS) + ret = wc_HmacUpdate(&hmac, flatSeq, sizeof(flatSeq)); + if (ret == WS_SUCCESS) + ret = wc_HmacUpdate(&hmac, in, inSz); + if (ret == WS_SUCCESS) + ret = wc_HmacFinal(&hmac, checkMac); + if (ConstantCompare(checkMac, mac, ssh->peerMacSz) != 0) + ret = WS_VERIFY_MAC_E; + break; + default: ret = WS_INVALID_ALGO_ID; } @@ -10077,6 +10211,8 @@ struct wolfSSH_sigKeyBlockFull { /* Size of Kyber public key (bigger than ciphertext) and some extra for the * ECC hybrid component. */ #define KEX_F_SIZE 1024 +#elif !defined(WOLFSSH_NO_DH_GROUP16_SHA512) + #define KEX_F_SIZE (512 + 1) #else #define KEX_F_SIZE (256 + 1) #endif @@ -10216,6 +10352,14 @@ static int GetDHPrimeGroup(int kexId, const byte** primeGroup, *generatorSz = dhGeneratorSz; break; #endif + #ifndef WOLFSSH_NO_DH_GROUP16_SHA512 + case ID_DH_GROUP16_SHA512: + *primeGroup = dhPrimeGroup16; + *primeGroupSz = dhPrimeGroup16Sz; + *generator = dhGenerator; + *generatorSz = dhGeneratorSz; + break; + #endif #ifndef WOLFSSH_NO_DH_GEX_SHA256 case ID_DH_GEX_SHA256: *primeGroup = dhPrimeGroup14; @@ -11500,6 +11644,12 @@ int SendKexDhReply(WOLFSSH* ssh) msgId = MSGID_KEXDH_REPLY; break; #endif +#ifndef WOLFSSH_NO_DH_GROUP16_SHA512 + case ID_DH_GROUP16_SHA512: + useDh = 1; + msgId = MSGID_KEXDH_REPLY; + break; +#endif #ifndef WOLFSSH_NO_DH_GEX_SHA256 case ID_DH_GEX_SHA256: useDh = 1; @@ -12069,6 +12219,15 @@ int SendKexDhInit(WOLFSSH* ssh) generatorSz = dhGeneratorSz; break; #endif +#ifndef WOLFSSH_NO_DH_GROUP16_SHA512 + case ID_DH_GROUP16_SHA512: + ssh->handshake->useDh = 1; + primeGroup = dhPrimeGroup16; + primeGroupSz = dhPrimeGroup16Sz; + generator = dhGenerator; + generatorSz = dhGeneratorSz; + break; +#endif #ifndef WOLFSSH_NO_DH_GEX_SHA256 case ID_DH_GEX_SHA256: ssh->handshake->useDh = 1; diff --git a/src/ssh.c b/src/ssh.c index 4fdff0c77..1d0bb5b5d 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -2921,6 +2921,9 @@ static const char* MacNameForId(byte macid, byte cipherid) case ID_HMAC_SHA2_256: return "HMAC-SHA-256"; + + case ID_HMAC_SHA2_512: + return "HMAC-SHA-512"; } } else { @@ -3010,6 +3013,11 @@ size_t wolfSSH_GetText(WOLFSSH *ssh, WS_Text id, char *str, size_t strSz) ssh->primeGroupSz*8, 14); break; + case ID_DH_GROUP16_SHA512: + ret = WSNPRINTF(str, strSz, standard_dh_format, + ssh->primeGroupSz*8, 16); + break; + case ID_DH_GEX_SHA256: ret = WSNPRINTF(str, strSz, "%d-bit Diffie-Hellman with server-supplied group", diff --git a/tests/include.am b/tests/include.am index e8b1b548e..78f814655 100644 --- a/tests/include.am +++ b/tests/include.am @@ -3,9 +3,9 @@ # All paths should be given relative to the root check_PROGRAMS += tests/unit.test tests/api.test \ - tests/testsuite.test + tests/testsuite.test tests/kex.test noinst_PROGRAMS += tests/unit.test tests/api.test \ - tests/testsuite.test + tests/testsuite.test tests/kex.test tests_unit_test_SOURCES = tests/unit.c tests/unit.h tests_unit_test_CPPFLAGS = -DNO_MAIN_DRIVER @@ -100,3 +100,36 @@ tests_testsuite_test_CPPFLAGS += -DWOLFSSH_CERTS endif tests_testsuite_test_LDADD = src/libwolfssh.la tests_testsuite_test_DEPENDENCIES = src/libwolfssh.la + +tests_kex_test_SOURCES = tests/kex.c tests/kex.h \ + examples/echoserver/echoserver.c \ + examples/client/client.c \ + examples/client/common.c \ + examples/client/common.h +tests_kex_test_CPPFLAGS = -DNO_MAIN_DRIVER +if BUILD_KEYGEN +tests_kex_test_CPPFLAGS += -DWOLFSSH_KEYGEN +endif +if BUILD_SCP +tests_kex_test_CPPFLAGS += -DWOLFSSH_SCP +endif +if BUILD_SFTP +tests_kex_test_CPPFLAGS += -DWOLFSSH_SFTP +endif +if BUILD_TERM +tests_kex_test_CPPFLAGS += -DWOLFSSH_TERM +endif +if BUILD_SHELL +tests_kex_test_CPPFLAGS += -DWOLFSSH_SHELL +endif +if BUILD_AGENT +tests_kex_test_CPPFLAGS += -DWOLFSSH_AGENT +endif +if BUILD_FWD +tests_kex_test_CPPFLAGS += -DWOLFSSH_FWD +endif +if BUILD_CERTS +tests_kex_test_CPPFLAGS += -DWOLFSSH_CERTS +endif +tests_kex_test_LDADD = src/libwolfssh.la +tests_kex_test_DEPENDENCIES = src/libwolfssh.la diff --git a/tests/kex.c b/tests/kex.c new file mode 100644 index 000000000..3fb667ca5 --- /dev/null +++ b/tests/kex.c @@ -0,0 +1,313 @@ +/* kex.c + * + * Copyright (C) 2025 wolfSSL Inc. + * + * This file is part of wolfSSH. + * + * wolfSSH is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSH 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfSSH. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifdef WOLFSSL_USER_SETTINGS + #include +#else + #include +#endif + +#define WOLFSSH_TEST_CLIENT +#define WOLFSSH_TEST_SERVER +#ifndef SINGLE_THREADED + #define WOLFSSH_TEST_THREADING +#endif +#define WOLFSSH_TEST_LOCKING + +#include +#include +#include +#include +#include "examples/echoserver/echoserver.h" +#include "examples/client/client.h" +#include "tests/kex.h" + +#ifdef HAVE_FIPS + #include +#endif + + +#ifndef WOLFSSH_NO_ABORT + #define WABORT() abort() +#else + #define WABORT() +#endif + +#define PrintError(description, result) do { \ + printf("\nERROR - %s line %d failed with:", __FILE__, __LINE__); \ + printf("\n expected: "); printf description; \ + printf("\n result: "); printf result; printf("\n\n"); \ +} while(0) + +#ifdef WOLFSSH_ZEPHYR +#define Fail(description, result) do { \ + PrintError(description, result); \ + WABORT(); \ +} while(0) +#else +#define Fail(description, result) do { \ + PrintError(description, result); \ + WFFLUSH(stdout); \ + WABORT(); \ +} while(0) +#endif + +#define Assert(test, description, result) if (!(test)) Fail(description, result) + +#define AssertTrue(x) Assert( (x), ("%s is true", #x), (#x " => FALSE")) +#define AssertFalse(x) Assert(!(x), ("%s is false", #x), (#x " => TRUE")) +#define AssertNotNull(x) Assert( (x), ("%s is not null", #x), (#x " => NULL")) + +#define AssertNull(x) do { \ + PEDANTIC_EXTENSION void* _x = (void*)(x); \ + \ + Assert(!_x, ("%s is null", #x), (#x " => %p", _x)); \ +} while(0) + +#define AssertInt(x, y, op, er) do { \ + int _x = (int)(x); \ + int _y = (int)(y); \ + Assert(_x op _y, ("%s " #op " %s", #x, #y), ("%d " #er " %d", _x, _y)); \ +} while(0) + +#define AssertIntEQ(x, y) AssertInt(x, y, ==, !=) +#define AssertIntNE(x, y) AssertInt(x, y, !=, ==) +#define AssertIntGT(x, y) AssertInt(x, y, >, <=) +#define AssertIntLT(x, y) AssertInt(x, y, <, >=) +#define AssertIntGE(x, y) AssertInt(x, y, >=, <) +#define AssertIntLE(x, y) AssertInt(x, y, <=, >) + +#define AssertStr(x, y, op, er) do { \ + const char* _x = (const char*)(x); \ + const char* _y = (const char*)(y); \ + int _z = (_x && _y) ? strcmp(_x, _y) : -1; \ + Assert(_z op 0, ("%s " #op " %s", #x, #y), \ + ("\"%s\" " #er " \"%s\"", _x, _y));\ +} while(0) + +#define AssertStrEQ(x, y) AssertStr(x, y, ==, !=) +#define AssertStrNE(x, y) AssertStr(x, y, !=, ==) +#define AssertStrGT(x, y) AssertStr(x, y, >, <=) +#define AssertStrLT(x, y) AssertStr(x, y, <, >=) +#define AssertStrGE(x, y) AssertStr(x, y, >=, <) +#define AssertStrLE(x, y) AssertStr(x, y, <=, >) + +#define AssertPtr(x, y, op, er) do { \ + PRAGMA_GCC_DIAG_PUSH \ + /* remarkably, without this inhibition, */ \ + /* the _Pragma()s make the declarations warn. */ \ + PRAGMA_GCC("GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \ + /* inhibit "ISO C forbids conversion of function pointer */ \ + /* to object pointer type [-Werror=pedantic]" */ \ + PRAGMA_GCC("GCC diagnostic ignored \"-Wpedantic\"") \ + void* _x = (void*)(x); \ + void* _y = (void*)(y); \ + Assert(_x op _y, ("%s " #op " %s", #x, #y), ("%p " #er " %p", _x, _y)); \ + PRAGMA_GCC_DIAG_POP; \ +} while(0) + +#define AssertPtrEq(x, y) AssertPtr(x, y, ==, !=) +#define AssertPtrNE(x, y) AssertPtr(x, y, !=, ==) +#define AssertPtrGT(x, y) AssertPtr(x, y, >, <=) +#define AssertPtrLT(x, y) AssertPtr(x, y, <, >=) +#define AssertPtrGE(x, y) AssertPtr(x, y, >=, <) +#define AssertPtrLE(x, y) AssertPtr(x, y, <=, >) + + +#if !defined(NO_WOLFSSH_SERVER) && !defined(NO_WOLFSSH_CLIENT) && \ + !defined(SINGLE_THREADED) && !defined(WOLFSSH_TEST_BLOCK) + +static int tsClientUserAuth(byte authType, WS_UserAuthData* authData, void* ctx) +{ + static char password[] = "upthehill"; + + (void)authType; + (void)ctx; + + if (authType == WOLFSSH_USERAUTH_PASSWORD) { + authData->sf.password.password = (byte*)password; + authData->sf.password.passwordSz = (word32)WSTRLEN(password); + } + else { + return WOLFSSH_USERAUTH_INVALID_AUTHTYPE; + } + + return WOLFSSH_USERAUTH_SUCCESS; +} + + +#define NUMARGS 10 +#define ARGLEN 32 + +static int wolfSSH_wolfSSH_Group16_512(void) +{ + tcp_ready ready; + THREAD_TYPE serverThread; + func_args serverArgs; + func_args clientArgs; + char sA[NUMARGS][ARGLEN]; + char *serverArgv[NUMARGS] = + { sA[0], sA[1], sA[2], sA[3], sA[4], sA[5], sA[6], sA[7], sA[8], sA[9] }; + char cA[NUMARGS][ARGLEN]; + char *clientArgv[NUMARGS] = + { cA[0], cA[1], cA[2], cA[3], cA[4] }; + int serverArgc = 0; + int clientArgc = 0; + + WSTARTTCP(); + + #if defined(DEBUG_WOLFSSH) + wolfSSH_Debugging_ON(); + #endif + + wolfSSH_Init(); + + #if defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,2) + { + int i; + for (i = 0; i < FIPS_CAST_COUNT; i++) { + wc_RunCast_fips(i); + } + } + #endif /* HAVE_FIPS */ + + #if !defined(WOLFSSL_TIRTOS) + ChangeToWolfSshRoot(); + #endif + + InitTcpReady(&ready); + + WSTRNCPY(serverArgv[serverArgc++], "echoserver", ARGLEN); + WSTRNCPY(serverArgv[serverArgc++], "-1", ARGLEN); + WSTRNCPY(serverArgv[serverArgc++], "-f", ARGLEN); + #if !defined(USE_WINDOWS_API) && !defined(WOLFSSH_ZEPHYR) + WSTRNCPY(serverArgv[serverArgc++], "-p", ARGLEN); + WSTRNCPY(serverArgv[serverArgc++], "-0", ARGLEN); + #endif + WSTRNCPY(serverArgv[serverArgc++], "-x", ARGLEN); + WSTRNCPY(serverArgv[serverArgc++], "diffie-hellman-group16-sha512", ARGLEN); + WSTRNCPY(serverArgv[serverArgc++], "-m", ARGLEN); + WSTRNCPY(serverArgv[serverArgc++], "hmac-sha2-512", ARGLEN); + + serverArgs.argc = serverArgc; + serverArgs.argv = serverArgv; + serverArgs.return_code = EXIT_SUCCESS; + serverArgs.signal = &ready; + serverArgs.user_auth = NULL; + ThreadStart(echoserver_test, &serverArgs, &serverThread); + WaitTcpReady(&ready); + + WSTRNCPY(cA[clientArgc++], "client", ARGLEN); + WSTRNCPY(cA[clientArgc++], "-u", ARGLEN); + WSTRNCPY(cA[clientArgc++], "jill", ARGLEN); + #if !defined(USE_WINDOWS_API) && !defined(WOLFSSH_ZEPHYR) + WSTRNCPY(cA[clientArgc++], "-p", ARGLEN); + WSNPRINTF(cA[clientArgc++], ARGLEN, "%d", ready.port); + #endif + + clientArgs.argc = clientArgc; + clientArgs.argv = clientArgv; + clientArgs.return_code = EXIT_SUCCESS; + clientArgs.signal = &ready; + clientArgs.user_auth = tsClientUserAuth; + + client_test(&clientArgs); + +#ifdef WOLFSSH_ZEPHYR + /* Weird deadlock without this sleep */ + k_sleep(Z_TIMEOUT_TICKS(100)); +#endif + ThreadJoin(serverThread); + + if (clientArgs.return_code == WS_SOCKET_ERROR_E) { + clientArgs.return_code = WS_SUCCESS; + } + if (serverArgs.return_code == WS_SOCKET_ERROR_E) { + serverArgs.return_code = WS_SUCCESS; + } +#if DEFAULT_HIGHWATER_MARK < 8000 + if (serverArgs.return_code == WS_REKEYING) { + serverArgs.return_code = WS_SUCCESS; + } + if (serverArgs.return_code == WS_REKEYING) { + serverArgs.return_code = WS_SUCCESS; + } +#endif + /* Socket error may printf, but this is fine */ + AssertIntEQ(WS_SUCCESS, clientArgs.return_code); + AssertIntEQ(WS_SUCCESS, serverArgs.return_code); + + FreeTcpReady(&ready); + + return EXIT_SUCCESS; +} + +#endif + +int wolfSSH_KexTest(int argc, char** argv) +{ + (void)argc; + (void)argv; + + +#if defined(NO_WOLFSSH_SERVER) || defined(NO_WOLFSSH_CLIENT) || \ + defined(SINGLE_THREADED) || defined(WOLFSSH_TEST_BLOCK) + return 77; +#else + AssertIntEQ(wolfSSH_Init(), WS_SUCCESS); + + #if defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,2) + { + int i; + for (i = 0; i < FIPS_CAST_COUNT; i++) { + AssertIntEQ(wc_RunCast_fips(i), WS_SUCCESS); + } + } + #endif /* HAVE_FIPS */ + +#if !defined(WOLFSSH_NO_DH_GROUP16_SHA512) && !defined(WOLFSSH_NO_HMAC_SHA2_512) + wolfSSH_wolfSSH_Group16_512(); +#endif + + AssertIntEQ(wolfSSH_Cleanup(), WS_SUCCESS); + + return 0; +#endif +} + + +#ifndef NO_TESTSUITE_MAIN_DRIVER + +int main(int argc, char** argv) +{ + return wolfSSH_KexTest(argc, argv); +} + + +int myoptind = 0; +char* myoptarg = NULL; + +#endif /* !NO_TESTSUITE_MAIN_DRIVER */ diff --git a/tests/kex.h b/tests/kex.h new file mode 100644 index 000000000..8adffc297 --- /dev/null +++ b/tests/kex.h @@ -0,0 +1,26 @@ +/* kex.h + * + * Copyright (C) 2025 wolfSSL Inc. + * + * This file is part of wolfSSH. + * + * wolfSSH is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSH 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfSSH. If not, see . + */ + +#ifndef _WOLFSSH_TESTS_KEX_H_ +#define _WOLFSSH_TESTS_KEX_H_ + +int wolfSSH_KexTest(int argc, char** argv); + +#endif /* _WOLFSSH_TESTS_KEX_H_ */ diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 2bf7f35ee..3a0bb09c6 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -125,9 +125,14 @@ extern "C" { #undef WOLFSSH_NO_HMAC_SHA2_256 #define WOLFSSH_NO_HMAC_SHA2_256 #endif +#if defined(NO_HMAC) || defined(NO_SHA512) + #undef WOLFSSH_NO_HMAC_SHA2_512 + #define WOLFSSH_NO_HMAC_SHA2_512 +#endif #if defined(WOLFSSH_NO_HMAC_SHA1) && \ defined(WOLFSSH_NO_HMAC_SHA1_96) && \ - defined(WOLFSSH_NO_HMAC_SHA2_256) + defined(WOLFSSH_NO_HMAC_SHA2_256) && \ + defined(WOLFSSH_NO_HMAC_SHA2_512) #error "You need at least one MAC algorithm." #endif @@ -144,6 +149,10 @@ extern "C" { #undef WOLFSSH_NO_DH_GROUP14_SHA256 #define WOLFSSH_NO_DH_GROUP14_SHA256 #endif +#if defined(WOLFSSH_NO_DH) || defined(WOLFSSH_NO_SHA512) + #undef WOLFSSH_NO_DH_GROUP16_SHA512 + #define WOLFSSH_NO_DH_GROUP16_SHA512 +#endif #if defined(WOLFSSH_NO_DH) || defined(NO_SHA256) #undef WOLFSSH_NO_DH_GEX_SHA256 #define WOLFSSH_NO_DH_GEX_SHA256 @@ -178,6 +187,7 @@ extern "C" { #if defined(WOLFSSH_NO_DH_GROUP1_SHA1) && \ defined(WOLFSSH_NO_DH_GROUP14_SHA1) && \ defined(WOLFSSH_NO_DH_GROUP14_SHA256) && \ + defined(WOLFSSH_NO_DH_GROUP16_SHA512) && \ defined(WOLFSSH_NO_DH_GEX_SHA256) && \ defined(WOLFSSH_NO_ECDH_SHA2_NISTP256) && \ defined(WOLFSSH_NO_ECDH_SHA2_NISTP384) && \ @@ -190,6 +200,7 @@ extern "C" { #if defined(WOLFSSH_NO_DH_GROUP1_SHA1) && \ defined(WOLFSSH_NO_DH_GROUP14_SHA1) && \ defined(WOLFSSH_NO_DH_GROUP14_SHA256) && \ + defined(WOLFSSH_NO_DH_GROUP16_SHA512) && \ defined(WOLFSSH_NO_DH_GEX_SHA256) #undef WOLFSSH_NO_DH #define WOLFSSH_NO_DH @@ -313,11 +324,13 @@ enum { ID_HMAC_SHA1, ID_HMAC_SHA1_96, ID_HMAC_SHA2_256, + ID_HMAC_SHA2_512, /* Key Exchange IDs */ ID_DH_GROUP1_SHA1, ID_DH_GROUP14_SHA1, ID_DH_GROUP14_SHA256, + ID_DH_GROUP16_SHA512, ID_DH_GEX_SHA256, ID_ECDH_SHA2_NISTP256, ID_ECDH_SHA2_NISTP384,