From 077b39de8dcca02f5aaed27372a701756c5c4ff6 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 22 Feb 2024 16:12:15 -0800 Subject: [PATCH 1/9] SHA1 Revision 1. Restore SHA-1 as enabled by default. 2. Introduce a "soft disable" for SHA-1 algorithms. SHA-1 is allowed to be used, but the default configuration will not advertise it as available in the KEX. --- src/internal.c | 83 +++++++++++++++++++++++++++------------------- wolfssh/internal.h | 7 +--- 2 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/internal.c b/src/internal.c index fccbb5d67..94bd3e3bb 100644 --- a/src/internal.c +++ b/src/internal.c @@ -69,6 +69,11 @@ use of the function if the flag isn't set. If using wolfCrypt v4.5.0 or later, and not building with configure, set this flag. default: off + WOLFSSH_NO_SHA1_SOFT_DISABLE + SHA-1 is normally soft-disabled. The default configuration will not + advertise the availability of SHA-1 based algorithms during KEX. SHA-1 + algorithms still work. Setting this flag will advertise SHA-1 based + algorithms during KEX by default. WOLFSSH_NO_SHA1 Set when SHA1 is disabled. Set to disable use of SHA1 in HMAC and digital signature support. @@ -3025,29 +3030,33 @@ static const byte cannedMacAlgo[] = { #ifndef WOLFSSH_NO_HMAC_SHA2_256 ID_HMAC_SHA2_256, #endif -#ifndef WOLFSSH_NO_HMAC_SHA1_96 - ID_HMAC_SHA1_96, -#endif -#ifndef WOLFSSH_NO_HMAC_SHA1 - ID_HMAC_SHA1, -#endif +#ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE + #ifndef WOLFSSH_NO_HMAC_SHA1_96 + ID_HMAC_SHA1_96, + #endif + #ifndef WOLFSSH_NO_HMAC_SHA1 + ID_HMAC_SHA1, + #endif +#endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ }; static const byte cannedKeyAlgoClient[] = { #ifdef WOLFSSH_CERTS -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - ID_X509V3_ECDSA_SHA2_NISTP521, -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - ID_X509V3_ECDSA_SHA2_NISTP384, -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - ID_X509V3_ECDSA_SHA2_NISTP256, -#endif -#ifndef WOLFSSH_NO_SSH_RSA_SHA1 - ID_X509V3_SSH_RSA, -#endif -#endif + #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 + ID_X509V3_ECDSA_SHA2_NISTP521, + #endif + #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 + ID_X509V3_ECDSA_SHA2_NISTP384, + #endif + #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 + ID_X509V3_ECDSA_SHA2_NISTP256, + #endif + #ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE + #ifndef WOLFSSH_NO_SSH_RSA_SHA1 + ID_X509V3_SSH_RSA, + #endif /* WOLFSSH_NO_SSH_RSA_SHA1 */ + #endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ +#endif /* WOLFSSH_CERTS */ #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 ID_ECDSA_SHA2_NISTP521, #endif @@ -3063,9 +3072,11 @@ static const byte cannedKeyAlgoClient[] = { #ifndef WOLFSSH_NO_RSA_SHA2_256 ID_RSA_SHA2_256, #endif -#ifndef WOLFSSH_NO_SSH_RSA_SHA1 - ID_SSH_RSA, -#endif +#ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE + #ifndef WOLFSSH_NO_SSH_RSA_SHA1 + ID_SSH_RSA, + #endif /* WOLFSSH_NO_SSH_RSA_SHA1 */ +#endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ }; static const byte cannedKexAlgo[] = { @@ -3084,12 +3095,14 @@ static const byte cannedKexAlgo[] = { #ifndef WOLFSSH_NO_DH_GEX_SHA256 ID_DH_GEX_SHA256, #endif -#ifndef WOLFSSH_NO_DH_GROUP14_SHA1 - ID_DH_GROUP14_SHA1, -#endif -#ifndef WOLFSSH_NO_DH_GROUP1_SHA1 - ID_DH_GROUP1_SHA1, -#endif +#ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE + #ifndef WOLFSSH_NO_DH_GROUP14_SHA1 + ID_DH_GROUP14_SHA1, + #endif + #ifndef WOLFSSH_NO_DH_GROUP1_SHA1 + ID_DH_GROUP1_SHA1, + #endif +#endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ }; static const word32 cannedEncAlgoSz = (word32)sizeof(cannedEncAlgo); @@ -8865,12 +8878,14 @@ static const char cannedMacAlgoNames[] = #if !defined(WOLFSSH_NO_HMAC_SHA2_256) "hmac-sha2-256," #endif -#if !defined(WOLFSSH_NO_HMAC_SHA1_96) - "hmac-sha1-96," -#endif -#if !defined(WOLFSSH_NO_HMAC_SHA1) - "hmac-sha1," -#endif +#if defined(WOLFSSH_NO_SHA1_SOFT_DISABLE) + #if !defined(WOLFSSH_NO_HMAC_SHA1_96) + "hmac-sha1-96," + #endif + #if !defined(WOLFSSH_NO_HMAC_SHA1) + "hmac-sha1," + #endif +#endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ ""; diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 8b8c41ec7..219b176cb 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -67,14 +67,9 @@ extern "C" { /* - * Force some options. Do not want ssh-rsa with SHA1 at anymore. Not ready - * for rsa-sha2-512 yet. + * Not ready for rsa-sha2-512 yet. */ -#undef WOLFSSH_NO_SSH_RSA_SHA1 -#ifndef WOLFSSH_YES_SSH_RSA_SHA1 - #define WOLFSSH_NO_SSH_RSA_SHA1 -#endif #undef WOLFSSH_NO_RSA_SHA2_512 #ifndef WOLFSSH_YES_RSA_SHA2_512 #define WOLFSSH_NO_RSA_SHA2_512 From 672d36e2453c3d0e1f48fd1c7e6724d3053b7c8f Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 26 Feb 2024 09:25:17 -0800 Subject: [PATCH 2/9] KEX Cipher Lists 1. Add APIs for setting the algorithm lists used in the KEX initization messages. 2. Add API to check if a specified algorithm name is available. 3. Add APIs to list available algorithms. 4. Add algorithm lists to the WOLFSSH_CTX and WOLFSSH structures. 5. Added a local function to fetch algorithm strings based on their type and an index. 6. Added starter tests for the algorithm functions. 7. Move the canned algorithm list strings before CtxInit() so they may be used for default lists in the WOLFSSH_CTX. 8. Carry over the algorithm name lists from WOLFSSH_CTX to WOLFSSH. 9. Remove dead code. 10. Add parameter names to a few function prototypes. --- src/internal.c | 343 +++++++++++++++++++++++++-------------------- src/ssh.c | 244 +++++++++++++++++++++++++++++++- tests/api.c | 86 ++++++++++++ wolfssh/internal.h | 19 ++- wolfssh/ssh.h | 28 ++++ 5 files changed, 559 insertions(+), 161 deletions(-) diff --git a/src/internal.c b/src/internal.c index 94bd3e3bb..1cc1d0920 100644 --- a/src/internal.c +++ b/src/internal.c @@ -567,6 +567,111 @@ static const word32 cannedBannerSz = (word32)sizeof(cannedBanner) - 1; #endif /* DEBUG_WOLFSSH */ +#if 0 +static const char cannedKexAlgoNames[] = +#if !defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256) + "ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org," +#endif +#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP521) + "ecdh-sha2-nistp521," +#endif +#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP384) + "ecdh-sha2-nistp384," +#endif +#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP256) + "ecdh-sha2-nistp256," +#endif +#if !defined(WOLFSSH_NO_DH_GEX_SHA256) + "diffie-hellman-group-exchange-sha256," +#endif +#if !defined(WOLFSSH_NO_DH_GROUP14_SHA1) + "diffie-hellman-group14-sha1," +#endif +#if !defined(WOLFSSH_NO_DH_GROUP1_SHA1) + "diffie-hellman-group1-sha1," +#endif + ""; +#endif + +#ifndef WOLFSSH_NO_SSH_RSA_SHA1 + #ifdef WOLFSSH_CERTS + static const char cannedKeyAlgoX509RsaNames[] = "x509v3-ssh-rsa"; + #endif +#endif +#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 + static const char cannedKeyAlgoEcc256Names[] = "ecdsa-sha2-nistp256"; + #ifdef WOLFSSH_CERTS + static const char cannedKeyAlgoX509Ecc256Names[] = + "x509v3-ecdsa-sha2-nistp256"; + #endif +#endif +#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 + static const char cannedKeyAlgoEcc384Names[] = "ecdsa-sha2-nistp384"; + #ifdef WOLFSSH_CERTS + static const char cannedKeyAlgoX509Ecc384Names[] = + "x509v3-ecdsa-sha2-nistp384"; + #endif +#endif +#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 + static const char cannedKeyAlgoEcc521Names[] = "ecdsa-sha2-nistp521"; + #ifdef WOLFSSH_CERTS + static const char cannedKeyAlgoX509Ecc521Names[] = + "x509v3-ecdsa-sha2-nistp521"; + #endif +#endif +#ifndef WOLFSSH_NO_SSH_RSA_SHA1 + /* Used for both the signature algorithm and the RSA key format. */ + static const char cannedKeyAlgoSshRsaNames[] = "ssh-rsa"; +#endif +#ifndef WOLFSSH_NO_RSA_SHA2_256 + static const char cannedKeyAlgoRsaSha2_256Names[] = "rsa-sha2-256"; +#endif +#ifndef WOLFSSH_NO_RSA_SHA2_512 + static const char cannedKeyAlgoRsaSha2_512Names[] = "rsa-sha2-512"; +#endif + +#ifdef WOLFSSH_CERTS +static const char cannedKeyAlgoNames[] = + "rsa-sha2-256,x509v3-ssh-rsa,ecdsa-sha2-nistp256,x509v3-ecdsa-sha2-nistp256"; +#else +static const char cannedKeyAlgoNames[] = "rsa-sha2-256,ecdsa-sha2-nistp256"; +#endif + +static const char cannedEncAlgoNames[] = +#if !defined(WOLFSSH_NO_AES_GCM) + "aes256-gcm@openssh.com," + "aes192-gcm@openssh.com," + "aes128-gcm@openssh.com," +#endif +#if !defined(WOLFSSH_NO_AES_CTR) + "aes256-ctr," + "aes192-ctr," + "aes128-ctr," +#endif +#if !defined(WOLFSSH_NO_AES_CBC) + "aes256-cbc," + "aes192-cbc," + "aes128-cbc," +#endif + ""; + +static const char cannedMacAlgoNames[] = +#if !defined(WOLFSSH_NO_HMAC_SHA2_256) + "hmac-sha2-256," +#endif +#if defined(WOLFSSH_NO_SHA1_SOFT_DISABLE) + #if !defined(WOLFSSH_NO_HMAC_SHA1_96) + "hmac-sha1-96," + #endif + #if !defined(WOLFSSH_NO_HMAC_SHA1) + "hmac-sha1," + #endif +#endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ + ""; + +static const char cannedNoneNames[] = "none"; + + WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap) { word32 idx, count; @@ -604,6 +709,12 @@ WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap) ctx->windowSz = DEFAULT_WINDOW_SZ; ctx->maxPacketSz = DEFAULT_MAX_PACKET_SZ; ctx->sshProtoIdStr = sshProtoIdStr; +#if 0 + ctx->algoListKex = cannedKexAlgoNames; + ctx->algoListKey = cannedKeyAlgoNames; + ctx->algoListCipher = cannedEncAlgoNames; + ctx->algoListMac = cannedMacAlgoNames; +#endif count = (word32)(sizeof(ctx->privateKey) / sizeof(ctx->privateKey[0])); @@ -772,6 +883,10 @@ WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx) ssh->kSz = (word32)sizeof(ssh->k); ssh->handshake = handshake; ssh->connectChannelId = WOLFSSH_SESSION_SHELL; + ssh->algoListKex = ctx->algoListKex; + ssh->algoListKey = ctx->algoListKey; + ssh->algoListCipher = ctx->algoListCipher; + ssh->algoListMac = ctx->algoListMac; #ifdef WOLFSSH_SCP ssh->scpRequestState = SCP_PARSE_COMMAND; ssh->scpConfirmMsg = NULL; @@ -1950,140 +2065,141 @@ static int GenerateKeys(WOLFSSH* ssh, byte hashId, byte doKeyPad) typedef struct { byte id; + byte type; const char* name; } NameIdPair; static const NameIdPair NameIdMap[] = { - { ID_NONE, "none" }, + { ID_NONE, TYPE_OTHER, "none" }, /* Encryption IDs */ #ifndef WOLFSSH_NO_AES_CBC - { ID_AES128_CBC, "aes128-cbc" }, - { ID_AES192_CBC, "aes192-cbc" }, - { ID_AES256_CBC, "aes256-cbc" }, + { ID_AES128_CBC, TYPE_CIPHER, "aes128-cbc" }, + { ID_AES192_CBC, TYPE_CIPHER, "aes192-cbc" }, + { ID_AES256_CBC, TYPE_CIPHER, "aes256-cbc" }, #endif #ifndef WOLFSSH_NO_AES_CTR - { ID_AES128_CTR, "aes128-ctr" }, - { ID_AES192_CTR, "aes192-ctr" }, - { ID_AES256_CTR, "aes256-ctr" }, + { ID_AES128_CTR, TYPE_CIPHER, "aes128-ctr" }, + { ID_AES192_CTR, TYPE_CIPHER, "aes192-ctr" }, + { ID_AES256_CTR, TYPE_CIPHER, "aes256-ctr" }, #endif #ifndef WOLFSSH_NO_AES_GCM - { ID_AES128_GCM, "aes128-gcm@openssh.com" }, - { ID_AES192_GCM, "aes192-gcm@openssh.com" }, - { ID_AES256_GCM, "aes256-gcm@openssh.com" }, + { ID_AES128_GCM, TYPE_CIPHER, "aes128-gcm@openssh.com" }, + { ID_AES192_GCM, TYPE_CIPHER, "aes192-gcm@openssh.com" }, + { ID_AES256_GCM, TYPE_CIPHER, "aes256-gcm@openssh.com" }, #endif /* Integrity IDs */ #ifndef WOLFSSH_NO_HMAC_SHA1 - { ID_HMAC_SHA1, "hmac-sha1" }, + { ID_HMAC_SHA1, TYPE_MAC, "hmac-sha1" }, #endif #ifndef WOLFSSH_NO_HMAC_SHA1_96 - { ID_HMAC_SHA1_96, "hmac-sha1-96" }, + { ID_HMAC_SHA1_96, TYPE_MAC, "hmac-sha1-96" }, #endif #ifndef WOLFSSH_NO_HMAC_SHA2_256 - { ID_HMAC_SHA2_256, "hmac-sha2-256" }, + { ID_HMAC_SHA2_256, TYPE_MAC, "hmac-sha2-256" }, #endif /* Key Exchange IDs */ #ifndef WOLFSSH_NO_DH_GROUP1_SHA1 - { ID_DH_GROUP1_SHA1, "diffie-hellman-group1-sha1" }, + { ID_DH_GROUP1_SHA1, TYPE_KEX, "diffie-hellman-group1-sha1" }, #endif #ifndef WOLFSSH_NO_DH_GROUP14_SHA1 - { ID_DH_GROUP14_SHA1, "diffie-hellman-group14-sha1" }, + { ID_DH_GROUP14_SHA1, TYPE_KEX, "diffie-hellman-group14-sha1" }, #endif #ifndef WOLFSSH_NO_DH_GEX_SHA256 - { ID_DH_GEX_SHA256, "diffie-hellman-group-exchange-sha256" }, + { ID_DH_GEX_SHA256, TYPE_KEX, "diffie-hellman-group-exchange-sha256" }, #endif #ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256 - { ID_ECDH_SHA2_NISTP256, "ecdh-sha2-nistp256" }, + { ID_ECDH_SHA2_NISTP256, TYPE_KEX, "ecdh-sha2-nistp256" }, #endif #ifndef WOLFSSH_NO_ECDH_SHA2_NISTP384 - { ID_ECDH_SHA2_NISTP384, "ecdh-sha2-nistp384" }, + { ID_ECDH_SHA2_NISTP384, TYPE_KEX, "ecdh-sha2-nistp384" }, #endif #ifndef WOLFSSH_NO_ECDH_SHA2_NISTP521 - { ID_ECDH_SHA2_NISTP521, "ecdh-sha2-nistp521" }, + { ID_ECDH_SHA2_NISTP521, TYPE_KEX, "ecdh-sha2-nistp521" }, #endif #ifndef WOLFSSH_NO_ECDH_SHA2_ED25519 - { ID_ECDH_SHA2_ED25519, "curve25519-sha256" }, - { ID_ECDH_SHA2_ED25519_LIBSSH, "curve25519-sha256@libssh.org" }, + { ID_ECDH_SHA2_ED25519, TYPE_KEX, "curve25519-sha256" }, + { ID_ECDH_SHA2_ED25519_LIBSSH, TYPE_KEX, "curve25519-sha256@libssh.org" }, #endif #ifndef WOLFSSH_NO_DH_GEX_SHA256 - { ID_DH_GROUP14_SHA256, "diffie-hellman-group14-sha256" }, + { ID_DH_GROUP14_SHA256, TYPE_KEX, "diffie-hellman-group14-sha256" }, #endif #ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 /* We use kyber-512 here to achieve interop with OQS's fork. */ - { ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256, + { ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256, TYPE_KEX, "ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org" }, #endif - { ID_EXTINFO_S, "ext-info-s" }, - { ID_EXTINFO_C, "ext-info-c" }, + { ID_EXTINFO_S, TYPE_OTHER, "ext-info-s" }, + { ID_EXTINFO_C, TYPE_OTHER, "ext-info-c" }, /* Public Key IDs */ #ifndef WOLFSSH_NO_RSA - { ID_SSH_RSA, "ssh-rsa" }, + { ID_SSH_RSA, TYPE_KEY, "ssh-rsa" }, #ifndef WOLFSSH_NO_RSA_SHA2_256 - { ID_RSA_SHA2_256, "rsa-sha2-256" }, + { ID_RSA_SHA2_256, TYPE_KEY, "rsa-sha2-256" }, #endif #ifndef WOLFSSH_NO_RSA_SHA2_512 - { ID_RSA_SHA2_512, "rsa-sha2-512" }, + { ID_RSA_SHA2_512, TYPE_KEY, "rsa-sha2-512" }, #endif #endif /* WOLFSSH_NO_RSA */ #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - { ID_ECDSA_SHA2_NISTP256, "ecdsa-sha2-nistp256" }, + { ID_ECDSA_SHA2_NISTP256, TYPE_KEY, "ecdsa-sha2-nistp256" }, #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - { ID_ECDSA_SHA2_NISTP384, "ecdsa-sha2-nistp384" }, + { ID_ECDSA_SHA2_NISTP384, TYPE_KEY, "ecdsa-sha2-nistp384" }, #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - { ID_ECDSA_SHA2_NISTP521, "ecdsa-sha2-nistp521" }, + { ID_ECDSA_SHA2_NISTP521, TYPE_KEY, "ecdsa-sha2-nistp521" }, #endif #ifdef WOLFSSH_CERTS #ifndef WOLFSSH_NO_SSH_RSA_SHA1 - { ID_X509V3_SSH_RSA, "x509v3-ssh-rsa" }, + { ID_X509V3_SSH_RSA, TYPE_KEY, "x509v3-ssh-rsa" }, #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - { ID_X509V3_ECDSA_SHA2_NISTP256, "x509v3-ecdsa-sha2-nistp256" }, + { ID_X509V3_ECDSA_SHA2_NISTP256, TYPE_KEY, "x509v3-ecdsa-sha2-nistp256" }, #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - { ID_X509V3_ECDSA_SHA2_NISTP384, "x509v3-ecdsa-sha2-nistp384" }, + { ID_X509V3_ECDSA_SHA2_NISTP384, TYPE_KEY, "x509v3-ecdsa-sha2-nistp384" }, #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - { ID_X509V3_ECDSA_SHA2_NISTP521, "x509v3-ecdsa-sha2-nistp521" }, + { ID_X509V3_ECDSA_SHA2_NISTP521, TYPE_KEY, "x509v3-ecdsa-sha2-nistp521" }, #endif #endif /* WOLFSSH_CERTS */ /* Service IDs */ - { ID_SERVICE_USERAUTH, "ssh-userauth" }, - { ID_SERVICE_CONNECTION, "ssh-connection" }, + { ID_SERVICE_USERAUTH, TYPE_OTHER, "ssh-userauth" }, + { ID_SERVICE_CONNECTION, TYPE_OTHER, "ssh-connection" }, /* UserAuth IDs */ - { ID_USERAUTH_PASSWORD, "password" }, - { ID_USERAUTH_PUBLICKEY, "publickey" }, + { ID_USERAUTH_PASSWORD, TYPE_OTHER, "password" }, + { ID_USERAUTH_PUBLICKEY, TYPE_OTHER, "publickey" }, /* Channel Type IDs */ - { ID_CHANTYPE_SESSION, "session" }, + { ID_CHANTYPE_SESSION, TYPE_OTHER, "session" }, #ifdef WOLFSSH_FWD - { ID_CHANTYPE_TCPIP_FORWARD, "forwarded-tcpip" }, - { ID_CHANTYPE_TCPIP_DIRECT, "direct-tcpip" }, + { ID_CHANTYPE_TCPIP_FORWARD, TYPE_OTHER, "forwarded-tcpip" }, + { ID_CHANTYPE_TCPIP_DIRECT, TYPE_OTHER, "direct-tcpip" }, #endif /* WOLFSSH_FWD */ #ifdef WOLFSSH_AGENT - { ID_CHANTYPE_AUTH_AGENT, "auth-agent@openssh.com" }, + { ID_CHANTYPE_AUTH_AGENT, TYPE_OTHER, "auth-agent@openssh.com" }, #endif /* WOLFSSH_AGENT */ /* Global Request IDs */ #ifdef WOLFSSH_FWD - { ID_GLOBREQ_TCPIP_FWD, "tcpip-forward" }, - { ID_GLOBREQ_TCPIP_FWD_CANCEL, "cancel-tcpip-forward" }, + { ID_GLOBREQ_TCPIP_FWD, TYPE_OTHER, "tcpip-forward" }, + { ID_GLOBREQ_TCPIP_FWD_CANCEL, TYPE_OTHER, "cancel-tcpip-forward" }, #endif /* WOLFSSH_FWD */ /* Ext Info IDs */ - { ID_EXTINFO_SERVER_SIG_ALGS, "server-sig-algs" }, + { ID_EXTINFO_SERVER_SIG_ALGS, TYPE_OTHER, "server-sig-algs" }, /* Curve Name IDs */ - { ID_CURVE_NISTP256, "nistp256" }, - { ID_CURVE_NISTP384, "nistp384" }, - { ID_CURVE_NISTP521, "nistp521" }, + { ID_CURVE_NISTP256, TYPE_OTHER, "nistp256" }, + { ID_CURVE_NISTP384, TYPE_OTHER, "nistp384" }, + { ID_CURVE_NISTP521, TYPE_OTHER, "nistp521" }, }; @@ -2121,6 +2237,29 @@ const char* IdToName(byte id) } +const char* NameByIndexType(byte type, word32* index) +{ + const char* name = NULL; + + if (index != NULL) { + word32 i, mapSz; + + mapSz = (word32)(sizeof(NameIdMap)/sizeof(NameIdPair)); + + for (i = *index; i < mapSz; i++) { + if (NameIdMap[i].type == type) { + name = NameIdMap[i].name; + break; + } + } + + *index = i + 1; + } + + return name; +} + + WOLFSSH_CHANNEL* ChannelNew(WOLFSSH* ssh, byte channelType, word32 initialWindowSz, word32 maxPacketSz) { @@ -8856,112 +8995,6 @@ static int BuildNameList(char* buf, word32 bufSz, } -static const char cannedEncAlgoNames[] = -#if !defined(WOLFSSH_NO_AES_GCM) - "aes256-gcm@openssh.com," - "aes192-gcm@openssh.com," - "aes128-gcm@openssh.com," -#endif -#if !defined(WOLFSSH_NO_AES_CTR) - "aes256-ctr," - "aes192-ctr," - "aes128-ctr," -#endif -#if !defined(WOLFSSH_NO_AES_CBC) - "aes256-cbc," - "aes192-cbc," - "aes128-cbc," -#endif - ""; - -static const char cannedMacAlgoNames[] = -#if !defined(WOLFSSH_NO_HMAC_SHA2_256) - "hmac-sha2-256," -#endif -#if defined(WOLFSSH_NO_SHA1_SOFT_DISABLE) - #if !defined(WOLFSSH_NO_HMAC_SHA1_96) - "hmac-sha1-96," - #endif - #if !defined(WOLFSSH_NO_HMAC_SHA1) - "hmac-sha1," - #endif -#endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ - ""; - - -#ifndef WOLFSSH_NO_SSH_RSA_SHA1 - #ifdef WOLFSSH_CERTS - static const char cannedKeyAlgoX509RsaNames[] = "x509v3-ssh-rsa"; - #endif -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - static const char cannedKeyAlgoEcc256Names[] = "ecdsa-sha2-nistp256"; - #ifdef WOLFSSH_CERTS - static const char cannedKeyAlgoX509Ecc256Names[] = - "x509v3-ecdsa-sha2-nistp256"; - #endif -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - static const char cannedKeyAlgoEcc384Names[] = "ecdsa-sha2-nistp384"; - #ifdef WOLFSSH_CERTS - static const char cannedKeyAlgoX509Ecc384Names[] = - "x509v3-ecdsa-sha2-nistp384"; - #endif -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - static const char cannedKeyAlgoEcc521Names[] = "ecdsa-sha2-nistp521"; - #ifdef WOLFSSH_CERTS - static const char cannedKeyAlgoX509Ecc521Names[] = - "x509v3-ecdsa-sha2-nistp521"; - #endif -#endif -#ifndef WOLFSSH_NO_SSH_RSA_SHA1 - /* Used for both the signature algorithm and the RSA key format. */ - static const char cannedKeyAlgoSshRsaNames[] = "ssh-rsa"; -#endif -#ifndef WOLFSSH_NO_RSA_SHA2_256 - static const char cannedKeyAlgoRsaSha2_256Names[] = "rsa-sha2-256"; -#endif -#ifndef WOLFSSH_NO_RSA_SHA2_512 - static const char cannedKeyAlgoRsaSha2_512Names[] = "rsa-sha2-512"; -#endif - -#ifdef WOLFSSH_CERTS -static const char cannedKeyAlgoNames[] = - "rsa-sha2-256,x509v3-ssh-rsa,ecdsa-sha2-nistp256,x509v3-ecdsa-sha2-nistp256"; -#else -static const char cannedKeyAlgoNames[] = "rsa-sha2-256,ecdsa-sha2-nistp256"; -#endif - -#if 0 -static const char cannedKexAlgoNames[] = -#if !defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256) - "ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org," -#endif -#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP521) - "ecdh-sha2-nistp521," -#endif -#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP384) - "ecdh-sha2-nistp384," -#endif -#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP256) - "ecdh-sha2-nistp256," -#endif -#if !defined(WOLFSSH_NO_DH_GEX_SHA256) - "diffie-hellman-group-exchange-sha256," -#endif -#if !defined(WOLFSSH_NO_DH_GROUP14_SHA1) - "diffie-hellman-group14-sha1," -#endif -#if !defined(WOLFSSH_NO_DH_GROUP1_SHA1) - "diffie-hellman-group1-sha1," -#endif - ""; -#endif - - -static const char cannedNoneNames[] = "none"; - /* -1 for the null, some are -2 for the null and comma */ static const word32 cannedEncAlgoNamesSz = (word32)sizeof(cannedEncAlgoNames) - 2; diff --git a/src/ssh.c b/src/ssh.c index 73a48231a..7467c8614 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -1903,10 +1903,6 @@ int wolfSSH_ReadKey_file(const char* name, format = WOLFSSH_FORMAT_SSH; in[inSz] = 0; } -#if 0 - else if (WSTRNSTR((const char*)in, PrivBeginOpenSSH, inSz) != NULL && - WSTRNSTR((const char*)in, PrivEndOpenSSH, inSz) != NULL) { -#endif else if (WSTRNSTR((const char*)in, PrivBeginOpenSSH, inSz) != NULL) { *isPrivate = 1; format = WOLFSSH_FORMAT_OPENSSH; @@ -1935,6 +1931,246 @@ int wolfSSH_ReadKey_file(const char* name, #endif + +int wolfSSH_CheckAlgoName(const char* name) +{ + int ret = WS_INVALID_ALGO_ID; + + if (name) { + word32 nameSz = (word32)WSTRLEN(name); + if (NameToId(name, nameSz) != ID_UNKNOWN) { + ret = WS_SUCCESS; + } + } + + return ret; +} + + +int wolfSSH_CTX_SetAlgoListKex(WOLFSSH_CTX* ctx, const char* list) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx) { + ctx->algoListKex = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_CTX_GetAlgoListKex(WOLFSSH_CTX* ctx) +{ + const char* list = NULL; + + if (ctx) { + list = ctx->algoListKex; + } + + return list; +} + + +int wolfSSH_SetAlgoListKex(WOLFSSH* ssh, const char* list) +{ + int ret = WS_SSH_NULL_E; + + if (ssh) { + ssh->algoListKex = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_GetAlgoListKex(WOLFSSH* ssh) +{ + const char* list = NULL; + + if (ssh) { + list = ssh->algoListKex; + } + + return list; +} + + +int wolfSSH_CTX_SetAlgoListKey(WOLFSSH_CTX* ctx, const char* list) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx) { + ctx->algoListKey = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_CTX_GetAlgoListKey(WOLFSSH_CTX* ctx) +{ + const char* list = NULL; + + if (ctx) { + list = ctx->algoListKey; + } + + return list; +} + + +int wolfSSH_SetAlgoListKey(WOLFSSH* ssh, const char* list) +{ + int ret = WS_SSH_NULL_E; + + if (ssh) { + ssh->algoListKey = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_GetAlgoListKey(WOLFSSH* ssh) +{ + const char* list = NULL; + + if (ssh) { + list = ssh->algoListKey; + } + + return list; +} + + +int wolfSSH_CTX_SetAlgoListCipher(WOLFSSH_CTX* ctx, const char* list) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx) { + ctx->algoListCipher = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_CTX_GetAlgoListCipher(WOLFSSH_CTX* ctx) +{ + const char* list = NULL; + + if (ctx) { + list = ctx->algoListCipher; + } + + return list; +} + + +int wolfSSH_SetAlgoListCipher(WOLFSSH* ssh, const char* list) +{ + int ret = WS_SSH_NULL_E; + + if (ssh) { + ssh->algoListCipher = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_GetAlgoListCipher(WOLFSSH* ssh) +{ + const char* list = NULL; + + if (ssh) { + list = ssh->algoListCipher; + } + + return list; +} + + +int wolfSSH_CTX_SetAlgoListMac(WOLFSSH_CTX* ctx, const char* list) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx) { + ctx->algoListMac = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_CTX_GetAlgoListMac(WOLFSSH_CTX* ctx) +{ + const char* list = NULL; + + if (ctx) { + list = ctx->algoListMac; + } + + return list; +} + + +int wolfSSH_SetAlgoListMac(WOLFSSH* ssh, const char* list) +{ + int ret = WS_SSH_NULL_E; + + if (ssh) { + ssh->algoListMac = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_GetAlgoListMac(WOLFSSH* ssh) +{ + const char* list = NULL; + + if (ssh) { + list = ssh->algoListMac; + } + + return list; +} + + +const char* wolfSSH_QueryKex(word32* index) +{ + return NameByIndexType(TYPE_KEX, index); +} + + +const char* wolfSSH_QueryKey(word32* index) +{ + return NameByIndexType(TYPE_KEY, index); +} + + +const char* wolfSSH_QueryCipher(word32* index) +{ + return NameByIndexType(TYPE_CIPHER, index); +} + + +const char* wolfSSH_QueryMac(word32* index) +{ + return NameByIndexType(TYPE_MAC, index); +} + + int wolfSSH_CTX_SetBanner(WOLFSSH_CTX* ctx, const char* newBanner) { diff --git a/tests/api.c b/tests/api.c index 0e483e204..4799a00af 100644 --- a/tests/api.c +++ b/tests/api.c @@ -1305,8 +1305,92 @@ static void test_wolfSSH_RealPath(void) #else static void test_wolfSSH_RealPath(void) { ; } #endif + + +static void test_wolfSSH_SetAlgoList(void) +{ + const char* list = "aes128-ctr,aes128-cbc"; + const char* checkList = NULL; + WOLFSSH_CTX* ctx; + WOLFSSH* ssh; + + ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL); + ssh = wolfSSH_new(ctx); + + wolfSSH_SetAlgoListCipher(ssh, list); + checkList = wolfSSH_GetAlgoListCipher(ssh); + + if (checkList != list) { + printf("Didn't get back the correct list.\n"); + } + + wolfSSH_free(ssh); + wolfSSH_CTX_free(ctx); +} + + +static void test_wolfSSH_QueryAlgoList(void) +{ + word32 i; + const char* name; + + i = 0; + name = NULL; + printf("KEX:\n"); + do { + if (name != NULL) { + printf("\t%s\n", name); + } + name = wolfSSH_QueryKex(&i); + } while (name != NULL); + + i = 0; + name = NULL; + printf("Public key:\n"); + do { + if (name != NULL) { + printf("\t%s\n", name); + } + name = wolfSSH_QueryKey(&i); + } while (name != NULL); + + i = 0; + name = NULL; + printf("Cipher:\n"); + do { + if (name != NULL) { + printf("\t%s\n", name); + } + name = wolfSSH_QueryCipher(&i); + } while (name != NULL); + + i = 0; + name = NULL; + printf("MAC:\n"); + do { + if (name != NULL) { + printf("\t%s\n", name); + } + name = wolfSSH_QueryMac(&i); + } while (name != NULL); + + /* This test case picks up where the index left off. */ + name = wolfSSH_QueryKex(&i); + if (name != NULL) { + printf("That's not right.\n"); + } + + if (wolfSSH_CheckAlgoName("ssh-rsa")) + printf("Don't know ssh-rsa.\n"); + + if (!wolfSSH_CheckAlgoName("foofarah")) + printf("Fake algo name found.\n"); +} + + #endif /* WOLFSSH_TEST_BLOCK */ + int wolfSSH_ApiTest(int argc, char** argv) { (void)argc; @@ -1337,6 +1421,8 @@ int wolfSSH_ApiTest(int argc, char** argv) test_wolfSSH_CTX_UseCert_buffer(); test_wolfSSH_CertMan(); test_wolfSSH_ReadKey(); + test_wolfSSH_QueryAlgoList(); + test_wolfSSH_SetAlgoList(); /* SCP tests */ test_wolfSSH_SCP_CB(); diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 219b176cb..228854a5d 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -351,6 +351,11 @@ enum { }; +enum NameIdType { + TYPE_KEX, TYPE_KEY, TYPE_CIPHER, TYPE_MAC, TYPE_OTHER +}; + + #define WOLFSSH_MAX_NAMESZ 32 #ifndef WOLFSSH_MAX_CHN_NAMESZ @@ -425,8 +430,10 @@ enum { #define WOLFSSH_KEY_QUANTITY_REQ 1 #endif -WOLFSSH_LOCAL byte NameToId(const char*, word32); -WOLFSSH_LOCAL const char* IdToName(byte); + +WOLFSSH_LOCAL byte NameToId(const char* name, word32 nameSz); +WOLFSSH_LOCAL const char* IdToName(byte id); +WOLFSSH_LOCAL const char* NameByIndexType(byte type, word32* index); #define STATIC_BUFFER_LEN AES_BLOCK_SIZE @@ -502,6 +509,10 @@ struct WOLFSSH_CTX { word32 highwaterMark; const char* banner; const char* sshProtoIdStr; + const char* algoListKex; + const char* algoListKey; + const char* algoListCipher; + const char* algoListMac; word32 bannerSz; word32 windowSz; word32 maxPacketSz; @@ -638,6 +649,10 @@ struct WOLFSSH { word32 seq; word32 peerSeq; word32 packetStartIdx; /* Current send packet start index */ + const char* algoListKex; + const char* algoListKey; + const char* algoListCipher; + const char* algoListMac; byte acceptState; byte connectState; byte clientState; diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index 218a44484..dd07cb93e 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -90,6 +90,34 @@ WOLFSSH_API int wolfSSH_ReadKey_file(const char* name, byte** out, word32* outSz, const byte** outType, word32* outTypeSz, byte* isPrivate, void* heap); +WOLFSSH_API int wolfSSH_CheckAlgoName(const char* name); + +WOLFSSH_API int wolfSSH_CTX_SetAlgoListKex(WOLFSSH_CTX* ctx, const char* list); +WOLFSSH_API const char* wolfSSH_CTX_GetAlgoListKex(WOLFSSH_CTX* ctx); +WOLFSSH_API int wolfSSH_SetAlgoListKex(WOLFSSH* ssh, const char* list); +WOLFSSH_API const char* wolfSSH_GetAlgoListKex(WOLFSSH* ssh); + +WOLFSSH_API int wolfSSH_CTX_SetAlgoListKey(WOLFSSH_CTX* ctx, const char* list); +WOLFSSH_API const char* wolfSSH_CTX_GetAlgoListKey(WOLFSSH_CTX* ctx); +WOLFSSH_API int wolfSSH_SetAlgoListKey(WOLFSSH* ssh, const char* list); +WOLFSSH_API const char* wolfSSH_GetAlgoListKey(WOLFSSH* ssh); + +WOLFSSH_API int wolfSSH_CTX_SetAlgoListCipher(WOLFSSH_CTX* ctx, + const char* list); +WOLFSSH_API const char* wolfSSH_CTX_GetAlgoListCipher(WOLFSSH_CTX* ctx); +WOLFSSH_API int wolfSSH_SetAlgoListCipher(WOLFSSH* ssh, const char* list); +WOLFSSH_API const char* wolfSSH_GetAlgoListCipher(WOLFSSH* ssh); + +WOLFSSH_API int wolfSSH_CTX_SetAlgoListMac(WOLFSSH_CTX* ctx, const char* list); +WOLFSSH_API const char* wolfSSH_CTX_GetAlgoListMac(WOLFSSH_CTX* ctx); +WOLFSSH_API int wolfSSH_SetAlgoListMac(WOLFSSH* ssh, const char* list); +WOLFSSH_API const char* wolfSSH_GetAlgoListMac(WOLFSSH* ssh); + +WOLFSSH_API const char* wolfSSH_QueryKex(word32* index); +WOLFSSH_API const char* wolfSSH_QueryKey(word32* index); +WOLFSSH_API const char* wolfSSH_QueryCipher(word32* index); +WOLFSSH_API const char* wolfSSH_QueryMac(word32* index); + #define WS_CHANNEL_ID_SELF 0 #define WS_CHANNEL_ID_PEER 1 From 1319564bdddfc4877365456007b88086ff6e00e8 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 26 Feb 2024 14:55:08 -0800 Subject: [PATCH 3/9] KEX Cipher Lists 1. Using the configurable list from the WOLFSSH for setting the cipher list and the MAC list. 2. Removed the ID lists for the cipher list and MAC list used in DoKextInit(). 3. Changing DoKexInit() to use the configurable cipher and MAC lists. --- src/internal.c | 199 ++++++++++++++++++++++++------------------------- 1 file changed, 97 insertions(+), 102 deletions(-) diff --git a/src/internal.c b/src/internal.c index 1cc1d0920..b77f2a2d3 100644 --- a/src/internal.c +++ b/src/internal.c @@ -712,9 +712,9 @@ WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap) #if 0 ctx->algoListKex = cannedKexAlgoNames; ctx->algoListKey = cannedKeyAlgoNames; +#endif ctx->algoListCipher = cannedEncAlgoNames; ctx->algoListMac = cannedMacAlgoNames; -#endif count = (word32)(sizeof(ctx->privateKey) / sizeof(ctx->privateKey[0])); @@ -3147,38 +3147,6 @@ static int GetNameList(byte* idList, word32* idListSz, return ret; } -static const byte cannedEncAlgo[] = { -#ifndef WOLFSSH_NO_AES_GCM - ID_AES256_GCM, - ID_AES192_GCM, - ID_AES128_GCM, -#endif -#ifndef WOLFSSH_NO_AES_CTR - ID_AES256_CTR, - ID_AES192_CTR, - ID_AES128_CTR, -#endif -#ifndef WOLFSSH_NO_AES_CBC - ID_AES256_CBC, - ID_AES192_CBC, - ID_AES128_CBC, -#endif -}; - -static const byte cannedMacAlgo[] = { -#ifndef WOLFSSH_NO_HMAC_SHA2_256 - ID_HMAC_SHA2_256, -#endif -#ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE - #ifndef WOLFSSH_NO_HMAC_SHA1_96 - ID_HMAC_SHA1_96, - #endif - #ifndef WOLFSSH_NO_HMAC_SHA1 - ID_HMAC_SHA1, - #endif -#endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ -}; - static const byte cannedKeyAlgoClient[] = { #ifdef WOLFSSH_CERTS #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 @@ -3244,8 +3212,6 @@ static const byte cannedKexAlgo[] = { #endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ }; -static const word32 cannedEncAlgoSz = (word32)sizeof(cannedEncAlgo); -static const word32 cannedMacAlgoSz = (word32)sizeof(cannedMacAlgo); static const word32 cannedKeyAlgoClientSz = (word32)sizeof(cannedKeyAlgoClient); static const word32 cannedKexAlgoSz = (word32)sizeof(cannedKexAlgo); @@ -3533,13 +3499,29 @@ static INLINE byte AeadModeForId(byte id) } +static word32 AlgoListSz(const char* algoList) +{ + word32 algoListSz; + + algoListSz = (word32)WSTRLEN(algoList); + if (algoList[algoListSz-1] == ',') { + --algoListSz; + } + + return algoListSz; +} + + static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) { int ret = WS_SUCCESS; int side = WOLFSSH_ENDPOINT_SERVER; byte algoId; byte list[24] = {ID_NONE}; + byte cannedList[24] = {ID_NONE}; word32 listSz; + word32 cannedListSz; + word32 cannedAlgoNamesSz; word32 skipSz; word32 begin; @@ -3589,18 +3571,18 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: KEX Algorithms"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (ret == WS_SUCCESS) { - ssh->handshake->kexIdGuess = list[0]; - algoId = MatchIdLists(side, list, listSz, - cannedKexAlgo, cannedKexAlgoSz); - if (algoId == ID_UNKNOWN) { - WLOG(WS_LOG_DEBUG, "Unable to negotiate KEX Algo"); - ret = WS_MATCH_KEX_ALGO_E; - } - else { - ssh->handshake->kexId = algoId; - ssh->handshake->kexHashId = HashForId(algoId); - } + } + if (ret == WS_SUCCESS) { + ssh->handshake->kexIdGuess = list[0]; + algoId = MatchIdLists(side, list, listSz, + cannedKexAlgo, cannedKexAlgoSz); + if (algoId == ID_UNKNOWN) { + WLOG(WS_LOG_DEBUG, "Unable to negotiate KEX Algo"); + ret = WS_MATCH_KEX_ALGO_E; + } + else { + ssh->handshake->kexId = algoId; + ssh->handshake->kexHashId = HashForId(algoId); } /* Extension Info Flag */ @@ -3652,13 +3634,19 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: Enc Algorithms - Client to Server"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (ret == WS_SUCCESS) { - algoId = MatchIdLists(side, list, listSz, - cannedEncAlgo, cannedEncAlgoSz); - if (algoId == ID_UNKNOWN) { - WLOG(WS_LOG_DEBUG, "Unable to negotiate Encryption Algo C2S"); - ret = WS_MATCH_ENC_ALGO_E; - } + } + if (ret == WS_SUCCESS) { + cannedAlgoNamesSz = AlgoListSz(ssh->algoListCipher); + cannedListSz = (word32)sizeof(cannedList); + ret = GetNameListRaw(cannedList, &cannedListSz, + (const byte*)ssh->algoListCipher, cannedAlgoNamesSz); + } + if (ret == WS_SUCCESS) { + algoId = MatchIdLists(side, list, listSz, + cannedList, cannedListSz); + if (algoId == ID_UNKNOWN) { + WLOG(WS_LOG_DEBUG, "Unable to negotiate Encryption Algo C2S"); + ret = WS_MATCH_ENC_ALGO_E; } } @@ -3667,30 +3655,33 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: Enc Algorithms - Server to Client"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (MatchIdLists(side, list, listSz, &algoId, 1) == ID_UNKNOWN) { + } + if (ret == WS_SUCCESS) { + algoId = MatchIdLists(side, list, listSz, &algoId, 1); + if (algoId == ID_UNKNOWN) { WLOG(WS_LOG_DEBUG, "Unable to negotiate Encryption Algo S2C"); ret = WS_MATCH_ENC_ALGO_E; } + } + if (ret == WS_SUCCESS) { + ssh->handshake->encryptId = algoId; + ssh->handshake->aeadMode = AeadModeForId(algoId); + ssh->handshake->blockSz = BlockSzForId(algoId); + ssh->handshake->keys.encKeySz = + ssh->handshake->peerKeys.encKeySz = + KeySzForId(algoId); + if (!ssh->handshake->aeadMode) { + ssh->handshake->keys.ivSz = + ssh->handshake->peerKeys.ivSz = + ssh->handshake->blockSz; + } else { - ssh->handshake->encryptId = algoId; - ssh->handshake->aeadMode = AeadModeForId(algoId); - ssh->handshake->blockSz = BlockSzForId(algoId); - ssh->handshake->keys.encKeySz = - ssh->handshake->peerKeys.encKeySz = - KeySzForId(algoId); - if (!ssh->handshake->aeadMode) { - ssh->handshake->keys.ivSz = - ssh->handshake->peerKeys.ivSz = - ssh->handshake->blockSz; - } - else { #ifndef WOLFSSH_NO_AEAD - ssh->handshake->keys.ivSz = - ssh->handshake->peerKeys.ivSz = - AEAD_NONCE_SZ; - ssh->handshake->macSz = ssh->handshake->blockSz; + ssh->handshake->keys.ivSz = + ssh->handshake->peerKeys.ivSz = + AEAD_NONCE_SZ; + ssh->handshake->macSz = ssh->handshake->blockSz; #endif - } } } @@ -3699,9 +3690,16 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: MAC Algorithms - Client to Server"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (ret == WS_SUCCESS && !ssh->aeadMode) { - algoId = MatchIdLists(side, list, listSz, - cannedMacAlgo, cannedMacAlgoSz); + } + if (!ssh->handshake->aeadMode) { + if (ret == WS_SUCCESS) { + cannedAlgoNamesSz = AlgoListSz(ssh->algoListMac); + cannedListSz = (word32)sizeof(cannedList); + ret = GetNameListRaw(cannedList, &cannedListSz, + (const byte*)cannedMacAlgoNames, cannedAlgoNamesSz); + } + if (ret == WS_SUCCESS) { + algoId = MatchIdLists(side, list, listSz, cannedList, cannedListSz); if (algoId == ID_UNKNOWN) { WLOG(WS_LOG_DEBUG, "Unable to negotiate MAC Algo C2S"); ret = WS_MATCH_MAC_ALGO_E; @@ -3714,18 +3712,21 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: MAC Algorithms - Server to Client"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (ret == WS_SUCCESS && !ssh->handshake->aeadMode) { - if (MatchIdLists(side, list, listSz, &algoId, 1) == ID_UNKNOWN) { + } + if (!ssh->handshake->aeadMode) { + if (ret == WS_SUCCESS) { + algoId = MatchIdLists(side, list, listSz, &algoId, 1); + if (algoId == ID_UNKNOWN) { WLOG(WS_LOG_DEBUG, "Unable to negotiate MAC Algo S2C"); ret = WS_MATCH_MAC_ALGO_E; } - else { + } + if (ret == WS_SUCCESS) { ssh->handshake->macId = algoId; ssh->handshake->macSz = MacSzForId(algoId); ssh->handshake->keys.macKeySz = ssh->handshake->peerKeys.macKeySz = KeySzForId(algoId); - } } } @@ -8995,19 +8996,7 @@ static int BuildNameList(char* buf, word32 bufSz, } -/* -1 for the null, some are -2 for the null and comma */ -static const word32 cannedEncAlgoNamesSz = - (word32)sizeof(cannedEncAlgoNames) - 2; -static const word32 cannedMacAlgoNamesSz = - (word32)sizeof(cannedMacAlgoNames) - 2; -#if 0 -static const word32 cannedKexAlgoNamesSz = - (word32)sizeof(cannedKexAlgoNames) - 2; -#endif -static const word32 cannedNoneNamesSz = - (word32)sizeof(cannedNoneNames) - 1; - -#define KEY_ALGO_SIZE_GUESS 28 +/* -1 for the null */ #ifndef WOLFSSH_NO_SSH_RSA_SHA1 static const word32 cannedKeyAlgoSshRsaNamesSz = @@ -9060,7 +9049,10 @@ int SendKexInit(WOLFSSH* ssh) char* keyAlgoNames = NULL; const byte* algo = NULL; word32 algoCount = 0, idx = 0, payloadSz = 0, - kexAlgoNamesSz = 0, keyAlgoNamesSz = 0; + kexAlgoNamesSz = 0, keyAlgoNamesSz = 0, + encAlgoNamesSz = 0, macAlgoNamesSz = 0, + noneNamesSz = 0; + int ret = WS_SUCCESS; WLOG(WS_LOG_DEBUG, "Entering SendKexInit()"); @@ -9139,11 +9131,14 @@ int SendKexInit(WOLFSSH* ssh) } if (ret == WS_SUCCESS) { + encAlgoNamesSz = AlgoListSz(ssh->algoListCipher); + macAlgoNamesSz = AlgoListSz(ssh->algoListMac); + noneNamesSz = AlgoListSz(cannedNoneNames); payloadSz = MSG_ID_SZ + COOKIE_SZ + (LENGTH_SZ * 11) + BOOLEAN_SZ + kexAlgoNamesSz + keyAlgoNamesSz + - (cannedEncAlgoNamesSz * 2) + - (cannedMacAlgoNamesSz * 2) + - (cannedNoneNamesSz * 2); + (encAlgoNamesSz * 2) + + (macAlgoNamesSz * 2) + + (noneNamesSz * 2); ret = PreparePacket(ssh, payloadSz); } @@ -9165,12 +9160,12 @@ int SendKexInit(WOLFSSH* ssh) CopyNameList(output, &idx, kexAlgoNames, kexAlgoNamesSz); CopyNameList(output, &idx, keyAlgoNames, keyAlgoNamesSz); - CopyNameList(output, &idx, cannedEncAlgoNames, cannedEncAlgoNamesSz); - CopyNameList(output, &idx, cannedEncAlgoNames, cannedEncAlgoNamesSz); - CopyNameList(output, &idx, cannedMacAlgoNames, cannedMacAlgoNamesSz); - CopyNameList(output, &idx, cannedMacAlgoNames, cannedMacAlgoNamesSz); - CopyNameList(output, &idx, cannedNoneNames, cannedNoneNamesSz); - CopyNameList(output, &idx, cannedNoneNames, cannedNoneNamesSz); + CopyNameList(output, &idx, ssh->algoListCipher, encAlgoNamesSz); + CopyNameList(output, &idx, ssh->algoListCipher, encAlgoNamesSz); + CopyNameList(output, &idx, ssh->algoListMac, macAlgoNamesSz); + CopyNameList(output, &idx, ssh->algoListMac, macAlgoNamesSz); + CopyNameList(output, &idx, cannedNoneNames, noneNamesSz); + CopyNameList(output, &idx, cannedNoneNames, noneNamesSz); c32toa(0, output + idx); /* Languages - Client To Server (0) */ idx += LENGTH_SZ; c32toa(0, output + idx); /* Languages - Server To Client (0) */ From c8e00a409b99caad0e69bb1893e14082a69e538d Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 26 Feb 2024 16:34:32 -0800 Subject: [PATCH 4/9] KEX Cipher Lists 1. Using the configurable list from the WOLFSSH for setting the KEX algorithm list. 2. Removed the ID lists for the KEX algorithm list used in DoKexInit(). 3. Changing DoKexInit() to use the configurable KEX list. --- src/internal.c | 155 ++++++++++++++++++++----------------------------- 1 file changed, 64 insertions(+), 91 deletions(-) diff --git a/src/internal.c b/src/internal.c index b77f2a2d3..34bb920ca 100644 --- a/src/internal.c +++ b/src/internal.c @@ -567,7 +567,6 @@ static const word32 cannedBannerSz = (word32)sizeof(cannedBanner) - 1; #endif /* DEBUG_WOLFSSH */ -#if 0 static const char cannedKexAlgoNames[] = #if !defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256) "ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org," @@ -584,14 +583,15 @@ static const char cannedKexAlgoNames[] = #if !defined(WOLFSSH_NO_DH_GEX_SHA256) "diffie-hellman-group-exchange-sha256," #endif -#if !defined(WOLFSSH_NO_DH_GROUP14_SHA1) - "diffie-hellman-group14-sha1," -#endif -#if !defined(WOLFSSH_NO_DH_GROUP1_SHA1) - "diffie-hellman-group1-sha1," -#endif +#ifndef WOLFSSH_NO_SHA1_SOFT_DISABLE + #if !defined(WOLFSSH_NO_DH_GROUP14_SHA1) + "diffie-hellman-group14-sha1," + #endif + #if !defined(WOLFSSH_NO_DH_GROUP1_SHA1) + "diffie-hellman-group1-sha1," + #endif +#endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ ""; -#endif #ifndef WOLFSSH_NO_SSH_RSA_SHA1 #ifdef WOLFSSH_CERTS @@ -709,8 +709,8 @@ WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap) ctx->windowSz = DEFAULT_WINDOW_SZ; ctx->maxPacketSz = DEFAULT_MAX_PACKET_SZ; ctx->sshProtoIdStr = sshProtoIdStr; -#if 0 ctx->algoListKex = cannedKexAlgoNames; +#if 0 ctx->algoListKey = cannedKeyAlgoNames; #endif ctx->algoListCipher = cannedEncAlgoNames; @@ -3186,34 +3186,7 @@ static const byte cannedKeyAlgoClient[] = { #endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ }; -static const byte cannedKexAlgo[] = { -#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 - ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256, -#endif -#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP521 - ID_ECDH_SHA2_NISTP521, -#endif -#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP384 - ID_ECDH_SHA2_NISTP384, -#endif -#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256 - ID_ECDH_SHA2_NISTP256, -#endif -#ifndef WOLFSSH_NO_DH_GEX_SHA256 - ID_DH_GEX_SHA256, -#endif -#ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE - #ifndef WOLFSSH_NO_DH_GROUP14_SHA1 - ID_DH_GROUP14_SHA1, - #endif - #ifndef WOLFSSH_NO_DH_GROUP1_SHA1 - ID_DH_GROUP1_SHA1, - #endif -#endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ -}; - static const word32 cannedKeyAlgoClientSz = (word32)sizeof(cannedKeyAlgoClient); -static const word32 cannedKexAlgoSz = (word32)sizeof(cannedKexAlgo); static byte MatchIdLists(int side, const byte* left, word32 leftSz, @@ -3572,31 +3545,36 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); } + if (ret == WS_SUCCESS) { + cannedAlgoNamesSz = AlgoListSz(ssh->algoListKex); + cannedListSz = (word32)sizeof(cannedList); + ret = GetNameListRaw(cannedList, &cannedListSz, + (const byte*)ssh->algoListKex, cannedAlgoNamesSz); + } if (ret == WS_SUCCESS) { ssh->handshake->kexIdGuess = list[0]; algoId = MatchIdLists(side, list, listSz, - cannedKexAlgo, cannedKexAlgoSz); + cannedList, cannedListSz); if (algoId == ID_UNKNOWN) { WLOG(WS_LOG_DEBUG, "Unable to negotiate KEX Algo"); ret = WS_MATCH_KEX_ALGO_E; } - else { - ssh->handshake->kexId = algoId; - ssh->handshake->kexHashId = HashForId(algoId); - } - - /* Extension Info Flag */ - if (ret == WS_SUCCESS) { - /* Only checking for this is we are server. Our client does - * not have anything to say to a server, yet. */ - if (side == WOLFSSH_ENDPOINT_SERVER) { - byte extInfo; + } + if (ret == WS_SUCCESS) { + ssh->handshake->kexId = algoId; + ssh->handshake->kexHashId = HashForId(algoId); + } + /* Extension Info Flag */ + if (ret == WS_SUCCESS) { + /* Only checking for this is we are server. Our client does + * not have anything to say to a server, yet. */ + if (side == WOLFSSH_ENDPOINT_SERVER) { + byte extInfo; - /* Match the client accepts extInfo. */ - algoId = ID_EXTINFO_C; - extInfo = MatchIdLists(side, list, listSz, &algoId, 1); - ssh->sendExtInfo = extInfo == algoId; - } + /* Match the client accepts extInfo. */ + algoId = ID_EXTINFO_C; + extInfo = MatchIdLists(side, list, listSz, &algoId, 1); + ssh->sendExtInfo = extInfo == algoId; } } @@ -8948,6 +8926,24 @@ static INLINE void CopyNameList(byte* buf, word32* idx, } +static INLINE void CopyNameListPlus(byte* buf, word32* idx, + const char* src, word32 srcSz, const char* plus, word32 plusSz) +{ + word32 begin = *idx; + + c32toa(srcSz + plusSz, buf + begin); + begin += LENGTH_SZ; + WMEMCPY(buf + begin, src, srcSz); + begin += srcSz; + if (plusSz) { + WMEMCPY(buf + begin, plus, plusSz); + } + begin += plusSz; + + *idx = begin; +} + + /* * Iterates over a list of ID values and builds a string of names. * @@ -9045,13 +9041,13 @@ int SendKexInit(WOLFSSH* ssh) { byte* output = NULL; byte* payload = NULL; - char* kexAlgoNames = NULL; char* keyAlgoNames = NULL; + const char* kexAlgoNamesPlus = NULL; const byte* algo = NULL; word32 algoCount = 0, idx = 0, payloadSz = 0, - kexAlgoNamesSz = 0, keyAlgoNamesSz = 0, - encAlgoNamesSz = 0, macAlgoNamesSz = 0, - noneNamesSz = 0; + kexAlgoNamesSz = 0, kexAlgoNamesPlusSz = 0, + keyAlgoNamesSz = 0, encAlgoNamesSz = 0, + macAlgoNamesSz = 0, noneNamesSz = 0; int ret = WS_SUCCESS; @@ -9077,34 +9073,6 @@ int SendKexInit(WOLFSSH* ssh) } } - if (ret == WS_SUCCESS) { - byte algoList[8]; - word32 algoListSz; - - WMEMCPY(algoList, cannedKexAlgo, cannedKexAlgoSz); - algoListSz = cannedKexAlgoSz; - if (ssh->ctx->side == WOLFSSH_ENDPOINT_CLIENT) { - algoList[cannedKexAlgoSz] = ID_EXTINFO_C; - algoListSz++; - } - - kexAlgoNamesSz = BuildNameList(NULL, 0, algoList, algoListSz) + 1; - kexAlgoNames = (char*)WMALLOC(kexAlgoNamesSz, - ssh->ctx->heap, DYNTYPE_STRING); - if (kexAlgoNames == NULL) { - ret = WS_MEMORY_E; - } - - if (ret == WS_SUCCESS) { - ret = BuildNameList(kexAlgoNames, kexAlgoNamesSz, - algoList, algoListSz); - if (ret > 0) { - kexAlgoNamesSz = (word32)ret; - ret = WS_SUCCESS; - } - } - } - if (ret == WS_SUCCESS) { if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) { algoCount = ssh->ctx->publicKeyAlgoCount; @@ -9131,14 +9099,18 @@ int SendKexInit(WOLFSSH* ssh) } if (ret == WS_SUCCESS) { + if (ssh->ctx->side == WOLFSSH_ENDPOINT_CLIENT) { + kexAlgoNamesPlus = ",ext-info-c"; + kexAlgoNamesPlusSz = (word32)WSTRLEN(kexAlgoNamesPlus); + } + + kexAlgoNamesSz = AlgoListSz(ssh->algoListKex); encAlgoNamesSz = AlgoListSz(ssh->algoListCipher); macAlgoNamesSz = AlgoListSz(ssh->algoListMac); noneNamesSz = AlgoListSz(cannedNoneNames); payloadSz = MSG_ID_SZ + COOKIE_SZ + (LENGTH_SZ * 11) + BOOLEAN_SZ + - kexAlgoNamesSz + keyAlgoNamesSz + - (encAlgoNamesSz * 2) + - (macAlgoNamesSz * 2) + - (noneNamesSz * 2); + + kexAlgoNamesSz + kexAlgoNamesPlusSz + keyAlgoNamesSz + + (encAlgoNamesSz * 2) + (macAlgoNamesSz * 2) + (noneNamesSz * 2); ret = PreparePacket(ssh, payloadSz); } @@ -9158,7 +9130,9 @@ int SendKexInit(WOLFSSH* ssh) idx += COOKIE_SZ; - CopyNameList(output, &idx, kexAlgoNames, kexAlgoNamesSz); + CopyNameListPlus(output, &idx, + ssh->algoListKex, kexAlgoNamesSz, + kexAlgoNamesPlus, kexAlgoNamesPlusSz); CopyNameList(output, &idx, keyAlgoNames, keyAlgoNamesSz); CopyNameList(output, &idx, ssh->algoListCipher, encAlgoNamesSz); CopyNameList(output, &idx, ssh->algoListCipher, encAlgoNamesSz); @@ -9193,7 +9167,6 @@ int SendKexInit(WOLFSSH* ssh) } } - WFREE(kexAlgoNames, ssh->ctx->heap, DYNTYPE_STRING); WFREE(keyAlgoNames, ssh->ctx->heap, DYNTYPE_STRING); if (ret == WS_SUCCESS) { From cfe99cc696abebc62afdd9bc29c4ea6ebbfec44a Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 27 Feb 2024 17:28:11 -0800 Subject: [PATCH 5/9] KEX Cipher Lists 1. Fix using the MAC algorithm list from the WOLFSSH object when matching the peer's algorithm. 2. Fix polarity checking WOLFSSH_NO_SHA1_SOFT_DISABLE. 3. Remove some redundant size constants. Use strlen(). 4. Rearrange the canned key algorithm names, add the missing items, and add guards. 5. Whitespace. --- src/internal.c | 105 +++++++++++++++---------------------------------- 1 file changed, 31 insertions(+), 74 deletions(-) diff --git a/src/internal.c b/src/internal.c index 34bb920ca..a32976a3b 100644 --- a/src/internal.c +++ b/src/internal.c @@ -583,7 +583,7 @@ static const char cannedKexAlgoNames[] = #if !defined(WOLFSSH_NO_DH_GEX_SHA256) "diffie-hellman-group-exchange-sha256," #endif -#ifndef WOLFSSH_NO_SHA1_SOFT_DISABLE +#ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE #if !defined(WOLFSSH_NO_DH_GROUP14_SHA1) "diffie-hellman-group14-sha1," #endif @@ -630,12 +630,19 @@ static const char cannedKexAlgoNames[] = static const char cannedKeyAlgoRsaSha2_512Names[] = "rsa-sha2-512"; #endif -#ifdef WOLFSSH_CERTS static const char cannedKeyAlgoNames[] = - "rsa-sha2-256,x509v3-ssh-rsa,ecdsa-sha2-nistp256,x509v3-ecdsa-sha2-nistp256"; -#else -static const char cannedKeyAlgoNames[] = "rsa-sha2-256,ecdsa-sha2-nistp256"; -#endif + "rsa-sha2-256," + "ecdsa-sha2-nistp256," +#ifdef WOLFSSH_CERTS + "x509v3-ecdsa-sha2-nistp256," + #ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE + "x509v3-ssh-rsa," + #endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ +#endif /* WOLFSSH_CERTS */ +#ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE + "ssh-rsa," +#endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ + ""; static const char cannedEncAlgoNames[] = #if !defined(WOLFSSH_NO_AES_GCM) @@ -710,9 +717,6 @@ WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap) ctx->maxPacketSz = DEFAULT_MAX_PACKET_SZ; ctx->sshProtoIdStr = sshProtoIdStr; ctx->algoListKex = cannedKexAlgoNames; -#if 0 - ctx->algoListKey = cannedKeyAlgoNames; -#endif ctx->algoListCipher = cannedEncAlgoNames; ctx->algoListMac = cannedMacAlgoNames; @@ -3674,7 +3678,7 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) cannedAlgoNamesSz = AlgoListSz(ssh->algoListMac); cannedListSz = (word32)sizeof(cannedList); ret = GetNameListRaw(cannedList, &cannedListSz, - (const byte*)cannedMacAlgoNames, cannedAlgoNamesSz); + (const byte*)ssh->algoListMac, cannedAlgoNamesSz); } if (ret == WS_SUCCESS) { algoId = MatchIdLists(side, list, listSz, cannedList, cannedListSz); @@ -3700,11 +3704,11 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) } } if (ret == WS_SUCCESS) { - ssh->handshake->macId = algoId; - ssh->handshake->macSz = MacSzForId(algoId); - ssh->handshake->keys.macKeySz = - ssh->handshake->peerKeys.macKeySz = - KeySzForId(algoId); + ssh->handshake->macId = algoId; + ssh->handshake->macSz = MacSzForId(algoId); + ssh->handshake->keys.macKeySz = + ssh->handshake->peerKeys.macKeySz = + KeySzForId(algoId); } } @@ -3802,7 +3806,8 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) } if (ret == WS_SUCCESS) { - ret = HashUpdate(hash, hashId, (const byte*)ssh->ctx->sshProtoIdStr, strSz); + ret = HashUpdate(hash, hashId, + (const byte*)ssh->ctx->sshProtoIdStr, strSz); } if (ret == WS_SUCCESS) { @@ -8992,51 +8997,6 @@ static int BuildNameList(char* buf, word32 bufSz, } -/* -1 for the null */ - -#ifndef WOLFSSH_NO_SSH_RSA_SHA1 - static const word32 cannedKeyAlgoSshRsaNamesSz = - (word32)sizeof(cannedKeyAlgoSshRsaNames) - 1; -#endif -#ifndef WOLFSSH_NO_RSA_SHA2_256 - static const word32 cannedKeyAlgoRsaSha2_256NamesSz = - (word32)sizeof(cannedKeyAlgoRsaSha2_256Names) - 1; -#endif -#ifndef WOLFSSH_NO_RSA_SHA2_512 - static const word32 cannedKeyAlgoRsaSha2_512NamesSz = - (word32)sizeof(cannedKeyAlgoRsaSha2_512Names) - 1; -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - static const word32 cannedKeyAlgoEcc256NamesSz = - (word32)sizeof(cannedKeyAlgoEcc256Names) - 1; -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - static const word32 cannedKeyAlgoEcc384NamesSz = - (word32)sizeof(cannedKeyAlgoEcc384Names) - 1; -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - static const word32 cannedKeyAlgoEcc521NamesSz = - (word32)sizeof(cannedKeyAlgoEcc521Names) - 1; -#endif -#ifdef WOLFSSH_CERTS -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - static const word32 cannedKeyAlgoX509Ecc256NamesSz = - (word32)sizeof(cannedKeyAlgoX509Ecc256Names) - 1; -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - static const word32 cannedKeyAlgoX509Ecc384NamesSz = - (word32)sizeof(cannedKeyAlgoX509Ecc384Names) - 1; -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - static const word32 cannedKeyAlgoX509Ecc521NamesSz = - (word32)sizeof(cannedKeyAlgoX509Ecc521Names) - 1; -#endif -#endif /* WOLFSSH_CERTS */ - -static const word32 cannedKeyAlgoNamesSz = - (word32)sizeof(cannedKeyAlgoNames) - 1; - - int SendKexInit(WOLFSSH* ssh) { byte* output = NULL; @@ -11250,12 +11210,14 @@ int SendServiceAccept(WOLFSSH* ssh, byte serviceId) #define WS_EXTINFO_EXTENSION_COUNT 1 static const char serverSigAlgsName[] = "server-sig-algs"; -static word32 serverSigAlgsNameSz = (word32)sizeof(serverSigAlgsName) - 1; + int SendExtInfo(WOLFSSH* ssh) { byte* output; word32 idx; + word32 cannedKeyAlgoNamesSz = 0; + word32 serverSigAlgsNameSz = 0; int ret = WS_SUCCESS; WLOG(WS_LOG_DEBUG, "Entering SendExtInfo()"); @@ -11265,6 +11227,8 @@ int SendExtInfo(WOLFSSH* ssh) } if (ret == WS_SUCCESS) { + cannedKeyAlgoNamesSz = AlgoListSz(cannedKeyAlgoNames); + serverSigAlgsNameSz = AlgoListSz(serverSigAlgsName); ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ + (LENGTH_SZ * 2) + serverSigAlgsNameSz + cannedKeyAlgoNamesSz); } @@ -11482,19 +11446,16 @@ static int BuildUserAuthRequestRsa(WOLFSSH* ssh, #ifndef WOLFSSH_NO_SSH_RSA_SHA1 case ID_SSH_RSA: names = cannedKeyAlgoSshRsaNames; - namesSz = cannedKeyAlgoSshRsaNamesSz; break; #endif #ifndef WOLFSSH_NO_RSA_SHA2_256 case ID_RSA_SHA2_256: names = cannedKeyAlgoRsaSha2_256Names; - namesSz = cannedKeyAlgoRsaSha2_256NamesSz; break; #endif #ifndef WOLFSSH_NO_RSA_SHA2_512 case ID_RSA_SHA2_512: names = cannedKeyAlgoRsaSha2_512Names; - namesSz = cannedKeyAlgoRsaSha2_512NamesSz; break; #endif default: @@ -11503,6 +11464,7 @@ static int BuildUserAuthRequestRsa(WOLFSSH* ssh, } if (ret == WS_SUCCESS) { + namesSz = (word32)WSTRLEN(names); c32toa(keySig->sigSz + namesSz + LENGTH_SZ * 2, output + begin); begin += LENGTH_SZ; c32toa(namesSz, output + begin); @@ -11916,19 +11878,16 @@ static int BuildUserAuthRequestEcc(WOLFSSH* ssh, #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 case ID_ECDSA_SHA2_NISTP256: names = cannedKeyAlgoEcc256Names; - namesSz = cannedKeyAlgoEcc256NamesSz; break; #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 case ID_ECDSA_SHA2_NISTP384: names = cannedKeyAlgoEcc384Names; - namesSz = cannedKeyAlgoEcc384NamesSz; break; #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 case ID_ECDSA_SHA2_NISTP521: names = cannedKeyAlgoEcc521Names; - namesSz = cannedKeyAlgoEcc521NamesSz; break; #endif default: @@ -11937,6 +11896,8 @@ static int BuildUserAuthRequestEcc(WOLFSSH* ssh, } if (ret == WS_SUCCESS) { + namesSz = (word32)WSTRLEN(names); + c32toa(rSz + rPad + sSz + sPad + namesSz + LENGTH_SZ * 4, output + begin); begin += LENGTH_SZ; @@ -12160,37 +12121,31 @@ static int BuildUserAuthRequestEccCert(WOLFSSH* ssh, #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 case ID_ECDSA_SHA2_NISTP256: names = cannedKeyAlgoEcc256Names; - namesSz = cannedKeyAlgoEcc256NamesSz; break; #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 case ID_ECDSA_SHA2_NISTP384: names = cannedKeyAlgoEcc384Names; - namesSz = cannedKeyAlgoEcc384NamesSz; break; #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 case ID_ECDSA_SHA2_NISTP521: names = cannedKeyAlgoEcc521Names; - namesSz = cannedKeyAlgoEcc521NamesSz; break; #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 case ID_X509V3_ECDSA_SHA2_NISTP256: names = cannedKeyAlgoX509Ecc256Names; - namesSz = cannedKeyAlgoX509Ecc256NamesSz; break; #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 case ID_X509V3_ECDSA_SHA2_NISTP384: names = cannedKeyAlgoX509Ecc384Names; - namesSz = cannedKeyAlgoX509Ecc384NamesSz; break; #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 case ID_X509V3_ECDSA_SHA2_NISTP521: names = cannedKeyAlgoX509Ecc521Names; - namesSz = cannedKeyAlgoX509Ecc521NamesSz; break; #endif default: @@ -12199,6 +12154,8 @@ static int BuildUserAuthRequestEccCert(WOLFSSH* ssh, } if (ret == WS_SUCCESS) { + namesSz = (word32)WSTRLEN(names); + c32toa(rSz + rPad + sSz + sPad + namesSz+ LENGTH_SZ * 4, output + begin); begin += LENGTH_SZ; From 2fabf0644171cff1cca17c2f7967d02549da5056 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 28 Feb 2024 16:11:37 -0800 Subject: [PATCH 6/9] KEX Cipher Lists 1. Change SendKexInit() to send the configured Key algorithm list or the default list if a client or server with a list set. If the server doesn't have a list set, use the list from adding the keys. 2. Add the soft disable macro around setting ssh-rsa to the list of public key types in the server. 3. Change DoKexInit() to use the appropriate key algorithm list for decoding and matching the peer's list. 4. Whitespace. 5. Rearrange the new functions and prototypes in a different order. --- src/internal.c | 146 +++++++++++++++++++++++++++---------------------- src/ssh.c | 30 +++++----- wolfssh/ssh.h | 4 +- 3 files changed, 98 insertions(+), 82 deletions(-) diff --git a/src/internal.c b/src/internal.c index a32976a3b..8c7c773b2 100644 --- a/src/internal.c +++ b/src/internal.c @@ -717,6 +717,9 @@ WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap) ctx->maxPacketSz = DEFAULT_MAX_PACKET_SZ; ctx->sshProtoIdStr = sshProtoIdStr; ctx->algoListKex = cannedKexAlgoNames; + if (side == WOLFSSH_ENDPOINT_CLIENT) { + ctx->algoListKey = cannedKeyAlgoNames; + } ctx->algoListCipher = cannedEncAlgoNames; ctx->algoListMac = cannedMacAlgoNames; @@ -1525,13 +1528,15 @@ static void RefreshPublicKeyAlgo(WOLFSSH_CTX* ctx) publicKeyAlgoCount++; } #endif - #ifndef WOLFSSH_NO_SSH_RSA_SHA1 - if (publicKeyAlgoCount < WOLFSSH_MAX_PUB_KEY_ALGO) { - *publicKeyAlgo = ID_SSH_RSA; - publicKeyAlgo++; - publicKeyAlgoCount++; - } - #endif + #ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE + #ifndef WOLFSSH_NO_SSH_RSA_SHA1 + if (publicKeyAlgoCount < WOLFSSH_MAX_PUB_KEY_ALGO) { + *publicKeyAlgo = ID_SSH_RSA; + publicKeyAlgo++; + publicKeyAlgoCount++; + } + #endif /* WOLFSSH_NO_SSH_RSA_SHA1 */ + #endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ } else { if (publicKeyAlgoCount < WOLFSSH_MAX_PUB_KEY_ALGO) { @@ -3587,27 +3592,27 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: Server Host Key Algorithms"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (ret == WS_SUCCESS) { - const byte *cannedKeyAlgo = NULL; - word32 cannedKeyAlgoSz = 0; - - if (side == WOLFSSH_ENDPOINT_SERVER) { - cannedKeyAlgo = ssh->ctx->publicKeyAlgo; - cannedKeyAlgoSz = ssh->ctx->publicKeyAlgoCount; - } - else { - cannedKeyAlgo = cannedKeyAlgoClient; - cannedKeyAlgoSz = cannedKeyAlgoClientSz; - } - algoId = MatchIdLists(side, list, listSz, - cannedKeyAlgo, cannedKeyAlgoSz); - if (algoId == ID_UNKNOWN) { - WLOG(WS_LOG_DEBUG, "Unable to negotiate Server Host Key Algo"); - return WS_MATCH_KEY_ALGO_E; - } - else { - ssh->handshake->pubKeyId = algoId; - } + } + if (ret == WS_SUCCESS) { + if (side == WOLFSSH_ENDPOINT_SERVER && !ssh->algoListKey) { + cannedListSz = ssh->ctx->publicKeyAlgoCount; + WMEMCPY(cannedList, ssh->ctx->publicKeyAlgo, cannedListSz); + } + else { + cannedAlgoNamesSz = AlgoListSz(ssh->algoListKey); + cannedListSz = (word32)sizeof(cannedList); + ret = GetNameListRaw(cannedList, &cannedListSz, + (const byte*)ssh->algoListKey, cannedAlgoNamesSz); + } + } + if (ret == WS_SUCCESS) { + algoId = MatchIdLists(side, list, listSz, cannedList, cannedListSz); + if (algoId == ID_UNKNOWN) { + WLOG(WS_LOG_DEBUG, "Unable to negotiate Server Host Key Algo"); + return WS_MATCH_KEY_ALGO_E; + } + else { + ssh->handshake->pubKeyId = algoId; } } @@ -3624,8 +3629,7 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) (const byte*)ssh->algoListCipher, cannedAlgoNamesSz); } if (ret == WS_SUCCESS) { - algoId = MatchIdLists(side, list, listSz, - cannedList, cannedListSz); + algoId = MatchIdLists(side, list, listSz, cannedList, cannedListSz); if (algoId == ID_UNKNOWN) { WLOG(WS_LOG_DEBUG, "Unable to negotiate Encryption Algo C2S"); ret = WS_MATCH_ENC_ALGO_E; @@ -3720,11 +3724,12 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: Compression Algorithms - Client to Server"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (ret == WS_SUCCESS) { - if (MatchIdLists(side, list, listSz, &algoId, 1) == ID_UNKNOWN) { - WLOG(WS_LOG_DEBUG, "Unable to negotiate Compression Algo C2S"); - ret = WS_INVALID_ALGO_ID; - } + } + if (ret == WS_SUCCESS) { + algoId = MatchIdLists(side, list, listSz, &algoId, 1); + if (algoId == ID_UNKNOWN) { + WLOG(WS_LOG_DEBUG, "Unable to negotiate Compression Algo C2S"); + ret = WS_INVALID_ALGO_ID; } } @@ -3733,11 +3738,12 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: Compression Algorithms - Server to Client"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (ret == WS_SUCCESS) { - if (MatchIdLists(side, list, listSz, &algoId, 1) == ID_UNKNOWN) { - WLOG(WS_LOG_DEBUG, "Unable to negotiate Compression Algo S2C"); - ret = WS_INVALID_ALGO_ID; - } + } + if (ret == WS_SUCCESS) { + algoId = MatchIdLists(side, list, listSz, &algoId, 1); + if (algoId == ID_UNKNOWN) { + WLOG(WS_LOG_DEBUG, "Unable to negotiate Compression Algo S2C"); + ret = WS_INVALID_ALGO_ID; } } @@ -9003,8 +9009,7 @@ int SendKexInit(WOLFSSH* ssh) byte* payload = NULL; char* keyAlgoNames = NULL; const char* kexAlgoNamesPlus = NULL; - const byte* algo = NULL; - word32 algoCount = 0, idx = 0, payloadSz = 0, + word32 idx = 0, payloadSz = 0, kexAlgoNamesSz = 0, kexAlgoNamesPlusSz = 0, keyAlgoNamesSz = 0, encAlgoNamesSz = 0, macAlgoNamesSz = 0, noneNamesSz = 0; @@ -9034,27 +9039,25 @@ int SendKexInit(WOLFSSH* ssh) } if (ret == WS_SUCCESS) { - if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) { - algoCount = ssh->ctx->publicKeyAlgoCount; - algo = ssh->ctx->publicKeyAlgo; - } - else { - algoCount = cannedKeyAlgoClientSz; - algo = cannedKeyAlgoClient; - } - keyAlgoNamesSz = BuildNameList(NULL, 0, algo, algoCount) + 1; - keyAlgoNames = (char*)WMALLOC(keyAlgoNamesSz, - ssh->ctx->heap, DYNTYPE_STRING); - if (keyAlgoNames == NULL) { - ret = WS_MEMORY_E; - } - } - - if (ret == WS_SUCCESS) { - ret = BuildNameList(keyAlgoNames, keyAlgoNamesSz, algo, algoCount); - if (ret > 0) { - keyAlgoNamesSz = (word32)ret; - ret = WS_SUCCESS; + if (!ssh->algoListKey && ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) { + keyAlgoNamesSz = BuildNameList(NULL, 0, + ssh->ctx->publicKeyAlgo, + ssh->ctx->publicKeyAlgoCount) + + 1; + keyAlgoNames = (char*)WMALLOC(keyAlgoNamesSz, + ssh->ctx->heap, DYNTYPE_STRING); + if (keyAlgoNames) { + ret = BuildNameList(keyAlgoNames, keyAlgoNamesSz, + ssh->ctx->publicKeyAlgo, + ssh->ctx->publicKeyAlgoCount); + if (ret > 0) { + keyAlgoNamesSz = (word32)ret; + ret = WS_SUCCESS; + } + } + else { + ret = WS_MEMORY_E; + } } } @@ -9066,6 +9069,12 @@ int SendKexInit(WOLFSSH* ssh) kexAlgoNamesSz = AlgoListSz(ssh->algoListKex); encAlgoNamesSz = AlgoListSz(ssh->algoListCipher); + if (!keyAlgoNames) { + keyAlgoNamesSz = (word32)WSTRLEN(ssh->algoListKey); + } + else { + keyAlgoNamesSz = AlgoListSz(keyAlgoNames); + } macAlgoNamesSz = AlgoListSz(ssh->algoListMac); noneNamesSz = AlgoListSz(cannedNoneNames); payloadSz = MSG_ID_SZ + COOKIE_SZ + (LENGTH_SZ * 11) + BOOLEAN_SZ + @@ -9093,7 +9102,12 @@ int SendKexInit(WOLFSSH* ssh) CopyNameListPlus(output, &idx, ssh->algoListKex, kexAlgoNamesSz, kexAlgoNamesPlus, kexAlgoNamesPlusSz); - CopyNameList(output, &idx, keyAlgoNames, keyAlgoNamesSz); + if (!keyAlgoNames) { + CopyNameList(output, &idx, ssh->algoListKey, keyAlgoNamesSz); + } + else { + CopyNameList(output, &idx, keyAlgoNames, keyAlgoNamesSz); + } CopyNameList(output, &idx, ssh->algoListCipher, encAlgoNamesSz); CopyNameList(output, &idx, ssh->algoListCipher, encAlgoNamesSz); CopyNameList(output, &idx, ssh->algoListMac, macAlgoNamesSz); @@ -9127,7 +9141,9 @@ int SendKexInit(WOLFSSH* ssh) } } - WFREE(keyAlgoNames, ssh->ctx->heap, DYNTYPE_STRING); + if (keyAlgoNames) { + WFREE(keyAlgoNames, ssh->ctx->heap, DYNTYPE_STRING); + } if (ret == WS_SUCCESS) { /* increase amount to be sent only if BundlePacket will be called */ diff --git a/src/ssh.c b/src/ssh.c index 7467c8614..5edb6ee9a 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -1932,21 +1932,6 @@ int wolfSSH_ReadKey_file(const char* name, #endif -int wolfSSH_CheckAlgoName(const char* name) -{ - int ret = WS_INVALID_ALGO_ID; - - if (name) { - word32 nameSz = (word32)WSTRLEN(name); - if (NameToId(name, nameSz) != ID_UNKNOWN) { - ret = WS_SUCCESS; - } - } - - return ret; -} - - int wolfSSH_CTX_SetAlgoListKex(WOLFSSH_CTX* ctx, const char* list) { int ret = WS_SSH_CTX_NULL_E; @@ -2147,6 +2132,21 @@ const char* wolfSSH_GetAlgoListMac(WOLFSSH* ssh) } +int wolfSSH_CheckAlgoName(const char* name) +{ + int ret = WS_INVALID_ALGO_ID; + + if (name) { + word32 nameSz = (word32)WSTRLEN(name); + if (NameToId(name, nameSz) != ID_UNKNOWN) { + ret = WS_SUCCESS; + } + } + + return ret; +} + + const char* wolfSSH_QueryKex(word32* index) { return NameByIndexType(TYPE_KEX, index); diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index dd07cb93e..3941561ea 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -90,8 +90,6 @@ WOLFSSH_API int wolfSSH_ReadKey_file(const char* name, byte** out, word32* outSz, const byte** outType, word32* outTypeSz, byte* isPrivate, void* heap); -WOLFSSH_API int wolfSSH_CheckAlgoName(const char* name); - WOLFSSH_API int wolfSSH_CTX_SetAlgoListKex(WOLFSSH_CTX* ctx, const char* list); WOLFSSH_API const char* wolfSSH_CTX_GetAlgoListKex(WOLFSSH_CTX* ctx); WOLFSSH_API int wolfSSH_SetAlgoListKex(WOLFSSH* ssh, const char* list); @@ -113,6 +111,8 @@ WOLFSSH_API const char* wolfSSH_CTX_GetAlgoListMac(WOLFSSH_CTX* ctx); WOLFSSH_API int wolfSSH_SetAlgoListMac(WOLFSSH* ssh, const char* list); WOLFSSH_API const char* wolfSSH_GetAlgoListMac(WOLFSSH* ssh); +WOLFSSH_API int wolfSSH_CheckAlgoName(const char* name); + WOLFSSH_API const char* wolfSSH_QueryKex(word32* index); WOLFSSH_API const char* wolfSSH_QueryKey(word32* index); WOLFSSH_API const char* wolfSSH_QueryCipher(word32* index); From ad135453054e06fd6f69ab8e138a9ef60963bd9a Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 29 Feb 2024 13:17:07 -0800 Subject: [PATCH 7/9] KEX Cipher Lists 1. Add new list for the public key algorithms the server can verify from the client for user authentication. 2. Add accessors for the key allowed list. --- src/internal.c | 14 +++++++------ src/ssh.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++ wolfssh/internal.h | 2 ++ wolfssh/ssh.h | 6 ++++++ 4 files changed, 66 insertions(+), 6 deletions(-) diff --git a/src/internal.c b/src/internal.c index 8c7c773b2..a6c5d1d30 100644 --- a/src/internal.c +++ b/src/internal.c @@ -722,6 +722,7 @@ WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap) } ctx->algoListCipher = cannedEncAlgoNames; ctx->algoListMac = cannedMacAlgoNames; + ctx->algoListKeyAccepted = cannedKeyAlgoNames; count = (word32)(sizeof(ctx->privateKey) / sizeof(ctx->privateKey[0])); @@ -894,6 +895,7 @@ WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx) ssh->algoListKey = ctx->algoListKey; ssh->algoListCipher = ctx->algoListCipher; ssh->algoListMac = ctx->algoListMac; + ssh->algoListKeyAccepted = ctx->algoListKeyAccepted; #ifdef WOLFSSH_SCP ssh->scpRequestState = SCP_PARSE_COMMAND; ssh->scpConfirmMsg = NULL; @@ -11232,7 +11234,7 @@ int SendExtInfo(WOLFSSH* ssh) { byte* output; word32 idx; - word32 cannedKeyAlgoNamesSz = 0; + word32 keyAlgoNamesSz = 0; word32 serverSigAlgsNameSz = 0; int ret = WS_SUCCESS; @@ -11243,10 +11245,10 @@ int SendExtInfo(WOLFSSH* ssh) } if (ret == WS_SUCCESS) { - cannedKeyAlgoNamesSz = AlgoListSz(cannedKeyAlgoNames); + keyAlgoNamesSz = AlgoListSz(ssh->algoListKeyAccepted); serverSigAlgsNameSz = AlgoListSz(serverSigAlgsName); ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ + (LENGTH_SZ * 2) - + serverSigAlgsNameSz + cannedKeyAlgoNamesSz); + + serverSigAlgsNameSz + keyAlgoNamesSz); } if (ret == WS_SUCCESS) { @@ -11262,10 +11264,10 @@ int SendExtInfo(WOLFSSH* ssh) WMEMCPY(output + idx, serverSigAlgsName, serverSigAlgsNameSz); idx += serverSigAlgsNameSz; - c32toa(cannedKeyAlgoNamesSz, output + idx); + c32toa(keyAlgoNamesSz, output + idx); idx += LENGTH_SZ; - WMEMCPY(output + idx, cannedKeyAlgoNames, cannedKeyAlgoNamesSz); - idx += cannedKeyAlgoNamesSz; + WMEMCPY(output + idx, ssh->algoListKeyAccepted, keyAlgoNamesSz); + idx += keyAlgoNamesSz; ssh->outputBuffer.length = idx; diff --git a/src/ssh.c b/src/ssh.c index 5edb6ee9a..73ee5fea8 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -2132,6 +2132,56 @@ const char* wolfSSH_GetAlgoListMac(WOLFSSH* ssh) } +int wolfSSH_CTX_SetAlgoListKeyAccepted(WOLFSSH_CTX* ctx, const char* list) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx) { + ctx->algoListKeyAccepted = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_CTX_GetAlgoListKeyAccepted(WOLFSSH_CTX* ctx) +{ + const char* list = NULL; + + if (ctx) { + list = ctx->algoListKeyAccepted; + } + + return list; +} + + +int wolfSSH_SetAlgoListKeyAccepted(WOLFSSH* ssh, const char* list) +{ + int ret = WS_SSH_NULL_E; + + if (ssh) { + ssh->algoListKeyAccepted = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_GetAlgoListKeyAccepted(WOLFSSH* ssh) +{ + const char* list = NULL; + + if (ssh) { + list = ssh->algoListKeyAccepted; + } + + return list; +} + + int wolfSSH_CheckAlgoName(const char* name) { int ret = WS_INVALID_ALGO_ID; diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 228854a5d..80ffefec0 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -513,6 +513,7 @@ struct WOLFSSH_CTX { const char* algoListKey; const char* algoListCipher; const char* algoListMac; + const char* algoListKeyAccepted; word32 bannerSz; word32 windowSz; word32 maxPacketSz; @@ -653,6 +654,7 @@ struct WOLFSSH { const char* algoListKey; const char* algoListCipher; const char* algoListMac; + const char* algoListKeyAccepted; byte acceptState; byte connectState; byte clientState; diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index 3941561ea..a303ae6c4 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -111,6 +111,12 @@ WOLFSSH_API const char* wolfSSH_CTX_GetAlgoListMac(WOLFSSH_CTX* ctx); WOLFSSH_API int wolfSSH_SetAlgoListMac(WOLFSSH* ssh, const char* list); WOLFSSH_API const char* wolfSSH_GetAlgoListMac(WOLFSSH* ssh); +WOLFSSH_API int wolfSSH_CTX_SetAlgoListKeyAccepted(WOLFSSH_CTX* ctx, + const char* list); +WOLFSSH_API const char* wolfSSH_CTX_GetAlgoListKeyAccepted(WOLFSSH_CTX* ctx); +WOLFSSH_API int wolfSSH_SetAlgoListKeyAccepted(WOLFSSH* ssh, const char* list); +WOLFSSH_API const char* wolfSSH_GetAlgoListKeyAccepted(WOLFSSH* ssh); + WOLFSSH_API int wolfSSH_CheckAlgoName(const char* name); WOLFSSH_API const char* wolfSSH_QueryKex(word32* index); From 6dd53b12ecafefb447be208dd142d1839d28b84e Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 1 Mar 2024 15:42:17 -0800 Subject: [PATCH 8/9] KEX Cipher Lists 1. Add API test. --- tests/api.c | 232 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 199 insertions(+), 33 deletions(-) diff --git a/tests/api.c b/tests/api.c index 4799a00af..0a9e763f2 100644 --- a/tests/api.c +++ b/tests/api.c @@ -1309,82 +1309,248 @@ static void test_wolfSSH_RealPath(void) { ; } static void test_wolfSSH_SetAlgoList(void) { - const char* list = "aes128-ctr,aes128-cbc"; - const char* checkList = NULL; + const char* newKexList = "diffie-hellman-group1-sha1,ecdh-sha2-nistp521"; + const char* newKeyList = "rsa-sha2-512,ecdsa-sha2-nistp521"; + const char* newCipherList = "aes128-ctr,aes128-cbc"; + const char* newMacList = "hmac-sha1"; + const char* newKeyAccList = "ssh-rsa"; + const char* defaultKexList = NULL; + const char* defaultKeyList = NULL; + const char* defaultCipherList = NULL; + const char* defaultMacList = NULL; + const char* defaultKeyAccList = NULL; + const char* checkKexList = NULL; + const char* checkKeyList = NULL; + const char* checkCipherList = NULL; + const char* checkMacList = NULL; + const char* checkKeyAccList = NULL; + const char* rawKey = NULL; WOLFSSH_CTX* ctx; WOLFSSH* ssh; + byte* key; + word32 keySz; + /* Create a ctx object. */ ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL); + AssertNotNull(ctx); + + /* Check that the ctx's default algo lists are not null */ + defaultKexList = wolfSSH_CTX_GetAlgoListKex(ctx); + AssertNotNull(defaultKexList); + + defaultKeyList = wolfSSH_CTX_GetAlgoListKey(ctx); + AssertNotNull(defaultKeyList); + + defaultCipherList = wolfSSH_CTX_GetAlgoListCipher(ctx); + AssertNotNull(defaultCipherList); + + defaultMacList = wolfSSH_CTX_GetAlgoListMac(ctx); + AssertNotNull(defaultMacList); + + defaultKeyAccList = wolfSSH_CTX_GetAlgoListKeyAccepted(ctx); + AssertNotNull(defaultKeyAccList); + + /* Create a new ssh object. */ ssh = wolfSSH_new(ctx); + AssertNotNull(ssh); - wolfSSH_SetAlgoListCipher(ssh, list); - checkList = wolfSSH_GetAlgoListCipher(ssh); + /* Check that the ssh's default algo lists match the ctx's algo lists. */ + checkKexList = wolfSSH_GetAlgoListKex(ssh); + AssertPtrEq(checkKexList, defaultKexList); - if (checkList != list) { - printf("Didn't get back the correct list.\n"); - } + checkKeyList = wolfSSH_GetAlgoListKey(ssh); + AssertPtrEq(checkKeyList, defaultKeyList); + + checkCipherList = wolfSSH_GetAlgoListCipher(ssh); + AssertPtrEq(checkCipherList, defaultCipherList); + + checkMacList = wolfSSH_GetAlgoListMac(ssh); + AssertPtrEq(checkMacList, defaultMacList); + + checkKeyAccList = wolfSSH_GetAlgoListKeyAccepted(ssh); + AssertPtrEq(checkKeyAccList, defaultKeyAccList); + + /* Set the ssh's algo lists, check they match new value. */ + wolfSSH_SetAlgoListKex(ssh, newKexList); + checkKexList = wolfSSH_GetAlgoListKex(ssh); + AssertPtrEq(checkKexList, newKexList); + + wolfSSH_SetAlgoListKey(ssh, newKeyList); + checkKeyList = wolfSSH_GetAlgoListKey(ssh); + AssertPtrEq(checkKeyList, newKeyList); + + wolfSSH_SetAlgoListCipher(ssh, newCipherList); + checkCipherList = wolfSSH_GetAlgoListCipher(ssh); + AssertPtrEq(checkCipherList, newCipherList); + + wolfSSH_SetAlgoListMac(ssh, newMacList); + checkMacList = wolfSSH_GetAlgoListMac(ssh); + AssertPtrEq(checkMacList, newMacList); + + wolfSSH_SetAlgoListKeyAccepted(ssh, newKeyAccList); + checkKeyAccList = wolfSSH_GetAlgoListKeyAccepted(ssh); + AssertPtrEq(checkKeyAccList, newKeyAccList); + + /* Delete the ssh. */ + wolfSSH_free(ssh); + + /* Set new algo lists on the ctx. */ + wolfSSH_CTX_SetAlgoListKex(ctx, newKexList); + defaultKexList = wolfSSH_CTX_GetAlgoListKex(ctx); + AssertPtrEq(defaultKexList, newKexList); + + wolfSSH_CTX_SetAlgoListKey(ctx, newKeyList); + defaultKeyList = wolfSSH_CTX_GetAlgoListKey(ctx); + AssertPtrEq(checkKeyList, newKeyList); + + wolfSSH_CTX_SetAlgoListCipher(ctx, newCipherList); + defaultCipherList = wolfSSH_CTX_GetAlgoListCipher(ctx); + AssertNotNull(defaultCipherList); + + wolfSSH_CTX_SetAlgoListMac(ctx, newMacList); + defaultMacList = wolfSSH_CTX_GetAlgoListMac(ctx); + AssertNotNull(defaultMacList); + + wolfSSH_CTX_SetAlgoListKeyAccepted(ctx, newKeyAccList); + defaultKeyAccList = wolfSSH_CTX_GetAlgoListKeyAccepted(ctx); + AssertNotNull(defaultKeyAccList); + + /* Create a new ssh object. */ + ssh = wolfSSH_new(ctx); + AssertNotNull(ssh); + + /* Check that the ssh's default algo lists match the ctx's algo lists. */ + checkKexList = wolfSSH_GetAlgoListKex(ssh); + AssertPtrEq(checkKexList, defaultKexList); + + checkKeyList = wolfSSH_GetAlgoListKey(ssh); + AssertPtrEq(checkKeyList, defaultKeyList); + + checkCipherList = wolfSSH_GetAlgoListCipher(ssh); + AssertPtrEq(checkCipherList, defaultCipherList); + + checkMacList = wolfSSH_GetAlgoListMac(ssh); + AssertPtrEq(checkMacList, defaultMacList); + + checkKeyAccList = wolfSSH_GetAlgoListKeyAccepted(ssh); + AssertPtrEq(checkKeyAccList, defaultKeyAccList); + /* Cleanup */ wolfSSH_free(ssh); wolfSSH_CTX_free(ctx); + + /* Create a ctx object. */ + ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL); + AssertNotNull(ctx); + + /* Check server ctx's key list is NULL. */ + defaultKeyList = wolfSSH_CTX_GetAlgoListKey(ctx); + AssertNull(defaultKeyList); + defaultKeyAccList = wolfSSH_CTX_GetAlgoListKeyAccepted(ctx); + AssertNotNull(defaultKeyAccList); + + /* Create a new ssh object. */ + ssh = wolfSSH_new(ctx); + AssertNotNull(ssh); + + /* Check server ssh's key list is NULL. */ + checkKeyList = wolfSSH_GetAlgoListKey(ssh); + AssertNull(checkKeyList); + + /* Delete the ssh. */ + wolfSSH_free(ssh); + + /* Set key on ctx. */ +#if !defined(WOLFSSH_NO_ECDSA) + rawKey = serverKeyEccDer; +#elif !defined(WOLFSSH_NO_RSA) + rawKey = serverKeyRsaDer; +#endif + AssertNotNull(rawKey); + AssertIntEQ(0, + ConvertHexToBin(rawKey, &key, &keySz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)); + AssertIntEQ(WS_SUCCESS, + wolfSSH_CTX_UsePrivateKey_buffer(ctx, + key, keySz, WOLFSSH_FORMAT_ASN1)); + + /* Check ctx's key algo list is still null. */ + checkKeyList = wolfSSH_CTX_GetAlgoListKey(ctx); + AssertNull(checkKeyList); + + /* Create a new ssh object. */ + ssh = wolfSSH_new(ctx); + AssertNotNull(ssh); + + /* Check ssh's key algo list is null. */ + checkKeyList = wolfSSH_GetAlgoListKey(ssh); + AssertNull(checkKeyList); + + /* Set a new list on ssh. */ + wolfSSH_SetAlgoListKey(ssh, newKeyList); + checkKeyList = wolfSSH_GetAlgoListKey(ssh); + AssertPtrEq(checkKeyList, newKeyList); + + /* Cleanup */ + wolfSSH_free(ssh); + wolfSSH_CTX_free(ctx); + FreeBins(key, NULL, NULL, NULL); } static void test_wolfSSH_QueryAlgoList(void) { - word32 i; const char* name; + word32 i, j; + int k; i = 0; name = NULL; - printf("KEX:\n"); do { - if (name != NULL) { - printf("\t%s\n", name); - } name = wolfSSH_QueryKex(&i); + AssertIntNE(i, 0); } while (name != NULL); i = 0; name = NULL; - printf("Public key:\n"); do { - if (name != NULL) { - printf("\t%s\n", name); - } name = wolfSSH_QueryKey(&i); + AssertIntNE(i, 0); } while (name != NULL); i = 0; name = NULL; - printf("Cipher:\n"); do { - if (name != NULL) { - printf("\t%s\n", name); - } name = wolfSSH_QueryCipher(&i); + AssertIntNE(i, 0); } while (name != NULL); i = 0; name = NULL; - printf("MAC:\n"); do { - if (name != NULL) { - printf("\t%s\n", name); - } name = wolfSSH_QueryMac(&i); + AssertIntNE(i, 0); } while (name != NULL); /* This test case picks up where the index left off. */ + j = i; name = wolfSSH_QueryKex(&i); - if (name != NULL) { - printf("That's not right.\n"); - } - - if (wolfSSH_CheckAlgoName("ssh-rsa")) - printf("Don't know ssh-rsa.\n"); - - if (!wolfSSH_CheckAlgoName("foofarah")) - printf("Fake algo name found.\n"); + AssertNull(name); + i = j; + name = wolfSSH_QueryKey(&i); + AssertNull(name); + i = j; + name = wolfSSH_QueryCipher(&i); + AssertNull(name); + i = j; + name = wolfSSH_QueryMac(&i); + AssertNull(name); + + k = wolfSSH_CheckAlgoName("ssh-rsa"); + AssertIntEQ(WS_SUCCESS, k); + + k = wolfSSH_CheckAlgoName("not-an-algo@wolfssl.com"); + AssertIntEQ(WS_INVALID_ALGO_ID, k); } From 8c28f7a3a5b04793691da82786387656566621ba Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 1 Mar 2024 16:02:30 -0800 Subject: [PATCH 9/9] Update Pragma Macro Use 1. The wrapper for the pragma PRAGMA_GCC_DIAG_PUSH and its friends are not set up to be used like a function. Remove the semicolons after their usage. (Clang doesn't care, but MSVC does.) --- tests/api.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/api.c b/tests/api.c index 0a9e763f2..2de3ab6f4 100644 --- a/tests/api.c +++ b/tests/api.c @@ -120,13 +120,13 @@ char* myoptarg = NULL; #define AssertStrLE(x, y) AssertStr(x, y, <=, >) #define AssertPtr(x, y, op, er) do { \ - PRAGMA_GCC_DIAG_PUSH; \ + PRAGMA_GCC_DIAG_PUSH \ /* remarkably, without this inhibition, */ \ /* the _Pragma()s make the declarations warn. */ \ - PRAGMA_GCC("GCC diagnostic ignored \"-Wdeclaration-after-statement\""); \ + 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\""); \ + 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)); \