Browse Source

Merge pull request #3044 from dgarske/sniffer_tls13

TLS v1.3 sniffer support
toddouska 3 years ago
parent
commit
e84defb268

+ 1 - 0
certs/include.am

@@ -108,6 +108,7 @@ include certs/ed25519/include.am
 include certs/ed448/include.am
 include certs/external/include.am
 include certs/ocsp/include.am
+include certs/statickeys/include.am
 include certs/test/include.am
 include certs/test-pathlen/include.am
 include certs/intermediate/include.am

+ 8 - 0
certs/statickeys/dh-ffdhe2048-params.pem

@@ -0,0 +1,8 @@
+-----BEGIN DH PARAMETERS-----
+MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
+87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
+YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
+7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
+ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
+-----END DH PARAMETERS-----

BIN
certs/statickeys/dh-ffdhe2048.der


+ 9 - 0
certs/statickeys/dh-ffdhe2048.pem

@@ -0,0 +1,9 @@
+-----BEGIN PRIVATE KEY-----
+MIIBPwIBADCCARcGCSqGSIb3DQEDATCCAQgCggEBAP//////////rfhUWKK7Spqv
+3FYgJz088di5xYPOLTaVqeE2QRRkM/vMk53OJJs++X0v42NjDHXY9oGyAq7EYXrT
+3x7V1f1lYSQz9R9fBm7QhWNlVT3tGvO1VxNef1fJNZhPDHDg5ot34qaJ2vPv6HId
+8VihNq3nNTCsyk9IOnl6vAqxgrMk+2HRCKlLssjj+7lq2rdg1/RoHU9Co945TfSu
+Vu3nY3K7GQsHp8juCm1wngL84c334uzANATNKDQvYZFy/pzphYP/jk8SMu7ygYPD
+/jsbTG+tczu1/LwuwiAFxY7xg30Wg7LG80omwbLv+ohrQjhhKFyX//////////8C
+AQIEHwIdXPuG9/pRAnlxnsApmAPPPmVG9jS4sMFVOvfIQ7g=
+-----END PRIVATE KEY-----

BIN
certs/statickeys/ecc-secp256r1.der


+ 5 - 0
certs/statickeys/ecc-secp256r1.pem

@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEINNrxmh23tiXlfbZji9Bc1P4A1ftkIAZ66pKkYqPMWNFoAoGCCqGSM49
+AwEHoUQDQgAEWKCAfFHs3UFfk6h6YEdH6c9aQOTdN+zKpxAcQ9roc4wo9cnsGjML
+Ji6XgC7guAGRFrTMAhi1Hcy6PO0EyaiSNw==
+-----END EC PRIVATE KEY-----

+ 12 - 0
certs/statickeys/gen-static.sh

@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# run from wolfssl root
+
+# SECP256R1
+openssl ecparam -name secp256r1 -genkey -noout -out certs/statickeys/ecc-secp256r1.pem -noout
+openssl ec -inform pem -in certs/statickeys/ecc-secp256r1.pem -outform der -out certs/statickeys/ecc-secp256r1.der
+
+# DH 2048-bit (keySz = 29)
+# Using one generated and capture with wolfSSL using wc_DhGenerateKeyPair (openssl generates DH keys with 2048-bits... based on the DH "p" prime size)
+#openssl genpkey -paramfile certs/statickeys/dh-ffdhe2048-params.pem -out certs/statickeys/dh-ffdhe2048.der
+openssl pkey -inform der -in certs/statickeys/dh-ffdhe2048.der -outform pem -out certs/statickeys/dh-ffdhe2048.pem

+ 17 - 0
certs/statickeys/include.am

@@ -0,0 +1,17 @@
+# vim:ft=automake
+# All paths should be given relative to the root
+#
+
+EXTRA_DIST += \
+		certs/statickeys/gen-static.sh
+
+# ECC
+EXTRA_DIST += \
+		certs/statickeys/ecc-secp256r1.der \
+		certs/statickeys/ecc-secp256r1.pem
+
+# DH FFDHE Groups
+EXTRA_DIST += \
+		certs/statickeys/dh-ffdhe2048-params.pem \
+		certs/statickeys/dh-ffdhe2048.der \
+		certs/statickeys/dh-ffdhe2048.pem

+ 4 - 3
configure.ac

@@ -889,7 +889,7 @@ fi
 ENABLED_SNIFFTEST=no
 AS_IF([ test "x$ENABLED_SNIFFER" = "xyes" ],
       [
-          AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SNIFFER"
+          AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SNIFFER -DWOLFSSL_STATIC_EPHEMERAL"
           AC_CHECK_HEADERS([pcap/pcap.h],
               [ ENABLED_SNIFFTEST=yes ],
               [ AC_MSG_WARN([cannot enable sniffer test without having libpcap available.]) ]
@@ -5001,8 +5001,9 @@ AS_IF([test "x$ENABLED_LEANTLS" = "xyes" && \
       [AC_MSG_ERROR([please enable ecc if enabling leantls.])])
 
 AS_IF([test "x$ENABLED_SNIFFER" = "xyes" && \
-       test "x$ENABLED_RSA" = "xno"],
-      [AC_MSG_ERROR([please enable rsa if enabling sniffer.])])
+       test "x$ENABLED_RSA" = "xno" && \
+       test "x$ENABLED_ECC" = "xno"],
+      [AC_MSG_ERROR([please enable ecc or rsa if enabling sniffer.])])
 
 # Lean TLS forces off prereqs of SCEP.
 AS_IF([test "x$ENABLED_SCEP" = "xyes" && \

+ 23 - 0
doc/dox_comments/header_files/ssl.h

@@ -13529,3 +13529,26 @@ WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_3_method_ex(void* heap);
 */
 WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_3_method(void);
 
+/*!
+ \ingroup SSL
+ \brief This function sets a fixed / static ephemeral key for testing only
+ \return 0 Key loaded successfully
+ \param ctx A WOLFSSL_CTX context pointer
+ \param keyAlgo enum wc_PkType like WC_PK_TYPE_DH and WC_PK_TYPE_ECDH
+ \param key key file path (if keySz == 0) or actual key buffer (PEM or ASN.1)
+ \param keySz key size (should be 0 for "key" arg is file path)
+ \param format WOLFSSL_FILETYPE_ASN1 or WOLFSSL_FILETYPE_PEM
+ */
+WOLFSSL_API int wolfSSL_CTX_set_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, const char* key, unsigned int keySz, int format);
+
+/*!
+ \ingroup SSL
+ \brief This function sets a fixed / static ephemeral key for testing only
+ \return 0 Key loaded successfully
+ \param ssl A WOLFSSL object pointer
+ \param keyAlgo enum wc_PkType like WC_PK_TYPE_DH and WC_PK_TYPE_ECDH
+ \param key key file path (if keySz == 0) or actual key buffer (PEM or ASN.1)
+ \param keySz key size (should be 0 for "key" arg is file path)
+ \param format WOLFSSL_FILETYPE_ASN1 or WOLFSSL_FILETYPE_PEM
+ */
+WOLFSSL_API int wolfSSL_set_ephemeral_key(WOLFSSL* ssl, int keyAlgo, const char* key, unsigned int keySz, int format);

+ 4 - 3
examples/client/client.c

@@ -2396,10 +2396,11 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
     wolfSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack);
 #endif
 
-#if defined(WOLFSSL_SNIFFER)
+#ifdef WOLFSSL_SNIFFER
     if (cipherList == NULL && version < 4) {
-        /* don't use EDH, can't sniff tmp keys */
-        if (wolfSSL_CTX_set_cipher_list(ctx, "AES128-SHA") != WOLFSSL_SUCCESS) {
+        /* static RSA or ECC cipher suites */
+        const char* staticCipherList = "AES128-SHA:ECDH-ECDSA-AES128-SHA";
+        if (wolfSSL_CTX_set_cipher_list(ctx, staticCipherList) != WOLFSSL_SUCCESS) {
             wolfSSL_CTX_free(ctx); ctx = NULL;
             err_sys("client can't set cipher list 3");
         }

+ 24 - 3
examples/server/server.c

@@ -1654,6 +1654,25 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
     wolfSSL_CTX_set_TicketEncCb(ctx, myTicketEncCb);
 #endif
 
+#if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_STATIC_EPHEMERAL)
+    /* used for testing only to set a static/fixed ephemeral key 
+        for use with the sniffer */
+#if defined(HAVE_ECC) && !defined(NO_ECC_SECP) && \
+        (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES))
+    ret = wolfSSL_CTX_set_ephemeral_key(ctx, WC_PK_TYPE_ECDH,
+        "./certs/statickeys/ecc-secp256r1.pem", 0, WOLFSSL_FILETYPE_PEM);
+    if (ret != 0) {
+        err_sys_ex(runWithErrors, "error loading static ECDH key");
+    }
+#elif !defined(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) {
+        err_sys_ex(runWithErrors, "error loading static DH key");
+    }
+#endif
+#endif /* WOLFSSL_SNIFFER && WOLFSSL_STATIC_EPHEMERAL */
+
     if (cipherList && !useDefCipherList) {
         if (SSL_CTX_set_cipher_list(ctx, cipherList) != WOLFSSL_SUCCESS)
             err_sys_ex(runWithErrors, "server can't set custom cipher list");
@@ -1839,11 +1858,13 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
    }
 #endif
 
-#if defined(WOLFSSL_SNIFFER)
-    /* don't use EDH, can't sniff tmp keys */
+#ifdef WOLFSSL_SNIFFER
     if (cipherList == NULL && version < 4) {
-        if (SSL_CTX_set_cipher_list(ctx, "AES128-SHA") != WOLFSSL_SUCCESS)
+        /* static RSA or static ECC cipher suites */
+        const char* staticCipherList = "AES128-SHA:ECDH-ECDSA-AES128-SHA";
+        if (SSL_CTX_set_cipher_list(ctx, staticCipherList) != WOLFSSL_SUCCESS) {
             err_sys_ex(runWithErrors, "server can't set cipher list 3");
+        }
     }
 #endif
 

+ 3 - 0
scripts/include.am

@@ -85,6 +85,9 @@ endif
 
 EXTRA_DIST +=  scripts/testsuite.pcap \
                scripts/sniffer-ipv6.pcap \
+               scripts/sniffer-tls13-dh.pcap \
+               scripts/sniffer-tls13-ecc.pcap \
+               scripts/sniffer-tls13-gen.sh \
                scripts/ping.test
 
 # leave openssl.test as extra until non bash works

+ 21 - 0
scripts/sniffer-testsuite.test

@@ -2,13 +2,34 @@
 
 #sniffer-testsuite.test
 
+# ./configure --enable-sniffer [--enable-session-ticket]
+# Resumption tests require "--enable-session-ticket"
+
 echo -e "\nStaring snifftest on testsuite.pcap...\n"
 ./sslSniffer/sslSnifferTest/snifftest ./scripts/testsuite.pcap ./certs/server-key.pem 127.0.0.1 11111
 
 RESULT=$?
 [ $RESULT -ne 0 ] && echo -e "\nsnifftest failed\n" && exit 1
 
+# TLS v1.3 sniffer test ECC (and resumption)
+if test $# -ne 0
+then
+    ./sslSniffer/sslSnifferTest/snifftest ./scripts/sniffer-tls13-ecc.pcap ./certs/statickeys/ecc-secp256r1.pem 127.0.0.1 11111
+
+    RESULT=$?
+    [ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 ECC\n" && exit 1
+fi
+
+# TLS v1.3 sniffer test DH (and resumption)
+if test $# -ne 0
+then
+    ./sslSniffer/sslSnifferTest/snifftest ./scripts/sniffer-tls13-dh.pcap ./certs/statickeys/dh-ffdhe2048.pem 127.0.0.1 11111
+
+    RESULT=$?
+    [ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 DH\n" && exit 1
+fi
 
+# IPv6
 if test $# -ne 0 && test "x$1" = "x-6";
 then
     echo -e "\nStaring snifftest on sniffer-ipv6.pcap...\n"

BIN
scripts/sniffer-tls13-dh.pcap


BIN
scripts/sniffer-tls13-ecc.pcap


+ 24 - 0
scripts/sniffer-tls13-gen.sh

@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Run these configures and the example server/client below
+# Script to generate wireshark trace for sniffer-tls13-ecc.pcap
+#./configure --enable-sniffer --enable-session-ticket && make
+
+# Script to generate wireshark trace for sniffer-tls13-dh.pcap
+#./configure --enable-sniffer --enable-session-ticket --disable-ecc && make
+
+# TLS v1.3
+./examples/server/server -v 4 -l TLS13-AES128-GCM-SHA256 &
+./examples/client/client -v 4 -l TLS13-AES128-GCM-SHA256
+./examples/server/server -v 4 -l TLS13-AES256-GCM-SHA384 &
+./examples/client/client -v 4 -l TLS13-AES256-GCM-SHA384
+./examples/server/server -v 4 -l TLS13-CHACHA20-POLY1305-SHA256 &
+./examples/client/client -v 4 -l TLS13-CHACHA20-POLY1305-SHA256
+
+# TLS v1.3 Resumption
+./examples/server/server -v 4 -l TLS13-AES128-GCM-SHA256 -r &
+./examples/client/client -v 4 -l TLS13-AES128-GCM-SHA256 -r
+./examples/server/server -v 4 -l TLS13-AES256-GCM-SHA384 -r &
+./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

+ 40 - 99
src/internal.c

@@ -1897,6 +1897,11 @@ void SSL_CtxResourceFree(WOLFSSL_CTX* ctx)
         ctx->alpn_cli_protos = NULL;
     }
 #endif
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+    if (ctx->staticKE.key) {
+        FreeDer(&ctx->staticKE.key);
+    }
+#endif
 #ifdef WOLFSSL_STATIC_MEMORY
     if (ctx->heap != NULL) {
 #ifdef WOLFSSL_HEAP_TEST
@@ -5680,6 +5685,10 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
     ssl->options.useClientOrder = ctx->useClientOrder;
     ssl->options.mutualAuth = ctx->mutualAuth;
 
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+    ssl->staticKE = ctx->staticKE;
+#endif
+
 #ifdef WOLFSSL_TLS13
     #ifdef HAVE_SESSION_TICKET
         ssl->options.noTicketTls13 = ctx->noTicketTls13;
@@ -6409,6 +6418,11 @@ void SSL_ResourceFree(WOLFSSL* ssl)
         XFREE(curr, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
     }
 #endif
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+    if (ssl->staticKE.key != NULL && ssl->staticKE.key != ssl->ctx->staticKE.key) {
+        FreeDer(&ssl->staticKE.key);
+    }
+#endif
 
 #ifdef WOLFSSL_STATIC_MEMORY
     /* check if using fixed io buffers and free them */
@@ -7674,49 +7688,46 @@ static int EdDSA_Update(WOLFSSL* ssl, const byte* data, int sz)
 }
 #endif /* (HAVE_ED25519 || HAVE_ED448) && !WOLFSSL_NO_CLIENT_AUTH */
 
-int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz)
+int HashRaw(WOLFSSL* ssl, const byte* data, int sz)
 {
     int ret = 0;
 
-    (void)output;
+    (void)data;
     (void)sz;
 
-    if (ssl->hsHashes == NULL)
+    if (ssl->hsHashes == NULL) {
         return BAD_FUNC_ARG;
+    }
 
-#ifdef HAVE_FUZZER
-    if (ssl->fuzzerCb)
-        ssl->fuzzerCb(ssl, output, sz, FUZZ_HASH, ssl->fuzzerCtx);
-#endif
 #ifndef NO_OLD_TLS
     #ifndef NO_SHA
-        wc_ShaUpdate(&ssl->hsHashes->hashSha, output, sz);
+        wc_ShaUpdate(&ssl->hsHashes->hashSha, data, sz);
     #endif
     #ifndef NO_MD5
-        wc_Md5Update(&ssl->hsHashes->hashMd5, output, sz);
+        wc_Md5Update(&ssl->hsHashes->hashMd5, data, sz);
     #endif
 #endif /* NO_OLD_TLS */
 
     if (IsAtLeastTLSv1_2(ssl)) {
     #ifndef NO_SHA256
-        ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, output, sz);
+        ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, data, sz);
         if (ret != 0)
             return ret;
     #endif
     #ifdef WOLFSSL_SHA384
-        ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, output, sz);
+        ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, data, sz);
         if (ret != 0)
             return ret;
     #endif
     #ifdef WOLFSSL_SHA512
-        ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, output, sz);
+        ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, data, sz);
         if (ret != 0)
             return ret;
     #endif
     #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \
                ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \
                 (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH)))
-        ret = EdDSA_Update(ssl, output, sz);
+        ret = EdDSA_Update(ssl, data, sz);
         if (ret != 0)
             return ret;
     #endif
@@ -7728,7 +7739,6 @@ int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz)
 /* add output to md5 and sha handshake hashes, exclude record header */
 int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz)
 {
-    int ret = 0;
     const byte* adj;
 
     if (ssl->hsHashes == NULL)
@@ -7747,55 +7757,23 @@ int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz)
         sz  -= DTLS_RECORD_EXTRA;
     }
 #endif
-#ifndef NO_OLD_TLS
-    #ifndef NO_SHA
-        wc_ShaUpdate(&ssl->hsHashes->hashSha, adj, sz);
-    #endif
-    #ifndef NO_MD5
-        wc_Md5Update(&ssl->hsHashes->hashMd5, adj, sz);
-    #endif
-#endif
-
-    if (IsAtLeastTLSv1_2(ssl)) {
-    #ifndef NO_SHA256
-        ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    #ifdef WOLFSSL_SHA384
-        ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    #ifdef WOLFSSL_SHA512
-        ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \
-               ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \
-                (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH)))
-        ret = EdDSA_Update(ssl, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    }
 
-    return ret;
+    return HashRaw(ssl, adj, sz);
 }
 
 
 /* add input to md5 and sha handshake hashes, include handshake header */
 int HashInput(WOLFSSL* ssl, const byte* input, int sz)
 {
-    int ret = 0;
     const byte* adj;
 
+    if (ssl->hsHashes == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
     adj = input - HANDSHAKE_HEADER_SZ;
     sz += HANDSHAKE_HEADER_SZ;
 
-    (void)adj;
-
 #ifdef WOLFSSL_DTLS
     if (ssl->options.dtls) {
         adj -= DTLS_HANDSHAKE_EXTRA;
@@ -7803,45 +7781,7 @@ int HashInput(WOLFSSL* ssl, const byte* input, int sz)
     }
 #endif
 
-    if (ssl->hsHashes == NULL) {
-        return BAD_FUNC_ARG;
-    }
-
-#ifndef NO_OLD_TLS
-    #ifndef NO_SHA
-        wc_ShaUpdate(&ssl->hsHashes->hashSha, adj, sz);
-    #endif
-    #ifndef NO_MD5
-        wc_Md5Update(&ssl->hsHashes->hashMd5, adj, sz);
-    #endif
-#endif
-
-    if (IsAtLeastTLSv1_2(ssl)) {
-    #ifndef NO_SHA256
-        ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    #ifdef WOLFSSL_SHA384
-        ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    #ifdef WOLFSSL_SHA512
-        ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \
-               ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \
-                (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH)))
-        ret = EdDSA_Update(ssl, adj, sz);
-        if (ret != 0)
-            return ret;
-    #endif
-    }
-
-    return ret;
+    return HashRaw(ssl, adj, sz);
 }
 
 
