diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index 65712ff0..0c06500f 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -2087,7 +2087,7 @@ static void ShowUsage(void) printf(" -? display this help and exit\n"); printf(" -1 exit after single (one) connection\n"); printf(" -e expect ECC public key from client\n"); - printf(" -E use ECC private key\n"); + printf(" -E load ECC private key first\n"); #ifdef WOLFSSH_SHELL printf(" -f echo input\n"); #endif @@ -2327,12 +2327,26 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) bufSz = load_key(peerEcc, keyLoadBuf, bufSz); if (bufSz == 0) { - fprintf(stderr, "Couldn't load key file.\n"); + fprintf(stderr, "Couldn't load first key file.\n"); WEXIT(EXIT_FAILURE); } if (wolfSSH_CTX_UsePrivateKey_buffer(ctx, keyLoadBuf, bufSz, WOLFSSH_FORMAT_ASN1) < 0) { - fprintf(stderr, "Couldn't use key buffer.\n"); + fprintf(stderr, "Couldn't use first key buffer.\n"); + WEXIT(EXIT_FAILURE); + } + + peerEcc = !peerEcc; + bufSz = EXAMPLE_KEYLOAD_BUFFER_SZ; + + bufSz = load_key(peerEcc, keyLoadBuf, bufSz); + if (bufSz == 0) { + fprintf(stderr, "Couldn't load second key file.\n"); + WEXIT(EXIT_FAILURE); + } + if (wolfSSH_CTX_UsePrivateKey_buffer(ctx, keyLoadBuf, bufSz, + WOLFSSH_FORMAT_ASN1) < 0) { + fprintf(stderr, "Couldn't use second key buffer.\n"); WEXIT(EXIT_FAILURE); } diff --git a/src/internal.c b/src/internal.c index 13f5679d..198f9453 100644 --- a/src/internal.c +++ b/src/internal.c @@ -408,6 +408,9 @@ const char* GetErrorString(int err) case WS_CERT_KEY_SIZE_E: return "key size too small error"; + case WS_CTX_KEY_COUNT: + return "trying to add too many keys"; + default: return "Unknown error code"; } @@ -576,17 +579,32 @@ void CtxResourceFree(WOLFSSH_CTX* ctx) { WLOG(WS_LOG_DEBUG, "Entering CtxResourceFree()"); - if (ctx->privateKey) { - ForceZero(ctx->privateKey, ctx->privateKeySz); - WFREE(ctx->privateKey, ctx->heap, DYNTYPE_PRIVKEY); + if (ctx->privateKeyCount > 0) { + word32 i; + + for (i = 0; i < ctx->privateKeyCount; i++) { + if (ctx->privateKey[i] != NULL) { + ForceZero(ctx->privateKey[i], ctx->privateKeySz[i]); + WFREE(ctx->privateKey[i], ctx->heap, DYNTYPE_PRIVKEY); + ctx->privateKey[i] = NULL; + ctx->privateKeySz[i] = 0; + } + #ifdef WOLFSSH_CERTS + if (ctx->cert[i] != NULL) { + WFREE(ctx->cert[i], ctx->heap, DYNTYPE_PRIVKEY); + ctx->cert[i] = NULL; + ctx->certSz[i] = 0; + } + #endif + ctx->privateKeyId[i] = ID_NONE; + } + ctx->privateKeyCount = 0; } #ifdef WOLFSSH_CERTS if (ctx->certMan) { wolfSSH_CERTMAN_free(ctx->certMan); } - if (ctx->cert) { - WFREE(ctx->cert, ctx->heap, DYNTYPE_CERT); - } + ctx->certMan = NULL; #endif } @@ -776,19 +794,231 @@ union wolfSSH_key { #endif }; + +/* + * Identifies the flavor of a key, RSA or ECDSA, and returns the key type ID. + * The process is to decode the key as if it was RSA and if that fails try + * to load it as if ECDSA. Both public and private keys can be decoded. + * + * @param in key to identify + * @param inSz size of key + * @param isPrivate indicates private or public key + * @param heap heap to use for memory allocation + * @return keyId as int, WS_MEMORY_E, WS_UNIMPLEMENTED_E + */ +static int IdentifyKey(const byte* in, word32 inSz, int isPrivate, void* heap) +{ + union wolfSSH_key *key = NULL; + int keyId = ID_UNKNOWN; + word32 scratch; + int ret = WS_SUCCESS; + int dynType = isPrivate ? DYNTYPE_PRIVKEY : DYNTYPE_PUBKEY; + + key = (union wolfSSH_key*)WMALLOC(sizeof(union wolfSSH_key), heap, dynType); + if (key == NULL) { + ret = WS_MEMORY_E; + } + +#ifndef WOLFSSH_NO_RSA + if (ret == WS_SUCCESS) { + /* Check RSA key */ + if (keyId == ID_UNKNOWN) { + scratch = 0; + ret = wc_InitRsaKey(&key->rsa, NULL); + + if (ret == 0) { + if (isPrivate) { + ret = wc_RsaPrivateKeyDecode(in, &scratch, + &key->rsa, inSz); + } + else { + ret = wc_RsaPublicKeyDecode(in, &scratch, + &key->rsa, inSz); + } + + /* If decode was successful, this was an RSA key. */ + if (ret == 0) { + keyId = ID_SSH_RSA; + } + /* in case we need to check for another key flavor */ + ret = WS_SUCCESS; + } + + wc_FreeRsaKey(&key->rsa); + } + } +#endif +#ifndef WOLFSSH_NO_ECDSA + if (ret == WS_SUCCESS) { + if (keyId == ID_UNKNOWN) { + scratch = 0; + ret = wc_ecc_init_ex(&key->ecc, heap, INVALID_DEVID); + + if (ret == 0) { + if (isPrivate) { + ret = wc_EccPrivateKeyDecode(in, &scratch, + &key->ecc, inSz); + } + else { + ret = wc_EccPublicKeyDecode(in, &scratch, + &key->ecc, inSz); + } + + /* If decode was successful, this was an RSA key. */ + if (ret == 0) { + switch (wc_ecc_get_curve_id(key->ecc.idx)) { + case ECC_SECP256R1: + keyId = ID_ECDSA_SHA2_NISTP256; + break; + case ECC_SECP384R1: + keyId = ID_ECDSA_SHA2_NISTP384; + break; + case ECC_SECP521R1: + keyId = ID_ECDSA_SHA2_NISTP521; + break; + } + } + /* in case we need to check for another key flavor */ + ret = WS_SUCCESS; + } + + wc_ecc_free(&key->ecc); + } + } +#endif /* ! WOLFSSH_NO_ECDSA */ + + if (key != NULL) { + WFREE(key, heap, dynType); + } + + if (keyId == ID_UNKNOWN) { + ret = WS_UNIMPLEMENTED_E; + } + + return ret == WS_SUCCESS ? keyId : ret; +} + + +#ifdef WOLFSSH_CERTS +/* + * Identifies the flavor of an X.509 certificate, RSA or ECDSA, and returns + * the key type ID. The process is to decode the certificate and pass the + * public key to IdentifyKey. + * + * @param in certificate to identify + * @param inSz size of certificate + * @param heap heap to use for memory allocation + * @return keyId as int, WS_MEMORY_E, WS_UNIMPLEMENTED_E + */ +static int IdentifyCert(const byte* in, word32 inSz, void* heap) +{ + struct DecodedCert cert; + byte *key = NULL; + word32 keySz = 0; + int ret; + int keyId = ID_UNKNOWN; + + wc_InitDecodedCert(&cert, in, inSz, heap); + ret = wc_ParseCert(&cert, CERT_TYPE, 0, NULL); + if (ret == 0) { + ret = wc_GetPubKeyDerFromCert(&cert, NULL, &keySz); + if (ret == LENGTH_ONLY_E) { + ret = 0; + key = (byte*)WMALLOC(keySz, heap, DYNTYPE_PUBKEY); + if (key == NULL) { + ret = WS_MEMORY_E; + } + } + } + + if (ret == 0) { + ret = wc_GetPubKeyDerFromCert(&cert, key, &keySz); + } + + if (ret == 0) { + ret = IdentifyKey(key, keySz, 0, heap); + if (ret > 0) { + keyId = ret; + ret = WS_SUCCESS; + } + } + + if (key != NULL) { + WFREE(key, heap, DYNTYPE_PUBKEY); + } + wc_FreeDecodedCert(&cert); + + return ret == WS_SUCCESS ? keyId : ret; +} +#endif /* WOLFSSH_CERTS */ + + +static int SetHostPrivateKey(WOLFSSH_CTX* ctx, byte keyId, int isKey, + byte* der, word32 derSz) +{ + word32 destIdx = 0; + int ret = WS_SUCCESS; + + while (destIdx < ctx->privateKeyCount && + ctx->privateKeyId[destIdx] != keyId) { + destIdx++; + } + + if (destIdx >= WOLFSSH_MAX_PVT_KEYS) { + ret = WS_CTX_KEY_COUNT; + } + else { + if (ctx->privateKeyId[destIdx] == keyId) { + if (isKey) { + if (ctx->privateKey[destIdx] != NULL) { + ForceZero(ctx->privateKey[destIdx], + ctx->privateKeySz[destIdx]); + WFREE(ctx->privateKey[destIdx], heap, dynamicType); + } + } + #ifdef WOLFSSH_CERTS + else { + if (ctx->cert[destIdx] != NULL) { + WFREE(ctx->cert[destIdx], heap, dynamicType); + } + } + #endif /* WOLFSSH_CERTS */ + } + else { + ctx->privateKeyCount++; + ctx->privateKeyId[destIdx] = keyId; + } + + if (isKey) { + ctx->privateKey[destIdx] = der; + ctx->privateKeySz[destIdx] = derSz; + } + #ifdef WOLFSSH_CERTS + else { + ctx->cert[destIdx] = der; + ctx->certSz[destIdx] = derSz; + } + #endif /* WOLFSSH_CERTS */ + } + + return ret; +} + + int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx, const byte* in, word32 inSz, int format, int type) { int dynamicType = 0; int wcType; - int ret; + int ret = WS_SUCCESS; void* heap = NULL; byte* der; - word32 derSz, scratch = 0; - union wolfSSH_key *key_ptr = NULL; + word32 derSz; + byte keyId = ID_NONE; (void)dynamicType; + (void)wcType; (void)heap; if (ctx == NULL || in == NULL || inSz == 0) @@ -810,8 +1040,9 @@ int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx, dynamicType = DYNTYPE_PRIVKEY; wcType = PRIVATEKEY_TYPE; } - else + else { return WS_BAD_ARGUMENT; + } heap = ctx->heap; @@ -846,21 +1077,23 @@ int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx, /* Maybe decrypt */ if (type == BUFTYPE_PRIVKEY) { - if (ctx->privateKey) { - ForceZero(ctx->privateKey, ctx->privateKeySz); - WFREE(ctx->privateKey, heap, dynamicType); + ret = IdentifyKey(der, derSz, 1, ctx->heap); + if (ret < 0) { + WFREE(der, heap, dynamicType); + return ret; } - ctx->privateKey = der; - ctx->privateKeySz = derSz; - ctx->useEcc = 0; + keyId = (byte)ret; + ret = SetHostPrivateKey(ctx, keyId, 1, der, derSz); } #ifdef WOLFSSH_CERTS else if (type == BUFTYPE_CERT) { - if (ctx->cert != NULL) - WFREE(ctx->cert, heap, dynamicType); - ctx->cert = der; - ctx->certSz = derSz; - ctx->useCert = 1; + ret = IdentifyCert(der, derSz, ctx->heap); + if (ret < 0) { + WFREE(der, heap, dynamicType); + return ret; + } + keyId = (byte)ret; + ret = SetHostPrivateKey(ctx, keyId, 0, der, derSz); } else if (type == BUFTYPE_CA) { if (ctx->certMan != NULL) { @@ -873,74 +1106,10 @@ int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx, WFREE(der, heap, dynamicType); if (ret < 0) { WLOG(WS_LOG_DEBUG, "Error %d loading in CA buffer", ret); - goto end; } } #endif /* WOLFSSH_CERTS */ - else { - WFREE(der, heap, dynamicType); - return WS_UNIMPLEMENTED_E; - } - if (type == BUFTYPE_PRIVKEY && format != WOLFSSH_FORMAT_RAW) { - key_ptr = (union wolfSSH_key*)WMALLOC(sizeof(union wolfSSH_key), heap, - dynamicType); - if (key_ptr == NULL) { - WFREE(der, heap, dynamicType); - return WS_MEMORY_E; - } - - /* Check RSA key */ -#ifndef WOLFSSH_NO_RSA - scratch = 0; - if (wc_InitRsaKey(&key_ptr->rsa, NULL) < 0) { - ret = WS_RSA_E; - goto end; - } - - ret = wc_RsaPrivateKeyDecode(der, &scratch, &key_ptr->rsa, derSz); - wc_FreeRsaKey(&key_ptr->rsa); - - if (ret < 0) { -#endif -#ifndef WOLFSSH_NO_ECDSA - /* Couldn't decode as RSA key. Try decoding as ECC key. */ - scratch = 0; - if (wc_ecc_init_ex(&key_ptr->ecc, ctx->heap, INVALID_DEVID) != 0) { - ret = WS_ECC_E; - goto end; - } - - ret = wc_EccPrivateKeyDecode(ctx->privateKey, &scratch, - &key_ptr->ecc, ctx->privateKeySz); - if (ret == 0) { - int curveId = wc_ecc_get_curve_id(key_ptr->ecc.idx); - if (curveId == ECC_SECP256R1 || - curveId == ECC_SECP384R1 || - curveId == ECC_SECP521R1) { - - ctx->useEcc = curveId; - } - else - ret = WS_BAD_FILE_E; - } - wc_ecc_free(&key_ptr->ecc); - if (ret != 0) { - ret = WS_BAD_FILE_E; - goto end; - } -#endif /* ! WOLFSSH_NO_ECDSA */ - -#ifndef WOLFSSH_NO_RSA - } -#endif - } - ret = WS_SUCCESS; -end: - if (key_ptr) - WFREE(key_ptr, heap, dynamicType); - - (void)wcType; return ret; } @@ -2206,48 +2375,6 @@ static const byte cannedKeyAlgoClient[] = { #endif }; -#ifndef WOLFSSH_NO_SSH_RSA_SHA1 - static const byte cannedKeyAlgoRsa[] = {ID_SSH_RSA}; - static const word32 cannedKeyAlgoRsaSz = sizeof(cannedKeyAlgoRsa); -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - static const byte cannedKeyAlgoEcc256[] = {ID_ECDSA_SHA2_NISTP256}; - static const word32 cannedKeyAlgoEcc256Sz = sizeof(cannedKeyAlgoEcc256); -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - static const byte cannedKeyAlgoEcc384[] = {ID_ECDSA_SHA2_NISTP384}; - static const word32 cannedKeyAlgoEcc384Sz = sizeof(cannedKeyAlgoEcc384); -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - static const byte cannedKeyAlgoEcc521[] = {ID_ECDSA_SHA2_NISTP521}; - static const word32 cannedKeyAlgoEcc521Sz = sizeof(cannedKeyAlgoEcc521); -#endif -#ifdef WOLFSSH_CERTS -#ifndef WOLFSSH_NO_SSH_RSA_SHA1 - static const byte cannedKeyAlgoX509Rsa[] = {ID_X509V3_SSH_RSA}; - static const word32 cannedKeyAlgoX509RsaSz = sizeof(cannedKeyAlgoX509Rsa); -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - static const byte cannedKeyAlgoX509Ecc256[] = - {ID_X509V3_ECDSA_SHA2_NISTP256}; - static const word32 cannedKeyAlgoX509Ecc256Sz = - sizeof(cannedKeyAlgoX509Ecc256); -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - static const byte cannedKeyAlgoX509Ecc384[] = - {ID_X509V3_ECDSA_SHA2_NISTP384}; - static const word32 cannedKeyAlgoX509Ecc384Sz = - sizeof(cannedKeyAlgoX509Ecc384); -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - static const byte cannedKeyAlgoX509Ecc521[] = - {ID_X509V3_ECDSA_SHA2_NISTP521}; - static const word32 cannedKeyAlgoX509Ecc521Sz = - sizeof(cannedKeyAlgoX509Ecc521); -#endif -#endif /* WOLFSSH_CERTS */ - - static const byte cannedKexAlgo[] = { #ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256 ID_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256, @@ -2672,66 +2799,8 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) word32 cannedKeyAlgoSz = 0; if (side == WOLFSSH_ENDPOINT_SERVER) { - if (ssh->ctx->useEcc) { - switch (ssh->ctx->useEcc) { - #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - case ECC_SECP256R1: - if (ssh->ctx->useCert) { - #ifdef WOLFSSH_CERTS - cannedKeyAlgo = cannedKeyAlgoX509Ecc256; - cannedKeyAlgoSz = cannedKeyAlgoX509Ecc256Sz; - #endif - } - else { - cannedKeyAlgo = cannedKeyAlgoEcc256; - cannedKeyAlgoSz = cannedKeyAlgoEcc256Sz; - } - break; - #endif - #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - case ECC_SECP384R1: - if (ssh->ctx->useCert) { - #ifdef WOLFSSH_CERTS - cannedKeyAlgo = cannedKeyAlgoX509Ecc384; - cannedKeyAlgoSz = cannedKeyAlgoX509Ecc384Sz; - #endif - } - else { - cannedKeyAlgo = cannedKeyAlgoEcc384; - cannedKeyAlgoSz = cannedKeyAlgoEcc384Sz; - } - break; - #endif - #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - case ECC_SECP521R1: - if (ssh->ctx->useCert) { - #ifdef WOLFSSH_CERTS - cannedKeyAlgo = cannedKeyAlgoX509Ecc521; - cannedKeyAlgoSz = cannedKeyAlgoX509Ecc521Sz; - #endif - } - else { - cannedKeyAlgo = cannedKeyAlgoEcc521; - cannedKeyAlgoSz = cannedKeyAlgoEcc521Sz; - } - break; - #endif - } - } - else { - #ifndef WOLFSSH_NO_SSH_RSA_SHA1 - if (ssh->ctx->useCert) { - #ifdef WOLFSSH_CERTS - cannedKeyAlgo = cannedKeyAlgoX509Rsa; - cannedKeyAlgoSz = cannedKeyAlgoX509RsaSz; - #endif - } - else { - cannedKeyAlgo = cannedKeyAlgoRsa; - cannedKeyAlgoSz = cannedKeyAlgoRsaSz; - } - #endif - } + cannedKeyAlgo = ssh->ctx->privateKeyId; + cannedKeyAlgoSz = ssh->ctx->privateKeyCount; } else { /* XXX Does this need to be different for client? */ @@ -2808,7 +2877,7 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) cannedMacAlgo, cannedMacAlgoSz); if (algoId == ID_UNKNOWN) { WLOG(WS_LOG_DEBUG, "Unable to negotiate MAC Algo C2S"); - ret = WS_MATCH_ENC_ALGO_E; + ret = WS_MATCH_MAC_ALGO_E; } } } @@ -3304,6 +3373,7 @@ static int ParseAndVerifyCert(WOLFSSH* ssh, byte* in, word32 inSz, word32 certCount = 0; byte* certChain = NULL; word32 certChainSz = 0; + word32 count; /* Skip the name */ ret = GetSize(&l, in, inSz, &m); @@ -3315,9 +3385,7 @@ static int ParseAndVerifyCert(WOLFSSH* ssh, byte* in, word32 inSz, } if (ret == WS_SUCCESS) { - word32 count; - - WLOG(WS_LOG_INFO, "Peer sent certificate count of %u", certCount); + WLOG(WS_LOG_INFO, "Peer sent certificate count of %d", certCount); certChain = in + m; for (count = certCount; count > 0; count--) { @@ -7592,6 +7660,30 @@ static INLINE void CopyNameList(byte* buf, word32* idx, *idx = begin; } + +static word32 BuildNameList(char* buf, word32 bufSz, + const byte* src, word32 srcSz) +{ + const char* name; + word32 nameSz, idx; + + (void)bufSz; + idx = 0; + do { + name = IdToName(*src); + nameSz = (word32)WSTRLEN(name); + WMEMCPY(buf + idx, name, nameSz); + idx += nameSz; + buf[idx++] = ','; + + src++; + srcSz--; + } while (srcSz > 0); + + return idx - 1; /* Take off the size of last ','. */ +} + + static const char cannedEncAlgoNames[] = #if !defined(WOLFSSH_NO_AES_GCM) "aes256-gcm@openssh.com," @@ -7631,34 +7723,6 @@ static const char cannedMacAlgoNames[] = #warning "You need at least one MAC algorithm." #endif -static const char cannedKeyAlgoClientNames[] = -#ifdef WOLFSSH_CERTS - #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - "x509v3-ecdsa-sha2-nistp521," - #endif - #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - "x509v3-ecdsa-sha2-nistp384," - #endif - #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - "x509v3-ecdsa-sha2-nistp256," - #endif - #ifndef WOLFSSH_NO_SSH_RSA_SHA1 - "x509v3-ssh-rsa," - #endif -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - "ecdsa-sha2-nistp521," -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - "ecdsa-sha2-nistp384," -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - "ecdsa-sha2-nistp256," -#endif -#ifndef WOLFSSH_NO_SSH_RSA_SHA1 - "ssh-rsa," -#endif - ""; #if defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) && \ defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) && \ defined(WOLFSSH_NO_ECDSA_SHA2_NISTP521) && \ @@ -7666,20 +7730,32 @@ static const char cannedKeyAlgoClientNames[] = #warning "You need at least one signing algorithm." #endif -static const char cannedKeyAlgoRsaNames[] = "ssh-rsa"; -#ifdef WOLFSSH_CERTS -static const char cannedKeyAlgoX509RsaNames[] = "x509v3-ssh-rsa"; +#define KEY_ALGO_SIZE_GUESS 20 +#ifndef WOLFSSH_NO_SSH_RSA_SHA1 + #ifdef WOLFSSH_CERTS + static const char cannedKeyAlgoX509RsaNames[] = "x509v3-ssh-rsa"; + #endif #endif -#if !defined(WOLFSSH_NO_ECDSA) && !defined(WOLFSSH_NO_ECDH) -static const char cannedKeyAlgoEcc256Names[] = "ecdsa-sha2-nistp256"; -static const char cannedKeyAlgoEcc384Names[] = "ecdsa-sha2-nistp384"; -static const char cannedKeyAlgoEcc521Names[] = "ecdsa-sha2-nistp521"; -#ifdef WOLFSSH_CERTS -static const char cannedKeyAlgoX509Ecc256Names[] = "x509v3-ecdsa-sha2-nistp256"; -static const char cannedKeyAlgoX509Ecc384Names[] = "x509v3-ecdsa-sha2-nistp384"; -static const char cannedKeyAlgoX509Ecc521Names[] = "x509v3-ecdsa-sha2-nistp521"; +#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 static const char cannedKexAlgoNames[] = @@ -7721,32 +7797,22 @@ static const char cannedNoneNames[] = "none"; /* -1 for the null, some are -1 for the comma */ static const word32 cannedEncAlgoNamesSz = sizeof(cannedEncAlgoNames) - 2; static const word32 cannedMacAlgoNamesSz = sizeof(cannedMacAlgoNames) - 2; -static const word32 cannedKeyAlgoClientNamesSz = - sizeof(cannedKeyAlgoClientNames) - 2; -static const word32 cannedKeyAlgoRsaNamesSz = sizeof(cannedKeyAlgoRsaNames) - 1; -#ifdef WOLFSSH_CERTS -static const word32 cannedKeyAlgoX509RsaNamesSz = - sizeof(cannedKeyAlgoX509RsaNames) - 1; -#endif -#if !defined(WOLFSSH_NO_ECDSA) && !defined(WOLFSSH_NO_ECDH) -static const word32 cannedKeyAlgoEcc256NamesSz = - sizeof(cannedKeyAlgoEcc256Names) - 1; -static const word32 cannedKeyAlgoEcc384NamesSz = - sizeof(cannedKeyAlgoEcc384Names) - 1; -static const word32 cannedKeyAlgoEcc521NamesSz = - sizeof(cannedKeyAlgoEcc521Names) - 1; -#ifdef WOLFSSH_CERTS -static const word32 cannedKeyAlgoX509Ecc256NamesSz = - sizeof(cannedKeyAlgoX509Ecc256Names) - 1; -static const word32 cannedKeyAlgoX509Ecc384NamesSz = - sizeof(cannedKeyAlgoX509Ecc384Names) - 1; -static const word32 cannedKeyAlgoX509Ecc521NamesSz = - sizeof(cannedKeyAlgoX509Ecc521Names) - 1; -#endif -#endif static const word32 cannedKexAlgoNamesSz = sizeof(cannedKexAlgoNames) - 2; static const word32 cannedNoneNamesSz = sizeof(cannedNoneNames) - 1; +#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 + static const word32 cannedKeyAlgoEcc256NamesSz = + sizeof(cannedKeyAlgoEcc256Names) - 1; +#endif +#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 + static const word32 cannedKeyAlgoEcc384NamesSz = + sizeof(cannedKeyAlgoEcc384Names) - 1; +#endif +#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 + static const word32 cannedKeyAlgoEcc521NamesSz = + sizeof(cannedKeyAlgoEcc521Names) - 1; +#endif + int SendKexInit(WOLFSSH* ssh) { @@ -7755,14 +7821,19 @@ int SendKexInit(WOLFSSH* ssh) word32 idx = 0; word32 payloadSz = 0; int ret = WS_SUCCESS; - const char* cannedKeyAlgoNames = NULL; - word32 cannedKeyAlgoNamesSz = 0; + word32 keyAlgoNamesSz = 0; + char* keyAlgoNames = NULL; WLOG(WS_LOG_DEBUG, "Entering SendKexInit()"); if (ssh == NULL) ret = WS_BAD_ARGUMENT; + if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER && + ssh->ctx->privateKeyCount == 0) { + ret = WS_BAD_ARGUMENT; + } + if (ret == WS_SUCCESS) { ssh->isKeying = 1; if (ssh->handshake == NULL) { @@ -7775,73 +7846,28 @@ int SendKexInit(WOLFSSH* ssh) } if (ret == WS_SUCCESS) { + word32 privateKeyCount; + const byte* privateKey; + if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) { - switch (ssh->ctx->useEcc) { - #if !defined(WOLFSSH_NO_ECDSA) && !defined(WOLFSSH_NO_ECDH) - case ECC_SECP256R1: - if (ssh->ctx->useCert) { - #ifdef WOLFSSH_CERTS - cannedKeyAlgoNames = cannedKeyAlgoX509Ecc256Names; - cannedKeyAlgoNamesSz = - cannedKeyAlgoX509Ecc256NamesSz; - #endif - } - else { - cannedKeyAlgoNames = cannedKeyAlgoEcc256Names; - cannedKeyAlgoNamesSz = cannedKeyAlgoEcc256NamesSz; - } - - break; - case ECC_SECP384R1: - if (ssh->ctx->useCert) { - #ifdef WOLFSSH_CERTS - cannedKeyAlgoNames = cannedKeyAlgoX509Ecc384Names; - cannedKeyAlgoNamesSz = - cannedKeyAlgoX509Ecc384NamesSz; - #endif - } - else { - cannedKeyAlgoNames = cannedKeyAlgoEcc384Names; - cannedKeyAlgoNamesSz = cannedKeyAlgoEcc384NamesSz; - } - - break; - case ECC_SECP521R1: - if (ssh->ctx->useCert) { - #ifdef WOLFSSH_CERTS - cannedKeyAlgoNames = cannedKeyAlgoX509Ecc521Names; - cannedKeyAlgoNamesSz = - cannedKeyAlgoX509Ecc521NamesSz; - #endif - } - else { - cannedKeyAlgoNames = cannedKeyAlgoEcc521Names; - cannedKeyAlgoNamesSz = - cannedKeyAlgoEcc521NamesSz; - } - - break; - #endif - default: - if (ssh->ctx->useCert) { - #ifdef WOLFSSH_CERTS - cannedKeyAlgoNames = cannedKeyAlgoX509RsaNames; - cannedKeyAlgoNamesSz = cannedKeyAlgoX509RsaNamesSz; - #endif - } - else { - cannedKeyAlgoNames = cannedKeyAlgoRsaNames; - cannedKeyAlgoNamesSz = cannedKeyAlgoRsaNamesSz; - } - - } + privateKeyCount = ssh->ctx->privateKeyCount; + privateKey = ssh->ctx->privateKeyId; } else { - cannedKeyAlgoNames = cannedKeyAlgoClientNames; - cannedKeyAlgoNamesSz = cannedKeyAlgoClientNamesSz; + privateKeyCount = cannedKeyAlgoClientSz; + privateKey = cannedKeyAlgoClient; } + keyAlgoNamesSz = privateKeyCount * (KEY_ALGO_SIZE_GUESS + 1); + keyAlgoNames = (char*)WMALLOC(keyAlgoNamesSz, + ssh->ctx->heap, DYNTYPE_STRING); + + keyAlgoNamesSz = BuildNameList(keyAlgoNames, keyAlgoNamesSz, + privateKey, privateKeyCount); + } + + if (ret == WS_SUCCESS) { payloadSz = MSG_ID_SZ + COOKIE_SZ + (LENGTH_SZ * 11) + BOOLEAN_SZ + - cannedKexAlgoNamesSz + cannedKeyAlgoNamesSz + + cannedKexAlgoNamesSz + keyAlgoNamesSz + (cannedEncAlgoNamesSz * 2) + (cannedMacAlgoNamesSz * 2) + (cannedNoneNamesSz * 2); @@ -7865,7 +7891,7 @@ int SendKexInit(WOLFSSH* ssh) idx += COOKIE_SZ; CopyNameList(output, &idx, cannedKexAlgoNames, cannedKexAlgoNamesSz); - CopyNameList(output, &idx, cannedKeyAlgoNames, cannedKeyAlgoNamesSz); + CopyNameList(output, &idx, keyAlgoNames, keyAlgoNamesSz); CopyNameList(output, &idx, cannedEncAlgoNames, cannedEncAlgoNamesSz); CopyNameList(output, &idx, cannedEncAlgoNames, cannedEncAlgoNamesSz); CopyNameList(output, &idx, cannedMacAlgoNames, cannedMacAlgoNamesSz); @@ -7899,6 +7925,10 @@ int SendKexInit(WOLFSSH* ssh) } } + if (keyAlgoNames != NULL) { + WFREE(keyAlgoNames, ssh->ctx->heap, DYNTYPE_STRING); + } + if (ret == WS_SUCCESS) { /* increase amount to be sent only if BundlePacket will be called */ ssh->outputBuffer.length = idx; @@ -7980,21 +8010,29 @@ static int BuildRFC6187Info(WOLFSSH* ssh, int pubKeyID, localIdx = *idx; switch (pubKeyID) { + #ifndef WOLFSSH_NO_SSH_RSA_SHA1 case ID_X509V3_SSH_RSA: publicKeyType = (const byte*)cannedKeyAlgoX509RsaNames; break; + #endif + #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 case ID_X509V3_ECDSA_SHA2_NISTP256: publicKeyType = (const byte*)cannedKeyAlgoX509Ecc256Names; break; + #endif + #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 case ID_X509V3_ECDSA_SHA2_NISTP384: publicKeyType = (const byte*)cannedKeyAlgoX509Ecc384Names; break; + #endif + #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 case ID_X509V3_ECDSA_SHA2_NISTP521: publicKeyType = (const byte*)cannedKeyAlgoX509Ecc521Names; break; + #endif default: return WS_BAD_ARGUMENT; @@ -8058,7 +8096,7 @@ static int BuildRFC6187Info(WOLFSSH* ssh, int pubKeyID, * returns WS_SUCCESS on success */ static int SendKexGetSigningKey(WOLFSSH* ssh, struct wolfSSH_sigKeyBlockFull *sigKeyBlock_ptr, - enum wc_HashType enmhashId) + enum wc_HashType enmhashId, word32 keyIdx) { int ret; byte isCert = 0; @@ -8075,6 +8113,7 @@ static int SendKexGetSigningKey(WOLFSSH* ssh, heap = ssh->ctx->heap; + #ifdef WOLFSSL_CERTS switch (sigKeyBlock_ptr->pubKeyId) { case ID_X509V3_SSH_RSA: case ID_X509V3_ECDSA_SHA2_NISTP256: @@ -8082,6 +8121,7 @@ static int SendKexGetSigningKey(WOLFSSH* ssh, case ID_X509V3_ECDSA_SHA2_NISTP521: isCert = 1; } + #endif switch (sigKeyBlock_ptr->sigId) { case ID_SSH_RSA: @@ -8091,9 +8131,9 @@ static int SendKexGetSigningKey(WOLFSSH* ssh, sigKeyBlock_ptr->sk.rsa.nSz = sizeof(sigKeyBlock_ptr->sk.rsa.n); ret = wc_InitRsaKey(&sigKeyBlock_ptr->sk.rsa.key, heap); if (ret == 0) - ret = wc_RsaPrivateKeyDecode(ssh->ctx->privateKey, &scratch, - &sigKeyBlock_ptr->sk.rsa.key, - (int)ssh->ctx->privateKeySz); + ret = wc_RsaPrivateKeyDecode(ssh->ctx->privateKey[keyIdx], + &scratch, &sigKeyBlock_ptr->sk.rsa.key, + (int)ssh->ctx->privateKeySz[keyIdx]); /* hash in usual public key if not RFC6187 style cert use */ if (!isCert) { @@ -8198,9 +8238,9 @@ static int SendKexGetSigningKey(WOLFSSH* ssh, INVALID_DEVID); scratch = 0; if (ret == 0) - ret = wc_EccPrivateKeyDecode(ssh->ctx->privateKey, &scratch, - &sigKeyBlock_ptr->sk.ecc.key, - ssh->ctx->privateKeySz); + ret = wc_EccPrivateKeyDecode(ssh->ctx->privateKey[keyIdx], + &scratch, &sigKeyBlock_ptr->sk.ecc.key, + ssh->ctx->privateKeySz[keyIdx]); /* hash in usual public key if not RFC6187 style cert use */ if (!isCert) { @@ -8271,7 +8311,7 @@ static int SendKexGetSigningKey(WOLFSSH* ssh, word32 idx = 0; BuildRFC6187Info(ssh, sigKeyBlock_ptr->pubKeyId, - ssh->ctx->cert, ssh->ctx->certSz, NULL, 0, + ssh->ctx->cert[keyIdx], ssh->ctx->certSz[keyIdx], NULL, 0, NULL, &sigKeyBlock_ptr->sz, &idx); tmp = (byte*)WMALLOC(sigKeyBlock_ptr->sz, heap, DYNTYPE_TEMP); if (tmp == NULL) { @@ -8280,7 +8320,7 @@ static int SendKexGetSigningKey(WOLFSSH* ssh, else { idx = 0; BuildRFC6187Info(ssh, sigKeyBlock_ptr->pubKeyId, - ssh->ctx->cert, ssh->ctx->certSz, NULL, 0, + ssh->ctx->cert[keyIdx], ssh->ctx->certSz[keyIdx], NULL, 0, tmp, &sigKeyBlock_ptr->sz, &idx); ret = HashUpdate(&ssh->handshake->hash, enmhashId, tmp, sigKeyBlock_ptr->sz); @@ -8417,6 +8457,7 @@ int SendKexDhReply(WOLFSSH* ssh) word32 payloadSz = 0; byte* output; word32 idx; + word32 keyIdx = 0; byte msgId = MSGID_KEXDH_REPLY; enum wc_HashType enmhashId = WC_HASH_TYPE_NONE; #ifndef WOLFSSH_NO_DH @@ -8526,11 +8567,22 @@ int SendKexDhReply(WOLFSSH* ssh) enmhashId = (enum wc_HashType)ssh->handshake->hashId; } + if (ret == WS_SUCCESS) { + for (keyIdx = 0; keyIdx < ssh->ctx->privateKeyCount; keyIdx++) { + if (ssh->ctx->privateKeyId[keyIdx] == ssh->handshake->pubKeyId) { + break; + } + } + if (keyIdx == ssh->ctx->privateKeyCount) { + ret = WS_INVALID_ALGO_ID; + } + } + /* At this point, the exchange hash, H, includes items V_C, V_S, I_C, * and I_S. Next add K_S, the server's public host key. K_S will * either be RSA or ECDSA public key blob. */ if (ret == WS_SUCCESS) { - ret = SendKexGetSigningKey(ssh, sigKeyBlock_ptr, enmhashId); + ret = SendKexGetSigningKey(ssh, sigKeyBlock_ptr, enmhashId, keyIdx); } if (ret == WS_SUCCESS) { @@ -9040,12 +9092,8 @@ int SendKexDhReply(WOLFSSH* ssh) case ID_X509V3_ECDSA_SHA2_NISTP384: case ID_X509V3_ECDSA_SHA2_NISTP521: { - if (ssh->ctx->useCert != 1) { - ret = WS_FATAL_ERROR; - break; - } ret = BuildRFC6187Info(ssh, sigKeyBlock_ptr->pubKeyId, - ssh->ctx->cert, ssh->ctx->certSz, NULL, 0, + ssh->ctx->cert[keyIdx], ssh->ctx->certSz[keyIdx], NULL, 0, output, &ssh->outputBuffer.bufferSz, &idx); } break; diff --git a/tests/api.c b/tests/api.c index a5a2e176..5bc47735 100644 --- a/tests/api.c +++ b/tests/api.c @@ -473,7 +473,7 @@ static const char serverKeyEccDer[] = "7bb87f38c66dd5a00a06082a8648ce3d030107a144034200048113ffa42bb79c" "45747a834c61f33fad26cf22cda9a3bca561b47ce662d4c2f755439a31fb8011" "20b5124b24f578d7fd22ef4635f005586b5f63c8da1bc4f569"; -static const int serverKeyEccCurveId = ECC_SECP256R1; +static const byte serverKeyEccCurveId = ID_ECDSA_SHA2_NISTP256; #elif !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) static const char serverKeyEccDer[] = "3081a402010104303eadd2bbbf05a7be3a3f7c28151289de5bb3644d7011761d" @@ -482,7 +482,7 @@ static const char serverKeyEccDer[] = "7724316d46a23105873f2986d5c712803a6f471ab86850eb063e108961349cf8" "b4c6a4cf5e97bd7e51e975e3e9217261506eb9cf3c493d3eb88d467b5f27ebab" "2161c00066febd"; -static const int serverKeyEccCurveId = ECC_SECP384R1; +static const byte serverKeyEccCurveId = ID_ECDSA_SHA2_NISTP384; #elif !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP521) static const char serverKeyEccDer[] = "3081dc0201010442004ca4d86428d9400e7b2df3912eb996c195895043af92e8" @@ -492,7 +492,7 @@ static const char serverKeyEccDer[] = "d18046a9717f2c6f59519c827095b29a6313306218c235769400d0f96d000a19" "3ba346652beb409a9a45c597a3ed932dd5aaae96bf2f317e5a7ac7458b3c6cdb" "aa90c355382cdfcdca7377d92eb20a5e8c74237ca5a345b19e3f1a2290b154"; -static const int serverKeyEccCurveId = ECC_SECP521R1; +static const byte serverKeyEccCurveId = ID_ECDSA_SHA2_NISTP521; #endif #ifndef WOLFSSH_NO_SSH_RSA_SHA1 @@ -552,8 +552,9 @@ static void test_wolfSSH_CTX_UsePrivateKey_buffer(void) byte* rsaKey; word32 rsaKeySz; #endif - byte* lastKey = NULL; + const byte* lastKey = NULL; word32 lastKeySz = 0; + int i; #if !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) || \ !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) || \ @@ -573,77 +574,100 @@ static void test_wolfSSH_CTX_UsePrivateKey_buffer(void) #endif AssertNotNull(ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL)); - AssertNull(ctx->privateKey); - AssertIntEQ(0, ctx->privateKeySz); - AssertIntEQ(0, ctx->useEcc); + for (i = 0; i < WOLFSSH_MAX_PVT_KEYS; i++) { + AssertNull(ctx->privateKey[i]); + AssertIntEQ(0, ctx->privateKeySz[i]); + AssertIntEQ(ID_NONE, ctx->privateKeyId[i]); + } + AssertIntEQ(0, ctx->privateKeyCount); /* Fail: all NULL/BAD */ AssertIntNE(WS_SUCCESS, wolfSSH_CTX_UsePrivateKey_buffer(NULL, NULL, 0, TEST_BAD_FORMAT_NEXT)); - AssertNull(ctx->privateKey); - AssertIntEQ(0, ctx->privateKeySz); - AssertIntEQ(0, ctx->useEcc); + AssertNull(ctx->privateKey[0]); + AssertIntEQ(0, ctx->privateKeySz[0]); + AssertIntEQ(ID_NONE, ctx->privateKeyId[0]); + AssertIntEQ(0, ctx->privateKeyCount); /* Fail: ctx set, others NULL/bad */ AssertIntNE(WS_SUCCESS, wolfSSH_CTX_UsePrivateKey_buffer(ctx, NULL, 0, TEST_BAD_FORMAT_NEXT)); - AssertNull(ctx->privateKey); - AssertIntEQ(0, ctx->privateKeySz); - AssertIntEQ(0, ctx->useEcc); + AssertNull(ctx->privateKey[0]); + AssertIntEQ(0, ctx->privateKeySz[0]); + AssertIntEQ(ID_NONE, ctx->privateKeyId[0]); + AssertIntEQ(0, ctx->privateKeyCount); /* Fail: ctx set, key set, others bad */ AssertIntNE(WS_SUCCESS, wolfSSH_CTX_UsePrivateKey_buffer(ctx, lastKey, 0, TEST_BAD_FORMAT_NEXT)); - AssertNull(ctx->privateKey); - AssertIntEQ(0, ctx->privateKeySz); - AssertIntEQ(0, ctx->useEcc); + AssertNull(ctx->privateKey[0]); + AssertIntEQ(0, ctx->privateKeySz[0]); + AssertIntEQ(ID_NONE, ctx->privateKeyId[0]); + AssertIntEQ(0, ctx->privateKeyCount); /* Fail: ctx set, keySz set, others NULL/bad */ AssertIntNE(WS_SUCCESS, wolfSSH_CTX_UsePrivateKey_buffer(ctx, NULL, 1, TEST_BAD_FORMAT_NEXT)); - AssertNull(ctx->privateKey); - AssertIntEQ(0, ctx->privateKeySz); - AssertIntEQ(0, ctx->useEcc); + AssertNull(ctx->privateKey[0]); + AssertIntEQ(0, ctx->privateKeySz[0]); + AssertIntEQ(ID_NONE, ctx->privateKeyId[0]); + AssertIntEQ(0, ctx->privateKeyCount); /* Fail: ctx set, key set, keySz set, format invalid */ AssertIntNE(WS_SUCCESS, wolfSSH_CTX_UsePrivateKey_buffer(ctx, lastKey, lastKeySz, TEST_GOOD_FORMAT_PEM)); - AssertNull(ctx->privateKey); - AssertIntEQ(0, ctx->privateKeySz); - AssertIntEQ(0, ctx->useEcc); + AssertNull(ctx->privateKey[0]); + AssertIntEQ(0, ctx->privateKeySz[0]); + AssertIntEQ(ID_NONE, ctx->privateKeyId[0]); + AssertIntEQ(0, ctx->privateKeyCount); /* Pass */ #if !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) || \ !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) || \ !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP521) - lastKey = ctx->privateKey; - lastKeySz = ctx->privateKeySz; + lastKey = ctx->privateKey[ctx->privateKeyCount]; + lastKeySz = ctx->privateKeySz[ctx->privateKeyCount]; AssertIntEQ(WS_SUCCESS, wolfSSH_CTX_UsePrivateKey_buffer(ctx, eccKey, eccKeySz, TEST_GOOD_FORMAT_ASN1)); - AssertNotNull(ctx->privateKey); - AssertIntNE(0, ctx->privateKeySz); - AssertIntEQ(serverKeyEccCurveId, ctx->useEcc); + AssertIntEQ(1, ctx->privateKeyCount); + AssertNotNull(ctx->privateKey[0]); + AssertIntNE(0, ctx->privateKeySz[0]); + AssertIntEQ(serverKeyEccCurveId, ctx->privateKeyId[0]); - AssertIntEQ(0, (lastKey == ctx->privateKey)); - AssertIntNE(lastKeySz, ctx->privateKeySz); + AssertIntEQ(0, (lastKey == ctx->privateKey[0])); + AssertIntNE(lastKeySz, ctx->privateKeySz[0]); #endif #ifndef WOLFSSH_NO_RSA - lastKey = ctx->privateKey; - lastKeySz = ctx->privateKeySz; + lastKey = ctx->privateKey[ctx->privateKeyCount]; + lastKeySz = ctx->privateKeySz[ctx->privateKeyCount]; AssertIntEQ(WS_SUCCESS, wolfSSH_CTX_UsePrivateKey_buffer(ctx, rsaKey, rsaKeySz, TEST_GOOD_FORMAT_ASN1)); - AssertNotNull(ctx->privateKey); - AssertIntNE(0, ctx->privateKeySz); - AssertIntEQ(0, ctx->useEcc); + AssertIntNE(0, ctx->privateKeyCount); + AssertNotNull(ctx->privateKey[0]); + AssertIntNE(0, ctx->privateKeySz[0]); - AssertIntEQ(0, (lastKey == ctx->privateKey)); - AssertIntNE(lastKeySz, ctx->privateKeySz); + AssertIntEQ(0, (lastKey == ctx->privateKey[0])); + AssertIntNE(lastKeySz, ctx->privateKeySz[0]); +#endif + + /* Add the same keys again. This should succeed. */ +#if !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) || \ + !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) || \ + !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP521) + AssertIntEQ(WS_SUCCESS, + wolfSSH_CTX_UsePrivateKey_buffer(ctx, eccKey, eccKeySz, + TEST_GOOD_FORMAT_ASN1)); +#endif +#ifndef WOLFSSH_NO_RSA + AssertIntEQ(WS_SUCCESS, + wolfSSH_CTX_UsePrivateKey_buffer(ctx, rsaKey, rsaKeySz, + TEST_GOOD_FORMAT_ASN1)); #endif wolfSSH_CTX_free(ctx); diff --git a/wolfssh/error.h b/wolfssh/error.h index 41f6676e..1f74ee81 100644 --- a/wolfssh/error.h +++ b/wolfssh/error.h @@ -126,8 +126,9 @@ enum WS_ErrorCodes { WS_CERT_OTHER_E = -1085, /* Other certificate issue */ WS_CERT_PROFILE_E = -1086, /* Cert doesn't meet profile reqs */ WS_CERT_KEY_SIZE_E = -1087, /* Key size error */ + WS_CTX_KEY_COUNT = -1088, /* Adding too many private keys */ - WS_LAST_E = -1087 /* Update this to indicate last error */ + WS_LAST_E = -1088 /* Update this to indicate last error */ }; diff --git a/wolfssh/internal.h b/wolfssh/internal.h index aa5406bd..6816a067 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -374,6 +374,9 @@ enum { #ifndef WOLFSSH_MAX_FILE_SIZE #define WOLFSSH_MAX_FILE_SIZE (1024ul * 1024ul * 4) #endif +#ifndef WOLFSSH_MAX_PVT_KEYS + #define WOLFSSH_MAX_PVT_KEYS 2 +#endif WOLFSSH_LOCAL byte NameToId(const char*, word32); WOLFSSH_LOCAL const char* IdToName(byte); @@ -396,7 +399,6 @@ typedef struct Buffer { byte dynamicFlag; /* dynamic memory currently in use */ } Buffer; - WOLFSSH_LOCAL int BufferInit(Buffer*, word32, void*); WOLFSSH_LOCAL int GrowBuffer(Buffer*, word32, word32); WOLFSSH_LOCAL void ShrinkBuffer(Buffer* buf, int); @@ -431,16 +433,15 @@ struct WOLFSSH_CTX { #endif /* WOLFSSH_CERTS */ WS_CallbackPublicKeyCheck publicKeyCheckCb; /* Check server's public key callback */ - - byte* privateKey; /* Owned by CTX */ - word32 privateKeySz; - byte useEcc; /* Depends on the private key */ -#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256_KYBER_LEVEL1_SHA256 - byte useEccKyber; /* Depends on the private key */ + byte* privateKey[WOLFSSH_MAX_PVT_KEYS]; + /* Owned by CTX */ + word32 privateKeySz[WOLFSSH_MAX_PVT_KEYS]; +#ifdef WOLFSSH_CERTS + byte* cert[WOLFSSH_MAX_PVT_KEYS]; + word32 certSz[WOLFSSH_MAX_PVT_KEYS]; #endif - byte* cert; - word32 certSz; - byte useCert; + byte privateKeyId[WOLFSSH_MAX_PVT_KEYS]; + word32 privateKeyCount; word32 highwaterMark; const char* banner; word32 bannerSz;