From 22c67b26ce41fd39a7f014fc697a15218d91bdfd Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 15 Oct 2020 13:51:10 -0700 Subject: [PATCH] More Options 1. Moved the options checking to internal.h so other sources can use it. 2. Added some additional option checks and groups. 3. Added some guard checksto the key exchange. --- src/internal.c | 186 +++++++++++++++++++++------------------------ wolfssh/internal.h | 115 ++++++++++++++++++++++++++++ 2 files changed, 200 insertions(+), 101 deletions(-) diff --git a/src/internal.c b/src/internal.c index 03ee8b5..cdd5dfb 100644 --- a/src/internal.c +++ b/src/internal.c @@ -33,7 +33,7 @@ #include #include #include -#ifndef NO_DH +#ifndef WOLFSSH_NO_DH #include #endif #include @@ -109,68 +109,13 @@ Flags: WOLFSSH_NO_AEAD Set when AES-GCM is disabled. Set to disable use of AEAD ciphers for encryption. Setting this will force all AEAD ciphers off. + WOLFSSH_NO_DH + Set when all DH algorithms are disabled. Set to disable use of all DH + algorithms for key agreement. Setting this will force all DH key agreement + algorithms off. */ -#if defined(NO_HMAC) || defined(NO_SHA) - #define WOLFSSH_NO_HMAC_SHA1 -#endif -#if defined(NO_HMAC) || defined(NO_SHA) - #define WOLFSSH_NO_HMAC_SHA1_96 -#endif -#if defined(NO_HMAC) || defined(NO_SHA256) - #define WOLFSSH_NO_HMAC_SHA2_256 -#endif -#if defined(NO_DH) || defined(NO_SHA) - #define WOLFSSH_NO_DH_GROUP1_SHA1 -#endif -#if defined(NO_DH) || defined(NO_SHA) - #define WOLFSSH_NO_DH_GROUP14_SHA1 -#endif -#if defined(NO_DH) || defined(NO_SHA256) - #define WOLFSSH_NO_DH_GEX_SHA256 -#endif -#if !defined(HAVE_ECC) || defined(NO_SHA256) || defined(NO_ECC256) - #define WOLFSSH_NO_ECDH_SHA2_NISTP256 -#endif -#if !defined(HAVE_ECC) || !defined(WOLFSSL_SHA384) || !defined(HAVE_ECC384) - #define WOLFSSH_NO_ECDH_SHA2_NISTP384 -#endif -#if !defined(HAVE_ECC) || !defined(WOLFSSL_SHA512) || !defined(HAVE_ECC521) - #define WOLFSSH_NO_ECDH_SHA2_NISTP521 -#endif -#if !defined(HAVE_ED25519) || defined(NO_SHA256) - #define WOLFSSH_NO_ECDH_SHA2_ED25519 -#endif -#if defined(NO_RSA) || defined(NO_SHA) - #define WOLFSSH_NO_SSH_RSA_SHA1 -#endif -#if !defined(HAVE_ECC) || defined(NO_SHA256) || defined(NO_ECC256) - #define WOLFSSH_NO_ECDSA_SHA2_NISTP256 -#endif -#if !defined(HAVE_ECC) || !defined(WOLFSSL_SHA384) || !defined(HAVE_ECC384) - #define WOLFSSH_NO_ECDSA_SHA2_NISTP384 -#endif -#if !defined(HAVE_ECC) || !defined(WOLFSSL_SHA512) || !defined(HAVE_ECC521) - #define WOLFSSH_NO_ECDSA_SHA2_NISTP521 -#endif -#if defined(NO_AES) || !defined(HAVE_AES_CBC) - #define WOLFSSH_NO_AES_CBC -#endif -#if defined(NO_AES) || !defined(WOLFSSL_AES_COUNTER) - #define WOLFSSH_NO_AES_CTR -#endif -#if defined(NO_AES) || !defined(HAVE_AESGCM) - #define WOLFSSH_NO_AES_GCM -#endif -#if defined(WOLFSSH_NO_AES_GCM) - #define WOLFSSH_NO_AEAD - #ifndef WOLFSSH_NO_AES_GCM - #define WOLFSSH_AES_GCM - #endif -#endif - - static const char sshProtoIdStr[] = "SSH-2.0-wolfSSHv" LIBWOLFSSH_VERSION_STRING "\r\n"; @@ -478,7 +423,7 @@ static HandshakeInfo* HandshakeInfoNew(void* heap) newHs->macId = ID_NONE; newHs->blockSz = MIN_BLOCK_SZ; newHs->hashId = WC_HASH_TYPE_NONE; -#ifndef NO_DH +#ifndef WOLFSSH_NO_DH_GEX_SHA256 newHs->dhGexMinSz = WOLFSSH_DEFAULT_GEXDH_MIN; newHs->dhGexPreferredSz = WOLFSSH_DEFAULT_GEXDH_PREFERRED; newHs->dhGexMaxSz = WOLFSSH_DEFAULT_GEXDH_MAX; @@ -496,7 +441,7 @@ static void HandshakeInfoFree(HandshakeInfo* hs, void* heap) WLOG(WS_LOG_DEBUG, "Entering HandshakeInfoFree()"); if (hs) { WFREE(hs->kexInit, heap, DYNTYPE_STRING); -#ifndef NO_DH +#ifndef WOLFSSH_NO_DH WFREE(hs->primeGroup, heap, DYNTYPE_MPINT); WFREE(hs->generator, heap, DYNTYPE_MPINT); #endif @@ -2701,7 +2646,8 @@ static const byte dhPrimeGroup1[] = { static const word32 dhPrimeGroup1Sz = sizeof(dhPrimeGroup1); #endif -#ifndef WOLFSSH_NO_DH_GROUP14_SHA1 +#if !defined(WOLFSSH_NO_DH_GROUP14_SHA1) || \ + !defined(WOLFSSH_NO_DH_GEX_SHA256) static const byte dhPrimeGroup14[] = { /* SSH DH Group 14 (Oakley Group 14, 2048-bit MODP Group, RFC 3526) */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -3117,7 +3063,7 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) /* Generate and hash in the shared secret */ if (ret == 0) { if (!ssh->handshake->useEcc) { -#ifndef NO_DH +#ifndef WOLFSSH_NO_DH ret = wc_DhAgree(&ssh->handshake->privKey.dh, ssh->k, &ssh->kSz, ssh->handshake->x, ssh->handshake->xSz, @@ -3326,7 +3272,7 @@ static int DoNewKeys(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DNK: peer using cipher none"); break; -#ifndef WOLFSSH_NO_AES128_CBC +#ifndef WOLFSSH_NO_AES_CBC case ID_AES128_CBC: WLOG(WS_LOG_DEBUG, "DNK: peer using cipher aes128-cbc"); ret = wc_AesSetKey(&ssh->decryptCipher.aes, @@ -3335,7 +3281,7 @@ static int DoNewKeys(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) break; #endif -#ifndef WOLFSSH_NO_AES128_CTR +#ifndef WOLFSSH_NO_AES_CTR case ID_AES128_CTR: WLOG(WS_LOG_DEBUG, "DNK: peer using cipher aes128-ctr"); ret = wc_AesSetKey(&ssh->decryptCipher.aes, @@ -3344,7 +3290,7 @@ static int DoNewKeys(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) break; #endif -#ifndef WOLFSSH_NO_AES128_GCM +#ifndef WOLFSSH_NO_AES_GCM case ID_AES128_GCM: WLOG(WS_LOG_DEBUG, "DNK: peer using cipher aes128-gcm"); ret = wc_AesGcmSetKey(&ssh->decryptCipher.aes, @@ -3377,7 +3323,7 @@ static int DoNewKeys(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) } -#ifndef NO_DH +#ifndef WOLFSSH_NO_DH_GEX_SHA256 static int DoKexDhGexRequest(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) { @@ -5299,7 +5245,7 @@ static int DoPacket(WOLFSSH* ssh) } if (ssh->handshake->kexId == ID_DH_GEX_SHA256) { -#ifndef NO_DH +#ifndef WOLFSSH_NO_DH_GEX_SHA256 WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_GEX_GROUP"); ret = DoKexDhGexGroup(ssh, buf + idx, payloadSz, &payloadIdx); #endif @@ -5310,7 +5256,7 @@ static int DoPacket(WOLFSSH* ssh) } break; -#ifndef NO_DH +#ifndef WOLFSSH_NO_DH_GEX_SHA256 case MSGID_KEXDH_GEX_REQUEST: WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_GEX_REQUEST"); ret = DoKexDhGexRequest(ssh, buf + idx, payloadSz, &payloadIdx); @@ -5446,7 +5392,7 @@ static int DoPacket(WOLFSSH* ssh) } -#ifdef WOLFSSL_AES_COUNTER +#ifndef WOLFSSH_NO_AES_CTR #if defined(HAVE_FIPS) && defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION == 2) /* * The FIPSv2 version of wc_AesCtrEncrypt() only works if the input and @@ -6243,7 +6189,7 @@ static const char cannedKeyAlgoClientNames[] = #if defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) && \ defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) && \ defined(WOLFSSH_NO_ECDSA_SHA2_NISTP521) && \ - defined(WOLFSSH_NO_SSH_RSA_SHA2) + defined(WOLFSSH_NO_SSH_RSA_SHA1) #warning "You need at least one signing algorithm." #endif @@ -6427,11 +6373,11 @@ int SendKexInit(WOLFSSH* ssh) int SendKexDhReply(WOLFSSH* ssh) { /* This function and DoKexDhReply() are unwieldy and in need of refactoring. */ -#ifndef NO_DH - const byte* primeGroup = dhPrimeGroup14; - word32 primeGroupSz = dhPrimeGroup14Sz; - const byte* generator = dhGenerator; - word32 generatorSz = dhGeneratorSz; +#ifndef WOLFSSH_NO_DH + const byte* primeGroup = NULL; + word32 primeGroupSz = 0; + const byte* generator = NULL; + word32 generatorSz = 0; #endif byte useEcc = 0; @@ -6495,28 +6441,49 @@ int SendKexDhReply(WOLFSSH* ssh) sigKeyBlock.nameSz = (word32)strlen(sigKeyBlock.name); switch (ssh->handshake->kexId) { -#ifndef NO_DH +#ifndef WOLFSSH_NO_DH_GROUP1_SHA1 case ID_DH_GROUP1_SHA1: primeGroup = dhPrimeGroup1; primeGroupSz = dhPrimeGroup1Sz; + generator = dhGenerator; + generatorSz = dhGeneratorSz; break; - +#endif +#ifndef WOLFSSH_NO_DH_GROUP14_SHA1 case ID_DH_GROUP14_SHA1: - /* This is the default case. */ + primeGroup = dhPrimeGroup14; + primeGroupSz = dhPrimeGroup14Sz; + generator = dhGenerator; + generatorSz = dhGeneratorSz; break; - +#endif +#ifndef WOLFSSH_NO_DH_GEX_SHA256 case ID_DH_GEX_SHA256: + primeGroup = dhPrimeGroup14; + primeGroupSz = dhPrimeGroup14Sz; + generator = dhGenerator; + generatorSz = dhGeneratorSz; msgId = MSGID_KEXDH_GEX_REPLY; break; #endif - +#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256 case ID_ECDH_SHA2_NISTP256: + useEcc = 1; + msgId = MSGID_KEXDH_REPLY; + break; +#endif +#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP384 case ID_ECDH_SHA2_NISTP384: + useEcc = 1; + msgId = MSGID_KEXDH_REPLY; + break; +#endif +#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP521 case ID_ECDH_SHA2_NISTP521: useEcc = 1; msgId = MSGID_KEXDH_REPLY; break; - +#endif default: ret = WS_INVALID_ALGO_ID; } @@ -6691,7 +6658,7 @@ int SendKexDhReply(WOLFSSH* ssh) sigKeyBlock.sk.ecc.q, sigKeyBlock.sk.ecc.qSz); } -#ifndef NO_DH +#ifndef WOLFSSH_NO_DH_GEX_SHA256 /* If using DH-GEX include the GEX specific values. */ if (ssh->handshake->kexId == ID_DH_GEX_SHA256) { byte primeGroupPad = 0, generatorPad = 0; @@ -6783,7 +6750,7 @@ int SendKexDhReply(WOLFSSH* ssh) /* Or make the server's ECDH private value, and the shared secret K. */ if (ret == 0) { if (!useEcc) { -#ifndef NO_DH +#ifndef WOLFSSH_NO_DH DhKey privKey; byte y[MAX_KEX_KEY_SZ]; word32 ySz = sizeof(y); @@ -6910,7 +6877,7 @@ int SendKexDhReply(WOLFSSH* ssh) if (ret == WS_SUCCESS) { if (sigKeyBlock.useRsa) { -#ifndef NO_RSA +#ifndef WOLFSSH_NO_SSH_RSA_SHA1 byte encSig[MAX_ENCODED_SIG_SZ]; word32 encSigSz; @@ -6975,7 +6942,7 @@ int SendKexDhReply(WOLFSSH* ssh) } if (sigKeyBlock.useRsa) { -#ifndef NO_RSA +#ifndef WOLFSSH_NO_SSH_RSA_SHA1 wc_FreeRsaKey(&sigKeyBlock.sk.rsa.key); #endif } @@ -7010,7 +6977,7 @@ int SendKexDhReply(WOLFSSH* ssh) WMEMCPY(output + idx, sigKeyBlock.name, sigKeyBlock.nameSz); idx += sigKeyBlock.nameSz; if (sigKeyBlock.useRsa) { -#ifndef NO_RSA +#ifndef WOLFSSH_NO_SSH_RSA_SHA1 c32toa(sigKeyBlock.sk.rsa.eSz + sigKeyBlock.sk.rsa.ePad, output + idx); idx += LENGTH_SZ; @@ -7151,7 +7118,7 @@ int SendNewKeys(WOLFSSH* ssh) } -#ifndef NO_DH +#ifndef WOLFSSH_NO_DH_GEX_SHA256 int SendKexDhGexRequest(WOLFSSH* ssh) { byte* output; @@ -7275,11 +7242,11 @@ int SendKexDhInit(WOLFSSH* ssh) byte* output; word32 idx = 0; word32 payloadSz; -#ifndef NO_DH - const byte* primeGroup = dhPrimeGroup14; - word32 primeGroupSz = dhPrimeGroup14Sz; - const byte* generator = dhGenerator; - word32 generatorSz = dhGeneratorSz; +#ifndef WOLFSSH_NO_DH + const byte* primeGroup = NULL; + word32 primeGroupSz = 0; + const byte* generator = NULL; + word32 generatorSz = 0; #endif int ret = WS_SUCCESS; byte msgId = MSGID_KEXDH_INIT; @@ -7290,16 +7257,23 @@ int SendKexDhInit(WOLFSSH* ssh) WLOG(WS_LOG_DEBUG, "Entering SendKexDhInit()"); switch (ssh->handshake->kexId) { -#ifndef NO_DH +#ifndef WOLFSSH_NO_DH_GROUP1_SHA1 case ID_DH_GROUP1_SHA1: primeGroup = dhPrimeGroup1; primeGroupSz = dhPrimeGroup1Sz; + generator = dhGenerator; + generatorSz = dhGeneratorSz; break; - +#endif +#ifndef WOLFSSH_NO_DH_GROUP14_SHA1 case ID_DH_GROUP14_SHA1: - /* This is the default case. */ + primeGroup = dhPrimeGroup14; + primeGroupSz = dhPrimeGroup14Sz; + generator = dhGenerator; + generatorSz = dhGeneratorSz; break; - +#endif +#ifndef WOLFSSH_NO_DH_GEX_SHA256 case ID_DH_GEX_SHA256: primeGroup = ssh->handshake->primeGroup; primeGroupSz = ssh->handshake->primeGroupSz; @@ -7308,14 +7282,24 @@ int SendKexDhInit(WOLFSSH* ssh) msgId = MSGID_KEXDH_GEX_INIT; break; #endif - +#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256 case ID_ECDH_SHA2_NISTP256: + ssh->handshake->useEcc = 1; + msgId = MSGID_KEXECDH_INIT; + break; +#endif +#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP384 case ID_ECDH_SHA2_NISTP384: + ssh->handshake->useEcc = 1; + msgId = MSGID_KEXECDH_INIT; + break; +#endif +#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP521 case ID_ECDH_SHA2_NISTP521: ssh->handshake->useEcc = 1; msgId = MSGID_KEXECDH_INIT; break; - +#endif default: WLOG(WS_LOG_DEBUG, "Invalid algo: %u", ssh->handshake->kexId); ret = WS_INVALID_ALGO_ID; @@ -7324,7 +7308,7 @@ int SendKexDhInit(WOLFSSH* ssh) if (ret == WS_SUCCESS) { if (!ssh->handshake->useEcc) { -#ifndef NO_DH +#ifndef WOLFSSH_NO_DH DhKey* privKey = &ssh->handshake->privKey.dh; ret = wc_InitDhKey(privKey); diff --git a/wolfssh/internal.h b/wolfssh/internal.h index ca92680..28c896d 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -62,6 +62,121 @@ extern "C" { #endif +/* Check options set by wolfSSL and set wolfSSH options as appropriate. If + * the derived options and any override options leave wolfSSH without + * at least one algorithm to use, throw an error. */ + +#if defined(NO_HMAC) || defined(NO_SHA) + #define WOLFSSH_NO_HMAC_SHA1 +#endif +#if defined(NO_HMAC) || defined(NO_SHA) + #define WOLFSSH_NO_HMAC_SHA1_96 +#endif +#if defined(NO_HMAC) || defined(NO_SHA256) + #define WOLFSSH_NO_HMAC_SHA2_256 +#endif +#if defined(WOLFSSH_NO_HMAC_SHA1) && \ + defined(WOLFSSH_NO_HMAC_SHA1_96) && \ + defined(WOLFSSH_NO_HMAC_SHA2_256) + #error "You need at least one MAC algorithm." +#endif + + +#ifdef WOLFSSH_NO_DH + #undef WOLFSSH_NO_DH_GROUP1_SHA1 + #define WOLFSSH_NO_DH_GROUP1_SHA1 + #undef WOLFSSH_NO_DH_GROUP14_SHA1 + #define WOLFSSH_NO_DH_GROUP14_SHA1 + #undef WOLFSSH_NO_DH_GEX_SHA256 + #define WOLFSSH_NO_DH_GEX_SHA256 +#endif + +#if defined(NO_DH) || defined(NO_SHA) + #define WOLFSSH_NO_DH_GROUP1_SHA1 +#endif +#if defined(NO_DH) || defined(NO_SHA) + #define WOLFSSH_NO_DH_GROUP14_SHA1 +#endif +#if defined(NO_DH) || defined(NO_SHA256) + #define WOLFSSH_NO_DH_GEX_SHA256 +#endif +#if !defined(HAVE_ECC) || defined(NO_SHA256) || defined(NO_ECC256) + #define WOLFSSH_NO_ECDH_SHA2_NISTP256 +#endif +#if !defined(HAVE_ECC) || !defined(WOLFSSL_SHA384) || !defined(HAVE_ECC384) + #define WOLFSSH_NO_ECDH_SHA2_NISTP384 +#endif +#if !defined(HAVE_ECC) || !defined(WOLFSSL_SHA512) || !defined(HAVE_ECC521) + #define WOLFSSH_NO_ECDH_SHA2_NISTP521 +#endif +#if !defined(HAVE_ED25519) || defined(NO_SHA256) || 1 + /* ED25519 isn't supported yet. Force disabled. */ + #define WOLFSSH_NO_ECDH_SHA2_ED25519 +#endif + +#if defined(WOLFSSH_NO_DH_GROUP1_SHA1) && \ + defined(WOLFSSH_NO_DH_GROUP14_SHA1) && \ + defined(WOLFSSH_NO_DH_GEX_SHA256) && \ + defined(WOLFSSH_NO_ECDH_SHA2_NISTP256) && \ + defined(WOLFSSH_NO_ECDH_SHA2_NISTP384) && \ + defined(WOLFSSH_NO_ECDH_SHA2_NISTP521) && \ + defined(WOLFSSH_NO_ECDH_SHA2_ED25519) + #error "You need at least one key agreement algorithm." +#endif + +#if defined(WOLFSSH_NO_DH_GROUP1_SHA1) && \ + defined(WOLFSSH_NO_DH_GROUP14_SHA1) && \ + defined(WOLFSSH_NO_DH_GEX_SHA256) + #define WOLFSSH_NO_DH +#endif + + +#if defined(NO_RSA) || defined(NO_SHA) + #define WOLFSSH_NO_SSH_RSA_SHA1 +#endif +#if !defined(HAVE_ECC) || defined(NO_SHA256) || defined(NO_ECC256) + #define WOLFSSH_NO_ECDSA_SHA2_NISTP256 +#endif +#if !defined(HAVE_ECC) || !defined(WOLFSSL_SHA384) || !defined(HAVE_ECC384) + #define WOLFSSH_NO_ECDSA_SHA2_NISTP384 +#endif +#if !defined(HAVE_ECC) || !defined(WOLFSSL_SHA512) || !defined(HAVE_ECC521) + #define WOLFSSH_NO_ECDSA_SHA2_NISTP521 +#endif +#if defined(WOLFSSH_NO_SHA_RSA_SHA1) && \ + defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) && \ + defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) && \ + defined(WOLFSSH_NO_ECDSA_SHA2_NISTP521) + #error "You need at least one signing algorithm." +#endif + + +#ifdef WOLFSSH_NO_AEAD + #undef WOLFSSH_NO_AES_GCM + #define WOLFSSH_NO_AES_GCM +#endif + +#if defined(NO_AES) || !defined(HAVE_AES_CBC) + #define WOLFSSH_NO_AES_CBC +#endif +#if defined(NO_AES) || !defined(WOLFSSL_AES_COUNTER) + #define WOLFSSH_NO_AES_CTR +#endif +#if defined(NO_AES) || !defined(HAVE_AESGCM) + #define WOLFSSH_NO_AES_GCM +#endif + +#if defined(WOLFSSH_NO_AES_CBC) && \ + defined(WOLFSSH_NO_AES_CTR) && \ + defined(WOLFSSH_NO_AES_GCM) + #error "You need at least one encryption algorithm." +#endif + +#if defined(WOLFSSH_NO_AES_GCM) + #define WOLFSSH_NO_AEAD +#endif + + WOLFSSH_LOCAL const char* GetErrorString(int);