From 960551cee0a3d56b4da57237d9aa0d36b763ca52 Mon Sep 17 00:00:00 2001 From: Tobias Frauenschlaeger Date: Mon, 24 Aug 2026 21:53:41 +0000 Subject: [PATCH] Address review findings on the sniffer Encrypt-Then-MAC fix Hand the corrected plaintext length to the WOLFSSL_SNIFFER_STORE_DATA_CB callback. The previous commit fixed the length only for the branch that copies into the caller's buffer; the callback branch still passed the raw record size, which spans the explicit IV, the tag or MAC and any padding. The callback pointer already points at the start of the plaintext, so the extra bytes run off the end of the decrypt output buffer, which leaves only a record header of slack. AddressSanitizer reports a heap-buffer-overflow read of 68 bytes on a TLS 1.2 CBC capture before this change and is clean after it. Reject a non-empty encrypt_then_mac extension in the ServerHello. RFC 7366 section 3.1 specifies empty extension_data and TLSX_EncryptThenMac_Parse enforces it, as do the neighbouring length-constrained cases in the same switch. Clear the Encrypt-Then-MAC decision at the start of every ServerHello. Nothing reset it, so a renegotiation that dropped the extension kept stripping a MAC that was no longer there, and one that added it started stripping while the previous cipher was still active. Reset the decrypted flag at doMessage and gate the padSz subtraction on it. The flag is set inside the decrypt block and was never cleared, so it described whichever earlier record in the packet had last been decrypted. The handshake case already guards the same value with it. Set the decoded-data flag on the WOLFSSL_ASYNC_CRYPT drain path too. A record that goes pending is completed inside SnifferAsyncPollQueue rather than DecodePacket, so an async build could decrypt a capture correctly and still report that nothing was decrypted. Send that diagnostic to stderr rather than into the decoded output, and note the exit status in the usage text so a wrapper is not surprised by it. Add a TLS 1.2 CBC Encrypt-Then-MAC capture and the sniffer-gen.sh recipe that produces it, so the fix has a regression test that can be regenerated. The existing static RSA and IPv6 captures exercise the same path but no script in the tree can rebuild them. The new capture covers both failure modes: with an HMAC-SHA1 suite the old code fails the decrypt outright, and with HMAC-SHA256, whose MAC is a multiple of the block size, it silently decrypts the wrong byte range and emits 48 bytes where 14 are correct. Warn when the Encrypt-Then-MAC gate drops the TLS 1.2 CBC captures, so a build configuration that loses coverage says so, and regenerate the keylog reference output with a binary that carries the new feature token. --- .github/configs/os-check-linux.json | 8 ++ ChangeLog.md | 25 ++++- scripts/include.am | 11 ++ scripts/sniffer-gen.sh | 96 ++++++++++++++++- scripts/sniffer-ipv6.pcap | Bin 10204 -> 8690 bytes scripts/sniffer-static-rsa.pcap | Bin 9424 -> 7910 bytes scripts/sniffer-testsuite.test | 114 ++++++++++++++++++--- scripts/sniffer-tls12-etm-keylog.out | 4 + scripts/sniffer-tls12-etm-keylog.pcap | Bin 0 -> 16660 bytes scripts/sniffer-tls12-etm-keylog.sslkeylog | 4 + scripts/sniffer-tls12-etm.out | 4 + scripts/sniffer-tls12-etm.pcap | Bin 0 -> 15900 bytes scripts/sniffer-tls12-keylog.out | 4 - scripts/sniffer-tls13-keylog.out | 4 - src/sniffer.c | 103 +++++++++++++++++-- sslSniffer/sslSnifferTest/snifftest.c | 104 ++++++++++++++----- wolfssl/sniffer_error.h | 1 + wolfssl/sniffer_error.rc | 1 + 18 files changed, 415 insertions(+), 68 deletions(-) create mode 100644 scripts/sniffer-tls12-etm-keylog.out create mode 100644 scripts/sniffer-tls12-etm-keylog.pcap create mode 100644 scripts/sniffer-tls12-etm-keylog.sslkeylog create mode 100644 scripts/sniffer-tls12-etm.out create mode 100644 scripts/sniffer-tls12-etm.pcap diff --git a/.github/configs/os-check-linux.json b/.github/configs/os-check-linux.json index e48129f222..452055c594 100644 --- a/.github/configs/os-check-linux.json +++ b/.github/configs/os-check-linux.json @@ -123,6 +123,14 @@ {"name": "sniffer-curves-enckeys", "minutes": 2.2, "configure": ["--enable-sniffer", "--enable-curve25519", "--enable-curve448", "--enable-enckeys", "CPPFLAGS=-DWOLFSSL_DH_EXTRA"]}, +{"name": "sniffer-keylog-storedata", "minutes": 2.5, + "comment": "The sniffer keylog legs of scripts/sniffer-testsuite.test only run with WOLFSSL_SNIFFER_KEYLOGFILE, and the store data callback path is only compiled with WOLFSSL_SNIFFER_STORE_DATA_CB. Neither is set by any other entry.", + "configure": ["--enable-sniffer", "--enable-session-ticket", + "--enable-curve25519", "--enable-ed25519", + "CPPFLAGS=-DWOLFSSL_SNIFFER_KEYLOGFILE -DWOLFSSL_SNIFFER_STORE_DATA_CB"]}, +{"name": "sniffer-no-enc-then-mac", "minutes": 2.2, + "comment": "The sniffer cannot read a capture that negotiated RFC 7366 without Encrypt-Then-MAC support, and says so through a dedicated error. That arm, and the assertion for it in scripts/sniffer-testsuite.test, are only compiled here.", + "configure": ["--enable-sniffer", "--enable-enc-then-mac=no"]}, {"name": "cryptocb-keygen-utils-aes-setkey", "minutes": 2.2, "configure": ["--enable-cryptocb", "--enable-keygen", "--enable-cryptocbutils", "CPPFLAGS=-DWOLF_CRYPTO_CB_AES_SETKEY"]}, diff --git a/ChangeLog.md b/ChangeLog.md index 4db8c65fb9..947b8a8414 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -177,7 +177,13 @@ so for a CBC suite it passed the trailing MAC to the block decrypt along with the ciphertext, the length was not a multiple of the block size, and every record failed. Since wolfSSL peers negotiate it by default, this covered - most TLS 1.2 CBC captures. + most TLS 1.2 CBC captures. A build without Encrypt-Then-MAC support now + reports that, once the negotiated suite is known to be a block cipher, rather + than failing every record with a generic decrypt error. Both the + `client_key_exchange` handler and the TLS 1.3 ServerHello path also overwrote + a specific error with "Server Client Key Mismatch", which hid the reason a + session could not be decrypted; they now keep an error that has already been + described. * **Fix (sniffer reported plaintext lengths that included the MAC or AEAD tag)**: the length returned to the caller was taken from the record size @@ -185,7 +191,22 @@ `ssl->keys.padSz`, so a 14 byte payload was reported as 30 under TLS 1.2 AES-GCM. The plaintext itself was correct, only the length was wrong, so a caller trusting it read past the end of the message. The sniffer now - subtracts `padSz`, matching the non-sniffer read path. + subtracts `padSz`, matching the non-sniffer read path. The same corrected + length is handed to the `WOLFSSL_SNIFFER_STORE_DATA_CB` callback, which + previously received the raw record size and so read past the end of the + decrypt output buffer; that overread is confirmed by AddressSanitizer and is + fixed here. + +* **Fix (`snifftest` could not report a failed capture)**: the read loop + assigned `hadBadPacket` on every packet instead of accumulating it, so an + early error was erased by any later packet that decoded cleanly and the + process still exited 0. A new `-expectdata` option additionally exits + non-zero when no application data could be decrypted at all; it is off by + default so that a handshake-only capture still exits 0. The example + `WOLFSSL_SNIFFER_STORE_DATA_CB` callback also sized its buffer from the first + record of a packet and reused it for every later one, even though the offset + it is handed restarts at zero for each record, so a larger second record + wrote past the end; it now grows the buffer per record and appends. * **Fix (certificate manager left pointing at a released store)**: `wolfSSL_CTX_set_cert_store()` pairs the store handed to it with the diff --git a/scripts/include.am b/scripts/include.am index 927c237887..e732d228bf 100644 --- a/scripts/include.am +++ b/scripts/include.am @@ -128,6 +128,17 @@ dist_noinst_SCRIPTS+= scripts/tsp.test EXTRA_DIST += scripts/sniffer-static-rsa.pcap \ scripts/sniffer-ipv6.pcap \ + scripts/sniffer-tls12-etm.pcap \ + scripts/sniffer-tls12-etm.out \ + scripts/sniffer-tls12-etm-keylog.pcap \ + scripts/sniffer-tls12-etm-keylog.sslkeylog \ + scripts/sniffer-tls12-etm-keylog.out \ + scripts/sniffer-tls12-keylog.pcap \ + scripts/sniffer-tls12-keylog.sslkeylog \ + scripts/sniffer-tls12-keylog.out \ + scripts/sniffer-tls13-keylog.pcap \ + scripts/sniffer-tls13-keylog.sslkeylog \ + scripts/sniffer-tls13-keylog.out \ scripts/sniffer-tls13-dh.pcap \ scripts/sniffer-tls13-dh-resume.pcap \ scripts/sniffer-tls13-ecc.pcap \ diff --git a/scripts/sniffer-gen.sh b/scripts/sniffer-gen.sh index 47e2193725..06819a560c 100755 --- a/scripts/sniffer-gen.sh +++ b/scripts/sniffer-gen.sh @@ -25,6 +25,25 @@ fi server_pid=0 tcpdump_pid=0 +# tcpdump names the loopback interface differently across platforms. +if [ -z "$LOOPBACK_IF" ]; then + case "$(uname -s)" in + Darwin|*BSD) LOOPBACK_IF=lo0 ;; + *) LOOPBACK_IF=lo ;; + esac +fi + +# stdbuf is GNU coreutils, absent on the BSDs. +STDBUF=() +if command -v stdbuf >/dev/null 2>&1; then + STDBUF=(stdbuf -oL -eL) +fi + +# With no arguments every capture is regenerated, otherwise only the named +# ones, e.g. `scripts/sniffer-gen.sh tls12-etm ipv6`. +CAPTURES=("$@") +MATCHED=() + cleanup() { if [ "$server_pid" -ne 0 ]; then kill $server_pid; server_pid=0; fi if [ "$tcpdump_pid" -ne 0 ]; then sleep 1; kill -15 $tcpdump_pid; tcpdump_pid=0; fi @@ -42,11 +61,11 @@ run_test() { # Usage: run_test [serverArgs [clientArgs]] if [ "$CIPHER" != "" ]; then CIPHER="-l $CIPHER" fi - stdbuf -oL -eL ./examples/server/server -i -x $CIPHER $2 2>&1 | prepend "[server] " & + "${STDBUF[@]}" ./examples/server/server -i -x $CIPHER $2 2>&1 | prepend "[server] " & server_pid=$! ((server_pid--)) # Get the first PID in the pipe sleep 0.1 - stdbuf -oL -eL ./examples/client/client $CIPHER $3 2>&1 | prepend "[client] " + "${STDBUF[@]}" ./examples/client/client $CIPHER $3 2>&1 | prepend "[client] " RET=$? if [ "$RET" != 0 ]; then echo "Error in test: $RET" @@ -76,6 +95,14 @@ run_sequence() { run_test "TLS13-AES128-GCM-SHA256" "-v 4 -r -c ./certs/ed25519/server-ed25519.pem -k ./certs/ed25519/server-ed25519-priv.pem -A ./certs/ed25519/client-ed25519.pem" "-v 4 -r -c ./certs/ed25519/client-ed25519.pem -k ./certs/ed25519/client-ed25519-priv.pem -A ./certs/ed25519/root-ed25519.pem" run_test "TLS13-AES256-GCM-SHA384" "-v 4 -r -c ./certs/ed25519/server-ed25519.pem -k ./certs/ed25519/server-ed25519-priv.pem -A ./certs/ed25519/client-ed25519.pem" "-v 4 -r -c ./certs/ed25519/client-ed25519.pem -k ./certs/ed25519/client-ed25519-priv.pem -A ./certs/ed25519/root-ed25519.pem" run_test "TLS13-CHACHA20-POLY1305-SHA256" "-v 4 -r -c ./certs/ed25519/server-ed25519.pem -k ./certs/ed25519/server-ed25519-priv.pem -A ./certs/ed25519/client-ed25519.pem" "-v 4 -r -c ./certs/ed25519/client-ed25519.pem -k ./certs/ed25519/client-ed25519-priv.pem -A ./certs/ed25519/root-ed25519.pem" + elif [ "$1" == "tls12-etm" ]; then # TLS v1.2 static RSA CBC, Encrypt-Then-MAC + run_test "AES128-SHA" "-v 3" "-v 3" + run_test "AES256-SHA256" "-v 3" "-v 3" + elif [ "$1" == "tls12-etm-keylog" ]; then # TLS v1.2 ECDHE CBC, Encrypt-Then-MAC + run_test "ECDHE-RSA-AES128-SHA256" "-v 3" "-v 3" + run_test "ECDHE-RSA-AES256-SHA384" "-v 3" "-v 3" + elif [ "$1" == "static-rsa" ] || [ "$1" == "ipv6" ]; then # TLS v1.2 static RSA + run_test "AES128-SHA" "-v 3" "-v 3" elif [ "$1" == "tls13-hrr" ]; then # TLS v1.3 Hello Retry Request run_test "" "-v 4 -g" "-v 4 -J" else @@ -87,6 +114,12 @@ run_sequence() { run_capture() { local config_flags=() + + if [ ${#CAPTURES[@]} -ne 0 ] && + ! printf '%s\n' "${CAPTURES[@]}" | grep -qx -- "$1"; then + return + fi + MATCHED+=("$1") echo -e "\nconfiguring and building wolfssl ($1)..." # Add default flags @@ -101,22 +134,64 @@ run_capture() { ./configure "${config_flags[@]}" 1>/dev/null || exit $? make 1>/dev/null || exit $? - if [[ "$1" == "tls12-keylog" || "$1" == "tls13-keylog" ]]; then + if [[ "$1" == *keylog ]]; then rm -f ./sslkeylog.log fi echo "starting capture" - tcpdump -i lo -n port 11111 -w ./scripts/sniffer-${1}.pcap -U & + tcpdump -i "$LOOPBACK_IF" -n port 11111 -w ./scripts/sniffer-${1}.pcap -U & tcpdump_pid=$! run_sequence $1 sleep 1 kill -15 $tcpdump_pid; tcpdump_pid=0 - if [[ "$1" == "tls12-keylog" || "$1" == "tls13-keylog" ]]; then + if [[ "$1" == *keylog ]]; then cp ./sslkeylog.log ./scripts/sniffer-${1}.sslkeylog fi + + run_snifftest $1 } +# Regenerate the known good output for the captures that sniffer-testsuite.test +# compares against one. The arguments have to match the ones the test uses. +run_snifftest() { + local args=() + + case "$1" in + tls12-etm) + args=(-key ./certs/server-key.pem) ;; + tls12-keylog|tls13-keylog|tls12-etm-keylog) + args=(-keylogfile "./scripts/sniffer-${1}.sslkeylog") ;; + *) + return ;; + esac + + echo "regenerating scripts/sniffer-${1}.out" + + # Only the decrypted records are compared by sniffer-testsuite.test, and + # they are the only lines every build agrees on: the banner names whatever + # features the capture happened to be built with. Write to a temporary + # file so a failed run cannot leave the tracked one truncated. + local out + out=$(mktemp) + ./sslSniffer/sslSnifferTest/snifftest -expectdata \ + -pcap ./scripts/sniffer-${1}.pcap "${args[@]}" \ + -server 127.0.0.1 -port 11111 \ + | grep '^SSL App Data' > "$out" + local rc=$? + + if [ $rc -ne 0 ]; then + rm -f "$out" + echo "snifftest could not read scripts/sniffer-${1}.pcap" + exit $rc + fi + + mv "$out" ./scripts/sniffer-${1}.out + chmod 644 ./scripts/sniffer-${1}.out # mktemp hands back 0600 +} + +run_capture "static-rsa" "--enable-enc-then-mac=no" +run_capture "ipv6" "--enable-enc-then-mac=no --enable-ipv6" run_capture "tls12" "" run_capture "tls12-keylog" "--enable-enc-then-mac=no --enable-keylog-export CFLAGS='-Wno-cpp -DWOLFSSL_SNIFFER_KEYLOGFILE'" run_capture "tls13-keylog" "--enable-keylog-export CFLAGS='-Wno-cpp -DWOLFSSL_SNIFFER_KEYLOGFILE'" @@ -126,6 +201,17 @@ run_capture "tls13-dh" "--disable-ecc" run_capture "tls13-dh-resume" "--disable-ecc --enable-session-ticket" run_capture "tls13-x25519" "--enable-curve25519 --enable-ed25519 --disable-dh --disable-ecc --disable-mlkem" run_capture "tls13-x25519-resume" "--enable-curve25519 --enable-ed25519 --disable-dh --disable-ecc --disable-mlkem --enable-session-ticket" +run_capture "tls12-etm" "" +run_capture "tls12-etm-keylog" "--enable-keylog-export CFLAGS='-Wno-cpp -DWOLFSSL_SNIFFER_KEYLOGFILE'" run_capture "tls13-hrr" "--disable-dh CFLAGS=-DWOLFSSL_SNIFFER_WATCH" +if [ ${#CAPTURES[@]} -ne 0 ]; then + for want in "${CAPTURES[@]}"; do + if ! printf '%s\n' "${MATCHED[@]}" | grep -qx -- "$want"; then + echo "No such capture: $want" + exit 1 + fi + done +fi + echo "Tests passed in $SECONDS seconds" diff --git a/scripts/sniffer-ipv6.pcap b/scripts/sniffer-ipv6.pcap index f5188f05257b2c4320fb229bc27942ff65bc2286..cc2237bc2c9163763c46471ac551c87f257e3663 100644 GIT binary patch delta 3608 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 | grep -- 'encrypt_then_mac ' if [ $? -eq 0 ]; then has_etm=yes +else + echo -e "\nWARNING: sniffer built without Encrypt-Then-MAC, skipping sniffer-tls12-etm.pcap\n" +fi +# A build that cannot read the capture has to say why, rather than failing +# every record with a generic decrypt error. +if test $has_etm == no && test $has_rsa == yes && test $has_tlsv12 == yes && test $has_static_rsa == yes +then + echo -e "\nChecking the Encrypt-Then-MAC diagnostic on sniffer-tls12-etm.pcap...\n" + + TMPFILE=$(mktemp) + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "\nsnifftest Encrypt-Then-MAC diagnostic failed: unable to create tmpfile\n" && exit 1 + + ./sslSniffer/sslSnifferTest/snifftest \ + -pcap ./scripts/sniffer-tls12-etm.pcap -key ./certs/server-key.pem \ + -server 127.0.0.1 -port 11111 > $TMPFILE 2>&1 + + RESULT=$? + [ $RESULT -eq 0 ] && echo -e "\nsnifftest read an Encrypt-Then-MAC capture it cannot support\n" && rm $TMPFILE && exit 1 + + grep -q "Encrypt-Then-MAC not supported in this build" $TMPFILE + + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "\nsnifftest did not report the missing Encrypt-Then-MAC support\n" && rm $TMPFILE && exit 1 + + rm $TMPFILE + RESULT=0 fi # ./configure --enable-sniffer CFLAGS="-DWOLFSSL_SNIFFER_KEYLOGFILE" has_keylog=no @@ -93,25 +121,81 @@ has_packets() { } # TLS v1.2 Static RSA Test -if test $RESULT -eq 0 && test $has_rsa == yes && test $has_tlsv12 == yes && test $has_static_rsa == yes && test $has_etm == yes && has_packets ./scripts/sniffer-static-rsa.pcap +if test $RESULT -eq 0 && test $has_rsa == yes && test $has_tlsv12 == yes && test $has_static_rsa == yes && has_packets ./scripts/sniffer-static-rsa.pcap then echo -e "\nStarting snifftest on sniffer-static-rsa.pcap...\n" - ./sslSniffer/sslSnifferTest/snifftest -pcap ./scripts/sniffer-static-rsa.pcap -key ./certs/server-key.pem -server 127.0.0.1 -port 11111 + ./sslSniffer/sslSnifferTest/snifftest -expectdata -pcap ./scripts/sniffer-static-rsa.pcap -key ./certs/server-key.pem -server 127.0.0.1 -port 11111 RESULT=$? [ $RESULT -ne 0 ] && echo -e "\nsnifftest static RSA failed\n" && exit 1 fi +# TLS v1.2 CBC Encrypt-Then-MAC Test (RFC 7366). The decrypted lengths are +# compared against known good output, since Encrypt-Then-MAC changes how much +# of a record is payload and a wrong length still decrypts. +if test $RESULT -eq 0 && test $has_rsa == yes && test $has_tlsv12 == yes && test $has_static_rsa == yes && test $has_etm == yes && has_packets ./scripts/sniffer-tls12-etm.pcap +then + echo -e "\nStarting snifftest on sniffer-tls12-etm.pcap...\n" + + TMPFILE=$(mktemp) + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "\nsnifftest Encrypt-Then-MAC failed: unable to create tmpfile\n" && exit 1 + + ./sslSniffer/sslSnifferTest/snifftest -expectdata \ + -pcap ./scripts/sniffer-tls12-etm.pcap \ + -key ./certs/server-key.pem \ + -server 127.0.0.1 -port 11111 | tee $TMPFILE + + RESULT=${PIPESTATUS[0]} + [ $RESULT -ne 0 ] && echo -e "\nsnifftest Encrypt-Then-MAC failed: snifftest returned $RESULT\n" && rm $TMPFILE && exit 1 + + # use grep to only compare against decrypted output + SEARCH_STRING="SSL App Data" + grep "$SEARCH_STRING" $TMPFILE | diff - <(grep "$SEARCH_STRING" scripts/sniffer-tls12-etm.out) + + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "\nsnifftest Encrypt-Then-MAC failed: snifftest diff returned $RESULT\n" && rm $TMPFILE && exit 1 + + rm $TMPFILE +fi + # TLS v1.2 Static RSA Test (IPv6) -if test $RESULT -eq 0 && test $has_rsa == yes && test $has_tlsv12 == yes && test $has_static_rsa == yes && test $has_etm == yes && has_packets ./scripts/sniffer-ipv6.pcap +if test $RESULT -eq 0 && test $has_rsa == yes && test $has_tlsv12 == yes && test $has_static_rsa == yes && has_packets ./scripts/sniffer-ipv6.pcap then echo -e "\nStarting snifftest on sniffer-ipv6.pcap...\n" - ./sslSniffer/sslSnifferTest/snifftest -pcap ./scripts/sniffer-ipv6.pcap -key ./certs/server-key.pem -server ::1 -port 11111 + ./sslSniffer/sslSnifferTest/snifftest -expectdata -pcap ./scripts/sniffer-ipv6.pcap -key ./certs/server-key.pem -server ::1 -port 11111 RESULT=$? [ $RESULT -ne 0 ] && echo -e "\nsnifftest (ipv6) failed\n" && exit 1 fi +# TLS v1.2 ECDHE CBC Encrypt-Then-MAC Test (RFC 7366) +if test $RESULT -eq 0 && test $has_rsa == yes && test $has_tlsv12 == yes && test $has_ecc == yes && test $has_etm == yes && test $has_keylog == yes +then + echo -e "\nStarting snifftest on sniffer-tls12-etm-keylog.pcap...\n" + + TMPFILE=$(mktemp) + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "\nsnifftest ECDHE Encrypt-Then-MAC failed: unable to create tmpfile\n" && exit 1 + + ./sslSniffer/sslSnifferTest/snifftest -expectdata \ + -pcap ./scripts/sniffer-tls12-etm-keylog.pcap \ + -keylogfile ./scripts/sniffer-tls12-etm-keylog.sslkeylog \ + -server 127.0.0.1 -port 11111 | tee $TMPFILE + + RESULT=${PIPESTATUS[0]} + [ $RESULT -ne 0 ] && echo -e "\nsnifftest ECDHE Encrypt-Then-MAC failed: snifftest returned $RESULT\n" && rm $TMPFILE && exit 1 + + # use grep to only compare against decrypted output + SEARCH_STRING="SSL App Data" + grep "$SEARCH_STRING" $TMPFILE | diff - <(grep "$SEARCH_STRING" scripts/sniffer-tls12-etm-keylog.out) + + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "\nsnifftest ECDHE Encrypt-Then-MAC failed: snifftest diff returned $RESULT\n" && rm $TMPFILE && exit 1 + + rm $TMPFILE +fi + # TLS v1.2 and v1.3 sniffer keylog file test: runs sniffer on pcap and associated keylog file and compares decrypted traffic with known good output. # To regenerate the known good output, run `scripts/sniffer-gen.sh` to regenerate the pcap and keylog file, then run the sniffer on it # with the same arguments as in the test below, but redirect output to `./scripts/sniffer-tls12-keylog.out`. @@ -123,7 +207,7 @@ then [[ $tlsver == "tls12" && $has_tlsv12 == "no" ]] && continue [[ $tlsver == "tls13" && $has_tlsv13 == "no" ]] && continue - has_packets scripts/sniffer-$tlsver-keylog.pcap || continue + has_packets ./scripts/sniffer-$tlsver-keylog.pcap || continue echo -e "\nStarting snifftest on sniffer-$tlsver-keylog.pcap...\n" @@ -131,7 +215,7 @@ then RESULT=$? [ $RESULT -ne 0 ] && echo -e "\n$tlsver snifftest keylog test failed: unable to create tmpfile\n" && rm $TMPFILE && exit 1 - ./sslSniffer/sslSnifferTest/snifftest \ + ./sslSniffer/sslSnifferTest/snifftest -expectdata \ -pcap scripts/sniffer-$tlsver-keylog.pcap \ -keylogfile scripts/sniffer-$tlsver-keylog.sslkeylog \ -server 127.0.0.1 -port 11111 | tee $TMPFILE @@ -154,7 +238,7 @@ fi if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_ecc == yes && has_packets ./scripts/sniffer-tls13-ecc.pcap then echo -e "\nStarting snifftest on sniffer-tls13-ecc.pcap...\n" - ./sslSniffer/sslSnifferTest/snifftest -pcap ./scripts/sniffer-tls13-ecc.pcap -key ./certs/statickeys/ecc-secp256r1.pem -server 127.0.0.1 -port 11111 + ./sslSniffer/sslSnifferTest/snifftest -expectdata -pcap ./scripts/sniffer-tls13-ecc.pcap -key ./certs/statickeys/ecc-secp256r1.pem -server 127.0.0.1 -port 11111 RESULT=$? [ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 ECC failed\n" && exit 1 @@ -164,7 +248,7 @@ fi if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_dh == yes && has_packets ./scripts/sniffer-tls13-dh.pcap then echo -e "\nStarting snifftest on sniffer-tls13-dh.pcap...\n" - ./sslSniffer/sslSnifferTest/snifftest -pcap ./scripts/sniffer-tls13-dh.pcap -key ./certs/statickeys/dh-ffdhe2048.pem -server 127.0.0.1 -port 11111 + ./sslSniffer/sslSnifferTest/snifftest -expectdata -pcap ./scripts/sniffer-tls13-dh.pcap -key ./certs/statickeys/dh-ffdhe2048.pem -server 127.0.0.1 -port 11111 RESULT=$? [ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 DH failed\n" && exit 1 @@ -174,7 +258,7 @@ fi if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_x25519 == yes && has_packets ./scripts/sniffer-tls13-x25519.pcap then echo -e "\nStarting snifftest on sniffer-tls13-x25519.pcap...\n" - ./sslSniffer/sslSnifferTest/snifftest -pcap ./scripts/sniffer-tls13-x25519.pcap -key ./certs/statickeys/x25519.pem -server 127.0.0.1 -port 11111 + ./sslSniffer/sslSnifferTest/snifftest -expectdata -pcap ./scripts/sniffer-tls13-x25519.pcap -key ./certs/statickeys/x25519.pem -server 127.0.0.1 -port 11111 RESULT=$? [ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 X25519 failed\n" && exit 1 @@ -184,7 +268,7 @@ fi if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_ecc == yes && test $session_ticket == yes && has_packets ./scripts/sniffer-tls13-ecc-resume.pcap then echo -e "\nStarting snifftest on sniffer-tls13-ecc-resume.pcap...\n" - ./sslSniffer/sslSnifferTest/snifftest -pcap ./scripts/sniffer-tls13-ecc-resume.pcap -key ./certs/statickeys/ecc-secp256r1.pem -server 127.0.0.1 -port 11111 + ./sslSniffer/sslSnifferTest/snifftest -expectdata -pcap ./scripts/sniffer-tls13-ecc-resume.pcap -key ./certs/statickeys/ecc-secp256r1.pem -server 127.0.0.1 -port 11111 RESULT=$? [ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 ECC failed\n" && exit 1 @@ -194,7 +278,7 @@ fi if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_dh == yes && test $session_ticket == yes && has_packets ./scripts/sniffer-tls13-dh-resume.pcap then echo -e "\nStarting snifftest on sniffer-tls13-dh-resume.pcap...\n" - ./sslSniffer/sslSnifferTest/snifftest -pcap ./scripts/sniffer-tls13-dh-resume.pcap -key ./certs/statickeys/dh-ffdhe2048.pem -server 127.0.0.1 -port 11111 + ./sslSniffer/sslSnifferTest/snifftest -expectdata -pcap ./scripts/sniffer-tls13-dh-resume.pcap -key ./certs/statickeys/dh-ffdhe2048.pem -server 127.0.0.1 -port 11111 RESULT=$? [ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 DH failed\n" && exit 1 @@ -204,7 +288,7 @@ fi if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_x25519 == yes && test $session_ticket == yes && has_packets ./scripts/sniffer-tls13-x25519-resume.pcap then echo -e "\nStarting snifftest on sniffer-tls13-x25519-resume.pcap...\n" - ./sslSniffer/sslSnifferTest/snifftest -pcap ./scripts/sniffer-tls13-x25519-resume.pcap -key ./certs/statickeys/x25519.pem -server 127.0.0.1 -port 11111 + ./sslSniffer/sslSnifferTest/snifftest -expectdata -pcap ./scripts/sniffer-tls13-x25519-resume.pcap -key ./certs/statickeys/x25519.pem -server 127.0.0.1 -port 11111 RESULT=$? [ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 X25519 failed\n" && exit 1 @@ -214,7 +298,7 @@ fi if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_ecc == yes && has_packets ./scripts/sniffer-tls13-hrr.pcap then echo -e "\nStarting snifftest on sniffer-tls13-hrr.pcap...\n" - ./sslSniffer/sslSnifferTest/snifftest -pcap ./scripts/sniffer-tls13-hrr.pcap -key ./certs/statickeys/ecc-secp256r1.pem -server 127.0.0.1 -port 11111 + ./sslSniffer/sslSnifferTest/snifftest -expectdata -pcap ./scripts/sniffer-tls13-hrr.pcap -key ./certs/statickeys/ecc-secp256r1.pem -server 127.0.0.1 -port 11111 RESULT=$? [ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 HRR failed\n" && exit 1 diff --git a/scripts/sniffer-tls12-etm-keylog.out b/scripts/sniffer-tls12-etm-keylog.out new file mode 100644 index 0000000000..a062aef405 --- /dev/null +++ b/scripts/sniffer-tls12-etm-keylog.out @@ -0,0 +1,4 @@ +SSL App Data(31:14):hello wolfssl! +SSL App Data(33:22):I hear you fa shizzle! +SSL App Data(72:14):hello wolfssl! +SSL App Data(74:22):I hear you fa shizzle! diff --git a/scripts/sniffer-tls12-etm-keylog.pcap b/scripts/sniffer-tls12-etm-keylog.pcap new file mode 100644 index 0000000000000000000000000000000000000000..f171eed0c6ef38fb9f5d383032adb136e2c9c979 GIT binary patch literal 16660 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 X$;(JichwTUJ6Cl$8qf~rUGo0|tHRt1 literal 0 HcmV?d00001 diff --git a/scripts/sniffer-tls12-keylog.out b/scripts/sniffer-tls12-keylog.out index ca8c7c774b..7ae22f4064 100644 --- a/scripts/sniffer-tls12-keylog.out +++ b/scripts/sniffer-tls12-keylog.out @@ -1,7 +1,3 @@ -snifftest 5.9.2 -sniffer features: key_callback tls_v13 tls_v12 session_ticket static_ephemeral sni extended_master rsa dh ecc x22519 rsa_static dh_static ssl_keylog_file - -Using packet filter: (ip6 or ip) and tcp and port 11111 SSL App Data(26:14):hello wolfssl! SSL App Data(27:22):I hear you fa shizzle! SSL App Data(58:14):hello wolfssl! diff --git a/scripts/sniffer-tls13-keylog.out b/scripts/sniffer-tls13-keylog.out index 1d86745efc..1ab28a11b7 100644 --- a/scripts/sniffer-tls13-keylog.out +++ b/scripts/sniffer-tls13-keylog.out @@ -1,7 +1,3 @@ -snifftest 5.9.2 -sniffer features: key_callback tls_v13 tls_v12 session_ticket static_ephemeral sni extended_master rsa dh ecc x22519 rsa_static dh_static ssl_keylog_file - -Using packet filter: (ip6 or ip) and tcp and port 11111 SSL App Data(22:14):hello wolfssl! SSL App Data(24:22):I hear you fa shizzle! SSL App Data(50:14):hello wolfssl! diff --git a/src/sniffer.c b/src/sniffer.c index 4cde1a6c1e..84eeec76e1 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -378,6 +378,7 @@ static const char* const msgTable[] = /* 99 */ "Invalid or missing keylog file", + "Encrypt-Then-MAC not supported in this build", }; @@ -467,6 +468,9 @@ typedef struct Flags { #endif byte gotFinished; /* processed finished */ byte secRenegEn; /* secure renegotiation enabled */ +#if !defined(HAVE_ENCRYPT_THEN_MAC) || defined(WOLFSSL_AEAD_ONLY) + byte etmUnsupported; /* peer negotiated RFC 7366, we cannot */ +#endif #ifdef WOLFSSL_ASYNC_CRYPT byte wasPolled; #endif @@ -2498,6 +2502,25 @@ static void FreeSetupKeysArgs(WOLFSSL* ssl, void* pArgs) } /* Process Keys */ +#if !defined(HAVE_ENCRYPT_THEN_MAC) || defined(WOLFSSL_AEAD_ONLY) +/* RFC 7366 only covers block ciphers and a peer must not negotiate it for an + * AEAD or stream suite, so a session that asked for it is still readable here + * unless the negotiated suite turns out to be a block cipher. + returns 0 on success, WOLFSSL_FATAL_ERROR on a suite this build cannot read + */ +static int CheckEncryptThenMac(SnifferSession* session, char* error) +{ + if (session->flags.etmUnsupported && + session->sslServer->specs.cipher_type == block) { + SetError(ETM_NOT_SUPPORTED_STR, error, session, FATAL_ERROR_STATE); + session->verboseErr = 1; + return WOLFSSL_FATAL_ERROR; + } + + return 0; +} +#endif + static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, char* error, KeyShareInfo* ksInfo) { @@ -3230,6 +3253,12 @@ static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, ret = WOLFSSL_FATAL_ERROR; break; } + #if !defined(HAVE_ENCRYPT_THEN_MAC) || defined(WOLFSSL_AEAD_ONLY) + if (CheckEncryptThenMac(session, error) != 0) { + ret = WOLFSSL_FATAL_ERROR; break; + } + #endif + #ifdef WOLFSSL_TLS13 /* TLS v1.3 derive handshake key */ if (IsAtLeastTLSv1_3(session->sslServer->version)) { @@ -3678,6 +3707,11 @@ static int DoResume(SnifferSession* session, char* error) return WOLFSSL_FATAL_ERROR; } +#if !defined(HAVE_ENCRYPT_THEN_MAC) || defined(WOLFSSL_AEAD_ONLY) + if (CheckEncryptThenMac(session, error) != 0) + return WOLFSSL_FATAL_ERROR; +#endif + #ifdef WOLFSSL_TLS13 if (IsAtLeastTLSv1_3(session->sslServer->version)) { #ifdef HAVE_SESSION_TICKET @@ -3823,6 +3857,20 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, return WOLFSSL_FATAL_ERROR; } + /* Encrypt-Then-MAC has to be re-negotiated in every ServerHello, so drop + * any earlier decision before parsing this one. Only the negotiated value + * is recorded here: it governs the records protected by the cipher spec + * this ServerHello is negotiating, and the ones still in flight under the + * previous one have to keep the decision they were made with. It is + * applied in ProcessMessage() when that cipher spec is switched to, the + * same point at which the library applies it. */ +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + session->sslServer->options.encThenMac = 0; + session->sslClient->options.encThenMac = 0; +#else + session->flags.etmUnsupported = 0; +#endif + /* extensions */ if ((initialBytes - *sslBytes) < msgSz) { word16 len; @@ -3936,10 +3984,24 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, break; #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) case EXT_ENCRYPT_THEN_MAC: + /* RFC 7366 requires empty extension_data in the ServerHello. */ + if (extLen != 0) { + SetError(SERVER_HELLO_INPUT_STR, error, session, + FATAL_ERROR_STATE); + return WOLFSSL_FATAL_ERROR; + } /* MAC covers the ciphertext, so it has to be stripped before * the record is decrypted. */ - session->sslServer->options.startedETMRead = 1; - session->sslClient->options.startedETMRead = 1; + session->sslServer->options.encThenMac = 1; + session->sslClient->options.encThenMac = 1; + break; + #else + case EXT_ENCRYPT_THEN_MAC: + /* The session negotiated RFC 7366, but this build cannot + * strip the MAC ahead of decryption. Only a block cipher + * suite is actually unreadable, so the complaint waits until + * the suite is known. */ + session->flags.etmUnsupported = 1; break; #endif case EXT_MASTER_SECRET: @@ -4069,8 +4131,10 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, return ret; } #endif - SetError(KEY_MISMATCH_STR, error, session, FATAL_ERROR_STATE); - session->verboseErr = 1; + if (!session->verboseErr) { + SetError(KEY_MISMATCH_STR, error, session, FATAL_ERROR_STATE); + session->verboseErr = 1; + } return ret; } @@ -4890,7 +4954,7 @@ static int DoHandShake(const byte* input, int* sslBytes, if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) return ret; #endif - if (ret != 0) { + if (ret != 0 && !session->verboseErr) { SetError(KEY_MISMATCH_STR, error, session, FATAL_ERROR_STATE); session->verboseErr = 1; } @@ -6462,6 +6526,7 @@ static int ProcessMessage(const byte* sslFrame, SnifferSession* session, WOLFSSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ? session->sslServer : session->sslClient; doMessage: + decrypted = 0; notEnough = 0; rhSize = 0; @@ -6512,6 +6577,11 @@ doMessage: session->flags.clientCipherOn = 1; session->sslClient->options.handShakeState = HANDSHAKE_DONE; session->sslClient->options.handShakeDone = 1; +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + /* The ChangeCipherSpec that would have applied it was missed too. */ + session->sslClient->options.startedETMRead = + session->sslClient->options.encThenMac; +#endif } /* decrypt if needed */ @@ -6537,8 +6607,10 @@ doMessage: sslFrame = DecryptMessage(ssl, sslFrame, rhSize, ssl->buffers.outputBuffer.buffer, &errCode, &ivAdvance, &rh); - recordEnd = sslFrame - ivAdvance + rhSize; /* sslFrame moved so - should recordEnd */ + if (sslFrame != NULL) { + /* sslFrame moved so should recordEnd */ + recordEnd = sslFrame - ivAdvance + rhSize; + } decrypted = 1; #ifdef WOLFSSL_SNIFFER_STATS @@ -6605,6 +6677,12 @@ doPart: else session->flags.clientCipherOn = 1; Trace(GOT_CHANGE_CIPHER_STR); +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + /* The records this side sends from here on are protected by the + cipher spec whose Encrypt-Then-MAC decision the last ServerHello + carried, so it only takes effect now. */ + ssl->options.startedETMRead = ssl->options.encThenMac; +#endif ssl->options.handShakeState = HANDSHAKE_DONE; ssl->options.handShakeDone = 1; @@ -6638,8 +6716,11 @@ doPart: /* padSz covers the AEAD tag or record MAC, any block * padding and the TLS 1.3 inner content type, matching what - * the non-sniffer read path removes from ssl->curSize. */ - ret -= (int)ssl->keys.padSz; + * the non-sniffer read path removes from ssl->curSize. + * Only valid when this record went through + * DecryptMessage(), as in the handshake case above. */ + if (decrypted) + ret -= (int)ssl->keys.padSz; TraceGotData(ret); if (ret > 0) { /* may be blank message */ @@ -6670,7 +6751,9 @@ doPart: int stored; buf = ssl->buffers.clearOutputBuffer.buffer; - bufSz = ssl->buffers.clearOutputBuffer.length; + /* Same corrected extent the sibling branch + * copies, not the raw record size. */ + bufSz = (word32)ret; do { stored = StoreDataCb(buf, bufSz, offset, ctx); diff --git a/sslSniffer/sslSnifferTest/snifftest.c b/sslSniffer/sslSnifferTest/snifftest.c index 7c3c1295ba..7713f28acc 100644 --- a/sslSniffer/sslSnifferTest/snifftest.c +++ b/sslSniffer/sslSnifferTest/snifftest.c @@ -170,7 +170,6 @@ static pcap_t* pcap = NULL; static pcap_if_t* alldevs = NULL; static struct bpf_program pcap_fp; static const char *traceFile = "./tracefile.txt"; -static int sawDecryptedData = 0; static void FreeAll(void) { @@ -315,13 +314,19 @@ static int myWatchCb(void* vSniffer, #ifdef WOLFSSL_SNIFFER_STORE_DATA_CB +typedef struct StoreDataCtx { + byte* data; /* plaintext of every record decoded from one packet */ + word32 len; /* bytes stored so far */ +} StoreDataCtx; + static int myStoreDataCb(const unsigned char* decryptBuf, unsigned int decryptBufSz, unsigned int decryptBufOffset, void* ctx) { - byte** data = (byte**)ctx; - unsigned int qty; + StoreDataCtx* store = (StoreDataCtx*)ctx; + unsigned int qty; + byte* tmpData; - if (data == NULL) + if (store == NULL) return -1; if (decryptBufSz < decryptBufOffset) @@ -329,21 +334,28 @@ static int myStoreDataCb(const unsigned char* decryptBuf, qty = min(decryptBufSz - decryptBufOffset, STORE_DATA_BLOCK_SZ); - if (*data == NULL) { - byte* tmpData; - tmpData = (byte*)XREALLOC(*data, decryptBufSz + 1, - NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (tmpData == NULL) { - XFREE(*data, NULL, DYNAMIC_TYPE_TMP_BUFFER); - *data = NULL; - return -1; - } - *data = tmpData; + /* One packet can carry several records, and the offset restarts at zero + * for each of them, so grow for this record and append after the ones + * already stored. The extra byte lets the caller null terminate. */ + tmpData = (byte*)XREALLOC(store->data, store->len + decryptBufSz + 1, + NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (tmpData == NULL) { + XFREE(store->data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + store->data = NULL; + store->len = 0; + return -1; + } + store->data = tmpData; + + XMEMCPY(store->data + store->len + decryptBufOffset, + decryptBuf + decryptBufOffset, qty); + + if (decryptBufOffset + qty == decryptBufSz) { + /* record complete, the next one appends after it */ + store->len += decryptBufSz; } - XMEMCPY(*data + decryptBufOffset, decryptBuf + decryptBufOffset, qty); - - return qty; + return (int)qty; } #endif /* WOLFSSL_SNIFFER_STORE_DATA_CB */ @@ -646,6 +658,7 @@ typedef struct SnifferWorker { char *passwd; int port; int hadBadPacket; /* track if sniffer worker saw bad packet */ + int sawDecryptedData; /* track if sniffer worker decrypted app data */ int unused; int id; int shutdown; @@ -659,6 +672,8 @@ static int ssl_Init_SnifferWorker(SnifferWorker* worker, int port, worker->keyFilesSrc = (char*)keyFilesSrc; worker->passwd = (char*)passwd; worker->port = port; + worker->hadBadPacket = 0; + worker->sawDecryptedData = 0; worker->unused = 0; worker->shutdown = 0; worker ->id = id; @@ -747,7 +762,8 @@ static int SnifferWorkerPacketAdd(SnifferWorker* worker, int lastRet, } #endif /* THREADED_SNIFFTEST */ -static int DecodePacket(byte* packet, int length, int packetNumber, char err[]) +static int DecodePacket(byte* packet, int length, int packetNumber, char err[], + int* sawData) { int ret, j; int hadBadPacket = 0; @@ -756,6 +772,9 @@ static int DecodePacket(byte* packet, int length, int packetNumber, char err[]) void* chain; byte* data = NULL; /* pointer to decrypted data */ SSLInfo sslInfo; +#ifdef WOLFSSL_SNIFFER_STORE_DATA_CB + StoreDataCtx store; +#endif #ifdef WOLFSSL_SNIFFER_CHAIN_INPUT struct iovec chains[CHAIN_INPUT_COUNT]; unsigned int remainder; @@ -778,6 +797,10 @@ static int DecodePacket(byte* packet, int length, int packetNumber, char err[]) chainSz = length; #endif +#ifdef WOLFSSL_SNIFFER_STORE_DATA_CB + XMEMSET(&store, 0, sizeof(store)); +#endif + #if defined(DEBUG_SNIFFER) printf("Packet Number: %d\n", packetNumber); #endif @@ -807,13 +830,15 @@ static int DecodePacket(byte* packet, int length, int packetNumber, char err[]) #elif defined(WOLFSSL_SNIFFER_CHAIN_INPUT) && \ defined(WOLFSSL_SNIFFER_STORE_DATA_CB) ret = ssl_DecodePacketWithChainSessionInfoStoreData(chain, chainSz, - &data, &sslInfo, err); + &store, &sslInfo, err); + data = store.data; #elif defined(WOLFSSL_SNIFFER_CHAIN_INPUT) (void)sslInfo; ret = ssl_DecodePacketWithChain(chain, chainSz, &data, err); #elif defined(WOLFSSL_SNIFFER_STORE_DATA_CB) ret = ssl_DecodePacketWithSessionInfoStoreData(packet, - length, &data, &sslInfo, err); + length, &store, &sslInfo, err); + data = store.data; #else ret = ssl_DecodePacketWithSessionInfo(packet, length, &data, &sslInfo, err); @@ -834,8 +859,7 @@ static int DecodePacket(byte* packet, int length, int packetNumber, char err[]) data[ret] = 0; printf("SSL App Data(%d:%d):%s\n", packetNumber, ret, data); ssl_FreeZeroDecodeBuffer(&data, ret, err); - /* Plain store so worker threads do not race on a counter. */ - sawDecryptedData = 1; + *sawData = 1; } (void)isChain; @@ -874,12 +898,17 @@ static void* snifferWorker(void* arg) int packetNumber; #ifdef WOLFSSL_ASYNC_CRYPT SSLInfo sslInfo; - byte* data; + byte* data = NULL; int queueSz = 0; /* poll hardware and attempt to process items in queue. If * returns > 0 then data pointer has decrypted something */ SnifferAsyncPollQueue(&data, err, &sslInfo, &queueSz); + if (data != NULL) { + /* Recovered here rather than in DecodePacket(), so + * record it. */ + worker->sawDecryptedData = 1; + } if (queueSz >= WOLF_ASYNC_MAX_PENDING) { /* queue full, poll again */ continue; @@ -909,7 +938,8 @@ static void* snifferWorker(void* arg) /* Decode Packet, ret value will indicate whether a * bad packet was encountered */ - ret = DecodePacket(packet, length, packetNumber, err); + ret = DecodePacket(packet, length, packetNumber, err, + &worker->sawDecryptedData); if (ret) { worker->hadBadPacket = 1; } @@ -957,6 +987,8 @@ int main(int argc, char** argv) int hadBadPacket = 0; int inum = 0; int saveFile = 0; + int expectData = 0; + int sawDecryptedData = 0; int i = 0, defDev = 0; int packetNumber = 0; int frame = ETHER_IF_FRAME_LEN; @@ -1011,6 +1043,9 @@ int main(int argc, char** argv) else if (strcmp(argv[i], "-tracefile") == 0 && i + 1 < argc) { traceFile = argv[++i]; } + else if (strcmp(argv[i], "-expectdata") == 0) { + expectData = 1; + } #if defined(WOLFSSL_SNIFFER_KEYLOGFILE) else if (strcmp(argv[i], "-keylogfile") == 0 && i + 1 < argc) { sslKeyLogFile = argv[++i]; @@ -1034,7 +1069,10 @@ int main(int argc, char** argv) #if defined(THREADED_SNIFFTEST) " [-threads threads_arg]" #endif /* THREADED_SNIFFTEST */ + " [-expectdata]" "\n", argv[0]); + fprintf(stderr, "-expectdata exits non-zero if no application" + " data could be decrypted.\n"); exit(EXIT_FAILURE); } } @@ -1301,6 +1339,10 @@ int main(int argc, char** argv) /* poll hardware and attempt to process items in queue. If returns > 0 * then data pointer has decrypted something */ SnifferAsyncPollQueue(&data, err, &sslInfo, &queueSz); + if (data != NULL) { + /* Recovered here rather than in DecodePacket(), so record it. */ + sawDecryptedData = 1; + } if (queueSz >= WOLF_ASYNC_MAX_PENDING) { /* queue full, poll again */ continue; @@ -1364,7 +1406,8 @@ int main(int argc, char** argv) #else /* Decode Packet, ret value will indicate whether a * bad packet was encountered */ - if (DecodePacket((byte*)packet, header->caplen, packetNumber, err)) + if (DecodePacket((byte*)packet, header->caplen, packetNumber, err, + &sawDecryptedData)) hadBadPacket = 1; #endif } @@ -1392,15 +1435,20 @@ int main(int argc, char** argv) if (workers[i].hadBadPacket) { hadBadPacket = 1; } + if (workers[i].sawDecryptedData) { + sawDecryptedData = 1; + } ssl_Free_SnifferWorker(&workers[i]); } #endif FreeAll(); - /* A capture file that yields no plaintext has tested nothing. */ - if (saveFile && !sawDecryptedData) { - printf("No application data was decrypted from %s\n", pcapFile); + /* Asked for, because a capture that yields no plaintext has tested + * nothing. Off by default so a handshake-only capture still exits 0. */ + if (expectData && !sawDecryptedData) { + fprintf(stderr, "No application data was decrypted from %s\n", + saveFile ? pcapFile : "the capture device"); hadBadPacket = 1; } diff --git a/wolfssl/sniffer_error.h b/wolfssl/sniffer_error.h index a5c5bc539c..30d5266319 100644 --- a/wolfssl/sniffer_error.h +++ b/wolfssl/sniffer_error.h @@ -144,6 +144,7 @@ #define KEY_MISMATCH_STR 98 #define KEYLOG_FILE_INVALID 99 +#define ETM_NOT_SUPPORTED_STR 100 /* !!!! also add to msgTable in sniffer.c and .rc file !!!! */ diff --git a/wolfssl/sniffer_error.rc b/wolfssl/sniffer_error.rc index dca40db807..dfe56736cf 100644 --- a/wolfssl/sniffer_error.rc +++ b/wolfssl/sniffer_error.rc @@ -120,4 +120,5 @@ STRINGTABLE 98, "Server Client Key Mismatch" 99, "Invalid or missing keylog file" + 100, "Encrypt-Then-MAC not supported in this build" }