@@ -16940,15 +16880,15 @@ int SendCertificate(WOLFSSL* ssl)
             if (!ssl->options.dtls) {
                 AddFragHeaders(output, fragSz, 0, payloadSz, certificate, ssl);
                 if (!IsEncryptionOn(ssl, 1))
-                    HashOutputRaw(ssl, output + RECORD_HEADER_SZ,
+                    HashRaw(ssl, output + RECORD_HEADER_SZ,
                                   HANDSHAKE_HEADER_SZ);
             }
             else {
             #ifdef WOLFSSL_DTLS
                 AddHeaders(output, payloadSz, certificate, ssl);
-                HashOutputRaw(ssl,
-                              output + RECORD_HEADER_SZ + DTLS_RECORD_EXTRA,
-                              HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA);
+                HashRaw(ssl,
+                        output + RECORD_HEADER_SZ + DTLS_RECORD_EXTRA,
+                        HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA);
                 /* Adding the headers increments these, decrement them for
                  * actual message header. */
                 ssl->keys.dtls_handshake_number--;
@@ -16960,22 +16900,22 @@ int SendCertificate(WOLFSSL* ssl)
             /* list total */
             c32to24(listSz, output + i);
             if (ssl->options.dtls || !IsEncryptionOn(ssl, 1))
-                HashOutputRaw(ssl, output + i, CERT_HEADER_SZ);
+                HashRaw(ssl, output + i, CERT_HEADER_SZ);
             i += CERT_HEADER_SZ;
             length -= CERT_HEADER_SZ;
             fragSz -= CERT_HEADER_SZ;
             if (certSz) {
                 c32to24(certSz, output + i);
                 if (ssl->options.dtls || !IsEncryptionOn(ssl, 1))
-                    HashOutputRaw(ssl, output + i, CERT_HEADER_SZ);
+                    HashRaw(ssl, output + i, CERT_HEADER_SZ);
                 i += CERT_HEADER_SZ;
                 length -= CERT_HEADER_SZ;
                 fragSz -= CERT_HEADER_SZ;
 
                 if (ssl->options.dtls || !IsEncryptionOn(ssl, 1)) {
-                    HashOutputRaw(ssl, ssl->buffers.certificate->buffer, certSz);
+                    HashRaw(ssl, ssl->buffers.certificate->buffer, certSz);
                     if (certChainSz)
-                        HashOutputRaw(ssl, ssl->buffers.certChain->buffer,
+                        HashRaw(ssl, ssl->buffers.certChain->buffer,
                                       certChainSz);
                 }
             }
@@ -21029,7 +20969,7 @@ exit_dpk:
         return ret;
     }
 
-#endif /* HAVE_ECC */
+#endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */
 
 /* Persistable DoServerKeyExchange arguments */
 typedef struct DskeArgs {
@@ -28102,6 +28042,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
 #endif
     } InternalTicket;
 
+    /* RFC 5077 defines this for session tickets */
     /* fit within SESSION_TICKET_LEN */
     typedef struct ExternalTicket {
         byte key_name[WOLFSSL_TICKET_NAME_SZ];  /* key context name */

File diff suppressed because it is too large
+ 589 - 142
src/sniffer.c


+ 125 - 19
src/ssl.c

@@ -24959,9 +24959,9 @@ long wolfSSL_set_tlsext_debug_arg(WOLFSSL* ssl, void *arg)
 #endif /* HAVE_PK_CALLBACKS */
 
 #if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY)
-const unsigned char *SSL_SESSION_get0_id_context(const SSL_SESSION *sess, unsigned int *sid_ctx_length)
+const unsigned char *SSL_SESSION_get0_id_context(const WOLFSSL_SESSION *sess, unsigned int *sid_ctx_length)
 {
-    const byte *c = wolfSSL_SESSION_get_id((SSL_SESSION *)sess, sid_ctx_length);
+    const byte *c = wolfSSL_SESSION_get_id((WOLFSSL_SESSION *)sess, sid_ctx_length);
     return c;
 }
 #endif
@@ -28687,21 +28687,21 @@ int SetDhInternal(WOLFSSL_DH* dh)
     int            ret = WOLFSSL_FATAL_ERROR;
     int            pSz = 1024;
     int            gSz = 1024;
-#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
+#ifdef WOLFSSL_DH_EXTRA
     int            privSz = 256; /* Up to 2048-bit */
     int            pubSz  = 256;
 #endif
 #ifdef WOLFSSL_SMALL_STACK
     unsigned char* p   = NULL;
     unsigned char* g   = NULL;
-    #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
+    #ifdef WOLFSSL_DH_EXTRA
         unsigned char* priv_key = NULL;
         unsigned char* pub_key = NULL;
     #endif
 #else
     unsigned char  p[1024];
     unsigned char  g[1024];
-    #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
+    #ifdef WOLFSSL_DH_EXTRA
         unsigned char priv_key[256];
         unsigned char pub_key[256];
     #endif
@@ -28715,21 +28715,22 @@ int SetDhInternal(WOLFSSL_DH* dh)
         WOLFSSL_MSG("Bad p internal size");
     else if (wolfSSL_BN_bn2bin(dh->g, NULL) > gSz)
         WOLFSSL_MSG("Bad g internal size");
-    #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
+#ifdef WOLFSSL_DH_EXTRA
     else if (wolfSSL_BN_bn2bin(dh->priv_key, NULL) > privSz)
         WOLFSSL_MSG("Bad private key internal size");
     else if (wolfSSL_BN_bn2bin(dh->pub_key, NULL) > privSz)
         WOLFSSL_MSG("Bad public key internal size");
-    #endif
+#endif
     else {
     #ifdef WOLFSSL_SMALL_STACK
         p = (unsigned char*)XMALLOC(pSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
         g = (unsigned char*)XMALLOC(gSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
-
-    #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
-        priv_key = (unsigned char*)XMALLOC(privSz,NULL,DYNAMIC_TYPE_PRIVATE_KEY);
-        pub_key  = (unsigned char*)XMALLOC(pubSz,NULL,DYNAMIC_TYPE_PUBLIC_KEY);
-    #endif
+        #ifdef WOLFSSL_DH_EXTRA
+            priv_key = (unsigned char*)XMALLOC(privSz, NULL, 
+                DYNAMIC_TYPE_PRIVATE_KEY);
+            pub_key  = (unsigned char*)XMALLOC(pubSz, NULL, 
+                DYNAMIC_TYPE_PUBLIC_KEY);
+        #endif
 
         if (p == NULL || g == NULL) {
             XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
@@ -28738,7 +28739,7 @@ int SetDhInternal(WOLFSSL_DH* dh)
         }
     #endif /* WOLFSSL_SMALL_STACK */
 
-    #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
+    #ifdef WOLFSSL_DH_EXTRA
         privSz = wolfSSL_BN_bn2bin(dh->priv_key, priv_key);
         pubSz  = wolfSSL_BN_bn2bin(dh->pub_key,  pub_key);
         if (privSz <= 0) {
@@ -28748,13 +28749,17 @@ int SetDhInternal(WOLFSSL_DH* dh)
             WOLFSSL_MSG("No public key size.");
         }
         if (privSz > 0 || pubSz > 0) {
-            ret = wc_DhSetFullKeys((DhKey*)dh->internal,priv_key,privSz,
-                                    pub_key,pubSz);
-            if (ret == WOLFSSL_FAILURE) {
+            ret = wc_DhImportKeyPair((DhKey*)dh->internal, priv_key, privSz,
+                                     pub_key, pubSz);
+            if (ret == 0) {
+                ret = WOLFSSL_SUCCESS;
+            }
+            else {
                 WOLFSSL_MSG("Failed setting private or public key.");
+                ret = WOLFSSL_FAILURE;
             }
         }
-    #endif /* WOLFSSL_QT || OPENSSL_ALL */
+    #endif /* WOLFSSL_DH_EXTRA */
 
         pSz = wolfSSL_BN_bn2bin(dh->p, p);
         gSz = wolfSSL_BN_bn2bin(dh->g, g);
@@ -28771,14 +28776,13 @@ int SetDhInternal(WOLFSSL_DH* dh)
     #ifdef WOLFSSL_SMALL_STACK
         XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
         XFREE(g, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
-        #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
+        #ifdef WOLFSSL_DH_EXTRA
             XFREE(priv_key, NULL, DYNAMIC_TYPE_PRIVATE_KEY);
             XFREE(pub_key,  NULL, DYNAMIC_TYPE_PUBLIC_KEY);
         #endif
     #endif
     }
 
-
     return ret;
 }
 
@@ -47749,4 +47753,106 @@ int wolfSSL_X509_REQ_set_pubkey(WOLFSSL_X509 *req, WOLFSSL_EVP_PKEY *pkey)
 }
 #endif /* OPENSSL_EXTRA && !NO_CERTS && WOLFSSL_CERT_GEN && WOLFSSL_CERT_REQ */
 
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+static int SetStaticEphemeralKey(StaticKeyExchangeInfo_t* staticKE, int keyAlgo, 
+    const char* key, unsigned int keySz, int format, void* heap)
+{
+    int ret = 0;
+    byte* keyBuf = NULL;
+#ifndef NO_FILESYSTEM
+    const char* keyFile = NULL;
+#endif
+
+    /* allow empty key to free buffer */
+    if (staticKE == NULL || (key == NULL && keySz > 0)) {
+        return BAD_FUNC_ARG;
+    }
+
+    /* check if just free'ing key */
+    if (key == NULL && keySz == 0) {
+        return 0;
+    }
+
+#ifndef NO_FILESYSTEM
+    /* load file from filesystem */
+    if (key && keySz == 0) {
+        size_t keyBufSz = 0;
+        keyFile = (const char*)key;
+        ret = wc_FileLoad(keyFile, &keyBuf, &keyBufSz, heap);
+        if (ret != 0) {
+            return ret;
+        }
+        keySz = (unsigned int)keyBufSz;
+    }
+    else
+#endif
+    {
+        /* use as key buffer directly */
+        keyBuf = (byte*)key;
+    }
+
+    if (format == WOLFSSL_FILETYPE_PEM) {
+    #ifdef WOLFSSL_PEM_TO_DER
+        int keyFormat = 0;
+        ret = PemToDer(keyBuf, keySz, PRIVATEKEY_TYPE, &staticKE->key, 
+            heap, NULL, &keyFormat);
+        /* auto detect key type */
+        if (ret == 0 && keyAlgo == 0) {
+            if (keyFormat == ECDSAk)
+                keyAlgo = WC_PK_TYPE_ECDH;
+            else
+                keyAlgo = WC_PK_TYPE_DH;
+        }
+    #else
+        ret = NOT_COMPILED_IN;
+    #endif
+    }
+    else {
+        ret = AllocDer(&staticKE->key, keySz, PRIVATEKEY_TYPE, heap);
+        if (ret == 0) {
+            XMEMCPY(staticKE->key->buffer, keyBuf, keySz);
+        }
+    }
+    staticKE->keyAlgo = keyAlgo;
+
+#ifndef NO_FILESYSTEM
+    if (keyFile && keyBuf) {
+        XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
+    }
+#endif
+    return ret;
+}
+
+int wolfSSL_CTX_set_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, 
+    const char* key, unsigned int keySz, int format)
+{
+    if (ctx == NULL) {
+        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);
+}
+
+int wolfSSL_set_ephemeral_key(WOLFSSL* ssl, int keyAlgo, 
+    const char* key, unsigned int keySz, int format)
+{
+    if (ssl == NULL) {
+        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);
+}
 
+#endif /* WOLFSSL_STATIC_EPHEMERAL */

+ 49 - 16
src/tls.c

@@ -6621,14 +6621,14 @@ static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse)
         return ret;
     }
 
-    /* Allocate space for the public key. */
+    /* Allocate space for the public key */
     dataSz = params->p_len;
     keyData = (byte*)XMALLOC(dataSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
     if (keyData == NULL) {
         ret = MEMORY_E;
         goto end;
     }
-    /* Allocate space for the private key. */
+    /* Allocate space for the private key */
     key = (byte*)XMALLOC(keySz, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
     if (key == NULL) {
         ret = MEMORY_E;
@@ -6642,20 +6642,34 @@ static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse)
     if (ret != 0)
         goto end;
 
-    /* Generate a new key pair. */
-    ret = wc_DhGenerateKeyPair(dhKey, ssl->rng, (byte*)key, &keySz, keyData,
-                               &dataSz);
-#ifdef WOLFSSL_ASYNC_CRYPT
-    /* TODO: Make this function non-blocking */
-    if (ret == WC_PENDING_E) {
-        ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE);
+#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;
+        word32 idx = 0;
+        WOLFSSL_MSG("Using static DH key");
+        ret = wc_DhKeyDecode(keyDer->buffer, &idx, dhKey, keyDer->length);
+        if (ret == 0) {
+            ret = wc_DhExportKeyPair(dhKey, (byte*)key, &keySz, keyData, &dataSz);
+        }
     }
+    else
 #endif
+    {
+        /* Generate a new key pair */
+        ret = wc_DhGenerateKeyPair(dhKey, ssl->rng, (byte*)key, &keySz, keyData,
+                                &dataSz);
+    #ifdef WOLFSSL_ASYNC_CRYPT
+        /* TODO: Make this function non-blocking */
+        if (ret == WC_PENDING_E) {
+            ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE);
+        }
+    #endif
+    }
     if (ret != 0)
         goto end;
 
     if (params->p_len != dataSz) {
-        /* Pad the front of the key data with zeros. */
+        /* Zero pad the front of the public key to match prime "p" size */
         XMEMMOVE(keyData + params->p_len - dataSz, keyData, dataSz);
         XMEMSET(keyData, 0, params->p_len - dataSz);
     }
@@ -6913,13 +6927,26 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse)
     ret = wc_ecc_init_ex(eccKey, ssl->heap, ssl->devId);
     if (ret != 0)
         goto end;
-    ret = wc_ecc_make_key_ex(ssl->rng, keySize, eccKey, curveId);
-#ifdef WOLFSSL_ASYNC_CRYPT
-    /* TODO: Make this function non-blocking */
-    if (ret == WC_PENDING_E) {
-        ret = wc_AsyncWait(ret, &eccKey->asyncDev, WC_ASYNC_FLAG_NONE);
+
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+    if (ssl->staticKE.key && ssl->staticKE.keyAlgo == WC_PK_TYPE_ECDH) {
+        DerBuffer* keyDer = ssl->staticKE.key;
+        word32 idx = 0;
+        WOLFSSL_MSG("Using static ECDH key");
+        ret = wc_EccPrivateKeyDecode(keyDer->buffer, &idx, eccKey, keyDer->length);
     }
+    else
 #endif
+    {
+        /* Generate ephemeral ECC key */
+        ret = wc_ecc_make_key_ex(ssl->rng, keySize, eccKey, curveId);
+    #ifdef WOLFSSL_ASYNC_CRYPT
+        /* TODO: Make this function non-blocking */
+        if (ret == WC_PENDING_E) {
+            ret = wc_AsyncWait(ret, &eccKey->asyncDev, WC_ASYNC_FLAG_NONE);
+        }
+    #endif
+    }
     if (ret != 0)
         goto end;
 
@@ -9120,6 +9147,7 @@ void TLSX_FreeAll(TLSX* list, void* heap)
                 MFL_FREE_ALL(extension->data, heap);
                 break;
 
+            case TLSX_EXTENDED_MASTER_SECRET:
             case TLSX_TRUNCATED_HMAC:
                 /* Nothing to do. */
                 break;
@@ -9235,7 +9263,6 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
         /* extension type + extension data length. */
         length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
 
-
         switch (extension->type) {
 
             case TLSX_SERVER_NAME:
@@ -9254,6 +9281,7 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
                 length += MFL_GET_SIZE(extension->data);
                 break;
 
+            case TLSX_EXTENDED_MASTER_SECRET:
             case TLSX_TRUNCATED_HMAC:
                 /* always empty. */
                 break;
@@ -9404,6 +9432,11 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
                 offset += MFL_WRITE((byte*)extension->data, output + offset);
                 break;
 
+            case TLSX_EXTENDED_MASTER_SECRET:
+                WOLFSSL_MSG("Extended Master Secret");
+                /* always empty. */
+                break;
+
             case TLSX_TRUNCATED_HMAC:
                 WOLFSSL_MSG("Truncated HMAC extension to write");
                 /* always empty. */

+ 76 - 68
src/tls13.c

@@ -444,6 +444,9 @@ static const byte binderKeyLabel[BINDER_KEY_LABEL_SZ + 1] =
 static int DeriveBinderKey(WOLFSSL* ssl, byte* key)
 {
     WOLFSSL_MSG("Derive Binder Key");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     return DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret,
                         binderKeyLabel, BINDER_KEY_LABEL_SZ,
                         NULL, 0, ssl->specs.mac_algorithm);
@@ -467,6 +470,9 @@ static const byte binderKeyResumeLabel[BINDER_KEY_RESUME_LABEL_SZ + 1] =
 static int DeriveBinderKeyResume(WOLFSSL* ssl, byte* key)
 {
     WOLFSSL_MSG("Derive Binder Key - Resumption");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     return DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret,
                         binderKeyResumeLabel, BINDER_KEY_RESUME_LABEL_SZ,
                         NULL, 0, ssl->specs.mac_algorithm);
@@ -491,6 +497,9 @@ static int DeriveEarlyTrafficSecret(WOLFSSL* ssl, byte* key)
 {
     int ret;
     WOLFSSL_MSG("Derive Early Traffic Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKey(ssl, key, -1, ssl->arrays->secret,
                     earlyTrafficLabel, EARLY_TRAFFIC_LABEL_SZ,
                     ssl->specs.mac_algorithm, 1);
@@ -523,6 +532,9 @@ static int DeriveEarlyExporterSecret(WOLFSSL* ssl, byte* key)
 {
     int ret;
     WOLFSSL_MSG("Derive Early Exporter Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKey(ssl, key, -1, ssl->arrays->secret,
                     earlyExporterLabel, EARLY_EXPORTER_LABEL_SZ,
                     ssl->specs.mac_algorithm, 1);
@@ -556,6 +568,9 @@ static int DeriveClientHandshakeSecret(WOLFSSL* ssl, byte* key)
 {
     int ret;
     WOLFSSL_MSG("Derive Client Handshake Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret,
                     clientHandshakeLabel, CLIENT_HANDSHAKE_LABEL_SZ,
                     ssl->specs.mac_algorithm, 1);
@@ -587,6 +602,9 @@ static int DeriveServerHandshakeSecret(WOLFSSL* ssl, byte* key)
 {
     int ret;
     WOLFSSL_MSG("Derive Server Handshake Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret,
                     serverHandshakeLabel, SERVER_HANDSHAKE_LABEL_SZ,
                     ssl->specs.mac_algorithm, 1);
@@ -618,6 +636,9 @@ static int DeriveClientTrafficSecret(WOLFSSL* ssl, byte* key)
 {
     int ret;
     WOLFSSL_MSG("Derive Client Traffic Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret,
                     clientAppLabel, CLIENT_APP_LABEL_SZ,
                     ssl->specs.mac_algorithm, 1);
@@ -649,6 +670,9 @@ static int DeriveServerTrafficSecret(WOLFSSL* ssl, byte* key)
 {
     int ret;
     WOLFSSL_MSG("Derive Server Traffic Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret,
                     serverAppLabel, SERVER_APP_LABEL_SZ,
                     ssl->specs.mac_algorithm, 1);
@@ -681,6 +705,9 @@ static int DeriveExporterSecret(WOLFSSL* ssl, byte* key)
 {
     int ret;
     WOLFSSL_MSG("Derive Exporter Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret,
                     exporterMasterLabel, EXPORTER_MASTER_LABEL_SZ,
                     ssl->specs.mac_algorithm, 1);
@@ -710,9 +737,12 @@ static const byte resumeMasterLabel[RESUME_MASTER_LABEL_SZ + 1] =
  * key  The derived key.
  * returns 0 on success, otherwise failure.
  */
-static int DeriveResumptionSecret(WOLFSSL* ssl, byte* key)
+int DeriveResumptionSecret(WOLFSSL* ssl, byte* key)
 {
     WOLFSSL_MSG("Derive Resumption Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     return DeriveKey(ssl, key, -1, ssl->arrays->masterSecret,
                      resumeMasterLabel, RESUME_MASTER_LABEL_SZ,
                      ssl->specs.mac_algorithm, 1);
@@ -761,9 +791,12 @@ static int DeriveTrafficSecret(WOLFSSL* ssl, byte* secret)
  *
  * ssl  The SSL/TLS object.
  */
-static int DeriveEarlySecret(WOLFSSL* ssl)
+int DeriveEarlySecret(WOLFSSL* ssl)
 {
     WOLFSSL_MSG("Derive Early Secret");
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
     return Tls13_HKDF_Extract(ssl->arrays->secret, NULL, 0,
             ssl->arrays->psk_key, ssl->arrays->psk_keySz,
@@ -784,13 +817,14 @@ static const byte derivedLabel[DERIVED_LABEL_SZ + 1] =
  *
  * ssl  The SSL/TLS object.
  */
-static int DeriveHandshakeSecret(WOLFSSL* ssl)
+int DeriveHandshakeSecret(WOLFSSL* ssl)
 {
     byte key[WC_MAX_DIGEST_SIZE];
     int ret;
-
     WOLFSSL_MSG("Derive Handshake Secret");
-
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret,
                         derivedLabel, DERIVED_LABEL_SZ,
                         NULL, 0, ssl->specs.mac_algorithm);
@@ -807,13 +841,14 @@ static int DeriveHandshakeSecret(WOLFSSL* ssl)
  *
  * ssl  The SSL/TLS object.
  */
-static int DeriveMasterSecret(WOLFSSL* ssl)
+int DeriveMasterSecret(WOLFSSL* ssl)
 {
     byte key[WC_MAX_DIGEST_SIZE];
     int ret;
-
     WOLFSSL_MSG("Derive Master Secret");
-
+    if (ssl == NULL || ssl->arrays == NULL) {
+        return BAD_FUNC_ARG;
+    }
     ret = DeriveKeyMsg(ssl, key, -1, ssl->arrays->preMasterSecret,
                         derivedLabel, DERIVED_LABEL_SZ,
                         NULL, 0, ssl->specs.mac_algorithm);
@@ -838,8 +873,7 @@ static const byte resumptionLabel[RESUMPTION_LABEL_SZ+1] = "resumption";
  * secret    The derived secret.
  * returns 0 on success, otherwise failure.
  */
-static int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen,
-                               byte* secret)
+int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen, byte* secret)
 {
     int         digestAlg;
     /* Only one protocol version defined at this time. */
@@ -894,6 +928,10 @@ static int BuildTls13HandshakeHmac(WOLFSSL* ssl, byte* key, byte* hash,
     int  hashSz = WC_SHA256_DIGEST_SIZE;
     int  ret = BAD_FUNC_ARG;
 
+    if (ssl == NULL || key == NULL || hash == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
     /* Get the hash of the previous handshake messages. */
     switch (ssl->specs.mac_algorithm) {
     #ifndef NO_SHA256
@@ -965,7 +1003,7 @@ static const byte writeIVLabel[WRITE_IV_LABEL_SZ+1]   = "iv";
  *          store ready for provisioning.
  * returns 0 on success, otherwise failure.
  */
-static int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store)
+int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store)
 {
     int   ret = BAD_FUNC_ARG; /* Assume failure */
     int   i = 0;
@@ -1321,39 +1359,6 @@ end:
 #endif /* HAVE_SESSION_TICKET || !NO_PSK */
 
 
-#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_SESSION_TICKET) || \
-                                    !defined(NO_PSK))
-/* Add input to all handshake hashes.
- *
- * ssl    The SSL/TLS object.
- * input  The data to hash.
- * sz     The size of the data to hash.
- * returns 0 on success, otherwise failure.
- */
-static int HashInputRaw(WOLFSSL* ssl, const byte* input, int sz)
-{
-    int ret = BAD_FUNC_ARG;
-
-#ifndef NO_SHA256
-    ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, input, sz);
-    if (ret != 0)
-        return ret;
-#endif
-#ifdef WOLFSSL_SHA384
-    ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, input, sz);
-    if (ret != 0)
-        return ret;
-#endif
-#ifdef WOLFSSL_TLS13_SHA512
-    ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, input, sz);
-    if (ret != 0)
-        return ret;
-#endif
-
-    return ret;
-}
-#endif
-
 /* Extract the handshake header information.
  *
  * ssl       The SSL/TLS object.
@@ -2402,10 +2407,10 @@ static int RestartHandshakeHash(WOLFSSL* ssl)
     ret = InitHandshakeHashes(ssl);
     if (ret != 0)
         return ret;
-    ret = HashOutputRaw(ssl, header, sizeof(header));
+    ret = HashRaw(ssl, header, sizeof(header));
     if (ret != 0)
         return ret;
-    return HashOutputRaw(ssl, hash, hashSz);
+    return HashRaw(ssl, hash, hashSz);
 }
 
 /* The value in the random field of a ServerHello to indicate
@@ -2578,7 +2583,7 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx)
         return ret;
 
     /* Hash binders to complete the hash of the ClientHello. */
-    ret = HashOutputRaw(ssl, output + idx, len);
+    ret = HashRaw(ssl, output + idx, len);
     if (ret < 0)
         return ret;
 
@@ -3456,7 +3461,7 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
     }
 
     /* Hash the rest of the ClientHello. */
-    ret = HashInputRaw(ssl, input + helloSz - bindersLen, bindersLen);
+    ret = HashRaw(ssl, input + helloSz - bindersLen, bindersLen);
     if (ret != 0)
         return ret;
 
@@ -3624,9 +3629,9 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
     AddTls13HandShakeHeader(header, hashSz, 0, 0, message_hash, ssl);
     if ((ret = InitHandshakeHashes(ssl)) != 0)
         return ret;
-    if ((ret = HashOutputRaw(ssl, header, sizeof(header))) != 0)
+    if ((ret = HashRaw(ssl, header, sizeof(header))) != 0)
         return ret;
-    if ((ret = HashOutputRaw(ssl, cookieData + idx, hashSz)) != 0)
+    if ((ret = HashRaw(ssl, cookieData + idx, hashSz)) != 0)
         return ret;
 
     /* Reconstruct the HelloRetryMessage for handshake hash. */
@@ -3705,9 +3710,9 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
     WOLFSSL_BUFFER(cookieData, cookie->len);
 #endif
 
-    if ((ret = HashOutputRaw(ssl, hrr, hrrIdx)) != 0)
+    if ((ret = HashRaw(ssl, hrr, hrrIdx)) != 0)
         return ret;
-    return HashOutputRaw(ssl, cookieData, cookie->len);
+    return HashRaw(ssl, cookieData, cookie->len);
 }
 #endif
 
@@ -5849,7 +5854,7 @@ exit_dcv:
  * sniff     Indicates whether we are sniffing packets.
  * returns 0 on success and otherwise failure.
  */
-static int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
+int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
                            word32 size, word32 totalSz, int sniff)
 {
     int    ret;
@@ -5888,19 +5893,22 @@ static int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
 
         secret = ssl->keys.server_write_MAC_secret;
     }
-    else
+    else {
         secret = ssl->keys.client_write_MAC_secret;
+    }
 
-    ret = BuildTls13HandshakeHmac(ssl, secret, mac, &finishedSz);
-    if (ret != 0)
-        return ret;
-    if (size != finishedSz)
-        return BUFFER_ERROR;
+    if (sniff == NO_SNIFF) {
+        ret = BuildTls13HandshakeHmac(ssl, secret, mac, &finishedSz);
+        if (ret != 0)
+            return ret;
+        if (size != finishedSz)
+            return BUFFER_ERROR;
+    }
 
-    #ifdef WOLFSSL_CALLBACKS
-        if (ssl->hsInfoOn) AddPacketName(ssl, "Finished");
-        if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo);
-    #endif
+#ifdef WOLFSSL_CALLBACKS
+    if (ssl->hsInfoOn) AddPacketName(ssl, "Finished");
+    if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo);
+#endif
 
     if (sniff == NO_SNIFF) {
         /* Actually check verify data. */
@@ -6349,8 +6357,8 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input,
     word32 ageAdd;
     word16 length;
     word32 now;
-    const byte*  nonce;
-    byte         nonceLength;
+    const byte* nonce;
+    byte        nonceLength;
 
     WOLFSSL_START(WC_FUNC_NEW_SESSION_TICKET_DO);
     WOLFSSL_ENTER("DoTls13NewSessionTicket");
@@ -6506,14 +6514,14 @@ static int ExpectedResumptionSecret(WOLFSSL* ssl)
 #ifdef WOLFSSL_EARLY_DATA
     if (ssl->earlyData != no_early_data) {
         static byte endOfEarlyData[] = { 0x05, 0x00, 0x00, 0x00 };
-        ret = HashInputRaw(ssl, endOfEarlyData, sizeof(endOfEarlyData));
+        ret = HashRaw(ssl, endOfEarlyData, sizeof(endOfEarlyData));
         if (ret != 0)
             return ret;
     }
 #endif
-    if ((ret = HashInputRaw(ssl, header, sizeof(header))) != 0)
+    if ((ret = HashRaw(ssl, header, sizeof(header))) != 0)
         return ret;
-    if ((ret = HashInputRaw(ssl, mac, finishedSz)) != 0)
+    if ((ret = HashRaw(ssl, mac, finishedSz)) != 0)
         return ret;
 
     if ((ret = DeriveResumptionSecret(ssl, ssl->session.masterSecret)) != 0)

+ 640 - 0
sslSniffer/README.md

@@ -0,0 +1,640 @@
+# wolfSSL Sniffer
+
+The wolfSSL sniffer can be used to passively sniff SSL traffic including https traffic. Of course the server’s private key is required in order to decode the SSL handshake and allow future decryption of SSL messages. Input to the sniffer should be raw packets beginning with the IP header.
+
+## Installation
+
+The wolfSSL sniffer requires the wolfSSL library version 1.8.0 or later. Future releases can be obtained from http://www.wolfssl.com
+
+To build and install wolfSSL including the wolfSSL sniffer:
+
+```sh
+./configure --enable-sniffer
+make
+sudo make install
+```
+
+
+## Build Options
+
+The wolfSSL sniffer has several build options to include some extra behavior: SSL Statistics, Session Watching, Store Data Callback, Chain Input, and allowing STARTTLS protocols.
+
+The SSL Statistics option provides the logging of some additional statistics regarding the sessions being decoded. The statistics tracking uses a mutex to protect access to the tracking storage. To enable this option, use the following configure command line and build as before:
+
+`./configure --enable-sniffer CPPFLAGS=-DWOLFSSL_SNIFFER_STATS`
+
+The Session Watching option allows the sniffer to watch any packet provided it without initial setup. It will start to decode all TLS sessions and when the server’s certificate is detected, the certificate is given to a callback function provided by the user which should provide the appropriate private key. To enable this option, use the following configure command line and build as before:
+
+`./configure --enable-sniffer CPPFLAGS=-DWOLFSSL_SNIFFER_WATCH`
+
+The Store Data Callback option allows the sniffer to take a callback that is called when storing the application data into a custom buffer rather than into the reallocated data pointer the callback is called in a loop until all data is consumed. To enable this option, use the following configure command line and build as before:
+
+`./configure --enable-sniffer CPPFLAGS=-DWOLFSSL_SNIFFER_STORE_DATA_CB`
+
+The Chain Input option allows the sniffer to receive its input as a struct iovec list rather than a pointer to a raw packet. To enable this option, use the following configure command line and build as before:
+
+`./configure --enable-sniffer CPPFLAGS=-DWOLFSSL_SNIFFER_CHAIN_INPUT`
+
+The STARTTLS option allows the sniffer to receive and ignore plaintext before receiving the first TLS handshake message. This is useful for protocols like SMTP and POP3 which start out in plaintext and switch to TLS during the connection. To enable this option, use the following configure command line and build as before:
+
+`./configure --enable-sniffer CPPFLAGS=-DSTARTTLS_ALLOWED`
+
+All options may be enabled with the following configure command line:
+
+```sh
+./configure --enable-sniffer \
+    CPPFLAGS=”-DWOLFSSL_SNIFFER_STATS -DWOLFSSL_SNIFFER_WATCH \
+    -DWOLFSSL_SNIFFER_STORE_DATA_CB -DWOLFSSL_SNIFFER_CHAIN_INPUT \
+    -DSTARTTLS_ALLOWED”
+```
+
+To add some other cipher support to the sniffer, you can add options like:
+
+```sh
+--enable-arc4
+--enable-nullcipher
+--enable-des3
+```
+
+By default, wolfSSL restricts RSA key sizes to 1024-bits minimum. To allow the decoding of smaller, less secure RSA keys like 512-bit keys, you will need to add the compiler flag `-DWOLFSSL_MIN_RSA_BITS=512` to CFLAGS or CPPFLAGS, or define it in your user-settings header.
+
+
+## Synchronous Cryptography Offload Options
+
+The sniffer can take advantage of some crypto offload hardware if available. If you have an Intel QuickAssist board or a Cavium OCTEON II or III. Currently, only the algorithms AES-CBC, AES-GCM, and DES3-CBC are offloaded to the hardware. These directions assume you already have the QAT or OCTEON-SDK libraries built.
+
+To build for QAT, use the following configure options:
+
+```sh
+./configure --enable-sniffer --enable-cryptocb \
+    --with-intelqa-sync=/path/to/qat
+```
+
+To build with OCTEON II support for a standalone host:
+
+```sh
+./configure --enable-sniffer --enable-cryptocb \
+    --with-octeon-sync=/path/to/octeon-sdk
+```
+
+To build with OCTEON III support for a Linux host:
+
+```sh
+./configure --enable-sniffer --enable-cryptocb \
+    --with-octeon-sync=/path/to/octeon-sdk \
+    OCTEON_OBJ=obj-octeon3 OCTEON_HOST=linux
+```
+
+
+## Command Line Options
+
+The wolfSSL sniffer includes a test application `snifftest` in the `sslSniffer/sslSnifferTest/ directory`. The command line application has several options that can be passed in at runtime to change the default behavior of the application. To execute a “live” sniff just run the application without any parameters and then pick an interface to sniff on followed by the port.
+
+An example startup may look like this:
+
+```sh
+$ cd sslSniffer/sslSnifferTest
+$ ./snifftest
+
+1. en0 (No description available)
+2. fw0 (No description available)
+3. en1 (No description available)
+4. fw1 (No description available)
+5. p2p0 (No description available)
+6. en3 (No description available)
+7. lo0 (No description available)
+
+Enter the interface number (1-7): 7
+server = 127.0.0.1
+server = ::1
+server = fe80::1
+
+Enter the port to scan: 11111
+```
+
+The above example sniffs on the localhost interface (lo0) with the default wolfSSL port of 11111 and uses the default wolfSSL server key `../../certs/server-key.pem` for RSA and `../../certs/ecc-key.pem` for ECC.
+
+Trace output will be written to a file named `tracefile.txt`.
+
+To decode a previously saved pcap file you will need to enter a few parameters.
+
+The following table lists the accepted inputs in saved file mode.
+
+Synopsis:
+
+`snifftest  dumpFile pemKey [server] [port] [password]`
+
+`snifftest` Options Summary:
+
+```
+Option      Description                                 Default Value
+dumpFile    A previously saved pcap file                NA
+pemKey      The server’s private key in PEM format      NA
+server      The server’s IP address (v4 or v6)          127.0.0.1
+port        The server port to sniff                    443
+password    Private Key Password if required            NA
+```
+
+To decode a pcap file named test.pcap with a server key file called myKey.pem that was generated on the localhost with a server at port 443 just use:
+
+`./snifftest test.pcap myKey.pem`
+
+If the server was on 10.0.1.2 and on port 12345 you could instead use:
+
+`./snifftest test.pcap myKey.pem 10.0.1.2 12345`
+
+If the server was on localhost using IPv6 and on port 12345 you could instead use:
+
+`./snifftest test.pcap myKey.pem ::1 12345`
+
+
+## API Usage
+
+The wolfSSL sniffer can be integrated into any application using the existing sniffer API.
+
+Use the include `#include <wolfssl/sniffer.h>`.
+
+### ssl_InitSniffer
+
+```c
+void ssl_InitSniffer(void);
+```
+
+Initializes the wolfSSL sniffer for use and should be called once per application.  
+
+### ssl_FreeSniffer
+
+```c
+void ssl_FreeSniffer(void);
+```
+
+Frees all resources consumed by the wolfSSL sniffer and should be called when use of the wolfSSL sniffer is no longer required.
+
+### ssl_Trace
+
+```c
+int ssl_Trace(const char* traceFile, char* error);
+```
+
+Enables Tracing when a file is passed in.  Disables Tracing if previously on and a NULL value is passed in for the file.
+
+Returns Values:
+
+* 0 on success
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+### ssl_SetPrivateKey
+
+```c
+int ssl_SetPrivateKey(const char* serverAddress, int port,
+                      const char* keyFile, int keyFormat,
+                      const char* password, char* error);
+```
+
+Creates a sniffer session based on the `serverAddress` and `port` inputs using the ECC or RSA `keyFile` as the server’s key.
+
+The `keyFormat` can be either `FILETYPE_PEM` or `FILETYPE_DER`. If the keyFile has password protection then the password parameter can hold the proper value.
+
+Return Values:
+
+* 0 on success
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+### ssl_SetPrivateKeyBuffer
+
+```c
+int ssl_SetPrivateKeyBuffer(const char* address, int port,
+                            const char* keyBuf, int keySz, int typeKey,
+                            const char* password, char* error)
+```
+
+Creates a sniffer session based on the `serverAddress` and `port` inputs using the ECC or RSA `keyBuf` and `keySz` as the server’s key.
+
+The `keyFormat` can be either `FILETYPE_PEM` or `FILETYPE_DER`. If the keyFile has password protection then the password parameter can hold the proper value.
+
+Return Values:
+
+* 0 on success
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+
+### ssl_SetNamedPrivateKey
+
+```c
+int ssl_SetNamedPrivateKey(const char* name,
+                           const char* serverAddress, int port,
+                           const char* keyFile, int keyFormat,
+                           const char* password, char* error);
+```
+
+Creates a sniffer session for a server named `name` based on the `serverAddress` and `port` inputs using the ECC or RSA `keyFile` as the server’s key.
+
+The `keyFormat` can be either `FILETYPE_PEM` or `FILETYPE_DER`. If the keyFile has password protection then the password parameter can hold the proper value.
+
+This function requires that the SNI extension is enabled in the build (`HAVE_SNI`).
+
+Return Values:
+
+* 0 on success
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+### ssl_SetNamedPrivateKeyBuffer
+
+```c
+int ssl_SetNamedPrivateKeyBuffer(const char* name,
+                                 const char* address, int port,
+                                 const char* keyBuf, int keySz, int typeKey,
+                                 const char* password, char* error)
+```
+
+Creates a sniffer session for a server named `name` based on the `serverAddress` and `port` inputs using the ECC or RSA `keyBuf` and `keySz` as the server’s key.
+
+The `keyFormat` can be either `FILETYPE_PEM` or `FILETYPE_DER`. If the keyFile has password protection then the password parameter can hold the proper value.
+
+This function requires that the SNI extension is enabled in the build (`HAVE_SNI`).
+
+Return Values:
+
+* 0 on success
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+### ssl_SetNamedEphemeralKey
+
+```c
+int ssl_SetNamedEphemeralKey(const char* name,
+                             const char* address, int port,
+                             const char* keyFile, int typeKey,
+                             const char* password, char* error)
+```
+
+Creates a sniffer session for a server named `name` based on the `serverAddress` and `port` inputs using ECC or DH static ephemeral key.
+
+The `keyFormat` can be either `FILETYPE_PEM` or `FILETYPE_DER`. If the keyFile has password protection then the password parameter can hold the proper value.
+
+This function requires that static ephemeral key support (`WOLFSSL_STATIC_EPHEMERAL`) and the SNI extension (`HAVE_SNI`) are enabled in the build.
+
+Return Values:
+
+* 0 on success
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+### ssl_SetEphemeralKey
+
+```c
+int ssl_SetEphemeralKey(const char* address, int port, 
+                        const char* keyFile, int typeKey, 
+                        const char* password, char* error)
+```
+Creates a sniffer session based on the `serverAddress` and `port` inputs using ECC or DH static ephemeral key.
+
+The `keyFormat` can be either `FILETYPE_PEM` or `FILETYPE_DER`. If the keyFile has password protection then the password parameter can hold the proper value.
+
+This function requires that static ephemeral key support (`WOLFSSL_STATIC_EPHEMERAL`) and the SNI extension (`HAVE_SNI`) are enabled in the build.
+
+Return Values:
+
+* 0 on success
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+### ssl_DecodePacket
+
+```c
+int ssl_DecodePacket(const unsigned char** packet, int length,
+    unsigned char* data, char* error);
+```
+
+### ssl_DecodePacketWithSessionInfo
+
+```c
+int ssl_DecodePacketWithSessionInfo(const unsigned char* packet, int length,
+    unsigned char** data, SSLInfo* sslInfo, char* error);
+```
+
+Decodes a raw packet that begins with the IP header and is length bytes long. Any SSL application data will be stored in data which should be at least 16,384 bytes, the maximum SSL record size. Information about the SSL session will be copied into `sslInfo` if it is non-null.
+
+The `SSLInfo` structure can be found in `sniffer.h`. It has information about the protocol version, cipher suite, server name indication, and key size in bits.
+
+```c
+typedef struct SSLInfo
+{
+    unsigned char  isValid;                    /* indicates if the info in this struct is valid: 0 = no, 1 = yes */
+    unsigned char  protocolVersionMajor;       /* SSL Version: major */
+    unsigned char  protocolVersionMinor;       /* SSL Version: minor */
+    unsigned char  serverCipherSuite0;         /* first byte, normally 0 */
+    unsigned char  serverCipherSuite;          /* second byte, actual suite */
+    unsigned char  serverCipherSuiteName[256]; /* cipher name, e.g., "TLS_RSA_..." */
+    unsigned char  serverNameIndication[128];
+    unsigned int   keySize;
+} SSLInfo;
+```
+
+Return Values:
+
+* >0 on success and indicates the number of bytes written to data
+* 0 indicates no SSL data is ready yet
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+
+### ssl_SetConnectionCb
+
+```c
+int ssl_SetConnectionCb(SSLConnCb cb);
+```
+
+Sets a callback function that will be called when the full session information is known and will provide a pointer to the session’s information. The callback function has the signature:
+
+```c
+typedef void (*SSLConnCb)(const void* session, SSLInfo* info, void* ctx);
+```
+
+Where session is the current session. info will be a pointer to the session’s info. The ctx is application specific context data passed to the callback.
+
+Return Values:
+
+* >0 on success and indicates the number of bytes written to data
+* 0 indicates no SSL data is ready yet
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+### ssl_SetConnectionCtx
+
+```c
+int ssl_SetConnectionCtx(void* ctx);
+```
+
+Stores ctx, a pointer to application specific context data that will be passed to the connection callback function. The wolfSSL sniffer will not know anything about the context data.
+
+Return Values:
+
+* 0 on success
+* -1 if a problem occurred
+
+
+## API Usage: SSL Statistics options
+
+For an example on the use of the sniffer stats option, search the source `snifftest.c` for `WOLFSSL_SNIFFER_STATS`.
+
+See the header file `sniffer.h` for the structure `SSLStats` for the list of statistics that can be read.
+
+```c
+typedef struct SSLStats
+{
+    unsigned long int sslStandardConns;
+    unsigned long int sslClientAuthConns;
+    unsigned long int sslResumedConns;
+    unsigned long int sslEphemeralMisses;
+    unsigned long int sslResumeMisses;
+    unsigned long int sslCiphersUnsupported;
+    unsigned long int sslKeysUnmatched;
+    unsigned long int sslKeyFails;
+    unsigned long int sslDecodeFails;
+    unsigned long int sslAlerts;
+    unsigned long int sslDecryptedBytes;
+    unsigned long int sslEncryptedBytes;
+    unsigned long int sslEncryptedPackets;
+    unsigned long int sslDecryptedPackets;
+    unsigned long int sslKeyMatches;
+    unsigned long int sslEncryptedConns;
+
+    unsigned long int sslResumptionValid;
+    unsigned long int sslResumptionInserts;
+} SSLStats;
+```
+
+### ssl_ResetStatistics
+
+```c
+int ssl_ResetStatistics(void);
+```
+
+Zeroes out the SSL sniffer statistics tracking storage.
+
+Return Values:
+
+* 0 on success
+* -1 if a problem occurred
+
+### ssl_ReadStatistics
+
+```c
+int ssl_ReadStatistics(SSLStats* stats);
+```
+
+Copies the SSL sniffer statistics into the provided `SSLStats` record, stats.
+
+Return Values:
+
+* 0 on success
+* -1 if a problem occurred
+
+### ssl_ReadResetStatistics
+
+```c
+int ssl_ReadResetStatistics(SSLStats* stats);
+```
+
+Copies the SSL sniffer statistics into the provided `SSLStats` records, stats, and then zeroes out the SSL sniffer statistics tracking storage in one action.
+
+Return Values:
+
+* 0 on success
+* -1 if a problem occurred
+
+
+## API Usage: Session Watching option
+
+For an example on the use of the session watching option, search the source `snifftest.c` for `WOLFSSL_SNIFFER_WATCH`.
+
+### ssl_SetWatchKeyCallback
+
+```c
+int ssl_SetWatchKeyCallback(SSLWatchCb cb, char* error);
+int ssl_SetWatchKeyCallback_ex(SSLWatchCb cb, int devId, char* error);
+```
+
+Assigns a callback function to the wolfSSL sniffer used to locate and load a private key for a session at the time the sniffer knows the true identity of the server, when receiving its certificate message. The callback function is given to the parameter cb and any error string will be written into error. The function ssl_SetWatchKeyCallback_ex() takes an additional parameter called devId, the device ID of the hardware device handling the cryptography. The callback function has the signature:
+
+```c
+typedef int (*SSLWatchCb)(void* vSniffer,
+    const unsigned char* certHash, unsigned int certHashSz,
+    const unsigned char* certChain, unsigned int certChainSz,
+    void* ctx, char* error);
+```
+
+The parameter `vSniffer` is a typeless pointer to the current sniffer session and is meant to be passed directly to the function `ssl_SetWatchKey`. `certHash` is a SHA-256 hash of the certificate sent by the server, and its size is `certHashSz`. A pointer to certificate message’s payload is provided in the parameter `certChain`, and the certificate chain’s size in `certChainSz`. This will be a list of pairs of 24-bit certificate sizes and raw DER certificates in network order from the wire. The application space callback context data is provided in parameter ctx and is set by the function `ssl_SetWatchKeyCtx`. Any error string is copied into parameter error. Your callback function can use these values to locate the appropriate private key and load it into the sniffer session with the function `ssl_SetWatchKey`.
+
+Return Values:
+
+* 0 on success
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+### ssl_SetWatchKeyCtx
+
+```c
+int ssl_SetWatchKeyCtx(void* ctx, char* error);
+```
+
+Stores ctx, a pointer to application specific context data that will be passed to the watch key callback function. The wolfSSL sniffer will not know anything about the context data.
+
+Return Values:
+
+* 0 on success
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+### ssl_SetWatchKey_file
+
+```c
+int ssl_SetWatchKey_file(void* vSniffer, const char* keyFile, int keyType,
+    const char* password, char* error);
+```
+
+This function must be called from the watch key callback. Gives the sniffer session, vSniffer, the private key to be used to decrypt the pre-master secret. The key’s file name is given in the parameter keyFile, and that file will be loaded. The keyType is either `FILETYPE_PEM` or `FILETYPE_DER`. If the private key is encrypted, provide the text string password. Any error string is returned in error.
+
+Return Values:
+
+* 0 on success
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+### ssl_SetWatchKey_buffer
+
+```c
+int ssl_SetWatchKey_buffer(void* vSniffer, const unsigned char* key, 
+    unsigned int keySz, int keyType, char* error);
+```
+
+This function must be called from the watch key callback. Gives the sniffer session, vSniffer, the private key to be used to decrypt the pre-master secret. The key is passed in by the pointer key, and is of size keySz. The keyType is either `FILETYPE_PEM` or `FILETYPE_DER`. Any error string is returned in error.
+
+Return Values:
+
+* 0 on success
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+
+## API Usage: Store Data Callback option
+
+For an example on the use of the store data callback option, search the source `snifftest.c` for `WOLFSSL_SNIFFER_STORE_DATA_CB`.
+
+### ssl_SetStoreDataCallback
+
+```c
+int ssl_SetStoreDataCallback(SSLStoreDataCb cb);
+```
+
+Assigns a callback function to the wolfSSL sniffer used to store data when processing an application data record. The callback function is given to the parameter cb.
+
+The callback function has the signature:
+
+```c
+typedef int (*SSLStoreDataCb)(const unsigned char* decryptBuf,
+    unsigned int decryptBufSz, unsigned int decryptBufOffset,
+    void* ctx);
+```
+
+The parameter `decryptBuf` is a pointer to the beginning of the decrypted application data buffer. The value `decryptBufSz` is the number of bytes stored in the `decryptBuf`. `decryptBufOffset` is the offset into the `decryptBuf` where a copy should start. The `ctx` is an application specific parameter passed in the call to `ssl_DecodePacketWithSessionInfoStoreData()`. The callback should return the number of bytes copied out of `decryptBuf`. `decryptBufOffset` is a running sum of the bytes returned by the callback, and the loop stops when all bytes are consumed.
+
+Return Values:
+
+* 0 on success
+* -1 if a problem occurred
+
+### ssl_DecodePacketWithSessionInfoStoreData
+
+```c
+int ssl_DecodePacketWithSessionInfoStoreData(const unsigned char* packet,
+    in1t length, void* ctx, SSLInfo* sslInfo, char* error);
+```
+
+Decodes a raw packet that begins with the IP header and is length bytes long. Any SSL application data will be handed to the store data callback function, along with the parameter `ctx`. Information about the SSL session will be copied into `sslInfo` if it is non-null.
+
+The SSLInfo structure can be found in sniffer.h. It has information about the protocol version, cipher suite, server name indication, and key size in bits.
+
+Return Values:
+
+* >0 on success and indicates the number of bytes written by the store data callback
+* 0 indicates no SSL data is ready yet
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+
+## API Usage: Chain Input option
+
+For an example on the use of the chain input option, search the source `snifftest.c` for `WOLFSSL_SNIFFER_CHAIN_INPUT`.
+
+### ssl_DecodePacketWithChain
+
+```c
+int ssl_DecodePacketWithChain(void* vChain, unsigned int chainSz,
+    unsigned char** data, char* error);
+```
+
+Decodes a raw chain of packet buffers stored in an iovec passed in as the value vChain. The first buffer in the chain begins with the IP header. The chain is chainSz packets long. Any SSL application data will be stored in data, which may be allocated by the sniffer. Information about the SSL session will be copied into sslInfo if it is non-null.
+
+The SSLInfo structure can be found in sniffer.h. It has information about the protocol version, cipher suite, server name indication, and key size in bits.
+
+Return Values:
+
+* >0 on success and indicates the number of bytes written by the store data callback
+* 0 indicates no SSL data is ready yet
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+### ssl_DecodePacketWithChainSessionInfoStoreData
+
+```c
+int ssl_DecodePacketWithChainSessionInfoStoreData(void* vChain,
+    unsigned int chainSz, void* ctx, SSLInfo* sslInfo, char* error);
+```
+
+This combines the options of decoding a chain input and storing data using a callback. Decodes a raw chain of packet buffers stored in an iovec passed in as the value vChain. The first buffer in the chain begins with the IP header. The chain is chainSz packets long. Any SSL application data will be handed to the store data callback function, along with the parameter ctx. Information about the SSL session will be copied into sslInfo if it is non-null.
+
+The SSLInfo structure can be found in sniffer.h. It has information about the protocol version, cipher suite, server name indication, and key size in bits.
+
+Return Values:
+
+* >0 on success and indicates the number of bytes written by the store data callback
+* 0 indicates no SSL data is ready yet
+* -1 if a problem occurred, the string error will hold a message describing the problem
+
+
+## Notes
+
+### Performance
+
+Once your SSL sniffing is working as expected you should be able to get some performance gains by compiling wolfSSL with fastmath enabled. You can do this by adding `--enable-fastmath` to your ./configure options.
+
+### Start up
+
+Remember to always start the sniffing application before the server.  This is important because if the SSL handshake is missed then future packets from that session will not be decoded.  In addition, any future sessions that use the “missed” session to do session resumption, renegotiation, or use session tickets based on that “missed” session will have the same problems.
+
+### Cipher Suite Limitations
+
+As a passive sniffer the wolfSSL sniffer will not be able to decode any SSL session that uses DHE (Ephemeral Diffie-Hellman) because it will not have access to the temporary key that the server generates.  You may need to disable DHE cipher suites on the server and/or client to prevent these cipher suites from being used.
+
+### Thread Safety
+
+Access to the sniffer session table is thread safe.  What is not thread safe, is using the same sniffer session from multiple threads.  For example, say sniffer session A is created by thread X. If 3 new packets come in for session A and threads X, Y, and Z all try to handle those packets concurrently that's a problem.  Ideally, the main thread would associate an ssl sniffer session (client ip/client port <-> server ip/server port) with a particular thread and use that same thread for the lifetime of the session.  Short of that, the sniffer session would need a lock which isn't ideal in a multithreaded scenario because once thread X locks the first packet from session A threads Y and Z would be blocked until thread X is done.  That defeats the whole purpose doing multithreaded sniffing.
+
+### Server Name Indication
+
+Some webservers use virtual domain name mapping where multiple servers using separate SSL keys and certificates are sharing the same IP address and port. The Server Name Indication client hello extension allows the SSL client to specify the name of the server it is connecting to. When running the configure command in section 2.1, add the option --enable-sni.
+
+### STARTTLS
+
+Many protocols use ssl as a layer between them and the network layer, and have a dedicated port for the secure connection. Other protocols start out on their classic well known port number in the clear and then offer the “STARTTLS” command which tells the server the client wants to use ssl. The server responds with an affirmation, and the client sends its TLS client hello message and starts negotiation. The sniffer can ignore non-TLS messages on a session until the client starts to negotiate TLS and then proceed as normal.
+
+
+## Missing Features
+
+### PSK
+
+While wolfSSL supports Pre Shared Keys, the current version of the sniffer does not.
+
+### Client Certificate URLs
+
+Neither wolfSSL nor the sniffer current supports the TLS extension Client Certificate URLs.
+
+### Secure Renegotiation
+
+While wolfSSL supports secure renegotiation, the current version of the sniffer does not. The sniffer does support session resumption.
+
+
+## Support
+
+For issues or questions please email support@wolfssl.com.

+ 1 - 0
sslSniffer/sslSnifferTest/include.am

@@ -8,6 +8,7 @@ sslSniffer_sslSnifferTest_snifftest_SOURCES = sslSniffer/sslSnifferTest/snifftes
 sslSniffer_sslSnifferTest_snifftest_LDADD        = src/libwolfssl.la -lpcap $(LIB_STATIC_ADD)
 sslSniffer_sslSnifferTest_snifftest_DEPENDENCIES = src/libwolfssl.la
 endif
+EXTRA_DIST += sslSniffer/README.md
 EXTRA_DIST += sslSniffer/sslSniffer.vcproj
 EXTRA_DIST += sslSniffer/sslSniffer.vcxproj
 EXTRA_DIST += sslSniffer/sslSnifferTest/sslSniffTest.vcproj

+ 165 - 112
sslSniffer/sslSnifferTest/snifftest.c

@@ -25,6 +25,8 @@
 #endif
 
 #include <wolfssl/wolfcrypt/settings.h>
+#include <wolfssl/wolfcrypt/types.h>
+#include <wolfssl/wolfcrypt/logging.h>
 
 #ifdef WOLFSSL_SNIFFER_STORE_DATA_CB
     #include <wolfssl/wolfcrypt/memory.h>
@@ -49,8 +51,8 @@ int main(void)
 /* do a full build */
 
 #ifdef _MSC_VER
-	/* builds on *nix too, for scanf device and port */
-	#define _CRT_SECURE_NO_WARNINGS
+    /* builds on *nix too, for scanf device and port */
+    #define _CRT_SECURE_NO_WARNINGS
 #endif
 
 #include <pcap/pcap.h>     /* pcap stuff */
@@ -96,6 +98,44 @@ enum {
 #endif
 
 
+#define DEFAULT_SERVER_EPH_KEY_ECC "../../certs/statickeys/ecc-secp256r1.pem"
+#define DEFAULT_SERVER_EPH_KEY_DH  "../../certs/statickeys/dh-ffdhe2048.pem"
+#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
+    #elif !defined(NO_DH)
+        #define DEFAULT_SERVER_EPH_KEY DEFAULT_SERVER_EPH_KEY_DH
+    #endif
+#endif
+
+#define DEFAULT_SERVER_KEY_RSA "../../certs/server-key.pem"
+#define DEFAULT_SERVER_KEY_ECC "../../certs/ecc-key.pem"
+#ifndef DEFAULT_SERVER_KEY
+    #ifndef NO_RSA
+        #define DEFAULT_SERVER_KEY DEFAULT_SERVER_KEY_RSA
+    #elif defined(HAVE_ECC)
+        #define DEFAULT_SERVER_KEY DEFAULT_SERVER_KEY_ECC
+    #endif
+#endif
+     
+
+#ifdef WOLFSSL_SNIFFER_WATCH
+static const byte rsaHash[] = {
+    0x4e, 0xa8, 0x55, 0x02, 0xe1, 0x84, 0x7e, 0xe1, 
+    0xb5, 0x97, 0xd2, 0xf0, 0x92, 0x3a, 0xfd, 0x0d, 
+    0x98, 0x26, 0x06, 0x85, 0x8d, 0xa4, 0xc7, 0x35, 
+    0xd4, 0x74, 0x8f, 0xd0, 0xe7, 0xa8, 0x27, 0xaa
+};
+static const byte eccHash[] = {
+    0x80, 0x3d, 0xff, 0xca, 0x2e, 0x20, 0xd9, 0xdf, 
+    0xfe, 0x64, 0x4e, 0x25, 0x6a, 0xee, 0xee, 0x60, 
+    0xc1, 0x48, 0x7b, 0xff, 0xa0, 0xfb, 0xeb, 0xac, 
+    0xe2, 0xa4, 0xdd, 0xb5, 0x18, 0x38, 0x78, 0x38
+};
+#endif
+
+
 pcap_t* pcap = NULL;
 pcap_if_t* alldevs = NULL;
 
@@ -113,7 +153,6 @@ static void FreeAll(void)
 
 
 #ifdef WOLFSSL_SNIFFER_STATS
-
 static void DumpStats(void)
 {
     SSLStats sslStats;
@@ -152,8 +191,7 @@ static void DumpStats(void)
     printf("SSL Stats (sslEncryptedConns):%lu\n",
             sslStats.sslEncryptedConns);
 }
-
-#endif
+#endif /* WOLFSSL_SNIFFER_STATS */
 
 
 static void sig_handler(const int sig)
@@ -170,64 +208,45 @@ static void sig_handler(const int sig)
 
 static void err_sys(const char* msg)
 {
-	fprintf(stderr, "%s\n", msg);
+    fprintf(stderr, "%s\n", msg);
     if (msg)
-	    exit(EXIT_FAILURE);
+        exit(EXIT_FAILURE);
 }
 
 
 #ifdef _WIN32
-	#define SNPRINTF _snprintf
+    #define SNPRINTF _snprintf
 #else
-	#define SNPRINTF snprintf
+    #define SNPRINTF snprintf
 #endif
 
 
 static char* iptos(const struct in_addr* addr)
 {
-	static char    output[32];
-	byte *p = (byte*)&addr->s_addr;
+    static char output[32];
+    byte *p = (byte*)&addr->s_addr;
 
-	snprintf(output, sizeof(output), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+    snprintf(output, sizeof(output), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
 
-	return output;
+    return output;
 }
 
-
 static const char* ip6tos(const struct in6_addr* addr)
 {
-	static char    output[42];
-	return inet_ntop(AF_INET6, addr, output, 42);
+    static char output[42];
+    return inet_ntop(AF_INET6, addr, output, 42);
 }
 
 
 #if defined(WOLFSSL_SNIFFER_STORE_DATA_CB) || defined(WOLFSSL_SNIFFER_CHAIN_INPUT)
-
 static inline unsigned int min(unsigned int a, unsigned int b)
 {
     return a > b ? b : a;
 }
-
 #endif
 
 
 #ifdef WOLFSSL_SNIFFER_WATCH
-
-const byte rsaHash[] = {
-    0xD1, 0xB6, 0x12, 0xAD, 0xB6, 0x50, 0x7B, 0x59,
-    0x97, 0x83, 0x6B, 0xCB, 0x35, 0xF5, 0xB8, 0x67,
-    0xEB, 0x83, 0x75, 0x40, 0x1B, 0x42, 0x61, 0xF1,
-    0x03, 0x72, 0xDC, 0x09, 0x0D, 0x60, 0x83, 0x15
-};
-
-const byte eccHash[] = {
-    0xDA, 0x08, 0x6D, 0xB5, 0x0B, 0xC4, 0x9F, 0x8A,
-    0x9E, 0x61, 0x9E, 0x87, 0x57, 0x5F, 0x00, 0xAA,
-    0x76, 0xE5, 0x1C, 0x9C, 0x74, 0x2A, 0x19, 0xBE,
-    0x22, 0xAE, 0x25, 0x3F, 0xA8, 0xAF, 0x8E, 0x7F
-};
-
-
 static int myWatchCb(void* vSniffer,
         const unsigned char* certHash, unsigned int certHashSz,
         const unsigned char* certChain, unsigned int certChainSz,
@@ -240,23 +259,23 @@ static int myWatchCb(void* vSniffer,
     (void)ctx;
 
     if (certHashSz == sizeof(rsaHash) &&
-            memcmp(certHash, rsaHash, certHashSz) == 0)
-        certName = "../../certs/server-key.pem";
+            XMEMCMP(certHash, rsaHash, certHashSz) == 0) {
+        certName = DEFAULT_SERVER_KEY_RSA;
+    }
     if (certHashSz == sizeof(eccHash) &&
-            memcmp(certHash, eccHash, certHashSz) == 0)
-        certName = "../../certs/ecc-key.pem";
+            XMEMCMP(certHash, eccHash, certHashSz) == 0) {
+        certName = DEFAULT_SERVER_KEY_ECC;
+    }
 
     if (certName == NULL)
         return -1;
 
     return ssl_SetWatchKey_file(vSniffer, certName, FILETYPE_PEM, NULL, error);
 }
-
-#endif
+#endif /* WOLFSSL_SNIFFER_WATCH */
 
 
 #ifdef WOLFSSL_SNIFFER_STORE_DATA_CB
-
 static int myStoreDataCb(const unsigned char* decryptBuf,
         unsigned int decryptBufSz, unsigned int decryptBufOffset, void* ctx)
 {
@@ -283,29 +302,28 @@ static int myStoreDataCb(const unsigned char* decryptBuf,
         *data = tmpData;
     }
 
-    memcpy(*data + decryptBufOffset, decryptBuf + decryptBufOffset, qty);
+    XMEMCPY(*data + decryptBufOffset, decryptBuf + decryptBufOffset, qty);
 
     return qty;
 }
-
-#endif
+#endif /* WOLFSSL_SNIFFER_STORE_DATA_CB */
 
 
 int main(int argc, char** argv)
 {
     int          ret = 0;
     int          hadBadPacket = 0;
-	int		     inum;
-	int		     port;
+    int          inum = 0;
+    int          port = 0;
     int          saveFile = 0;
-	int		     i = 0;
+    int          i = 0, defDev = 0;
     int          frame = ETHER_IF_FRAME_LEN;
     char         err[PCAP_ERRBUF_SIZE];
-	char         filter[32];
-	const char  *server = NULL;
-	struct       bpf_program fp;
-	pcap_if_t   *d;
-	pcap_addr_t *a;
+    char         filter[32];
+    const char  *server = NULL;
+    struct       bpf_program fp;
+    pcap_if_t   *d;
+    pcap_addr_t *a;
 #ifdef WOLFSSL_SNIFFER_CHAIN_INPUT
     struct iovec chain[CHAIN_INPUT_COUNT];
     int          chainSz;
@@ -315,6 +333,9 @@ int main(int argc, char** argv)
 
 #ifndef _WIN32
     ssl_InitSniffer();   /* dll load on Windows */
+#endif
+#ifdef DEBUG_WOLFSSL
+    //wolfSSL_Debugging_ON();
 #endif
     ssl_Trace("./tracefile.txt", err);
     ssl_EnableRecovery(1, -1, err);
@@ -326,54 +347,58 @@ int main(int argc, char** argv)
 #endif
 
     if (argc == 1) {
+        char cmdLineArg[128];
         /* normal case, user chooses device and port */
 
-	    if (pcap_findalldevs(&alldevs, err) == -1)
-		    err_sys("Error in pcap_findalldevs");
+        if (pcap_findalldevs(&alldevs, err) == -1)
+            err_sys("Error in pcap_findalldevs");
 
-	    for (d = alldevs; d; d=d->next) {
-		    printf("%d. %s", ++i, d->name);
-		    if (d->description)
-			    printf(" (%s)\n", d->description);
-		    else
-			    printf(" (No description available)\n");
-	    }
+        for (d = alldevs; d; d=d->next) {
+            printf("%d. %s", ++i, d->name);
+            if (strcmp(d->name, "lo0") == 0) {
+                defDev = i;
+            }
+            if (d->description)
+                printf(" (%s)\n", d->description);
+            else
+                printf(" (No description available)\n");
+        }
 
-	    if (i == 0)
-		    err_sys("No interfaces found! Make sure pcap or WinPcap is"
+        if (i == 0)
+            err_sys("No interfaces found! Make sure pcap or WinPcap is"
                     " installed correctly and you have sufficient permissions");
 
-	    printf("Enter the interface number (1-%d): ", i);
-	    ret = scanf("%d", &inum);
-        if (ret != 1) {
-            printf("scanf port failed\n");
-        }
-
-	    if (inum < 1 || inum > i)
-		    err_sys("Interface number out of range");
+        printf("Enter the interface number (1-%d) [default: %d]: ", i, defDev);
+        XMEMSET(cmdLineArg, 0, sizeof(cmdLineArg));
+        if (XFGETS(cmdLineArg, sizeof(cmdLineArg), stdin))
+            inum = XATOI(cmdLineArg);
+        if (inum == 0)
+            inum = defDev;
+        else if (inum < 1 || inum > i)
+            err_sys("Interface number out of range");
 
-	    /* Jump to the selected adapter */
-	    for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++);
+        /* Jump to the selected adapter */
+        for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++);
 
-	    pcap = pcap_create(d->name, err);
+        pcap = pcap_create(d->name, err);
 
         if (pcap == NULL) printf("pcap_create failed %s\n", err);
 
         /* print out addresses for selected interface */
-	    for (a = d->addresses; a; a = a->next) {
+        for (a = d->addresses; a; a = a->next) {
             if (a->addr->sa_family == AF_INET) {
-				server =
+                server =
                     iptos(&((struct sockaddr_in *)a->addr)->sin_addr);
-		        printf("server = %s\n", server);
+                printf("server = %s\n", server);
             }
             else if (a->addr->sa_family == AF_INET6) {
                 server =
                     ip6tos(&((struct sockaddr_in6 *)a->addr)->sin6_addr);
-		        printf("server = %s\n", server);
+                printf("server = %s\n", server);
             }
-	    }
-	    if (server == NULL)
-		    err_sys("Unable to get device IPv4 or IPv6 address");
+        }
+        if (server == NULL)
+            err_sys("Unable to get device IPv4 or IPv6 address");
 
         ret = pcap_set_snaplen(pcap, 65536);
         if (ret != 0) printf("pcap_set_snaplen failed %s\n", pcap_geterr(pcap));
@@ -383,7 +408,7 @@ int main(int argc, char** argv)
 
         ret = pcap_set_buffer_size(pcap, 1000000);
         if (ret != 0)
-		    printf("pcap_set_buffer_size failed %s\n", pcap_geterr(pcap));
+            printf("pcap_set_buffer_size failed %s\n", pcap_geterr(pcap));
 
         ret = pcap_set_promisc(pcap, 1);
         if (ret != 0) printf("pcap_set_promisc failed %s\n", pcap_geterr(pcap));
@@ -392,24 +417,27 @@ int main(int argc, char** argv)
         ret = pcap_activate(pcap);
         if (ret != 0) printf("pcap_activate failed %s\n", pcap_geterr(pcap));
 
-	    printf("Enter the port to scan: ");
-	    ret = scanf("%d", &port);
-        if (ret != 1)
-            printf("scanf port failed\n");
+        printf("Enter the port to scan [default: 11111]: ");
+        XMEMSET(cmdLineArg, 0, sizeof(cmdLineArg));
+        if (XFGETS(cmdLineArg, sizeof(cmdLineArg), stdin)) {
+            port = XATOI(cmdLineArg);
+        }
+        if (port <= 0)
+            port = 11111;
 
-	    SNPRINTF(filter, sizeof(filter), "tcp and port %d", port);
+        SNPRINTF(filter, sizeof(filter), "tcp and port %d", port);
 
-	    ret = pcap_compile(pcap, &fp, filter, 0, 0);
+        ret = pcap_compile(pcap, &fp, filter, 0, 0);
         if (ret != 0) printf("pcap_compile failed %s\n", pcap_geterr(pcap));
 
         ret = pcap_setfilter(pcap, &fp);
         if (ret != 0) printf("pcap_setfilter failed %s\n", pcap_geterr(pcap));
 
-	    /* get IPv4 or IPv6 addresses for selected interface */
-	    for (a = d->addresses; a; a = a->next) {
+        /* get IPv4 or IPv6 addresses for selected interface */
+        for (a = d->addresses; a; a = a->next) {
             server = NULL;
             if (a->addr->sa_family == AF_INET) {
-				server =
+                server =
                     iptos(&((struct sockaddr_in *)a->addr)->sin_addr);
             }
             else if (a->addr->sa_family == AF_INET6) {
@@ -418,35 +446,41 @@ int main(int argc, char** argv)
             }
 
             if (server) {
-            #ifndef WOLFSSL_SNIFFER_WATCH
-                ret = ssl_SetPrivateKey(server, port,
-                        "../../certs/server-key.pem",
-                        FILETYPE_PEM, NULL, err);
+            #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
-                {
-                    char altName[128];
-
-                    printf("Enter alternate SNI: ");
-                    ret = scanf("%s", altName);
-
-                    if (strnlen(altName, 128) > 0) {
-                        ret = ssl_SetNamedPrivateKey(altName,
-                                server, port, "../../certs/server-key.pem",
+                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");
+                                    "sslSniffer/sslSnifferTest dir\n");
                         }
                     }
                 }
-            #endif
-            #endif
+            #endif /* HAVE_SNI */
+            #endif /* WOLFSSL_SNIFFER_WATCH */
             }
-	    }
+        }
     }
     else if (argc >= 3) {
         saveFile = 1;
@@ -457,6 +491,8 @@ 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";
@@ -465,13 +501,30 @@ int main(int argc, char** argv)
                 server = argv[3];
 
             if (argc >= 5)
-                port = atoi(argv[4]);
+                port = XATOI(argv[4]);
 
             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);
+                                FILETYPE_PEM, passwd, err);
+            if (ret == 0)
+                loadCount++;
+            if (loadCount > 0) {
+                ret = 0;
+            }
+            else {
+                printf("Failed loading private key %d\n", ret);
+                exit(EXIT_FAILURE);
+            }
         }
     }
     else {
@@ -498,8 +551,8 @@ int main(int argc, char** argv)
             byte* data = NULL;
 
             if (header.caplen > 40)  { /* min ip(20) + min tcp(20) */
-				packet        += frame;
-				header.caplen -= frame;
+                packet        += frame;
+                header.caplen -= frame;
             }
             else
                 continue;

+ 38 - 27
wolfcrypt/src/asn.c

@@ -1521,9 +1521,9 @@ static word32 SetBitString16Bit(word16 val, byte* output)
 #ifdef HAVE_ED448
     static const byte keyEd448Oid[] = {43, 101, 113};
 #endif /* HAVE_ED448 */
-#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL))
+#ifndef NO_DH
     static const byte keyDhOid[] = {42, 134, 72, 134, 247, 13, 1, 3, 1};
-#endif /* ! NO_DH ... */
+#endif /* !NO_DH */
 
 /* curveType */
 #ifdef HAVE_ECC
@@ -1869,12 +1869,12 @@ const byte* OidFromId(word32 id, word32 type, word32* oidSz)
                     *oidSz = sizeof(keyEd448Oid);
                     break;
                 #endif /* HAVE_ED448 */
-                #if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL))
+                #ifndef NO_DH
                 case DHk:
                     oid = keyDhOid;
                     *oidSz = sizeof(keyDhOid);
                     break;
-                #endif /* ! NO_DH && (WOLFSSL_QT || OPENSSL_ALL */
+                #endif /* !NO_DH */
                 default:
                     break;
             }
@@ -4416,17 +4416,20 @@ int wc_RsaPublicKeyDecodeRaw(const byte* n, word32 nSz, const byte* e,
 #endif /* !NO_RSA */
 
 #ifndef NO_DH
-
+/* Supports either:
+ * - DH params G/P (PKCS#3 DH) file or 
+ * - DH key file (if WOLFSSL_DH_EXTRA enabled) */
+/* The wc_DhParamsLoad function also loads DH params, but directly into buffers, not DhKey */
 int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz)
 {
     int ret = 0;
     int length;
-    #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
-    #if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
-                                (HAVE_FIPS_VERSION>2))
+#ifdef WOLFSSL_DH_EXTRA
+    #if !defined(HAVE_FIPS) || \
+        (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))
     word32 oid = 0, temp = 0;
     #endif
-    #endif
+#endif
 
     WOLFSSL_ENTER("wc_DhKeyDecode");
 
@@ -4435,26 +4438,33 @@ int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz)
 
     if (GetSequence(input, inOutIdx, &length, inSz) < 0)
         return ASN_PARSE_E;
-    #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
-    #if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
-                                (HAVE_FIPS_VERSION>2))
+
+#ifdef WOLFSSL_DH_EXTRA
+    #if !defined(HAVE_FIPS) || \
+        (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))
     temp = *inOutIdx;
-    #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
     #endif
-
+#endif
     /* Assume input started after 1.2.840.113549.1.3.1 dhKeyAgreement */
     if (GetInt(&key->p,  input, inOutIdx, inSz) < 0 ||
         GetInt(&key->g,  input, inOutIdx, inSz) < 0) {
         ret = ASN_DH_KEY_E;
     }
 
-    #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
-    #if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
-                                (HAVE_FIPS_VERSION>2))
+#ifdef WOLFSSL_DH_EXTRA
+    #if !defined(HAVE_FIPS) || \
+        (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))
     /* If ASN_DH_KEY_E: Check if input started at beginning of key */
     if (ret == ASN_DH_KEY_E) {
-        /* rewind back to after the first sequence */
         *inOutIdx = temp;
+
+        /* the version (0) */
+        if (GetASNInt(input, inOutIdx, &length, inSz) < 0) {
+            return ASN_PARSE_E;
+        }
+        *inOutIdx += length;
+
+        /* Size of dhKeyAgreement section */
         if (GetSequence(input, inOutIdx, &length, inSz) < 0)
             return ASN_PARSE_E;
 
@@ -4466,8 +4476,8 @@ int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz)
         if (GetSequence(input, inOutIdx, &length, inSz) < 0)
             return ASN_PARSE_E;
 
-        if (GetInt(&key->p,  input, inOutIdx, inSz) < 0 ||
-            GetInt(&key->g,  input, inOutIdx, inSz) < 0) {
+        if (GetInt(&key->p, input, inOutIdx, inSz) < 0 ||
+            GetInt(&key->g, input, inOutIdx, inSz) < 0) {
             return ASN_DH_KEY_E;
         }
     }
@@ -4487,7 +4497,9 @@ int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz)
             /* Found Octet String */
             if (GetInt(&key->priv, input, inOutIdx, inSz) == 0) {
                 WOLFSSL_MSG("Found Private Key");
-                ret = 0;
+
+                /* Compute public */
+                ret = mp_exptmod(&key->g, &key->priv, &key->p, &key->pub);
             }
         } else {
             /* Don't use length from failed CheckBitString/GetOctetString */
@@ -4496,14 +4508,13 @@ int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz)
         }
     }
     #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */
-    #endif /* WOLFSSL_QT || OPENSSL_ALL */
+#endif /* WOLFSSL_DH_EXTRA */
 
-    WOLFSSL_MSG("wc_DhKeyDecode Success");
+    WOLFSSL_LEAVE("wc_DhKeyDecode", ret);
 
     return ret;
 }
 
-
 int wc_DhParamsLoad(const byte* input, word32 inSz, byte* p, word32* pInOutSz,
                  byte* g, word32* gInOutSz)
 {
@@ -4541,7 +4552,7 @@ int wc_DhParamsLoad(const byte* input, word32 inSz, byte* p, word32* pInOutSz,
 
     return 0;
 }
-#endif /* NO_DH */
+#endif /* !NO_DH */
 
 
 #ifndef NO_DSA
@@ -9895,7 +9906,7 @@ int wc_PemGetHeaderFooter(int type, const char** header, const char** footer)
             if (footer) *footer = END_PUB_KEY;
             ret = 0;
             break;
-    #if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL))
+    #ifndef NO_DH
         case DH_PRIVATEKEY_TYPE:
     #endif
         case PKCS8_PRIVATEKEY_TYPE:
@@ -15068,7 +15079,7 @@ int StoreDHparams(byte* out, word32* outLen, mp_int* p, mp_int* g)
 
     return 0;
 }
