mirror of https://github.com/wolfSSL/wolfssl.git
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.pull/11319/head
parent
6a35183ab6
commit
960551cee0
|
|
@ -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"]},
|
||||
|
|
|
|||
25
ChangeLog.md
25
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
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 <cipher> [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"
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -59,12 +59,40 @@ has_static_rsa=no
|
|||
if [ $? -eq 0 ]; then
|
||||
has_static_rsa=yes
|
||||
fi
|
||||
# The TLS v1.2 CBC captures negotiated Encrypt-Then-MAC, so a sniffer built
|
||||
# without it cannot decrypt them.
|
||||
# sniffer-tls12-etm.pcap negotiated Encrypt-Then-MAC, so a sniffer built
|
||||
# without it cannot decrypt that capture. Every other capture is readable by
|
||||
# any build.
|
||||
has_etm=no
|
||||
./sslSniffer/sslSnifferTest/snifftest -? 2>&1 | 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
|
||||
|
|
|
|||
|
|
@ -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!
|
||||
Binary file not shown.
|
|
@ -0,0 +1,4 @@
|
|||
CLIENT_RANDOM 1810f69efd4315a092b03fc144a074df135ea6f2e0496206a0d374972abb39c9 7feab4a2632cd6b8ac603477c08d1b95e6d8bc7a5663d96ce6565b7cd95b2660ced0c8ce17159b79bfaad88ec585eebe
|
||||
CLIENT_RANDOM 1810f69efd4315a092b03fc144a074df135ea6f2e0496206a0d374972abb39c9 7feab4a2632cd6b8ac603477c08d1b95e6d8bc7a5663d96ce6565b7cd95b2660ced0c8ce17159b79bfaad88ec585eebe
|
||||
CLIENT_RANDOM f723e474965ef1d1c43e7040f293075d384c03d963b2904df65d54fb381ae5ea 4ee9a02ef5abecfdd9f5ff8d92276c91ba67e0d5bbacf849e2eb70058dd62c1749961cad9cb29ee45f63d922f0c095ea
|
||||
CLIENT_RANDOM f723e474965ef1d1c43e7040f293075d384c03d963b2904df65d54fb381ae5ea 4ee9a02ef5abecfdd9f5ff8d92276c91ba67e0d5bbacf849e2eb70058dd62c1749961cad9cb29ee45f63d922f0c095ea
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
SSL App Data(29:14):hello wolfssl!
|
||||
SSL App Data(31:22):I hear you fa shizzle!
|
||||
SSL App Data(68:14):hello wolfssl!
|
||||
SSL App Data(70:22):I hear you fa shizzle!
|
||||
Binary file not shown.
|
|
@ -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!
|
||||
|
|
|
|||
|
|
@ -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!
|
||||
|
|
|
|||
103
src/sniffer.c
103
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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 !!!! */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue