From 71d9f1e9bd8a8f694a20d98df632a3be7e6bf87f Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 9 Nov 2020 16:07:14 -0800 Subject: [PATCH] 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