-#endif /* !NO_DH && WOLFSSL_QT || OPENSSL_ALL */
+#endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */
 
 #ifdef HAVE_ECC
 

+ 79 - 41
wolfcrypt/src/dh.c

@@ -930,10 +930,10 @@ int wc_InitDhKey_ex(DhKey* key, void* heap, int devId)
 
     key->heap = heap; /* for XMALLOC/XFREE in future */
 
-#if !defined(WOLFSSL_QT) && !defined(OPENSSL_ALL)
-    if (mp_init_multi(&key->p, &key->g, &key->q, NULL, NULL, NULL) != MP_OKAY)
+#ifdef WOLFSSL_DH_EXTRA
+    if (mp_init_multi(&key->p, &key->g, &key->q, &key->pub, &key->priv, NULL) != MP_OKAY)
 #else
-    if (mp_init_multi(&key->p,&key->g,&key->q,&key->pub,&key->priv,NULL) != MP_OKAY)
+    if (mp_init_multi(&key->p, &key->g, &key->q, NULL, NULL, NULL) != MP_OKAY)
 #endif
         return MEMORY_E;
 
@@ -960,6 +960,10 @@ int wc_FreeDhKey(DhKey* key)
         mp_clear(&key->p);
         mp_clear(&key->g);
         mp_clear(&key->q);
