diff --git a/src/sniffer.c b/src/sniffer.c index 71cd4d9ae..78279f552 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -246,7 +246,9 @@ static const char* const msgTable[] = /* 81 */ "Bad Decrypt Size", "Extended Master Secret Hash Error", - "Handshake Message Split Across TLS Records" + "Handshake Message Split Across TLS Records", + "ECC Private Decode Error", + "ECC Public Decode Error" }; @@ -1476,13 +1478,13 @@ static int GetRecordHeader(const byte* input, RecordLayerHeader* rh, int* size) } -/* Process Client Key Exchange, RSA only */ +/* Process Client Key Exchange, RSA or static ECDH */ static int ProcessClientKeyExchange(const byte* input, int* sslBytes, SnifferSession* session, char* error) { word32 idx = 0; - RsaKey key; - int ret; + int tryEcc = 0; + int ret; if (session->sslServer->buffers.key == NULL || session->sslServer->buffers.key->buffer == NULL || @@ -1491,75 +1493,163 @@ static int ProcessClientKeyExchange(const byte* input, int* sslBytes, SetError(RSA_KEY_MISSING_STR, error, session, FATAL_ERROR_STATE); return -1; } - ret = wc_InitRsaKey(&key, 0); - if (ret == 0) - ret = wc_RsaPrivateKeyDecode(session->sslServer->buffers.key->buffer, - &idx, &key, session->sslServer->buffers.key->length); - if (ret == 0) { - int length = wc_RsaEncryptSize(&key); - if (IsTLS(session->sslServer)) - input += 2; /* tls pre length */ + { + RsaKey key; + int length; - if (length > *sslBytes) { - SetError(PARTIAL_INPUT_STR, error, session, FATAL_ERROR_STATE); - wc_FreeRsaKey(&key); - return -1; + ret = wc_InitRsaKey(&key, 0); + if (ret == 0) { + ret = wc_RsaPrivateKeyDecode( + session->sslServer->buffers.key->buffer, + &idx, &key, session->sslServer->buffers.key->length); + if (ret != 0) { + tryEcc = 1; + #ifndef HAVE_ECC + SetError(RSA_DECODE_STR, error, session, FATAL_ERROR_STATE); + #else + /* If we can do ECC, this isn't fatal. Not loading an ECC + * key will be fatal, though. */ + SetError(RSA_DECODE_STR, error, session, 0); + #endif + } } + + if (ret == 0) { + length = wc_RsaEncryptSize(&key); + if (IsTLS(session->sslServer)) { + input += 2; /* tls pre length */ + } + + if (length > *sslBytes) { + SetError(PARTIAL_INPUT_STR, error, session, FATAL_ERROR_STATE); + ret = -1; + } + } + + if (ret == 0) { #ifdef WC_RSA_BLINDING ret = wc_RsaSetRNG(&key, session->sslServer->rng); if (ret != 0) { SetError(RSA_DECRYPT_STR, error, session, FATAL_ERROR_STATE); - return -1; } #endif - do { - #ifdef WOLFSSL_ASYNC_CRYPT - ret = wc_AsyncWait(ret, &key.asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); - #endif - if (ret >= 0) { - ret = wc_RsaPrivateDecrypt(input, length, - session->sslServer->arrays->preMasterSecret, SECRET_LEN, - &key); - } - } while (ret == WC_PENDING_E); - if (ret != SECRET_LEN) { - SetError(RSA_DECRYPT_STR, error, session, FATAL_ERROR_STATE); - wc_FreeRsaKey(&key); - return -1; } + + if (ret == 0) { + do { + #ifdef WOLFSSL_ASYNC_CRYPT + ret = wc_AsyncWait(ret, &key.asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + #endif + if (ret >= 0) { + ret = wc_RsaPrivateDecrypt(input, length, + session->sslServer->arrays->preMasterSecret, + SECRET_LEN, &key); + } + } while (ret == WC_PENDING_E); + + if (ret != SECRET_LEN) { + SetError(RSA_DECRYPT_STR, error, session, FATAL_ERROR_STATE); + } + } + session->sslServer->arrays->preMasterSz = SECRET_LEN; - /* store for client side as well */ - XMEMCPY(session->sslClient->arrays->preMasterSecret, - session->sslServer->arrays->preMasterSecret, SECRET_LEN); - session->sslClient->arrays->preMasterSz = SECRET_LEN; - - #ifdef SHOW_SECRETS - { - int i; - printf("pre master secret: "); - for (i = 0; i < SECRET_LEN; i++) - printf("%02x", session->sslServer->arrays->preMasterSecret[i]); - printf("\n"); - } - #endif - } - else { - SetError(RSA_DECODE_STR, error, session, FATAL_ERROR_STATE); wc_FreeRsaKey(&key); - return -1; } + if (tryEcc) { +#ifdef HAVE_ECC + ecc_key key; + ecc_key pubKey; + int length, keyInit = 0, pubKeyInit = 0; + + idx = 0; + ret = wc_ecc_init(&key); + if (ret == 0) { + keyInit = 1; + ret = wc_ecc_init(&pubKey); + } + if (ret == 0) { + pubKeyInit = 1; + ret = wc_EccPrivateKeyDecode( + session->sslServer->buffers.key->buffer, + &idx, &key, session->sslServer->buffers.key->length); + if (ret != 0) { + SetError(ECC_DECODE_STR, error, session, FATAL_ERROR_STATE); + } + } + + if (ret == 0) { + length = wc_ecc_size(&key) * 2 + 1; + /* The length should be 2 times the key size (x and y), plus 1 + * for the type byte. */ + if (IsTLS(session->sslServer)) { + input += 1; /* Don't include the TLS length for the key. */ + } + + if (length + 1 > *sslBytes) { + SetError(PARTIAL_INPUT_STR, + error, session, FATAL_ERROR_STATE); + ret = -1; + } + } + + if (ret == 0) { + ret = wc_ecc_import_x963_ex(input, length, &pubKey, ECC_CURVE_DEF); + if (ret != 0) { + SetError(ECC_PUB_DECODE_STR, error, session, FATAL_ERROR_STATE); + } + } + + if (ret == 0) { + session->sslServer->arrays->preMasterSz = ENCRYPT_LEN; + + do { + #ifdef WOLFSSL_ASYNC_CRYPT + ret = wc_AsyncWait(ret, &key.asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + #endif + if (ret >= 0) { + ret = wc_ecc_shared_secret(&key, &pubKey, + session->sslServer->arrays->preMasterSecret, + &session->sslServer->arrays->preMasterSz); + } + } while (ret == WC_PENDING_E); + } + + if (keyInit) + wc_ecc_free(&key); + if (pubKeyInit) + wc_ecc_free(&pubKey); +#endif + } + + /* store for client side as well */ + XMEMCPY(session->sslClient->arrays->preMasterSecret, + session->sslServer->arrays->preMasterSecret, + session->sslServer->arrays->preMasterSz); + session->sslClient->arrays->preMasterSz = + session->sslServer->arrays->preMasterSz; + + #ifdef SHOW_SECRETS + { + int i; + printf("pre master secret: "); + for (i = 0; i < session->sslServer->arrays->preMasterSz; i++) + printf("%02x", session->sslServer->arrays->preMasterSecret[i]); + printf("\n"); + } + #endif + if (SetCipherSpecs(session->sslServer) != 0) { SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); - wc_FreeRsaKey(&key); return -1; } if (SetCipherSpecs(session->sslClient) != 0) { SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); - wc_FreeRsaKey(&key); return -1; } @@ -1591,7 +1681,6 @@ static int ProcessClientKeyExchange(const byte* input, int* sslBytes, } #endif - wc_FreeRsaKey(&key); return ret; } diff --git a/wolfssl/sniffer_error.h b/wolfssl/sniffer_error.h index bd215e896..68ebf321a 100644 --- a/wolfssl/sniffer_error.h +++ b/wolfssl/sniffer_error.h @@ -119,6 +119,8 @@ #define BAD_DECRYPT_SIZE 81 #define EXTENDED_MASTER_HASH_STR 82 #define SPLIT_HANDSHAKE_MSG_STR 83 +#define ECC_DECODE_STR 84 +#define ECC_PUB_DECODE_STR 85 /* !!!! also add to msgTable in sniffer.c and .rc file !!!! */ diff --git a/wolfssl/sniffer_error.rc b/wolfssl/sniffer_error.rc index 735e3184a..e133ae06e 100644 --- a/wolfssl/sniffer_error.rc +++ b/wolfssl/sniffer_error.rc @@ -100,5 +100,7 @@ STRINGTABLE 81, "Bad Decrypt Size" 82, "Extended Master Secret Hash Error" 83, "Handshake Message Split Across TLS Records" + 84, "ECC Private Decode Error" + 85, "ECC Public Decode Error" }