From b74f0fb6b8f7d11d5f787e7c613d2c7fb6c4c852 Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 4 Nov 2020 12:54:14 -0800 Subject: [PATCH 01/10] Fixes for sniffer with `hello_retry_request`. Fix for TLS v1.3 certificate processing. --- src/sniffer.c | 88 ++++++++++++++++++++++++++++++++-------- src/tls13.c | 2 +- wolfssl/internal.h | 1 + wolfssl/sniffer_error.h | 2 +- wolfssl/sniffer_error.rc | 2 + 5 files changed, 76 insertions(+), 19 deletions(-) diff --git a/src/sniffer.c b/src/sniffer.c index bec413fa3..673133d8b 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", }; @@ -2415,13 +2416,18 @@ static int ProcessKeyShare(KeyShareInfo* info, const byte* input, int len, /* 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 @@ -2502,13 +2508,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); @@ -2642,10 +2649,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 +2672,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,6 +2867,32 @@ 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)) { @@ -2950,7 +2987,7 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, #ifdef WOLFSSL_TLS13 /* Setup handshake keys */ - if (IsAtLeastTLSv1_3(session->sslServer->version)) { + if (IsAtLeastTLSv1_3(session->sslServer->version) && session->srvKs.key_len > 0) { DerBuffer* key = session->sslServer->buffers.key; #ifdef WOLFSSL_STATIC_EPHEMERAL if (session->sslServer->staticKE.key) @@ -3321,7 +3358,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 +3370,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 +3387,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 +3605,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); } @@ -4983,8 +5028,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/tls13.c b/src/tls13.c index e56f2fd1d..a3173732b 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/wolfssl/internal.h b/wolfssl/internal.h index e0df1438b..7e70fe3d4 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); 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..59d8f5c9e 100644 --- a/wolfssl/sniffer_error.rc +++ b/wolfssl/sniffer_error.rc @@ -112,5 +112,7 @@ STRINGTABLE 91, "No data destination Error" 92, "Store Data callback failed" 93, "Loading chain input" + 94, "Got encrypted extension" + 95, "Hello retry request" } From d208779974da4a1401cb544c4b3efcd9cdb807f3 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 6 Nov 2020 14:55:00 -0800 Subject: [PATCH 02/10] Added test case for TLS v1.3 with HRR (hello_retry_request) --- scripts/include.am | 1 + scripts/sniffer-testsuite.test | 10 ++++++++++ scripts/sniffer-tls13-gen.sh | 5 +++++ scripts/sniffer-tls13-hrr.pcap | Bin 0 -> 8789 bytes wolfssl/sniffer_error.rc | 3 +-- 5 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 scripts/sniffer-tls13-hrr.pcap 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 0000000000000000000000000000000000000000..c9b0789672b0663ebad9eff017cf62d1aa8d494d GIT binary patch literal 8789 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 a0|OXC<3$5Uyu1M|@(5sIVE8A)zyJWxNT107 literal 0 HcmV?d00001 diff --git a/wolfssl/sniffer_error.rc b/wolfssl/sniffer_error.rc index 59d8f5c9e..27bfdfe1c 100644 --- a/wolfssl/sniffer_error.rc +++ b/wolfssl/sniffer_error.rc @@ -113,6 +113,5 @@ STRINGTABLE 92, "Store Data callback failed" 93, "Loading chain input" 94, "Got encrypted extension" - 95, "Hello retry request" + 95, "Got Hello Retry Request" } - From 1c87f3bdc1b17651be4a4903d6ee0a2dfcf9caa5 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 9 Nov 2020 16:05:02 -0800 Subject: [PATCH 03/10] Improve sniffer resume logic. --- src/sniffer.c | 178 ++++++++++++++++++++++++++++---------------------- 1 file changed, 101 insertions(+), 77 deletions(-) diff --git a/src/sniffer.c b/src/sniffer.c index 673133d8b..627182d7c 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -2639,6 +2639,105 @@ static int ProcessSessionTicket(const byte* input, int* sslBytes, return 0; } +static int DoResume(SnifferSession* session, char* error) +{ + int ret; + WOLFSSL_SESSION* resume; +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(session->sslServer->version)) { + resume = GetSession(session->sslServer, + session->sslServer->session.masterSecret, 0); + if (resume == NULL) { + /* a session id without resume is okay */ + #ifdef WOLFSSL_SNIFFER_STATS + INC_STAT(SnifferStats.sslStandardConns); + #endif + return 0; + } + } + else +#endif + { + 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 */ +#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, @@ -2894,84 +2993,9 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, 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 { From 71d9f1e9bd8a8f694a20d98df632a3be7e6bf87f Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 9 Nov 2020 16:07:14 -0800 Subject: [PATCH 04/10] Static ephemeral refactor to support loading both DHE and ECDHE keys. Added ability to specify key using snifftest input at run-time. Improved snifftest key loading for named keys and static ephemeral. --- examples/server/server.c | 3 +- src/internal.c | 22 +++-- src/sniffer.c | 49 ++++++++--- src/ssl.c | 52 +++++++---- src/tls.c | 8 +- sslSniffer/sslSnifferTest/snifftest.c | 119 +++++++++++++++----------- wolfssl/internal.h | 9 +- 7 files changed, 172 insertions(+), 90 deletions(-) diff --git a/examples/server/server.c b/examples/server/server.c index 0bd6efd2c..511f2d7e0 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -1747,7 +1747,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/src/internal.c b/src/internal.c index 2d8e64f39..213ba41e0 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 627182d7c..972180f31 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -2067,11 +2067,26 @@ static void ShowTlsSecrets(SnifferSession* session) /* Process Keys */ + +/* contains static ephemeral keys */ +typedef struct { +#ifndef NO_DH + DerBuffer* ecKey; +#endif +#ifdef HAVE_ECC + DerBuffer* dhKey; +#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) @@ -2080,9 +2095,11 @@ 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) { @@ -2152,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) { @@ -2240,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) { @@ -2395,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) { @@ -2403,8 +2425,9 @@ 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)); + keys.rsaKey = session->sslServer->buffers.key; + return SetupKeys(input, sslBytes, session, error, NULL, &keys); } #ifdef WOLFSSL_TLS13 @@ -3012,13 +3035,19 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, #ifdef WOLFSSL_TLS13 /* Setup handshake keys */ if (IsAtLeastTLSv1_3(session->sslServer->version) && session->srvKs.key_len > 0) { - DerBuffer* key = session->sslServer->buffers.key; + 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; diff --git a/src/ssl.c b/src/ssl.c index 7a7f44af7..7437cc887 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -48874,9 +48874,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; @@ -48887,6 +48888,16 @@ static int SetStaticEphemeralKey(StaticKeyExchangeInfo_t* staticKE, int keyAlgo, return BAD_FUNC_ARG; } + /* if key is already set free it */ +#ifndef NO_DH + if (staticKE->dhKey && (ctx == NULL || staticKE->dhKey != ctx->staticKE.dhKey)) + FreeDer(&staticKE->dhKey); +#endif +#ifdef HAVE_ECC + if (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; @@ -48913,7 +48924,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) { @@ -48927,12 +48938,29 @@ 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) { @@ -48949,13 +48977,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, @@ -48965,13 +48988,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 fa7c71113..f99279f57 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/sslSniffer/sslSnifferTest/snifftest.c b/sslSniffer/sslSnifferTest/snifftest.c index c073d45da..94914c298 100644 --- a/sslSniffer/sslSnifferTest/snifftest.c +++ b/sslSniffer/sslSnifferTest/snifftest.c @@ -311,6 +311,43 @@ 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 */ +static int load_key(const char* name, const char* server, int port, + const char* keyFile, const char* passwd, char* err) +{ + int ret; + int loadCount = 0; + +#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); + ret = -1; + } + (void)name; + return ret; +} int main(int argc, char** argv) { @@ -323,7 +360,10 @@ int main(int argc, char** argv) int frame = ETHER_IF_FRAME_LEN; char err[PCAP_ERRBUF_SIZE]; char filter[32]; + const char *keyFile = NULL; + char keyFileBuf[128]; const char *server = NULL; + const char *sniName = NULL; struct bpf_program fp; pcap_if_t *d; pcap_addr_t *a; @@ -436,6 +476,31 @@ 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) + keyFile = DEFAULT_SERVER_EPH_KEY; + #else + keyFile = DEFAULT_SERVER_KEY; + #endif + printf("Enter the server key [default: %s]: ", keyFile); + XMEMSET(keyFileBuf, 0, sizeof(keyFileBuf)); + if (XFGETS(keyFileBuf, sizeof(keyFileBuf), stdin)) { + if (keyFileBuf[0] != '\r' && keyFileBuf[0] != '\n') { + keyFile = keyFileBuf; + } + } + + /* 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 +514,7 @@ int main(int argc, char** argv) } if (server) { - #ifdef DEFAULT_SERVER_KEY - ret = ssl_SetPrivateKey(server, port, DEFAULT_SERVER_KEY, - FILETYPE_PEM, NULL, err); - if (ret != 0) { - printf("Please run directly from sslSniffer/sslSnifferTest" - "dir\n"); - } - #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 */ + load_key(sniName, server, port, keyFile, NULL, err); } } } @@ -494,11 +527,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"; + keyFile = argv[2]; if (argc >= 4) server = argv[3]; @@ -509,22 +542,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, keyFile, passwd, err); + if (ret != 0) { exit(EXIT_FAILURE); } diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 7e70fe3d4..9e2152fad 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2625,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 From 720919198fae16dfa3a6067d65162788678dc18d Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 10 Nov 2020 09:40:23 -0800 Subject: [PATCH 05/10] Fix for Scan-buld and when building without ECC or DH. --- src/sniffer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sniffer.c b/src/sniffer.c index 972180f31..dddb417ef 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -2071,10 +2071,10 @@ static void ShowTlsSecrets(SnifferSession* session) /* contains static ephemeral keys */ typedef struct { #ifndef NO_DH - DerBuffer* ecKey; + DerBuffer* dhKey; #endif #ifdef HAVE_ECC - DerBuffer* dhKey; + DerBuffer* ecKey; #endif #if !defined(NO_RSA) && defined(WOLFSSL_STATIC_RSA) DerBuffer* rsaKey; @@ -2098,7 +2098,7 @@ static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, if (ksInfo == NULL && keys->rsaKey) { RsaKey key; int length; - + keyBuf = keys->rsaKey; ret = wc_InitRsaKey(&key, 0); @@ -2664,7 +2664,7 @@ static int ProcessSessionTicket(const byte* input, int* sslBytes, static int DoResume(SnifferSession* session, char* error) { - int ret; + int ret = 0; WOLFSSL_SESSION* resume; #ifdef WOLFSSL_TLS13 if (IsAtLeastTLSv1_3(session->sslServer->version)) { From 5cda549d00544a4bbedb85e8dfb46017e99f4f07 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 10 Nov 2020 11:57:31 -0800 Subject: [PATCH 06/10] Allow passing multiple keys (comma separated) with the sniffer test tool. This allows setting both DH and ECC static ephemeral keys. Do not fail on resume not found. --- src/sniffer.c | 19 +++---- sslSniffer/sslSnifferTest/snifftest.c | 78 ++++++++++++++++----------- 2 files changed, 53 insertions(+), 44 deletions(-) diff --git a/src/sniffer.c b/src/sniffer.c index dddb417ef..8ee8c21b0 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -2666,17 +2666,11 @@ 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); - if (resume == NULL) { - /* a session id without resume is okay */ - #ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslStandardConns); - #endif - return 0; - } } else #endif @@ -2684,13 +2678,12 @@ static int DoResume(SnifferSession* session, char* error) 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; + /* 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 */ diff --git a/sslSniffer/sslSnifferTest/snifftest.c b/sslSniffer/sslSnifferTest/snifftest.c index 94914c298..6d0989d85 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 @@ -313,38 +317,46 @@ static int myStoreDataCb(const unsigned char* decryptBuf, /* 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* keyFile, const char* passwd, char* err) + const char* keyFiles, const char* passwd, char* err) { - int ret; + 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); + ret = ssl_SetNamedEphemeralKey(name, server, port, keyFile, + FILETYPE_PEM, passwd, err); #else - ret = ssl_SetEphemeralKey(server, port, keyFile, - FILETYPE_PEM, passwd, err); + ret = ssl_SetEphemeralKey(server, port, keyFile, + FILETYPE_PEM, passwd, err); #endif - if (ret == 0) - loadCount++; + if (ret == 0) + loadCount++; #endif #ifdef HAVE_SNI - ret = ssl_SetNamedPrivateKey(name, server, port, keyFile, - FILETYPE_PEM, passwd, err); + ret = ssl_SetNamedPrivateKey(name, server, port, keyFile, + FILETYPE_PEM, passwd, err); #else - ret = ssl_SetPrivateKey(server, port, keyFile, - FILETYPE_PEM, passwd, err); + 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; + } - if (ret == 0) - loadCount++; - - if (loadCount == 0) { - printf("Failed loading private key %s: ret %d\n", keyFile, ret); - ret = -1; + keyFile = XSTRTOK(NULL, ",", &ptr); } + (void)name; return ret; } @@ -360,8 +372,8 @@ int main(int argc, char** argv) int frame = ETHER_IF_FRAME_LEN; char err[PCAP_ERRBUF_SIZE]; char filter[32]; - const char *keyFile = NULL; - char keyFileBuf[128]; + const char *keyFiles = NULL; + char keyFilesBuf[MAX_FILENAME_SZ]; const char *server = NULL; const char *sniName = NULL; struct bpf_program fp; @@ -478,17 +490,21 @@ int main(int argc, char** argv) /* optionally enter the private key to use */ #if defined(WOLFSSL_STATIC_EPHEMERAL) && defined(DEFAULT_SERVER_EPH_KEY) - keyFile = DEFAULT_SERVER_EPH_KEY; + keyFiles = DEFAULT_SERVER_EPH_KEY; #else - keyFile = DEFAULT_SERVER_KEY; + keyFiles = DEFAULT_SERVER_KEY; #endif - printf("Enter the server key [default: %s]: ", keyFile); - XMEMSET(keyFileBuf, 0, sizeof(keyFileBuf)); - if (XFGETS(keyFileBuf, sizeof(keyFileBuf), stdin)) { - if (keyFileBuf[0] != '\r' && keyFileBuf[0] != '\n') { - keyFile = keyFileBuf; + 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) @@ -514,7 +530,7 @@ int main(int argc, char** argv) } if (server) { - load_key(sniName, server, port, keyFile, NULL, err); + load_key(sniName, server, port, keyFiles, NULL, err); } } } @@ -531,7 +547,7 @@ int main(int argc, char** argv) /* defaults for server and port */ port = 443; server = "127.0.0.1"; - keyFile = argv[2]; + keyFiles = argv[2]; if (argc >= 4) server = argv[3]; @@ -542,7 +558,7 @@ int main(int argc, char** argv) if (argc >= 6) passwd = argv[5]; - ret = load_key(NULL, server, port, keyFile, passwd, err); + ret = load_key(NULL, server, port, keyFiles, passwd, err); if (ret != 0) { exit(EXIT_FAILURE); } From ea21ddf540f0f796c335fb86dc240f73dceeee6e Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 10 Nov 2020 13:08:04 -0800 Subject: [PATCH 07/10] Fix to only free existing key in `SetStaticEphemeralKey` if the incoming algorithm type has been specified. --- src/ssl.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index 7437cc887..0f7f49e7a 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -48888,13 +48888,17 @@ 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 (staticKE->dhKey && (ctx == NULL || staticKE->dhKey != ctx->staticKE.dhKey)) + if (keyAlgo == WC_PK_TYPE_DH && staticKE->dhKey && + (ctx == NULL || staticKE->dhKey != ctx->staticKE.dhKey)) FreeDer(&staticKE->dhKey); #endif #ifdef HAVE_ECC - if (staticKE->ecKey && (ctx == NULL || staticKE->ecKey != ctx->staticKE.ecKey)) + if (keyAlgo == WC_PK_TYPE_ECDH && staticKE->ecKey && + (ctx == NULL || staticKE->ecKey != ctx->staticKE.ecKey)) FreeDer(&staticKE->ecKey); #endif @@ -48967,6 +48971,9 @@ static int SetStaticEphemeralKey(StaticKeyExchangeInfo_t* staticKE, int keyAlgo, XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); } #endif + + WOLFSSL_LEAVE("SetStaticEphemeralKey", ret); + return ret; } From a53b734c8318726c9b51a26be2d16774ff0c417d Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 10 Nov 2020 14:03:25 -0800 Subject: [PATCH 08/10] Fix for `client_hello` keyshare with multiple entries. Fix for `change_cipher_spec` after `finished`. --- src/sniffer.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/sniffer.c b/src/sniffer.c index 8ee8c21b0..b223701cd 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -2436,6 +2436,9 @@ 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; @@ -2514,15 +2517,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, @@ -5017,6 +5020,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; @@ -5025,6 +5033,7 @@ doMessage: SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); return -1; } + sslFrame = DecryptMessage(ssl, sslFrame, rhSize, ssl->buffers.outputBuffer.buffer, &errCode, &ivAdvance, &rh); From a6f2081af1573fb42260407cd64b361aacf933a8 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 10 Nov 2020 14:13:38 -0800 Subject: [PATCH 09/10] Fixes for key loading errors in snifftest application. --- sslSniffer/sslSnifferTest/snifftest.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sslSniffer/sslSnifferTest/snifftest.c b/sslSniffer/sslSnifferTest/snifftest.c index 6d0989d85..cebbb2682 100644 --- a/sslSniffer/sslSnifferTest/snifftest.c +++ b/sslSniffer/sslSnifferTest/snifftest.c @@ -353,6 +353,9 @@ static int load_key(const char* name, const char* server, int port, printf("Please run directly from sslSniffer/sslSnifferTest dir\n"); ret = -1; } + else { + ret = 0; + } keyFile = XSTRTOK(NULL, ",", &ptr); } @@ -530,7 +533,10 @@ int main(int argc, char** argv) } if (server) { - load_key(sniName, server, port, keyFiles, NULL, err); + ret = load_key(sniName, server, port, keyFiles, NULL, err); + if (ret != 0) { + exit(EXIT_FAILURE); + } } } } From cdf44f6ff6600e7e0c62e11895263dc9eef83484 Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 11 Nov 2020 14:23:06 -0800 Subject: [PATCH 10/10] Pass static ephemeral keys for TLS v1.2 as well. --- src/sniffer.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sniffer.c b/src/sniffer.c index b223701cd..900211e74 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -2426,6 +2426,14 @@ static int ProcessClientKeyExchange(const byte* input, int* sslBytes, } 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); }