diff --git a/examples/server/server.c b/examples/server/server.c index 24c67af93..99e3b791c 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -1756,7 +1756,8 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) if (ret != 0) { err_sys_ex(runWithErrors, "error loading static ECDH key"); } -#elif !defined(NO_DH) +#endif +#ifndef NO_DH ret = wolfSSL_CTX_set_ephemeral_key(ctx, WC_PK_TYPE_DH, "./certs/statickeys/dh-ffdhe2048.pem", 0, WOLFSSL_FILETYPE_PEM); if (ret != 0) { diff --git a/scripts/include.am b/scripts/include.am index 23eaadf2f..fafdb43ab 100644 --- a/scripts/include.am +++ b/scripts/include.am @@ -91,6 +91,7 @@ EXTRA_DIST += scripts/testsuite.pcap \ scripts/sniffer-tls13-dh.pcap \ scripts/sniffer-tls13-ecc.pcap \ scripts/sniffer-tls13-gen.sh \ + scripts/sniffer-tls13-hrr.pcap \ scripts/ping.test \ scripts/benchmark.test \ scripts/memtest.sh diff --git a/scripts/sniffer-testsuite.test b/scripts/sniffer-testsuite.test index 69bfa50df..083974bcf 100755 --- a/scripts/sniffer-testsuite.test +++ b/scripts/sniffer-testsuite.test @@ -39,6 +39,16 @@ then [ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 DH\n" && exit 1 fi +# TLS v1.3 sniffer test hello_retry_request (HRR) with ECDHE +if test $# -ne 0 +then + ./sslSniffer/sslSnifferTest/snifftest ./scripts/sniffer-tls13-hrr.pcap ./certs/statickeys/ecc-secp256r1.pem 127.0.0.1 11111 + + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 HRR\n" && exit 1 +fi + + # IPv6 if test $# -ne 0 && test "x$1" = "x-6"; then diff --git a/scripts/sniffer-tls13-gen.sh b/scripts/sniffer-tls13-gen.sh index 7f7f537c9..a98e7b4d4 100755 --- a/scripts/sniffer-tls13-gen.sh +++ b/scripts/sniffer-tls13-gen.sh @@ -22,3 +22,8 @@ ./examples/client/client -v 4 -l TLS13-AES256-GCM-SHA384 -r ./examples/server/server -v 4 -l TLS13-CHACHA20-POLY1305-SHA256 -r & ./examples/client/client -v 4 -l TLS13-CHACHA20-POLY1305-SHA256 -r + +# TLS v1.3 Hello Retry Request (save this as sniffer-tls13-hrr.pcap) +# ./configure --enable-sniffer CFLAGS="-DWOLFSSL_SNIFFER_WATCH" --disable-dh && make +./examples/server/server -v 4 -i -x -g & +./examples/client/client -v 4 -J diff --git a/scripts/sniffer-tls13-hrr.pcap b/scripts/sniffer-tls13-hrr.pcap new file mode 100644 index 000000000..c9b078967 Binary files /dev/null and b/scripts/sniffer-tls13-hrr.pcap differ diff --git a/src/internal.c b/src/internal.c index 6d912cf58..6399b7116 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1897,9 +1897,14 @@ void SSL_CtxResourceFree(WOLFSSL_CTX* ctx) } #endif #ifdef WOLFSSL_STATIC_EPHEMERAL - if (ctx->staticKE.key) { - FreeDer(&ctx->staticKE.key); - } + #ifndef NO_DH + if (ctx->staticKE.dhKey) + FreeDer(&ctx->staticKE.dhKey); + #endif + #ifdef HAVE_ECC + if (ctx->staticKE.ecKey) + FreeDer(&ctx->staticKE.ecKey); + #endif #endif #ifdef WOLFSSL_STATIC_MEMORY if (ctx->heap != NULL) { @@ -6426,9 +6431,14 @@ void SSL_ResourceFree(WOLFSSL* ssl) } #endif #ifdef WOLFSSL_STATIC_EPHEMERAL - if (ssl->staticKE.key != NULL && ssl->staticKE.key != ssl->ctx->staticKE.key) { - FreeDer(&ssl->staticKE.key); - } + #ifndef NO_DH + if (ssl->staticKE.dhKey && ssl->staticKE.dhKey != ssl->ctx->staticKE.dhKey) + FreeDer(&ssl->staticKE.dhKey); + #endif + #ifdef HAVE_ECC + if (ssl->staticKE.ecKey && ssl->staticKE.ecKey != ssl->ctx->staticKE.ecKey) + FreeDer(&ssl->staticKE.ecKey); + #endif #endif #ifdef WOLFSSL_STATIC_MEMORY diff --git a/src/sniffer.c b/src/sniffer.c index bec413fa3..900211e74 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -299,6 +299,7 @@ static const char* const msgTable[] = "Store data callback failed", "Loading chain input", "Got encrypted extension", + "Got Hello Retry Request", }; @@ -2066,11 +2067,26 @@ static void ShowTlsSecrets(SnifferSession* session) /* Process Keys */ + +/* contains static ephemeral keys */ +typedef struct { +#ifndef NO_DH + DerBuffer* dhKey; +#endif +#ifdef HAVE_ECC + DerBuffer* ecKey; +#endif +#if !defined(NO_RSA) && defined(WOLFSSL_STATIC_RSA) + DerBuffer* rsaKey; +#endif +} KeyBuffers_t; + static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, - char* error, KeyShareInfo* ksInfo, DerBuffer* keyBuf) + char* error, KeyShareInfo* ksInfo, KeyBuffers_t* keys) { word32 idx = 0; int ret; + DerBuffer* keyBuf; #ifdef HAVE_ECC int useEccCurveId = ECC_CURVE_DEF; if (ksInfo && ksInfo->curve_id != 0) @@ -2079,10 +2095,12 @@ static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, #ifndef NO_RSA /* Static RSA */ - if (ksInfo == NULL) { + if (ksInfo == NULL && keys->rsaKey) { RsaKey key; int length; + keyBuf = keys->rsaKey; + ret = wc_InitRsaKey(&key, 0); if (ret == 0) { ret = wc_RsaPrivateKeyDecode(keyBuf->buffer, &idx, &key, keyBuf->length); @@ -2151,11 +2169,13 @@ static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, #if !defined(NO_DH) && defined(WOLFSSL_DH_EXTRA) /* Static DH Key */ - if (ksInfo && ksInfo->dh_key_bits != 0) { + if (ksInfo && ksInfo->dh_key_bits != 0 && keys->dhKey) { DhKey dhKey; const DhParams* params; word32 privKeySz; byte privKey[52]; /* max for TLS */ + + keyBuf = keys->dhKey; /* get DH params */ switch (ksInfo->named_group) { @@ -2239,11 +2259,12 @@ static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, #ifdef HAVE_ECC /* Static ECC Key */ - if (useEccCurveId >= ECC_CURVE_DEF) { + if (useEccCurveId >= ECC_CURVE_DEF && keys->ecKey) { ecc_key key; ecc_key pubKey; int length, keyInit = 0, pubKeyInit = 0; + keyBuf = keys->ecKey; idx = 0; ret = wc_ecc_init(&key); if (ret == 0) { @@ -2394,6 +2415,8 @@ static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, static int ProcessClientKeyExchange(const byte* input, int* sslBytes, SnifferSession* session, char* error) { + KeyBuffers_t keys; + if (session->sslServer->buffers.key == NULL || session->sslServer->buffers.key->buffer == NULL || session->sslServer->buffers.key->length == 0) { @@ -2402,8 +2425,17 @@ static int ProcessClientKeyExchange(const byte* input, int* sslBytes, return -1; } - return SetupKeys(input, sslBytes, session, error, NULL, - session->sslServer->buffers.key); + XMEMSET(&keys, 0, sizeof(keys)); +#ifdef WOLFSSL_STATIC_EPHEMERAL + #ifndef NO_DH + keys.dhKey = session->sslServer->staticKE.dhKey; + #endif + #ifdef HAVE_ECC + keys.ecKey = session->sslServer->staticKE.ecKey; + #endif +#endif + keys.rsaKey = session->sslServer->buffers.key; + return SetupKeys(input, sslBytes, session, error, NULL, &keys); } #ifdef WOLFSSL_TLS13 @@ -2412,16 +2444,24 @@ static int ProcessKeyShare(KeyShareInfo* info, const byte* input, int len, { int index = 0; while (index < len) { + /* clear info (reset dh_key_bits and curve_id) */ + XMEMSET(info, 0, sizeof(KeyShareInfo)); + /* Named group and public key */ info->named_group = (word16)((input[index] << 8) | input[index+1]); index += OPAQUE16_LEN; - info->key_len = (word16)((input[index] << 8) | input[index+1]); - index += OPAQUE16_LEN; - if (info->key_len == 0 || info->key_len > len - index) { - return -1; + info->key_len = 0; + info->key = NULL; + /* If key was provided... (a hello_retry_request will not send a key) */ + if (index + 2 <= len) { + info->key_len = (word16)((input[index] << 8) | input[index+1]); + index += OPAQUE16_LEN; + if (info->key_len == 0 || info->key_len > len - index) { + return -1; + } + info->key = &input[index]; + index += info->key_len; } - info->key = &input[index]; - index += info->key_len; switch (info->named_group) { #ifndef NO_DH @@ -2485,15 +2525,15 @@ static int ProcessKeyShare(KeyShareInfo* info, const byte* input, int len, break; #endif default: - /* unsupported curve */ - return ECC_PEERKEY_ERROR; + /* do not throw error here, keep iterating the client key share */ + break; } if (filter_group == 0 || filter_group == info->named_group) { return 0; } } - return -1; + return NO_PEER_KEY; /* unsupported key type */ } static int ProcessServerKeyShare(SnifferSession* session, const byte* input, int len, @@ -2502,13 +2542,14 @@ static int ProcessServerKeyShare(SnifferSession* session, const byte* input, int int ret; if (session->cliKeyShare == NULL || session->cliKeyShareSz == 0) { - SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); - return -1; + /* session->cliKeyShareSz could not be provided yet if the client_hello + did not send a key share to force a hello_retry_request */ + return 0; } - /* Get server_hello key share */ + /* Get server_hello key share (and key) */ ret = ProcessKeyShare(&session->srvKs, input, len, 0); - if (ret == 0) { + if (ret == 0 && session->srvKs.key_len > 0) { /* Get client_hello key share */ ret = ProcessKeyShare(&session->cliKs, session->cliKeyShare, session->cliKeyShareSz, session->srvKs.named_group); @@ -2632,6 +2673,98 @@ static int ProcessSessionTicket(const byte* input, int* sslBytes, return 0; } +static int DoResume(SnifferSession* session, char* error) +{ + int ret = 0; + WOLFSSL_SESSION* resume; + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(session->sslServer->version)) { + resume = GetSession(session->sslServer, + session->sslServer->session.masterSecret, 0); + } + else +#endif + { + resume = GetSession(session->sslServer, + session->sslServer->arrays->masterSecret, 0); + } + if (resume == NULL) { + /* a session id without resume is okay with hello_retry_request */ + #ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslStandardConns); + #endif + return 0; + } + + /* make sure client has master secret too */ +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(session->sslServer->version)) { + XMEMCPY(session->sslClient->session.masterSecret, + session->sslServer->session.masterSecret, SECRET_LEN); + } + else +#endif + { + XMEMCPY(session->sslClient->arrays->masterSecret, + session->sslServer->arrays->masterSecret, SECRET_LEN); + } + session->flags.resuming = 1; + + Trace(SERVER_DID_RESUMPTION_STR); +#ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslResumedConns); + INC_STAT(SnifferStats.sslResumptionValid); +#endif + if (SetCipherSpecs(session->sslServer) != 0) { + SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + if (SetCipherSpecs(session->sslClient) != 0) { + SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(session->sslServer->version)) { + #ifdef HAVE_SESSION_TICKET + /* Resumption PSK is resumption master secret. */ + session->sslServer->arrays->psk_keySz = session->sslServer->specs.hash_size; + session->sslClient->arrays->psk_keySz = session->sslClient->specs.hash_size; + ret = DeriveResumptionPSK(session->sslServer, session->sslServer->session.ticketNonce.data, + session->sslServer->session.ticketNonce.len, session->sslServer->arrays->psk_key); + /* Copy resumption PSK to client */ + XMEMCPY(session->sslClient->arrays->psk_key, + session->sslServer->arrays->psk_key, + session->sslServer->arrays->psk_keySz); + #endif + /* handshake key setup below and traffic keys done in SetupKeys */ + } + else +#endif + { + if (IsTLS(session->sslServer)) { + ret = DeriveTlsKeys(session->sslServer); + ret += DeriveTlsKeys(session->sslClient); + } + else { +#ifndef NO_OLD_TLS + ret = DeriveKeys(session->sslServer); + ret += DeriveKeys(session->sslClient); +#endif + } + ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE); + ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE); + } + + if (ret != 0) { + SetError(BAD_DERIVE_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + return ret; +} /* Process Server Hello */ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, @@ -2642,10 +2775,10 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, byte b, b0; int toRead = VERSION_SZ + RAN_LEN + ENUM_LEN; int doResume = 0; + const byte* inputHello = input; int initialBytes = *sslBytes; (void)msgSz; - (void)initialBytes; /* make sure we didn't miss ClientHello */ if (session->flags.clientHello == 0) { @@ -2665,6 +2798,10 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, session->sslServer->version = pv; session->sslClient->version = pv; + if (pv.minor >= TLSv1_MINOR) { + session->sslServer->options.tls = 1; + session->sslClient->options.tls = 1; + } XMEMCPY(session->sslServer->arrays->serverRandom, input, RAN_LEN); XMEMCPY(session->sslClient->arrays->serverRandom, input, RAN_LEN); @@ -2856,85 +2993,36 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, actual sessionID */ } +#ifdef WOLFSSL_TLS13 + /* Is TLS v1.3 hello_retry_request? */ + if (IsAtLeastTLSv1_3(session->sslServer->version) && session->srvKs.key_len == 0) { + Trace(GOT_HELLO_RETRY_REQ_STR); + + /* do not compute keys yet */ + session->flags.serverCipherOn = 0; + + /* make sure the mac and digest size are set */ + SetCipherSpecs(session->sslServer); + SetCipherSpecs(session->sslClient); + + /* reset hashes */ + RestartHandshakeHash(session->sslServer); + RestartHandshakeHash(session->sslClient); + + doResume = 0; + } +#endif + + /* hash server_hello */ + HashRaw(session->sslServer, inputHello - HANDSHAKE_HEADER_SZ, + initialBytes + HANDSHAKE_HEADER_SZ); + HashRaw(session->sslClient, inputHello - HANDSHAKE_HEADER_SZ, + initialBytes + HANDSHAKE_HEADER_SZ); + if (doResume) { - WOLFSSL_SESSION* resume; - if (IsAtLeastTLSv1_3(session->sslServer->version)) { - resume = GetSession(session->sslServer, - session->sslServer->session.masterSecret, 0); - } - else { - resume = GetSession(session->sslServer, - session->sslServer->arrays->masterSecret, 0); - } - if (resume == NULL) { -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslResumeMisses); -#endif - SetError(BAD_SESSION_RESUME_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - /* make sure client has master secret too */ - if (IsAtLeastTLSv1_3(session->sslServer->version)) { - XMEMCPY(session->sslClient->session.masterSecret, - session->sslServer->session.masterSecret, SECRET_LEN); - } - else { - XMEMCPY(session->sslClient->arrays->masterSecret, - session->sslServer->arrays->masterSecret, SECRET_LEN); - } - session->flags.resuming = 1; - - Trace(SERVER_DID_RESUMPTION_STR); -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslResumedConns); - INC_STAT(SnifferStats.sslResumptionValid); -#endif - if (SetCipherSpecs(session->sslServer) != 0) { - SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - if (SetCipherSpecs(session->sslClient) != 0) { - SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - #ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(session->sslServer->version)) { - #ifdef HAVE_SESSION_TICKET - /* Resumption PSK is resumption master secret. */ - session->sslServer->arrays->psk_keySz = session->sslServer->specs.hash_size; - session->sslClient->arrays->psk_keySz = session->sslClient->specs.hash_size; - ret = DeriveResumptionPSK(session->sslServer, session->sslServer->session.ticketNonce.data, - session->sslServer->session.ticketNonce.len, session->sslServer->arrays->psk_key); - /* Copy resumption PSK to client */ - XMEMCPY(session->sslClient->arrays->psk_key, - session->sslServer->arrays->psk_key, - session->sslServer->arrays->psk_keySz); - #endif - /* handshake key setup below and traffic keys done in SetupKeys */ - } - else - #endif - { - if (IsTLS(session->sslServer)) { - ret = DeriveTlsKeys(session->sslServer); - ret += DeriveTlsKeys(session->sslClient); - } - else { - #ifndef NO_OLD_TLS - ret = DeriveKeys(session->sslServer); - ret += DeriveKeys(session->sslClient); - #endif - } - ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE); - ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE); - } - + ret = DoResume(session, error); if (ret != 0) { - SetError(BAD_DERIVE_STR, error, session, FATAL_ERROR_STATE); - return -1; + return ret; } } else { @@ -2950,14 +3038,20 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, #ifdef WOLFSSL_TLS13 /* Setup handshake keys */ - if (IsAtLeastTLSv1_3(session->sslServer->version)) { - DerBuffer* key = session->sslServer->buffers.key; + if (IsAtLeastTLSv1_3(session->sslServer->version) && session->srvKs.key_len > 0) { + KeyBuffers_t keys; + XMEMSET(&keys, 0, sizeof(keys)); + keys.rsaKey = session->sslServer->buffers.key; #ifdef WOLFSSL_STATIC_EPHEMERAL - if (session->sslServer->staticKE.key) - key = session->sslServer->staticKE.key; + #ifndef NO_DH + keys.dhKey = session->sslServer->staticKE.dhKey; + #endif + #ifdef HAVE_ECC + keys.ecKey = session->sslServer->staticKE.ecKey; + #endif #endif ret = SetupKeys(session->cliKs.key, &session->cliKs.key_len, - session, error, &session->cliKs, key); + session, error, &session->cliKs, &keys); if (ret != 0) { SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); return ret; @@ -3321,7 +3415,6 @@ static int KeyWatchCall(SnifferSession* session, const byte* data, int dataSz, static int ProcessCertificate(const byte* input, int* sslBytes, SnifferSession* session, char* error) { - const byte* certChain; word32 certChainSz; word32 certSz; @@ -3334,6 +3427,15 @@ static int ProcessCertificate(const byte* input, int* sslBytes, SetError(BAD_CERT_MSG_STR, error, session, FATAL_ERROR_STATE); return -1; } + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(session->sslServer->version)) { + /* skip 1 byte (Request context len) */ + input += OPAQUE8_LEN; + *sslBytes -= OPAQUE8_LEN; + } +#endif + ato24(input, &certChainSz); *sslBytes -= CERT_HEADER_SZ; input += CERT_HEADER_SZ; @@ -3342,7 +3444,6 @@ static int ProcessCertificate(const byte* input, int* sslBytes, SetError(BAD_CERT_MSG_STR, error, session, FATAL_ERROR_STATE); return -1; } - certChain = input; ato24(input, &certSz); input += OPAQUE24_LEN; @@ -3561,12 +3662,13 @@ static int DoHandShake(const byte* input, int* sslBytes, #endif #ifdef WOLFSSL_TLS13 - if (type != client_hello) { + if (type != client_hello && type != server_hello) { /* For resumption the hash is before / after client_hello PSK binder */ /* hash the packet including header */ /* TLS v1.3 requires the hash for the handshake and transfer key derivation */ /* we hash even for non TLS v1.3, since we don't know if its actually TLS v1.3 till later at EXT_SUPPORTED_VERSIONS in server_hello */ + /* hello retry request restarts hash prior to server_hello hash calc */ HashRaw(session->sslServer, input - HANDSHAKE_HEADER_SZ, size + HANDSHAKE_HEADER_SZ); HashRaw(session->sslClient, input - HANDSHAKE_HEADER_SZ, size + HANDSHAKE_HEADER_SZ); } @@ -4926,6 +5028,11 @@ doMessage: || (session->flags.side == WOLFSSL_CLIENT_END && session->flags.clientCipherOn)) { int ivAdvance = 0; /* TLSv1.1 advance amount */ + + /* change_cipher_spec is not encrypted */ + if (rh.type == change_cipher_spec) { + goto doPart; + } if (ssl->decrypt.setup != 1) { SetError(DECRYPT_KEYS_NOT_SETUP, error, session, FATAL_ERROR_STATE); return -1; @@ -4934,6 +5041,7 @@ doMessage: SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); return -1; } + sslFrame = DecryptMessage(ssl, sslFrame, rhSize, ssl->buffers.outputBuffer.buffer, &errCode, &ivAdvance, &rh); @@ -4983,8 +5091,17 @@ doPart: } break; case change_cipher_spec: - if (session->flags.side == WOLFSSL_SERVER_END) - session->flags.serverCipherOn = 1; + if (session->flags.side == WOLFSSL_SERVER_END) { + #ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(session->sslServer->version) && session->srvKs.key_len == 0) { + session->flags.serverCipherOn = 0; + } + else + #endif + { + session->flags.serverCipherOn = 1; + } + } else session->flags.clientCipherOn = 1; Trace(GOT_CHANGE_CIPHER_STR); diff --git a/src/ssl.c b/src/ssl.c index 6c815639b..dae3ed52d 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -48914,9 +48914,10 @@ int wolfSSL_X509_REQ_set_pubkey(WOLFSSL_X509 *req, WOLFSSL_EVP_PKEY *pkey) #ifdef WOLFSSL_STATIC_EPHEMERAL static int SetStaticEphemeralKey(StaticKeyExchangeInfo_t* staticKE, int keyAlgo, - const char* key, unsigned int keySz, int format, void* heap) + const char* key, unsigned int keySz, int format, void* heap, WOLFSSL_CTX* ctx) { int ret = 0; + DerBuffer* der = NULL; byte* keyBuf = NULL; #ifndef NO_FILESYSTEM const char* keyFile = NULL; @@ -48927,6 +48928,20 @@ static int SetStaticEphemeralKey(StaticKeyExchangeInfo_t* staticKE, int keyAlgo, return BAD_FUNC_ARG; } + WOLFSSL_ENTER("SetStaticEphemeralKey"); + + /* if key is already set free it */ +#ifndef NO_DH + if (keyAlgo == WC_PK_TYPE_DH && staticKE->dhKey && + (ctx == NULL || staticKE->dhKey != ctx->staticKE.dhKey)) + FreeDer(&staticKE->dhKey); +#endif +#ifdef HAVE_ECC + if (keyAlgo == WC_PK_TYPE_ECDH && staticKE->ecKey && + (ctx == NULL || staticKE->ecKey != ctx->staticKE.ecKey)) + FreeDer(&staticKE->ecKey); +#endif + /* check if just free'ing key */ if (key == NULL && keySz == 0) { return 0; @@ -48953,7 +48968,7 @@ static int SetStaticEphemeralKey(StaticKeyExchangeInfo_t* staticKE, int keyAlgo, if (format == WOLFSSL_FILETYPE_PEM) { #ifdef WOLFSSL_PEM_TO_DER int keyFormat = 0; - ret = PemToDer(keyBuf, keySz, PRIVATEKEY_TYPE, &staticKE->key, + ret = PemToDer(keyBuf, keySz, PRIVATEKEY_TYPE, &der, heap, NULL, &keyFormat); /* auto detect key type */ if (ret == 0 && keyAlgo == 0) { @@ -48967,18 +48982,38 @@ static int SetStaticEphemeralKey(StaticKeyExchangeInfo_t* staticKE, int keyAlgo, #endif } else { - ret = AllocDer(&staticKE->key, keySz, PRIVATEKEY_TYPE, heap); + ret = AllocDer(&der, keySz, PRIVATEKEY_TYPE, heap); if (ret == 0) { - XMEMCPY(staticKE->key->buffer, keyBuf, keySz); + XMEMCPY(der->buffer, keyBuf, keySz); } } - staticKE->keyAlgo = keyAlgo; + + switch (keyAlgo) { + #ifndef NO_DH + case WC_PK_TYPE_DH: + staticKE->dhKey = der; + break; + #endif + #ifdef HAVE_ECC + case WC_PK_TYPE_ECDH: + staticKE->ecKey = der; + break; + #endif + default: + /* not supported */ + ret = NOT_COMPILED_IN; + FreeDer(&der); + break; + } #ifndef NO_FILESYSTEM if (keyFile && keyBuf) { XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); } #endif + + WOLFSSL_LEAVE("SetStaticEphemeralKey", ret); + return ret; } @@ -48989,13 +49024,8 @@ int wolfSSL_CTX_set_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, return BAD_FUNC_ARG; } - /* if key is already set free it */ - if (ctx->staticKE.key != NULL) { - FreeDer(&ctx->staticKE.key); - } - return SetStaticEphemeralKey(&ctx->staticKE, keyAlgo, key, keySz, format, - ctx->heap); + ctx->heap, NULL); } int wolfSSL_set_ephemeral_key(WOLFSSL* ssl, int keyAlgo, @@ -49005,13 +49035,8 @@ int wolfSSL_set_ephemeral_key(WOLFSSL* ssl, int keyAlgo, return BAD_FUNC_ARG; } - /* if key is already set and not created by ctx... set free it */ - if (ssl->staticKE.key != NULL && ssl->staticKE.key != ssl->ctx->staticKE.key) { - FreeDer(&ssl->staticKE.key); - } - return SetStaticEphemeralKey(&ssl->staticKE, keyAlgo, key, keySz, format, - ssl->heap); + ssl->heap, ssl->ctx); } #endif /* WOLFSSL_STATIC_EPHEMERAL */ diff --git a/src/tls.c b/src/tls.c index cdf24a91f..6fa50f9ec 100644 --- a/src/tls.c +++ b/src/tls.c @@ -6685,8 +6685,8 @@ static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse) goto end; #if defined(WOLFSSL_STATIC_EPHEMERAL) && defined(WOLFSSL_DH_EXTRA) - if (ssl->staticKE.key && ssl->staticKE.keyAlgo == WC_PK_TYPE_DH) { - DerBuffer* keyDer = ssl->staticKE.key; + if (ssl->staticKE.dhKey) { + DerBuffer* keyDer = ssl->staticKE.dhKey; word32 idx = 0; WOLFSSL_MSG("Using static DH key"); ret = wc_DhKeyDecode(keyDer->buffer, &idx, dhKey, keyDer->length); @@ -6971,8 +6971,8 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse) goto end; #ifdef WOLFSSL_STATIC_EPHEMERAL - if (ssl->staticKE.key && ssl->staticKE.keyAlgo == WC_PK_TYPE_ECDH) { - DerBuffer* keyDer = ssl->staticKE.key; + if (ssl->staticKE.ecKey) { + DerBuffer* keyDer = ssl->staticKE.ecKey; word32 idx = 0; WOLFSSL_MSG("Using static ECDH key"); ret = wc_EccPrivateKeyDecode(keyDer->buffer, &idx, eccKey, keyDer->length); diff --git a/src/tls13.c b/src/tls13.c index 2776ecb77..dfe55333e 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -2365,7 +2365,7 @@ static int CreateCookie(WOLFSSL* ssl, byte* hash, byte hashSz) * ssl The SSL/TLS object. * returns 0 on success, otherwise failure. */ -static int RestartHandshakeHash(WOLFSSL* ssl) +int RestartHandshakeHash(WOLFSSL* ssl) { int ret; Hashes hashes; diff --git a/sslSniffer/sslSnifferTest/snifftest.c b/sslSniffer/sslSnifferTest/snifftest.c index c073d45da..cebbb2682 100644 --- a/sslSniffer/sslSnifferTest/snifftest.c +++ b/sslSniffer/sslSnifferTest/snifftest.c @@ -103,7 +103,11 @@ enum { #ifndef DEFAULT_SERVER_EPH_KEY #if defined(HAVE_ECC) && !defined(NO_ECC_SECP) && \ (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) - #define DEFAULT_SERVER_EPH_KEY DEFAULT_SERVER_EPH_KEY_ECC + #if !defined(NO_DH) + #define DEFAULT_SERVER_EPH_KEY DEFAULT_SERVER_EPH_KEY_ECC "," DEFAULT_SERVER_EPH_KEY_DH + #else + #define DEFAULT_SERVER_EPH_KEY DEFAULT_SERVER_EPH_KEY_ECC + #endif #elif !defined(NO_DH) #define DEFAULT_SERVER_EPH_KEY DEFAULT_SERVER_EPH_KEY_DH #endif @@ -311,6 +315,54 @@ static int myStoreDataCb(const unsigned char* decryptBuf, } #endif /* WOLFSSL_SNIFFER_STORE_DATA_CB */ +/* try and load as both static ephemeral and private key */ +/* only fail if no key is loaded */ +/* Allow comma seperated list of files */ +static int load_key(const char* name, const char* server, int port, + const char* keyFiles, const char* passwd, char* err) +{ + int ret = -1; + int loadCount = 0; + char *keyFile, *ptr = NULL; + + keyFile = XSTRTOK((char*)keyFiles, ",", &ptr); + while (keyFile != NULL) { +#ifdef WOLFSSL_STATIC_EPHEMERAL + #ifdef HAVE_SNI + ret = ssl_SetNamedEphemeralKey(name, server, port, keyFile, + FILETYPE_PEM, passwd, err); + #else + ret = ssl_SetEphemeralKey(server, port, keyFile, + FILETYPE_PEM, passwd, err); + #endif + if (ret == 0) + loadCount++; +#endif + #ifdef HAVE_SNI + ret = ssl_SetNamedPrivateKey(name, server, port, keyFile, + FILETYPE_PEM, passwd, err); + #else + ret = ssl_SetPrivateKey(server, port, keyFile, + FILETYPE_PEM, passwd, err); + #endif + if (ret == 0) + loadCount++; + + if (loadCount == 0) { + printf("Failed loading private key %s: ret %d\n", keyFile, ret); + printf("Please run directly from sslSniffer/sslSnifferTest dir\n"); + ret = -1; + } + else { + ret = 0; + } + + keyFile = XSTRTOK(NULL, ",", &ptr); + } + + (void)name; + return ret; +} int main(int argc, char** argv) { @@ -323,7 +375,10 @@ int main(int argc, char** argv) int frame = ETHER_IF_FRAME_LEN; char err[PCAP_ERRBUF_SIZE]; char filter[32]; + const char *keyFiles = NULL; + char keyFilesBuf[MAX_FILENAME_SZ]; const char *server = NULL; + const char *sniName = NULL; struct bpf_program fp; pcap_if_t *d; pcap_addr_t *a; @@ -436,6 +491,35 @@ int main(int argc, char** argv) ret = pcap_setfilter(pcap, &fp); if (ret != 0) printf("pcap_setfilter failed %s\n", pcap_geterr(pcap)); + /* optionally enter the private key to use */ + #if defined(WOLFSSL_STATIC_EPHEMERAL) && defined(DEFAULT_SERVER_EPH_KEY) + keyFiles = DEFAULT_SERVER_EPH_KEY; + #else + keyFiles = DEFAULT_SERVER_KEY; + #endif + printf("Enter the server key [default: %s]: ", keyFiles); + XMEMSET(keyFilesBuf, 0, sizeof(keyFilesBuf)); + if (XFGETS(keyFilesBuf, sizeof(keyFilesBuf), stdin)) { + if (keyFilesBuf[0] != '\r' && keyFilesBuf[0] != '\n') { + keyFiles = keyFilesBuf; + } + } + if (keyFiles != keyFilesBuf) { + XSTRNCPY(keyFilesBuf, keyFiles, sizeof(keyFilesBuf)); + keyFiles = keyFilesBuf; + } + + /* optionally enter a named key (SNI) */ + #if !defined(WOLFSSL_SNIFFER_WATCH) && defined(HAVE_SNI) + printf("Enter alternate SNI [default: none]: "); + XMEMSET(cmdLineArg, 0, sizeof(cmdLineArg)); + if (XFGETS(cmdLineArg, sizeof(cmdLineArg), stdin)) { + if (XSTRLEN(cmdLineArg) > 0) { + sniName = cmdLineArg; + } + } + #endif /* !WOLFSSL_SNIFFER_WATCH && HAVE_SNI */ + /* get IPv4 or IPv6 addresses for selected interface */ for (a = d->addresses; a; a = a->next) { server = NULL; @@ -449,39 +533,10 @@ int main(int argc, char** argv) } if (server) { - #ifdef DEFAULT_SERVER_KEY - ret = ssl_SetPrivateKey(server, port, DEFAULT_SERVER_KEY, - FILETYPE_PEM, NULL, err); + ret = load_key(sniName, server, port, keyFiles, NULL, err); if (ret != 0) { - printf("Please run directly from sslSniffer/sslSnifferTest" - "dir\n"); + exit(EXIT_FAILURE); } - #endif - #if defined(WOLFSSL_STATIC_EPHEMERAL) && defined(DEFAULT_SERVER_EPH_KEY) - ret = ssl_SetEphemeralKey(server, port, DEFAULT_SERVER_EPH_KEY, - FILETYPE_PEM, NULL, err); - if (ret != 0) { - printf("Please run directly from sslSniffer/sslSnifferTest" - "dir\n"); - } - #endif /* WOLFSSL_STATIC_EPHEMERAL */ - #ifndef WOLFSSL_SNIFFER_WATCH - #ifdef HAVE_SNI - printf("Enter alternate SNI: "); - XMEMSET(cmdLineArg, 0, sizeof(cmdLineArg)); - if (XFGETS(cmdLineArg, sizeof(cmdLineArg), stdin)) { - if (XSTRLEN(cmdLineArg) > 0) { - ret = ssl_SetNamedPrivateKey(cmdLineArg, - server, port, DEFAULT_SERVER_KEY, - FILETYPE_PEM, NULL, err); - if (ret != 0) { - printf("Please run directly from " - "sslSniffer/sslSnifferTest dir\n"); - } - } - } - #endif /* HAVE_SNI */ - #endif /* WOLFSSL_SNIFFER_WATCH */ } } } @@ -494,11 +549,11 @@ int main(int argc, char** argv) } else { const char* passwd = NULL; - int loadCount = 0; /* defaults for server and port */ port = 443; server = "127.0.0.1"; + keyFiles = argv[2]; if (argc >= 4) server = argv[3]; @@ -509,22 +564,8 @@ int main(int argc, char** argv) if (argc >= 6) passwd = argv[5]; - /* try and load as both static ephemeral and private key */ - /* only fail if no key is loaded */ - #ifdef WOLFSSL_STATIC_EPHEMERAL - ret = ssl_SetEphemeralKey(server, port, argv[2], - FILETYPE_PEM, passwd, err); - if (ret == 0) - loadCount++; - #endif - ret = ssl_SetPrivateKey(server, port, argv[2], - FILETYPE_PEM, passwd, err); - - if (ret == 0) - loadCount++; - - if (loadCount == 0) { - printf("Failed loading private key %d\n", ret); + ret = load_key(NULL, server, port, keyFiles, passwd, err); + if (ret != 0) { exit(EXIT_FAILURE); } diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 9b209e3e7..491b1536a 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1727,6 +1727,7 @@ WOLFSSL_LOCAL int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, WOLFSSL_LOCAL int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 helloSz, byte* extMsgType); +WOLFSSL_LOCAL int RestartHandshakeHash(WOLFSSL* ssl); #endif int TimingPadVerify(WOLFSSL* ssl, const byte* input, int padLen, int t, int pLen, int content); @@ -2624,9 +2625,14 @@ enum SetCBIO { #endif #ifdef WOLFSSL_STATIC_EPHEMERAL +/* contains static ephemeral keys */ typedef struct { - int keyAlgo; - DerBuffer* key; +#ifndef NO_DH + DerBuffer* dhKey; +#endif +#ifdef HAVE_ECC + DerBuffer* ecKey; +#endif } StaticKeyExchangeInfo_t; #endif diff --git a/wolfssl/sniffer_error.h b/wolfssl/sniffer_error.h index 882aaeae7..f2710522f 100644 --- a/wolfssl/sniffer_error.h +++ b/wolfssl/sniffer_error.h @@ -109,7 +109,6 @@ #define GOT_CERT_STATUS_STR 73 #define RSA_KEY_MISSING_STR 74 #define NO_SECURE_RENEGOTIATION 75 - #define BAD_SESSION_STATS 76 #define REASSEMBLY_MAX_STR 77 #define DROPPING_LOST_FRAG_STR 78 @@ -131,6 +130,7 @@ #define STORE_DATA_FAIL_STR 92 #define CHAIN_INPUT_STR 93 #define GOT_ENC_EXT_STR 94 +#define GOT_HELLO_RETRY_REQ_STR 95 /* !!!! also add to msgTable in sniffer.c and .rc file !!!! */ diff --git a/wolfssl/sniffer_error.rc b/wolfssl/sniffer_error.rc index 72fe36e9e..27bfdfe1c 100644 --- a/wolfssl/sniffer_error.rc +++ b/wolfssl/sniffer_error.rc @@ -112,5 +112,6 @@ STRINGTABLE 91, "No data destination Error" 92, "Store Data callback failed" 93, "Loading chain input" + 94, "Got encrypted extension" + 95, "Got Hello Retry Request" } -