+    #ifdef WOLFSSL_DH_EXTRA
+        mp_clear(&key->pub);
+        mp_forcezero(&key->priv);
+    #endif
 
     #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_DH)
         wolfAsync_DevCtxFree(&key->asyncDev, WOLFSSL_ASYNC_MARKER_DH);
@@ -1148,7 +1152,6 @@ static int GeneratePrivateDh186(DhKey* key, WC_RNG* rng, byte* priv,
     }
 
     mp_forcezero(tmpX);
-    mp_clear(tmpX);
     mp_clear(tmpQ);
 #ifdef WOLFSSL_SMALL_STACK
     XFREE(tmpQ, key->heap, DYNAMIC_TYPE_DH);
@@ -1798,7 +1801,6 @@ int wc_DhCheckKeyPair(DhKey* key, const byte* pub, word32 pubSz,
     }
 
     mp_forcezero(privateKey);
-    mp_clear(privateKey);
     mp_clear(publicKey);
     mp_clear(checkKey);
 #ifdef WOLFSSL_SMALL_STACK
@@ -1834,7 +1836,6 @@ int wc_DhGenerateKeyPair(DhKey* key, WC_RNG* rng,
     return ret;
 }
 
-
 static int wc_DhAgree_Sync(DhKey* key, byte* agree, word32* agreeSz,
     const byte* priv, word32 privSz, const byte* otherPub, word32 pubSz)
 {
@@ -2065,76 +2066,113 @@ int wc_DhAgree(DhKey* key, byte* agree, word32* agreeSz, const byte* priv,
     return ret;
 }
 
-#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
+#ifdef WOLFSSL_DH_EXTRA
 /* Sets private and public key in DhKey if both are available, otherwise sets
-    either private or public key, depending on which is available.
-    Returns WOLFSSL_SUCCESS if at least one of the keys was set. */
-WOLFSSL_LOCAL int wc_DhSetFullKeys(DhKey* key,const byte* priv_key,word32 privSz,
-                                   const byte* pub_key, word32 pubSz)
+    either private or public key, depending on which is available. */
+int wc_DhImportKeyPair(DhKey* key, const byte* priv, word32 privSz,
+                       const byte* pub, word32 pubSz)
 {
-    byte havePriv = 0;
-    byte havePub = 0;
-    mp_int* keyPriv = NULL;
-    mp_int* keyPub  = NULL;
+    byte havePriv, havePub;
+    mp_int *keyPriv = NULL, *keyPub  = NULL;
 
     if (key == NULL) {
         return BAD_FUNC_ARG;
     }
 
-    havePriv = ( (priv_key != NULL) && (privSz > 0) );
-    havePub  = ( (pub_key  != NULL) && (pubSz  > 0) );
+    havePriv = ( (priv != NULL) && (privSz > 0) );
+    havePub  = ( (pub  != NULL) && (pubSz  > 0) );
 
     if (!havePub && !havePriv) {
         WOLFSSL_MSG("No Public or Private Key to Set");
         return BAD_FUNC_ARG;
     }
+
     /* Set Private Key */
-    if (havePriv == TRUE) {
+    if (havePriv) {
         /* may have leading 0 */
-        if (priv_key[0] == 0) {
-            privSz--; priv_key++;
+        if (priv[0] == 0) {
+            privSz--; priv++;
         }
         if (mp_init(&key->priv) != MP_OKAY)
-            havePriv = FALSE;
+            havePriv = 0;
     }
-
-    if (havePriv == TRUE) {
-        if (mp_read_unsigned_bin(&key->priv, priv_key, privSz) != MP_OKAY) {
-            havePriv = FALSE;
+    if (havePriv) {
+        if (mp_read_unsigned_bin(&key->priv, priv, privSz) != MP_OKAY) {
+            mp_clear(&key->priv);
+            havePriv = 0;
         } else {
             keyPriv = &key->priv;
-            WOLFSSL_MSG("DH Private Key Set.");
+            WOLFSSL_MSG("DH Private Key Set");
         }
     }
 
     /* Set Public Key */
-    if (havePub == TRUE) {
+    if (havePub) {
         /* may have leading 0 */
-        if (pub_key[0] == 0) {
-            pubSz--; pub_key++;
+        if (pub[0] == 0) {
+            pubSz--; pub++;
         }
         if (mp_init(&key->pub) != MP_OKAY)
-            havePub = FALSE;
+            havePub = 0;
     }
-
-    if (havePub == TRUE) {
-        if (mp_read_unsigned_bin(&key->pub, pub_key, pubSz) != MP_OKAY) {
-            havePub = FALSE;
+    if (havePub) {
+        if (mp_read_unsigned_bin(&key->pub, pub, pubSz) != MP_OKAY) {
+            mp_clear(&key->pub);
+            havePub = 0;
         } else {
             keyPub = &key->pub;
-            WOLFSSL_MSG("DH Public Key Set.");
+            WOLFSSL_MSG("DH Public Key Set");
         }
     }
-    /* Free Memory if error occured */
-    if (havePriv == FALSE && keyPriv != NULL)
+    /* Free Memory if error occurred */
+    if (havePriv == 0 && keyPriv != NULL)
         mp_clear(keyPriv);
-    if (havePub == FALSE && keyPub != NULL)
+    if (havePub == 0 && keyPub != NULL)
         mp_clear(keyPub);
 
-    /* WOLFSSL_SUCCESS if private or public was set else WOLFSSL_FAILURE */
-    return havePriv || havePub;
+    if (havePriv == 0 && havePub == 0) {
+        return MEMORY_E;
+    }
+
+    return 0;
 }
-#endif
+
+/* Can be used with WOLFSSL_DH_EXTRA when key is loaded with 
+    wc_DhKeyDecode or wc_DhImportKeyPair */
+int wc_DhExportKeyPair(DhKey* key, byte* priv, word32* pPrivSz, 
+    byte* pub, word32* pPubSz)
+{
+    int ret = 0;
+    word32 pubSz, privSz;
+
+    if (key == NULL || (priv && pPrivSz == NULL) || (pub && pPubSz == NULL)) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (priv) {
+        privSz = mp_unsigned_bin_size(&key->priv);
+        if (privSz > *pPrivSz) {
+            return BUFFER_E;
+        }
+        *pPrivSz = privSz;
+        ret |= mp_to_unsigned_bin(&key->priv, priv);
+    }
+
+    if (pub) {
+        pubSz = mp_unsigned_bin_size(&key->pub);
+        if (pubSz > *pPubSz) {
+            return BUFFER_E;
+        }
+        *pPubSz = pubSz;
+        ret |= mp_to_unsigned_bin(&key->pub,  pub);
+    }
+
+    if (ret != 0)
+        ret = ASN_DH_KEY_E;
+    return ret;
+}
+
+#endif /* WOLFSSL_DH_EXTRA */
 
 static int _DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
                    word32 gSz, const byte* q, word32 qSz, int trusted,

+ 56 - 3
wolfcrypt/src/wc_port.c

@@ -331,8 +331,60 @@ int wolfCrypt_Cleanup(void)
     return ret;
 }
 
-#if !defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR) && \
-	!defined(WOLFSSL_NUCLEUS) && !defined(WOLFSSL_NUCLEUS_1_2)
+#ifndef NO_FILESYSTEM
+
+/* Helpful function to load file into allocated buffer */
+int wc_FileLoad(const char* fname, unsigned char** buf, size_t* bufLen, 
+    void* heap)
+{
+    int ret;
+    size_t fileSz;
+    XFILE f;
+
+    if (fname == NULL || buf == NULL || bufLen == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    /* set defaults */
+    *buf = NULL;
+    *bufLen = 0;
+
+    /* open file (read-only binary) */
+    f = XFOPEN(fname, "rb");
+    if (!f) {
+        WOLFSSL_MSG("wc_LoadFile file load error");
+        return BAD_PATH_ERROR;
+    }
+
+    XFSEEK(f, 0, SEEK_END);
+    fileSz = XFTELL(f);
+    XREWIND(f);
+    if (fileSz > 0) {
+        *bufLen = fileSz;
+        *buf = (byte*)XMALLOC(*bufLen, heap, DYNAMIC_TYPE_TMP_BUFFER);
+        if (*buf == NULL) {
+            WOLFSSL_MSG("wc_LoadFile memory error");
+            ret = MEMORY_E;
+        }
+        else {
+            size_t readLen = XFREAD(*buf, 1, *bufLen, f);
+
+            /* check response code */
+            ret = (readLen == *bufLen) ? 0 : -1;
+        }
+    }
+    else {
+        ret = BUFFER_E;
+    }
+    XFCLOSE(f);
+
+    (void)heap;
+
+    return ret;
+}
+
+#if !defined(NO_WOLFSSL_DIR) && \
+    !defined(WOLFSSL_NUCLEUS) && !defined(WOLFSSL_NUCLEUS_1_2)
 
 /* File Handling Helpers */
 /* returns 0 if file found, WC_READDIR_NOFILE if no files or negative error */
@@ -631,7 +683,8 @@ void wc_ReadDirClose(ReadDirCtx* ctx)
 #endif
 }
 
-#endif /* !NO_FILESYSTEM && !NO_WOLFSSL_DIR */
+#endif /* !NO_WOLFSSL_DIR */
+#endif /* !NO_FILESYSTEM */
 
 #if !defined(NO_FILESYSTEM) && defined(WOLFSSL_ZEPHYR)
 XFILE z_fs_open(const char* filename, const char* perm)

+ 35 - 3
wolfcrypt/test/test.c

@@ -10385,7 +10385,10 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out)
     !defined(USE_CERT_BUFFERS_3072) && !defined(USE_CERT_BUFFERS_4096) && \
     !defined(NO_ASN)
     #ifndef NO_DH
-        static const char* dhKey = CERT_ROOT "dh2048.der";
+        static const char* dhParamsFile = CERT_ROOT "dh2048.der";
+        #ifdef WOLFSSL_DH_EXTRA
+            static const char* dhKeyFile = CERT_ROOT "statickeys/dh-ffdhe2048.der";
+        #endif
     #endif
     #ifndef NO_DSA
         static const char* dsaKey = CERT_ROOT "dsa2048.der";
@@ -14144,7 +14147,6 @@ static int dh_fips_generate_test(WC_RNG *rng)
     if (ret != 0) {
         ERROR_OUT(-7796, exit_gen_test);
     }
-
 #endif /* WOLFSSL_KEY_GEN */
 #endif /* HAVE_SELFTEST */
 
@@ -14428,7 +14430,7 @@ int dh_test(void)
 #elif defined(NO_ASN)
     /* don't use file, no DER parsing */
 #elif !defined(NO_FILESYSTEM)
-    XFILE  file = XFOPEN(dhKey, "rb");
+    XFILE  file = XFOPEN(dhParamsFile, "rb");
     if (!file)
         return -7900;
 
@@ -14545,6 +14547,36 @@ int dh_test(void)
     }
 #endif
 
+    
+
+    /* Test DH key import / export */
+#ifdef WOLFSSL_DH_EXTRA
+#if !defined(NO_ASN) && !defined(NO_FILESYSTEM)
+    file = XFOPEN(dhKeyFile, "rb");
+    if (!file)
+        return -7950;
+    bytes = (word32)XFREAD(tmp, 1, sizeof(tmp), file);
+    XFCLOSE(file);
+
+    idx = 0;
+    ret = wc_DhKeyDecode(tmp, &idx, &key, bytes);
+    if (ret != 0) {
+        return -7951;
+    }
+#endif
+
+    privSz = sizeof(priv);
+    pubSz = sizeof(pub);
+    ret = wc_DhExportKeyPair(&key, priv, &privSz, pub, &pubSz);
+    if (ret != 0) {
+        return -7952;
+    }
+    ret = wc_DhImportKeyPair(&key2, priv, privSz, pub, pubSz);
+    if (ret != 0) {
+        return -7953;
+    }
+#endif /* WOLFSSL_DH_EXTRA */
+
     ret = dh_generate_test(&rng);
     if (ret == 0)
         ret = dh_fips_generate_test(&rng);

+ 35 - 9
wolfssl/internal.h

@@ -1657,6 +1657,10 @@ WOLFSSL_LOCAL int InitSSL_Side(WOLFSSL* ssl, word16 side);
 /* for sniffer */
 WOLFSSL_LOCAL int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
                             word32 size, word32 totalSz, int sniff);
+#ifdef WOLFSSL_TLS13
+WOLFSSL_LOCAL int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
+                           word32 size, word32 totalSz, int sniff);
+#endif
 WOLFSSL_LOCAL int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx);
 /* TLS v1.3 needs these */
 WOLFSSL_LOCAL int  HandleTlsResumption(WOLFSSL* ssl, int bogusID,
@@ -1692,10 +1696,11 @@ WOLFSSL_LOCAL int  CheckAltNames(DecodedCert* dCert, char* domain);
 WOLFSSL_LOCAL int  CheckIPAddr(DecodedCert* dCert, const char* ipasc);
 #endif
 WOLFSSL_LOCAL int  CreateTicket(WOLFSSL* ssl);
-WOLFSSL_LOCAL int  HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz);
+WOLFSSL_LOCAL int  HashRaw(WOLFSSL* ssl, const byte* output, int sz);
 WOLFSSL_LOCAL int  HashOutput(WOLFSSL* ssl, const byte* output, int sz,
                               int ivSz);
 WOLFSSL_LOCAL int  HashInput(WOLFSSL* ssl, const byte* input, int sz);
+
 #if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
 WOLFSSL_LOCAL int SNI_Callback(WOLFSSL* ssl);
 #endif
@@ -2150,13 +2155,14 @@ typedef enum {
     TLSX_SUPPORTED_GROUPS           = 0x000a, /* a.k.a. Supported Curves */
     TLSX_EC_POINT_FORMATS           = 0x000b,
 #if !defined(WOLFSSL_NO_SIGALG)
-    TLSX_SIGNATURE_ALGORITHMS       = 0x000d,
+    TLSX_SIGNATURE_ALGORITHMS       = 0x000d, /* HELLO_EXT_SIG_ALGO */
 #endif
     TLSX_APPLICATION_LAYER_PROTOCOL = 0x0010, /* a.k.a. ALPN */
     TLSX_STATUS_REQUEST_V2          = 0x0011, /* a.k.a. OCSP stapling v2 */
 #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
     TLSX_ENCRYPT_THEN_MAC           = 0x0016, /* RFC 7366 */
 #endif
+    TLSX_EXTENDED_MASTER_SECRET     = 0x0017, /* HELLO_EXT_EXTMS */
     TLSX_QUANTUM_SAFE_HYBRID        = 0x0018, /* a.k.a. QSH  */
     TLSX_SESSION_TICKET             = 0x0023,
 #ifdef WOLFSSL_TLS13
@@ -2579,6 +2585,13 @@ enum DeriveKeyType {
     update_traffic_key
 };
 
+WOLFSSL_LOCAL int DeriveEarlySecret(WOLFSSL* ssl);
+WOLFSSL_LOCAL int DeriveHandshakeSecret(WOLFSSL* ssl);
+WOLFSSL_LOCAL int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store);
+WOLFSSL_LOCAL int DeriveMasterSecret(WOLFSSL* ssl);
+WOLFSSL_LOCAL int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen, byte* secret);
+WOLFSSL_LOCAL int DeriveResumptionSecret(WOLFSSL* ssl, byte* key);
+
 /* The key update request values for KeyUpdate message. */
 enum KeyUpdateRequest {
     update_not_requested,
@@ -2595,6 +2608,14 @@ enum SetCBIO {
 };
 #endif
 
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+typedef struct {
+    int keyAlgo;
+    DerBuffer* key;
+} StaticKeyExchangeInfo_t;
+#endif
+
+
 /* wolfSSL context type */
 struct WOLFSSL_CTX {
     WOLFSSL_METHOD* method;
@@ -2868,16 +2889,19 @@ struct WOLFSSL_CTX {
     #endif /* NO_RSA */
 #endif /* HAVE_PK_CALLBACKS */
 #ifdef HAVE_WOLF_EVENT
-        WOLF_EVENT_QUEUE event_queue;
+    WOLF_EVENT_QUEUE event_queue;
 #endif /* HAVE_WOLF_EVENT */
 #ifdef HAVE_EXT_CACHE
-        WOLFSSL_SESSION*(*get_sess_cb)(WOLFSSL*, unsigned char*, int, int*);
-        int (*new_sess_cb)(WOLFSSL*, WOLFSSL_SESSION*);
-        void (*rem_sess_cb)(WOLFSSL_CTX*, WOLFSSL_SESSION*);
+    WOLFSSL_SESSION*(*get_sess_cb)(WOLFSSL*, unsigned char*, int, int*);
+    int (*new_sess_cb)(WOLFSSL*, WOLFSSL_SESSION*);
+    void (*rem_sess_cb)(WOLFSSL_CTX*, WOLFSSL_SESSION*);
 #endif
 #if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256)
-        Srp*  srp;  /* TLS Secure Remote Password Protocol*/
-        byte* srp_password;
+    Srp*  srp;  /* TLS Secure Remote Password Protocol*/
+    byte* srp_password;
+#endif
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+    StaticKeyExchangeInfo_t staticKE;
 #endif
 };
 
@@ -2942,7 +2966,6 @@ enum KeyExchangeAlgorithm {
     ecc_static_diffie_hellman_kea       /* for verify suite only */
 };
 
-
 /* Supported Authentication Schemes */
 enum SignatureAlgorithm {
     anonymous_sa_algo = 0,
@@ -4220,6 +4243,9 @@ struct WOLFSSL {
     WOLFSSL_STACK* supportedCiphers; /* Used in wolfSSL_get_ciphers_compat */
     WOLFSSL_STACK* peerCertChain;    /* Used in wolfSSL_get_peer_cert_chain */
 #endif
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+    StaticKeyExchangeInfo_t staticKE;
+#endif
 };
 
 

+ 30 - 6
wolfssl/sniffer.h

@@ -49,18 +49,19 @@ SSL_SNIFFER_API int ssl_SetPrivateKey(const char* address, int port,
                                       const char* keyFile, int typeK,
                                       const char* password, char* error);
 
-WOLFSSL_API
-SSL_SNIFFER_API int ssl_SetNamedPrivateKey(const char* name,
-                                           const char* address, int port,
-                                           const char* keyFile, int typeK,
-                                           const char* password, char* error);
-
 WOLFSSL_API
 SSL_SNIFFER_API int ssl_SetPrivateKeyBuffer(const char* address, int port,
                                             const char* keyBuf, int keySz, 
                                             int typeK, const char* password, 
                                             char* error);
 
+
+WOLFSSL_API
+SSL_SNIFFER_API int ssl_SetNamedPrivateKey(const char* name,
+                                           const char* address, int port,
+                                           const char* keyFile, int typeK,
+                                           const char* password, char* error);
+
 WOLFSSL_API
 SSL_SNIFFER_API int ssl_SetNamedPrivateKeyBuffer(const char* name,
                                                  const char* address, int port,
@@ -68,6 +69,29 @@ SSL_SNIFFER_API int ssl_SetNamedPrivateKeyBuffer(const char* name,
                                                  int typeK, const char* password, 
                                                  char* error);
 
+WOLFSSL_API 
+SSL_SNIFFER_API int ssl_SetEphemeralKey(const char* address, int port, 
+                                        const char* keyFile, int typeKey, 
+                                        const char* password, char* error);
+
+WOLFSSL_API 
+SSL_SNIFFER_API int ssl_SetEphemeralKeyBuffer(const char* address, int port, 
+                                              const char* keyBuf, int keySz, int typeKey, 
+                                              const char* password, char* error);
+
+
+WOLFSSL_API 
+SSL_SNIFFER_API int ssl_SetNamedEphemeralKey(const char* name,
+                                             const char* address, int port,
+                                             const char* keyFile, int typeKey,
+                                             const char* password, char* error);
+
+WOLFSSL_API 
+SSL_SNIFFER_API int ssl_SetNamedEphemeralKeyBuffer(const char* name,
+                                                   const char* address, int port,
+                                                   const char* keyBuf, int keySz, int typeKey, 
+                                                   const char* password, char* error);
+
 WOLFSSL_API
 SSL_SNIFFER_API int ssl_DecodePacket(const unsigned char* packet, int length,
                                      unsigned char** data, char* error);

+ 1 - 0
wolfssl/sniffer_error.h

@@ -130,6 +130,7 @@
 #define NO_DATA_DEST_STR 91
 #define STORE_DATA_FAIL_STR 92
 #define CHAIN_INPUT_STR 93
+#define GOT_ENC_EXT_STR 94
 /* !!!! also add to msgTable in sniffer.c and .rc file !!!! */
 
 

+ 9 - 0
wolfssl/ssl.h

@@ -3910,6 +3910,15 @@ WOLFSSL_API int wolfSSL_CTX_AllowEncryptThenMac(WOLFSSL_CTX *, int);
 WOLFSSL_API int wolfSSL_AllowEncryptThenMac(WOLFSSL *s, int);
 #endif
 
+/* This feature is used to set a fixed ephemeral key and is for testing only */
+/* Currently allows ECDHE and DHE only */
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+WOLFSSL_API int wolfSSL_CTX_set_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, 
+    const char* key, unsigned int keySz, int format);
+WOLFSSL_API int wolfSSL_set_ephemeral_key(WOLFSSL* ssl, int keyAlgo, 
+    const char* key, unsigned int keySz, int format);
+#endif
+
 #ifdef __cplusplus
     }  /* extern "C" */
 #endif

+ 8 - 6
wolfssl/test.h

@@ -3613,15 +3613,16 @@ static WC_INLINE const char* mymktemp(char *tempfn, int len, int num)
                              int enc, byte* ticket, int inLen, int* outLen,
                              void* userCtx)
     {
-        (void)ssl;
-        (void)userCtx;
-
         int ret;
         word16 sLen = XHTONS(inLen);
         byte aad[WOLFSSL_TICKET_NAME_SZ + WOLFSSL_TICKET_IV_SZ + 2];
         int  aadSz = WOLFSSL_TICKET_NAME_SZ + WOLFSSL_TICKET_IV_SZ + 2;
         byte* tmp = aad;
 
+        (void)ssl;
+        (void)userCtx;
+
+        /* encrypt */
         if (enc) {
             XMEMCPY(key_name, myKey_ctx.name, WOLFSSL_TICKET_NAME_SZ);
 
@@ -3642,8 +3643,9 @@ static WC_INLINE const char* mymktemp(char *tempfn, int len, int num)
                                               mac);
             if (ret != 0) return WOLFSSL_TICKET_RET_REJECT;
             *outLen = inLen;  /* no padding in this mode */
-        } else {
-            /* decrypt */
+        }
+        /* decrypt */
+        else {
 
             /* see if we know this key */
             if (XMEMCMP(key_name, myKey_ctx.name, WOLFSSL_TICKET_NAME_SZ) != 0){
@@ -3670,7 +3672,7 @@ static WC_INLINE const char* mymktemp(char *tempfn, int len, int num)
         return WOLFSSL_TICKET_RET_OK;
     }
 
-#endif  /* HAVE_SESSION_TICKET && CHACHA20 && POLY1305 */
+#endif  /* HAVE_SESSION_TICKET && HAVE_CHACHA && HAVE_POLY1305 */
 
 static WC_INLINE word16 GetRandomPort(void)
 {

+ 22 - 10
wolfssl/wolfcrypt/dh.h

@@ -45,11 +45,19 @@
 #ifdef WOLFSSL_ASYNC_CRYPT
     #include <wolfssl/wolfcrypt/async.h>
 #endif
+
+/* Optional support extended DH public / private keys */
+#if !defined(WOLFSSL_DH_EXTRA) && (defined(WOLFSSL_QT) || \
+        defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH) || \
+        defined(WOLFSSL_STATIC_EPHEMERAL))
+    #define WOLFSSL_DH_EXTRA
+#endif
+
 typedef struct DhParams {
-    #ifdef HAVE_FFDHE_Q
+#ifdef HAVE_FFDHE_Q
     const byte* q;
     word32      q_len;
-    #endif /* HAVE_FFDHE_Q */
+#endif /* HAVE_FFDHE_Q */
     const byte* p;
     word32      p_len;
     const byte* g;
@@ -58,8 +66,8 @@ typedef struct DhParams {
 
 /* Diffie-Hellman Key */
 struct DhKey {
-    mp_int p, g, q;                         /* group parameters  */
-#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH)
+    mp_int p, g, q; /* group parameters */
+#ifdef WOLFSSL_DH_EXTRA
     mp_int pub;
     mp_int priv;
 #endif
@@ -101,15 +109,20 @@ WOLFSSL_API int wc_DhAgree(DhKey* key, byte* agree, word32* agreeSz,
                        word32 pubSz);
 
 WOLFSSL_API int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key,
-                           word32);
+                           word32); /* wc_DhKeyDecode is in asn.c */
+
 WOLFSSL_API int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
                         word32 gSz);
 WOLFSSL_API int wc_DhSetKey_ex(DhKey* key, const byte* p, word32 pSz,
                         const byte* g, word32 gSz, const byte* q, word32 qSz);
-#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL)
-WOLFSSL_LOCAL int wc_DhSetFullKeys(DhKey* key,const byte* priv_key,word32 privSz,
-                                   const byte* pub_key, word32 pubSz);
-#endif
+
+#ifdef WOLFSSL_DH_EXTRA
+WOLFSSL_API int wc_DhImportKeyPair(DhKey* key, const byte* priv, word32 privSz,
+                                   const byte* pub, word32 pubSz);
+WOLFSSL_API int wc_DhExportKeyPair(DhKey* key, byte* priv, word32* pPrivSz, 
+                                   byte* pub, word32* pPubSz);
+#endif /* WOLFSSL_DH_EXTRA */
+
 WOLFSSL_API int wc_DhSetCheckKey(DhKey* key, const byte* p, word32 pSz,
                         const byte* g, word32 gSz, const byte* q, word32 qSz,
                         int trusted, WC_RNG* rng);
@@ -136,4 +149,3 @@ WOLFSSL_API int wc_DhExportParamsRaw(DhKey* dh, byte* p, word32* pSz,
 
 #endif /* NO_DH */
 #endif /* WOLF_CRYPT_DH_H */
-

+ 3 - 0
wolfssl/wolfcrypt/wc_port.h

@@ -455,6 +455,9 @@ WOLFSSL_API int wolfCrypt_Cleanup(void);
         #define MAX_PATH 256
     #endif
 
+    WOLFSSL_LOCAL int wc_FileLoad(const char* fname, unsigned char** buf, 
+        size_t* bufLen, void* heap);
+
 #if !defined(NO_WOLFSSL_DIR) && !defined(WOLFSSL_NUCLEUS) && \
     !defined(WOLFSSL_NUCLEUS_1_2)
     typedef struct ReadDirCtx {

Some files were not shown because too many files changed in this diff