From e983ae0ad93f710f9c7b19e84d6be07a5d339dcb Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 7 Oct 2022 15:35:35 -0700 Subject: [PATCH] Multiple Server Keys 1. Allow user to add multiple server keys to the CTX up to a limit. 2. Clear the list of server's keys when releasing the CTX. 3. Update the API test case. 4. Server key algo list based on keys loaded. 5. Server uses key requested by client. 6. Change echoserver to load ECC and RSA key, -E option to select order. 7. Added a function to identify keys, and another to identify certs. 8. Added a function to add keys or certs to the list of keys and certs. 9. Fix return value for MAC Algo C2S match fail to the correct value. --- examples/echoserver/echoserver.c | 20 +- src/internal.c | 716 +++++++++++++++++-------------- tests/api.c | 96 +++-- wolfssh/error.h | 3 +- wolfssh/internal.h | 21 +- 5 files changed, 472 insertions(+), 384 deletions(-) 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;