Merge pull request #6717 from bigbrett/sniffer-keylogfile
sniffer keylog file support
This commit is contained in:
commit
3033371abc
12
configure.ac
12
configure.ac
@ -1324,6 +1324,17 @@ then
|
|||||||
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DTLS_MTU"
|
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DTLS_MTU"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# KeyLog file export
|
||||||
|
AC_ARG_ENABLE([keylog-export],
|
||||||
|
[AS_HELP_STRING([--enable-keylog-export],[Enable (DANGEROUS INSECURE) exporting TLS secrets to an NSS keylog file (default: disabled)])],
|
||||||
|
[ ENABLED_KEYLOG_EXPORT=$enableval ],
|
||||||
|
[ ENABLED_KEYLOG_EXPORT=no ]
|
||||||
|
)
|
||||||
|
if test "$ENABLED_KEYLOG_EXPORT" = "yes"
|
||||||
|
then
|
||||||
|
AM_CFLAGS="$AM_CFLAGS -DSHOW_SECRETS -DHAVE_SECRET_CALLBACK -DWOLFSSL_SSLKEYLOGFILE"
|
||||||
|
fi
|
||||||
|
|
||||||
# TLS v1.3 Draft 18 (Note: only final TLS v1.3 supported, here for backwards build compatibility)
|
# TLS v1.3 Draft 18 (Note: only final TLS v1.3 supported, here for backwards build compatibility)
|
||||||
AC_ARG_ENABLE([tls13-draft18],
|
AC_ARG_ENABLE([tls13-draft18],
|
||||||
[AS_HELP_STRING([--enable-tls13-draft18],[Enable wolfSSL TLS v1.3 Draft 18 (default: disabled)])],
|
[AS_HELP_STRING([--enable-tls13-draft18],[Enable wolfSSL TLS v1.3 Draft 18 (default: disabled)])],
|
||||||
@ -9449,6 +9460,7 @@ echo " * PSA: $ENABLED_PSA"
|
|||||||
echo " * System CA certs: $ENABLED_SYS_CA_CERTS"
|
echo " * System CA certs: $ENABLED_SYS_CA_CERTS"
|
||||||
echo " * ERR Queues per Thread: $ENABLED_ERRORQUEUEPERTHREAD"
|
echo " * ERR Queues per Thread: $ENABLED_ERRORQUEUEPERTHREAD"
|
||||||
echo " * rwlock: $ENABLED_RWLOCK"
|
echo " * rwlock: $ENABLED_RWLOCK"
|
||||||
|
echo " * keylog export: $ENABLED_KEYLOG_EXPORT"
|
||||||
echo ""
|
echo ""
|
||||||
echo "---"
|
echo "---"
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ run_sequence() {
|
|||||||
run_test "TLS13-AES128-GCM-SHA256" "-v 4" "-v 4"
|
run_test "TLS13-AES128-GCM-SHA256" "-v 4" "-v 4"
|
||||||
run_test "TLS13-AES256-GCM-SHA384" "-v 4" "-v 4"
|
run_test "TLS13-AES256-GCM-SHA384" "-v 4" "-v 4"
|
||||||
run_test "TLS13-CHACHA20-POLY1305-SHA256" "-v 4" "-v 4"
|
run_test "TLS13-CHACHA20-POLY1305-SHA256" "-v 4" "-v 4"
|
||||||
elif [ "$1" == "tls12" ]; then # TLS v1.2
|
elif [ "$1" == "tls12" ] || [ "$1" == "tls12-keylog" ]; then # TLS v1.2
|
||||||
run_test "ECDHE-ECDSA-AES128-GCM-SHA256" "-v 3 -A ./certs/ca-ecc-cert.pem -k ./certs/ecc-key.pem -c ./certs/intermediate/server-chain-ecc.pem -V" "-v 3 -A ./certs/ca-ecc-cert.pem -k ./certs/ecc-client-key.pem -c ./certs/intermediate/client-chain-ecc.pem -C"
|
run_test "ECDHE-ECDSA-AES128-GCM-SHA256" "-v 3 -A ./certs/ca-ecc-cert.pem -k ./certs/ecc-key.pem -c ./certs/intermediate/server-chain-ecc.pem -V" "-v 3 -A ./certs/ca-ecc-cert.pem -k ./certs/ecc-client-key.pem -c ./certs/intermediate/client-chain-ecc.pem -C"
|
||||||
run_test "ECDHE-ECDSA-AES256-GCM-SHA384" "-v 3 -A ./certs/ca-ecc-cert.pem -k ./certs/ecc-key.pem -c ./certs/intermediate/server-chain-ecc.pem -V" "-v 3 -A ./certs/ca-ecc-cert.pem -k ./certs/ecc-client-key.pem -c ./certs/intermediate/client-chain-ecc.pem -C"
|
run_test "ECDHE-ECDSA-AES256-GCM-SHA384" "-v 3 -A ./certs/ca-ecc-cert.pem -k ./certs/ecc-key.pem -c ./certs/intermediate/server-chain-ecc.pem -V" "-v 3 -A ./certs/ca-ecc-cert.pem -k ./certs/ecc-client-key.pem -c ./certs/intermediate/client-chain-ecc.pem -C"
|
||||||
elif [ "$1" == "tls13-dh-resume" ] || [ "$1" == "tls13-ecc-resume" ]; then # TLS v1.3 Resumption
|
elif [ "$1" == "tls13-dh-resume" ] || [ "$1" == "tls13-ecc-resume" ]; then # TLS v1.3 Resumption
|
||||||
@ -69,19 +69,37 @@ run_sequence() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
run_capture(){
|
|
||||||
|
run_capture() {
|
||||||
|
local config_flags=()
|
||||||
echo -e "\nconfiguring and building wolfssl ($1)..."
|
echo -e "\nconfiguring and building wolfssl ($1)..."
|
||||||
./configure --enable-sniffer $2 1>/dev/null || exit $?
|
|
||||||
|
# Add default flags
|
||||||
|
config_flags+=(--enable-sniffer)
|
||||||
|
|
||||||
|
# If additional arguments are provided, add them to the array
|
||||||
|
if [ -n "$2" ]; then
|
||||||
|
# Convert string into an array, respecting quoted strings as a single element
|
||||||
|
eval "config_flags+=($2)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
./configure "${config_flags[@]}" 1>/dev/null || exit $?
|
||||||
make 1>/dev/null || exit $?
|
make 1>/dev/null || exit $?
|
||||||
|
|
||||||
echo "starting capture"
|
echo "starting capture"
|
||||||
tcpdump -i lo -n port 11111 -w ./scripts/sniffer-${1}.pcap -U &
|
tcpdump -i lo -n port 11111 -w ./scripts/sniffer-${1}.pcap -U &
|
||||||
tcpdump_pid=$!
|
tcpdump_pid=$!
|
||||||
run_sequence $1
|
run_sequence $1
|
||||||
sleep 1
|
sleep 1
|
||||||
kill -15 $tcpdump_pid; tcpdump_pid=0
|
kill -15 $tcpdump_pid; tcpdump_pid=0
|
||||||
|
|
||||||
|
if [ "$1" == "tls12-keylog" ]; then
|
||||||
|
cp ./sslkeylog.log ./scripts/sniffer-${1}.sslkeylog
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
run_capture "tls12" ""
|
run_capture "tls12" ""
|
||||||
|
run_capture "tls12-keylog" "--enable-enc-then-mac=no --enable-keylog-export CFLAGS='-Wno-cpp -DWOLFSSL_SNIFFER_KEYLOGFILE'"
|
||||||
run_capture "tls13-ecc" ""
|
run_capture "tls13-ecc" ""
|
||||||
run_capture "tls13-ecc-resume" "--enable-session-ticket"
|
run_capture "tls13-ecc-resume" "--enable-session-ticket"
|
||||||
run_capture "tls13-dh" "--disable-ecc"
|
run_capture "tls13-dh" "--disable-ecc"
|
||||||
|
@ -59,6 +59,12 @@ has_static_rsa=no
|
|||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
has_static_rsa=yes
|
has_static_rsa=yes
|
||||||
fi
|
fi
|
||||||
|
# ./configure --enable-sniffer CFLAGS="-DWOLFSSL_SNIFFER_KEYLOGFILE"
|
||||||
|
has_keylog=no
|
||||||
|
./sslSniffer/sslSnifferTest/snifftest -? 2>&1 | grep -- 'ssl_keylog_file'
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
has_keylog=yes
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
RESULT=0
|
RESULT=0
|
||||||
@ -66,8 +72,8 @@ RESULT=0
|
|||||||
# TLS v1.2 Static RSA Test
|
# TLS v1.2 Static RSA Test
|
||||||
if test $RESULT -eq 0 && test $has_rsa == yes && test $has_tlsv12 == yes && test $has_static_rsa == yes
|
if test $RESULT -eq 0 && test $has_rsa == yes && test $has_tlsv12 == yes && test $has_static_rsa == yes
|
||||||
then
|
then
|
||||||
echo -e "\nStaring snifftest on testsuite.pcap...\n"
|
echo -e "\nStaring snifftest on sniffer-static-rsa.pcap...\n"
|
||||||
./sslSniffer/sslSnifferTest/snifftest ./scripts/sniffer-static-rsa.pcap ./certs/server-key.pem 127.0.0.1 11111
|
./sslSniffer/sslSnifferTest/snifftest -pcap ./scripts/sniffer-static-rsa.pcap -key ./certs/server-key.pem -server 127.0.0.1 -port 11111
|
||||||
|
|
||||||
RESULT=$?
|
RESULT=$?
|
||||||
[ $RESULT -ne 0 ] && echo -e "\nsnifftest static RSA failed\n" && exit 1
|
[ $RESULT -ne 0 ] && echo -e "\nsnifftest static RSA failed\n" && exit 1
|
||||||
@ -77,16 +83,45 @@ fi
|
|||||||
if test $RESULT -eq 0 && test $has_rsa == yes && test $has_tlsv12 == yes && test $has_static_rsa == yes
|
if test $RESULT -eq 0 && test $has_rsa == yes && test $has_tlsv12 == yes && test $has_static_rsa == yes
|
||||||
then
|
then
|
||||||
echo -e "\nStaring snifftest on sniffer-ipv6.pcap...\n"
|
echo -e "\nStaring snifftest on sniffer-ipv6.pcap...\n"
|
||||||
./sslSniffer/sslSnifferTest/snifftest ./scripts/sniffer-ipv6.pcap ./certs/server-key.pem ::1 11111
|
./sslSniffer/sslSnifferTest/snifftest -pcap ./scripts/sniffer-ipv6.pcap -key ./certs/server-key.pem -server ::1 -port 11111
|
||||||
|
|
||||||
RESULT=$?
|
RESULT=$?
|
||||||
[ $RESULT -ne 0 ] && echo -e "\nsnifftest (ipv6) failed\n" && exit 1
|
[ $RESULT -ne 0 ] && echo -e "\nsnifftest (ipv6) failed\n" && exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# TLS v1.2 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`.
|
||||||
|
if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_keylog == yes
|
||||||
|
then
|
||||||
|
echo -e "\nStaring snifftest on sniffer-tls12-keylog.pcap...\n"
|
||||||
|
|
||||||
|
TMPFILE=$(mktemp)
|
||||||
|
RESULT=$?
|
||||||
|
[ $RESULT -ne 0 ] && echo -e "\nsnifftest keylog test failed: unable to create tmpfile\n" && rm $TMPFILE && exit 1
|
||||||
|
|
||||||
|
./sslSniffer/sslSnifferTest/snifftest \
|
||||||
|
-pcap scripts/sniffer-tls12-keylog.pcap \
|
||||||
|
-keylogfile scripts/sniffer-tls12-keylog.sslkeylog \
|
||||||
|
-server 127.0.0.1 -port 11111 > $TMPFILE
|
||||||
|
|
||||||
|
RESULT=$?
|
||||||
|
[ $RESULT -ne 0 ] && echo -e "\nsnifftest keylog test failed: snifftest returned $RESULT\n" && rm $TMPFILE && exit 1
|
||||||
|
|
||||||
|
# sed '1d' strips out first line, which contains wolfSSL version
|
||||||
|
sed '1d' $TMPFILE | diff - <(sed '1d' scripts/sniffer-tls12-keylog.out)
|
||||||
|
|
||||||
|
RESULT=$?
|
||||||
|
[ $RESULT -ne 0 ] && echo -e "\nsnifftest keylog test failed: snifftest diff returned $RESULT\n" && rm $TMPFILE && exit 1
|
||||||
|
|
||||||
|
rm $TMPFILE
|
||||||
|
fi
|
||||||
|
|
||||||
# TLS v1.3 sniffer test ECC
|
# TLS v1.3 sniffer test ECC
|
||||||
if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_ecc == yes
|
if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_ecc == yes
|
||||||
then
|
then
|
||||||
./sslSniffer/sslSnifferTest/snifftest ./scripts/sniffer-tls13-ecc.pcap ./certs/statickeys/ecc-secp256r1.pem 127.0.0.1 11111
|
echo -e "\nStaring 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
|
||||||
|
|
||||||
RESULT=$?
|
RESULT=$?
|
||||||
[ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 ECC failed\n" && exit 1
|
[ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 ECC failed\n" && exit 1
|
||||||
@ -95,7 +130,8 @@ fi
|
|||||||
# TLS v1.3 sniffer test DH
|
# TLS v1.3 sniffer test DH
|
||||||
if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_dh == yes
|
if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_dh == yes
|
||||||
then
|
then
|
||||||
./sslSniffer/sslSnifferTest/snifftest ./scripts/sniffer-tls13-dh.pcap ./certs/statickeys/dh-ffdhe2048.pem 127.0.0.1 11111
|
echo -e "\nStaring 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
|
||||||
|
|
||||||
RESULT=$?
|
RESULT=$?
|
||||||
[ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 DH failed\n" && exit 1
|
[ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 DH failed\n" && exit 1
|
||||||
@ -104,7 +140,8 @@ fi
|
|||||||
# TLS v1.3 sniffer test X25519
|
# TLS v1.3 sniffer test X25519
|
||||||
if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_x25519 == yes
|
if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_x25519 == yes
|
||||||
then
|
then
|
||||||
./sslSniffer/sslSnifferTest/snifftest ./scripts/sniffer-tls13-x25519.pcap ./certs/statickeys/x25519.pem 127.0.0.1 11111
|
echo -e "\nStaring 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
|
||||||
|
|
||||||
RESULT=$?
|
RESULT=$?
|
||||||
[ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 X25519 failed\n" && exit 1
|
[ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 X25519 failed\n" && exit 1
|
||||||
@ -113,7 +150,8 @@ fi
|
|||||||
# TLS v1.3 sniffer test ECC resumption
|
# TLS v1.3 sniffer test ECC resumption
|
||||||
if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_ecc == yes && test $session_ticket == yes
|
if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_ecc == yes && test $session_ticket == yes
|
||||||
then
|
then
|
||||||
./sslSniffer/sslSnifferTest/snifftest ./scripts/sniffer-tls13-ecc-resume.pcap ./certs/statickeys/ecc-secp256r1.pem 127.0.0.1 11111
|
echo -e "\nStaring 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
|
||||||
|
|
||||||
RESULT=$?
|
RESULT=$?
|
||||||
[ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 ECC failed\n" && exit 1
|
[ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 ECC failed\n" && exit 1
|
||||||
@ -122,7 +160,8 @@ fi
|
|||||||
# TLS v1.3 sniffer test DH
|
# TLS v1.3 sniffer test DH
|
||||||
if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_dh == yes && test $session_ticket == yes
|
if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_dh == yes && test $session_ticket == yes
|
||||||
then
|
then
|
||||||
./sslSniffer/sslSnifferTest/snifftest ./scripts/sniffer-tls13-dh-resume.pcap ./certs/statickeys/dh-ffdhe2048.pem 127.0.0.1 11111
|
echo -e "\nStaring 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
|
||||||
|
|
||||||
RESULT=$?
|
RESULT=$?
|
||||||
[ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 DH failed\n" && exit 1
|
[ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 DH failed\n" && exit 1
|
||||||
@ -131,7 +170,8 @@ fi
|
|||||||
# TLS v1.3 sniffer test X25519
|
# TLS v1.3 sniffer test X25519
|
||||||
if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_x25519 == yes && test $session_ticket == yes
|
if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_x25519 == yes && test $session_ticket == yes
|
||||||
then
|
then
|
||||||
./sslSniffer/sslSnifferTest/snifftest ./scripts/sniffer-tls13-x25519-resume.pcap ./certs/statickeys/x25519.pem 127.0.0.1 11111
|
echo -e "\nStaring 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
|
||||||
|
|
||||||
RESULT=$?
|
RESULT=$?
|
||||||
[ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 X25519 failed\n" && exit 1
|
[ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 X25519 failed\n" && exit 1
|
||||||
@ -140,12 +180,12 @@ fi
|
|||||||
# TLS v1.3 sniffer test hello_retry_request (HRR) with ECDHE
|
# TLS v1.3 sniffer test hello_retry_request (HRR) with ECDHE
|
||||||
if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_ecc == yes
|
if test $RESULT -eq 0 && test $has_tlsv13 == yes && test $has_ecc == yes
|
||||||
then
|
then
|
||||||
./sslSniffer/sslSnifferTest/snifftest ./scripts/sniffer-tls13-hrr.pcap ./certs/statickeys/ecc-secp256r1.pem 127.0.0.1 11111
|
echo -e "\nStaring 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
|
||||||
|
|
||||||
RESULT=$?
|
RESULT=$?
|
||||||
[ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 HRR failed\n" && exit 1
|
[ $RESULT -ne 0 ] && echo -e "\nsnifftest TLS v1.3 HRR failed\n" && exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "\nSuccess!\n"
|
echo -e "\nSuccess!\n"
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
7
scripts/sniffer-tls12-keylog.out
Normal file
7
scripts/sniffer-tls12-keylog.out
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
snifftest 5.6.3
|
||||||
|
sniffer features: key_callback tls_v13 tls_v12 static_ephemeral sni extended_master rsa dh ecc rsa_static dh_static ssl_keylog_file
|
||||||
|
|
||||||
|
SSL App Data(26:14):hello wolfssl!
|
||||||
|
SSL App Data(27:22):I hear you fa shizzle!
|
||||||
|
SSL App Data(57:14):hello wolfssl!
|
||||||
|
SSL App Data(58:22):I hear you fa shizzle!
|
BIN
scripts/sniffer-tls12-keylog.pcap
Normal file
BIN
scripts/sniffer-tls12-keylog.pcap
Normal file
Binary file not shown.
12
scripts/sniffer-tls12-keylog.sslkeylog
Normal file
12
scripts/sniffer-tls12-keylog.sslkeylog
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
CLIENT_RANDOM 3827fef5d4172f3753d81661dbc228b41adcb2357e04e493f8d9d4d4a85777d3 5240740265eaa6a8622805728bf53fd88b546b1523e4b9c3d4b6573471bc081ce9f074520df99873c0c447d3a37ebdc6
|
||||||
|
CLIENT_RANDOM 3827fef5d4172f3753d81661dbc228b41adcb2357e04e493f8d9d4d4a85777d3 5240740265eaa6a8622805728bf53fd88b546b1523e4b9c3d4b6573471bc081ce9f074520df99873c0c447d3a37ebdc6
|
||||||
|
CLIENT_RANDOM 8d793a1160661700dc686746be0e77a01dcf94472971bfbb517c6d7d179b7bcd ac612c7b9292ad6bc5304176b9dcde81ee488b6adb63bb6917cbf38a0775e9e334766839e091506972450e77ba6ce977
|
||||||
|
CLIENT_RANDOM 8d793a1160661700dc686746be0e77a01dcf94472971bfbb517c6d7d179b7bcd ac612c7b9292ad6bc5304176b9dcde81ee488b6adb63bb6917cbf38a0775e9e334766839e091506972450e77ba6ce977
|
||||||
|
CLIENT_RANDOM 4a1d3695145e5136a2914756962f848f033b62d3a9b714f7e659ae3f133d2527 118442e0edd05696d1566eb73693a9a1316d24ac62e024f92e685c540eaec31a463e19091d45b63cfc8539d3bd11915b
|
||||||
|
CLIENT_RANDOM 4a1d3695145e5136a2914756962f848f033b62d3a9b714f7e659ae3f133d2527 118442e0edd05696d1566eb73693a9a1316d24ac62e024f92e685c540eaec31a463e19091d45b63cfc8539d3bd11915b
|
||||||
|
CLIENT_RANDOM 307abe19ea84d9b45621df5b89fee8d2f9ac66eb4303cf9303cf6e957ad1d75d dfb9bb0d29579a0b2f35be65982954f33268c30ea8709985a45c95633c1c6e94cbfdebe625bda975572921b4462d5153
|
||||||
|
CLIENT_RANDOM 307abe19ea84d9b45621df5b89fee8d2f9ac66eb4303cf9303cf6e957ad1d75d dfb9bb0d29579a0b2f35be65982954f33268c30ea8709985a45c95633c1c6e94cbfdebe625bda975572921b4462d5153
|
||||||
|
CLIENT_RANDOM 41ad4bceb3b900ffbc77f9b0c67d69a62f2b1d490f91b2af496cf6e78371900d 9752ea66a193ac04e4a20aca3c7160faa2637efb927d00c2a2d90b77e2e7875a760ee76f9ce509e549f8303625a2fd59
|
||||||
|
CLIENT_RANDOM 41ad4bceb3b900ffbc77f9b0c67d69a62f2b1d490f91b2af496cf6e78371900d 9752ea66a193ac04e4a20aca3c7160faa2637efb927d00c2a2d90b77e2e7875a760ee76f9ce509e549f8303625a2fd59
|
||||||
|
CLIENT_RANDOM 596ffcdec477ac0b24e0958ecd7c1fc7cc5b37337bac90803b864e3edbad8780 2f86705d0c4fb7e92c7cb1ef2f104955724d5a0b5abd18478d39c1dd96222b4462e4382982bec26e9a231ec970c2d509
|
||||||
|
CLIENT_RANDOM 596ffcdec477ac0b24e0958ecd7c1fc7cc5b37337bac90803b864e3edbad8780 2f86705d0c4fb7e92c7cb1ef2f104955724d5a0b5abd18478d39c1dd96222b4462e4382982bec26e9a231ec970c2d509
|
@ -7502,7 +7502,7 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_SECRET_CALLBACK) && defined(SHOW_SECRETS) && \
|
#if defined(HAVE_SECRET_CALLBACK) && defined(SHOW_SECRETS) && \
|
||||||
defined(WOLFSSL_SSLKEYLOGFILE)
|
defined(WOLFSSL_SSLKEYLOGFILE) && defined(WOLFSSL_TLS13)
|
||||||
(void)wolfSSL_set_tls13_secret_cb(ssl, tls13ShowSecrets, NULL);
|
(void)wolfSSL_set_tls13_secret_cb(ssl, tls13ShowSecrets, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -17651,7 +17651,7 @@ int ChachaAEADEncrypt(WOLFSSL* ssl, byte* out, const byte* input,
|
|||||||
*
|
*
|
||||||
* Return 0 on success negative values in error case
|
* Return 0 on success negative values in error case
|
||||||
*/
|
*/
|
||||||
static int ChachaAEADDecrypt(WOLFSSL* ssl, byte* plain, const byte* input,
|
int ChachaAEADDecrypt(WOLFSSL* ssl, byte* plain, const byte* input,
|
||||||
word16 sz)
|
word16 sz)
|
||||||
{
|
{
|
||||||
byte add[AEAD_AUTH_DATA_SZ];
|
byte add[AEAD_AUTH_DATA_SZ];
|
||||||
|
473
src/sniffer.c
473
src/sniffer.c
@ -373,6 +373,9 @@ static const char* const msgTable[] =
|
|||||||
"Setting up keys",
|
"Setting up keys",
|
||||||
"Unsupported TLS Version",
|
"Unsupported TLS Version",
|
||||||
"Server Client Key Mismatch",
|
"Server Client Key Mismatch",
|
||||||
|
|
||||||
|
/* 99 */
|
||||||
|
"Invalid or missing keylog file",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -436,6 +439,11 @@ typedef struct SnifferServer {
|
|||||||
NamedKey* namedKeys; /* mapping of names and keys */
|
NamedKey* namedKeys; /* mapping of names and keys */
|
||||||
wolfSSL_Mutex namedKeysMutex; /* mutex for namedKey list */
|
wolfSSL_Mutex namedKeysMutex; /* mutex for namedKey list */
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
|
||||||
|
byte useKeyLogFile; /* True if session secrets are coming from a
|
||||||
|
keylog file */
|
||||||
|
#endif /* WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
|
|
||||||
struct SnifferServer* next; /* for list */
|
struct SnifferServer* next; /* for list */
|
||||||
} SnifferServer;
|
} SnifferServer;
|
||||||
|
|
||||||
@ -652,6 +660,22 @@ static void UpdateMissedDataSessions(void)
|
|||||||
static WOLFSSL_GLOBAL int CryptoDeviceId = INVALID_DEVID;
|
static WOLFSSL_GLOBAL int CryptoDeviceId = INVALID_DEVID;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
|
||||||
|
static int addSecretNode(unsigned char* clientRandom,
|
||||||
|
unsigned char* masterSecret,
|
||||||
|
char* error);
|
||||||
|
static void hexToBin(const char* hex, unsigned char* bin, int binLength);
|
||||||
|
static int parseKeyLogFile(const char* fileName, char* error);
|
||||||
|
static unsigned char* findMasterSecret(unsigned char* clientRandom);
|
||||||
|
static void freeSecretList(void);
|
||||||
|
static int snifferSecretCb(unsigned char* client_random,
|
||||||
|
unsigned char* output_secret);
|
||||||
|
static void setSnifferSecretCb(SnifferSession* session);
|
||||||
|
static int addKeyLogSnifferServerHelper(const char* address,
|
||||||
|
int port,
|
||||||
|
char* error);
|
||||||
|
#endif /* WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
|
|
||||||
|
|
||||||
/* Initialize overall Sniffer */
|
/* Initialize overall Sniffer */
|
||||||
void ssl_InitSniffer_ex(int devId)
|
void ssl_InitSniffer_ex(int devId)
|
||||||
@ -867,8 +891,16 @@ void ssl_FreeSniffer(void)
|
|||||||
}
|
}
|
||||||
ServerList = NULL;
|
ServerList = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
UNLOCK_SESSION();
|
UNLOCK_SESSION();
|
||||||
UNLOCK_SERVER_LIST();
|
UNLOCK_SERVER_LIST();
|
||||||
|
|
||||||
|
#if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
|
||||||
|
freeSecretList();
|
||||||
|
#endif /* WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
|
|
||||||
|
|
||||||
#ifndef WOLFSSL_SNIFFER_NO_RECOVERY
|
#ifndef WOLFSSL_SNIFFER_NO_RECOVERY
|
||||||
wc_FreeMutex(&RecoveryMutex);
|
wc_FreeMutex(&RecoveryMutex);
|
||||||
#endif
|
#endif
|
||||||
@ -1162,8 +1194,14 @@ static void TraceSetServer(const char* srv, int port, const char* keyFile)
|
|||||||
{
|
{
|
||||||
if (TraceOn) {
|
if (TraceOn) {
|
||||||
XFPRINTF(TraceFile, "\tTrying to install a new Sniffer Server with\n");
|
XFPRINTF(TraceFile, "\tTrying to install a new Sniffer Server with\n");
|
||||||
XFPRINTF(TraceFile, "\tserver: %s, port: %d, keyFile: %s\n", srv, port,
|
if (keyFile != NULL) {
|
||||||
keyFile);
|
XFPRINTF(TraceFile, "\tserver: %s, port: %d, keyFile: %s\n",
|
||||||
|
srv, port, keyFile);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
XFPRINTF(TraceFile, "\tserver: %s, port: %d\n",
|
||||||
|
srv, port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1732,6 +1770,7 @@ static int CreateWatchSnifferServer(char* error)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Caller locks ServerListMutex */
|
/* Caller locks ServerListMutex */
|
||||||
static int SetNamedPrivateKey(const char* name, const char* address, int port,
|
static int SetNamedPrivateKey(const char* name, const char* address, int port,
|
||||||
const char* keyFile, int keySz, int typeKey, const char* password,
|
const char* keyFile, int keySz, int typeKey, const char* password,
|
||||||
@ -1780,10 +1819,11 @@ static int SetNamedPrivateKey(const char* name, const char* address, int port,
|
|||||||
if (serverIp.ip4 == XINADDR_NONE) {
|
if (serverIp.ip4 == XINADDR_NONE) {
|
||||||
#ifdef FUSION_RTOS
|
#ifdef FUSION_RTOS
|
||||||
if (XINET_PTON(AF_INET6, address, serverIp.ip6,
|
if (XINET_PTON(AF_INET6, address, serverIp.ip6,
|
||||||
sizeof(serverIp.ip4)) == 1) {
|
sizeof(serverIp.ip4)) == 1)
|
||||||
#else
|
#else
|
||||||
if (XINET_PTON(AF_INET6, address, serverIp.ip6) == 1) {
|
if (XINET_PTON(AF_INET6, address, serverIp.ip6) == 1)
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
serverIp.version = IPV6;
|
serverIp.version = IPV6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2463,6 +2503,17 @@ static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
|
||||||
|
if (session->context->useKeyLogFile) {
|
||||||
|
ret = 0;
|
||||||
|
XMEMSET(args, 0, sizeof(SetupKeysArgs));
|
||||||
|
|
||||||
|
/* We want to skip all the key setup and go right to master secret generation, which is
|
||||||
|
* where we inject the master secret obtained from the keylog file */
|
||||||
|
ssl->options.asyncState = TLS_ASYNC_FINALIZE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
switch (ssl->options.asyncState) {
|
switch (ssl->options.asyncState) {
|
||||||
case TLS_ASYNC_BEGIN:
|
case TLS_ASYNC_BEGIN:
|
||||||
{
|
{
|
||||||
@ -3084,12 +3135,17 @@ static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session,
|
|||||||
|
|
||||||
case TLS_ASYNC_FINALIZE:
|
case TLS_ASYNC_FINALIZE:
|
||||||
{
|
{
|
||||||
/* store for client side as well */
|
#if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
|
||||||
XMEMCPY(session->sslClient->arrays->preMasterSecret,
|
if (!session->context->useKeyLogFile)
|
||||||
session->sslServer->arrays->preMasterSecret,
|
#endif /* !WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
session->sslServer->arrays->preMasterSz);
|
{
|
||||||
session->sslClient->arrays->preMasterSz =
|
/* store for client side as well */
|
||||||
session->sslServer->arrays->preMasterSz;
|
XMEMCPY(session->sslClient->arrays->preMasterSecret,
|
||||||
|
session->sslServer->arrays->preMasterSecret,
|
||||||
|
session->sslServer->arrays->preMasterSz);
|
||||||
|
session->sslClient->arrays->preMasterSz =
|
||||||
|
session->sslServer->arrays->preMasterSz;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SHOW_SECRETS
|
#ifdef SHOW_SECRETS
|
||||||
PrintSecret("pre master secret",
|
PrintSecret("pre master secret",
|
||||||
@ -4556,14 +4612,21 @@ static int DoHandShake(const byte* input, int* sslBytes,
|
|||||||
Trace(GOT_CERT_REQ_STR);
|
Trace(GOT_CERT_REQ_STR);
|
||||||
break;
|
break;
|
||||||
case server_key_exchange:
|
case server_key_exchange:
|
||||||
#ifdef WOLFSSL_SNIFFER_STATS
|
|
||||||
INC_STAT(SnifferStats.sslEphemeralMisses);
|
|
||||||
#endif
|
|
||||||
Trace(GOT_SERVER_KEY_EX_STR);
|
Trace(GOT_SERVER_KEY_EX_STR);
|
||||||
/* can't know temp key passively */
|
|
||||||
SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
|
#if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
|
||||||
session->verboseErr = 1;
|
if (!session->context->useKeyLogFile)
|
||||||
ret = -1;
|
#endif /* WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
|
{
|
||||||
|
/* can't know temp key passively */
|
||||||
|
SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
|
||||||
|
session->verboseErr = 1;
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
|
#if defined(WOLFSSL_SNIFFER_STATS)
|
||||||
|
INC_STAT(SnifferStats.sslEphemeralMisses);
|
||||||
|
#endif /* WOLFSSL_SNIFFER_STATS */
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case encrypted_extensions:
|
case encrypted_extensions:
|
||||||
Trace(GOT_ENC_EXT_STR);
|
Trace(GOT_ENC_EXT_STR);
|
||||||
@ -4720,6 +4783,8 @@ static int DecryptDo(WOLFSSL* ssl, byte* plain, const byte* input,
|
|||||||
case wolfssl_aes_gcm:
|
case wolfssl_aes_gcm:
|
||||||
case wolfssl_aes_ccm: /* GCM AEAD macros use same size as CCM */
|
case wolfssl_aes_ccm: /* GCM AEAD macros use same size as CCM */
|
||||||
{
|
{
|
||||||
|
/* For ciphers that use AEAD use the encrypt routine to
|
||||||
|
* bypass the auth tag checking */
|
||||||
wc_AesAuthEncryptFunc aes_auth_fn;
|
wc_AesAuthEncryptFunc aes_auth_fn;
|
||||||
|
|
||||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||||
@ -4749,7 +4814,7 @@ static int DecryptDo(WOLFSSL* ssl, byte* plain, const byte* input,
|
|||||||
input + AESGCM_EXP_IV_SZ,
|
input + AESGCM_EXP_IV_SZ,
|
||||||
sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size,
|
sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size,
|
||||||
ssl->decrypt.nonce, AESGCM_NONCE_SZ,
|
ssl->decrypt.nonce, AESGCM_NONCE_SZ,
|
||||||
ssl->decrypt.additional, ssl->specs.aead_mac_size,
|
ssl->decrypt.additional, AEAD_AUTH_DATA_SZ,
|
||||||
NULL, 0)) < 0) {
|
NULL, 0)) < 0) {
|
||||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||||
if (ret == WC_PENDING_E) {
|
if (ret == WC_PENDING_E) {
|
||||||
@ -4782,7 +4847,7 @@ static int DecryptDo(WOLFSSL* ssl, byte* plain, const byte* input,
|
|||||||
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && \
|
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && \
|
||||||
!defined(NO_CHAPOL_AEAD)
|
!defined(NO_CHAPOL_AEAD)
|
||||||
case wolfssl_chacha:
|
case wolfssl_chacha:
|
||||||
ret = ChachaAEADEncrypt(ssl, plain, input, sz);
|
ret = ChachaAEADDecrypt(ssl, plain, input, sz);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -5122,6 +5187,13 @@ static SnifferSession* CreateSession(IpInfo* ipInfo, TcpInfo* tcpInfo,
|
|||||||
/* put server back into server mode */
|
/* put server back into server mode */
|
||||||
session->sslServer->options.side = WOLFSSL_SERVER_END;
|
session->sslServer->options.side = WOLFSSL_SERVER_END;
|
||||||
|
|
||||||
|
#if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
|
||||||
|
if (session->context->useKeyLogFile) {
|
||||||
|
setSnifferSecretCb(session);
|
||||||
|
}
|
||||||
|
#endif /* WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
|
|
||||||
|
|
||||||
row = SessionHash(ipInfo, tcpInfo);
|
row = SessionHash(ipInfo, tcpInfo);
|
||||||
|
|
||||||
/* add it to the session table */
|
/* add it to the session table */
|
||||||
@ -6492,10 +6564,10 @@ static int RemoveFatalSession(IpInfo* ipInfo, TcpInfo* tcpInfo,
|
|||||||
SnifferSession* session, char* error)
|
SnifferSession* session, char* error)
|
||||||
{
|
{
|
||||||
if (session && session->flags.fatalError == FATAL_ERROR_STATE) {
|
if (session && session->flags.fatalError == FATAL_ERROR_STATE) {
|
||||||
RemoveSession(session, ipInfo, tcpInfo, 0);
|
|
||||||
if (!session->verboseErr) {
|
if (!session->verboseErr) {
|
||||||
SetError(FATAL_ERROR_STR, error, NULL, 0);
|
SetError(FATAL_ERROR_STR, error, NULL, 0);
|
||||||
}
|
}
|
||||||
|
RemoveSession(session, ipInfo, tcpInfo, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -7132,6 +7204,367 @@ int ssl_PollSniffer(WOLF_EVENT** events, int maxEvents, WOLF_EVENT_FLAG flags,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
|
||||||
|
|
||||||
|
#define CLIENT_RANDOM_LABEL_LENGTH 13
|
||||||
|
#define CLIENT_RANDOM_LENGTH 32
|
||||||
|
#define MASTER_SECRET_LENGTH 48
|
||||||
|
#define CLIENT_RANDOM_BITS ((CLIENT_RANDOM_LENGTH) * 8)
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct SecretNode {
|
||||||
|
unsigned char clientRandom[CLIENT_RANDOM_LENGTH];
|
||||||
|
unsigned char masterSecret[MASTER_SECRET_LENGTH];
|
||||||
|
struct SecretNode* next;
|
||||||
|
} SecretNode;
|
||||||
|
|
||||||
|
|
||||||
|
/* Default to the same size hash table as the session table,
|
||||||
|
* but allow user to override */
|
||||||
|
#ifndef WOLFSSL_SNIFFER_KEYLOGFILE_HASH_TABLE_SIZE
|
||||||
|
#define WOLFSSL_SNIFFER_KEYLOGFILE_HASH_TABLE_SIZE HASH_SIZE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static THREAD_LS_T WOLFSSL_GLOBAL
|
||||||
|
SecretNode*
|
||||||
|
secretHashTable[WOLFSSL_SNIFFER_KEYLOGFILE_HASH_TABLE_SIZE] = {NULL};
|
||||||
|
#ifndef HAVE_C___ATOMIC
|
||||||
|
static WOLFSSL_GLOBAL wolfSSL_Mutex secretListMutex;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned int secretHashFunction(unsigned char* clientRandom);
|
||||||
|
|
||||||
|
#ifdef HAVE_C___ATOMIC
|
||||||
|
#define LOCK_SECRET_LIST() WC_DO_NOTHING
|
||||||
|
#define UNLOCK_SECRET_LIST() WC_DO_NOTHING
|
||||||
|
#else
|
||||||
|
#define LOCK_SECRET_LIST() wc_LockMutex(&secretListMutex)
|
||||||
|
#define UNLOCK_SECRET_LIST() wc_UnLockMutex(&secretListMutex)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic polynomial hash function that maps a 32-byte client random value to an
|
||||||
|
* array index
|
||||||
|
*/
|
||||||
|
static unsigned int secretHashFunction(unsigned char* clientRandom)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
unsigned int hash = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < CLIENT_RANDOM_LENGTH; i++) {
|
||||||
|
hash = (hash * CLIENT_RANDOM_BITS + clientRandom[i])
|
||||||
|
% WOLFSSL_SNIFFER_KEYLOGFILE_HASH_TABLE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int addSecretNode(unsigned char* clientRandom,
|
||||||
|
unsigned char* masterSecret,
|
||||||
|
char* error)
|
||||||
|
{
|
||||||
|
unsigned int index = 0;
|
||||||
|
SecretNode* newSecretNode = NULL;
|
||||||
|
|
||||||
|
newSecretNode = (SecretNode*)XMALLOC(sizeof(SecretNode),
|
||||||
|
NULL,
|
||||||
|
DYNAMIC_TYPE_SNIFFER_KEYLOG_NODE);
|
||||||
|
if (newSecretNode == NULL) {
|
||||||
|
SetError(MEMORY_STR, error, NULL, 0);
|
||||||
|
return WOLFSSL_SNIFFER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMEMCPY(newSecretNode->clientRandom, clientRandom, CLIENT_RANDOM_LENGTH);
|
||||||
|
XMEMCPY(newSecretNode->masterSecret, masterSecret, MASTER_SECRET_LENGTH);
|
||||||
|
|
||||||
|
LOCK_SECRET_LIST();
|
||||||
|
|
||||||
|
index = secretHashFunction(clientRandom);
|
||||||
|
newSecretNode->next = NULL;
|
||||||
|
|
||||||
|
if (secretHashTable[index] == NULL) {
|
||||||
|
secretHashTable[index] = newSecretNode;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SecretNode* current = secretHashTable[index];
|
||||||
|
while (current != NULL) {
|
||||||
|
if (memcmp(current->clientRandom,
|
||||||
|
clientRandom,
|
||||||
|
CLIENT_RANDOM_LENGTH) == 0) {
|
||||||
|
/* No need for a new node, since it already exists */
|
||||||
|
fprintf(stderr, "Found duplicate client random value in "
|
||||||
|
"keylog file. Rejecting.\n");
|
||||||
|
XFREE(newSecretNode, NULL, DYNAMIC_TYPE_SNIFFER_KEYLOG_NODE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (current->next == NULL) {
|
||||||
|
current->next = newSecretNode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UNLOCK_SECRET_LIST();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Looks up a master secret for a given client random from the keylog file
|
||||||
|
*/
|
||||||
|
static unsigned char* findMasterSecret(unsigned char* clientRandom)
|
||||||
|
{
|
||||||
|
unsigned char* secret = NULL;
|
||||||
|
SecretNode* node = NULL;
|
||||||
|
unsigned int index = 0;
|
||||||
|
|
||||||
|
LOCK_SECRET_LIST();
|
||||||
|
|
||||||
|
index = secretHashFunction(clientRandom);
|
||||||
|
node = secretHashTable[index];
|
||||||
|
|
||||||
|
while (node != NULL) {
|
||||||
|
if (XMEMCMP(node->clientRandom,
|
||||||
|
clientRandom, CLIENT_RANDOM_LENGTH) == 0) {
|
||||||
|
secret = node->masterSecret;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
UNLOCK_SECRET_LIST();
|
||||||
|
|
||||||
|
return secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hexToBin(const char* hex, unsigned char* bin, int binLength)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (i = 0; i < binLength; i++) {
|
||||||
|
sscanf(hex + 2 * i, "%02hhx", &bin[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int parseKeyLogFile(const char* fileName, char* error)
|
||||||
|
{
|
||||||
|
const char CLIENT_RANDOM_LABEL_STR[] = "CLIENT_RANDOM";
|
||||||
|
unsigned char clientRandom[CLIENT_RANDOM_LENGTH];
|
||||||
|
unsigned char masterSecret[MASTER_SECRET_LENGTH];
|
||||||
|
FILE* file = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
/* +1 for null terminator */
|
||||||
|
char clientRandomLabel[CLIENT_RANDOM_LABEL_LENGTH + 1] = {0};
|
||||||
|
/* 2 chars for Hexadecimal representation, plus null terminator */
|
||||||
|
char clientRandomHex[2 * CLIENT_RANDOM_LENGTH + 1] = {0};
|
||||||
|
char masterSecretHex[2 * MASTER_SECRET_LENGTH + 1] = {0};
|
||||||
|
|
||||||
|
|
||||||
|
file = fopen(fileName, "r");
|
||||||
|
if (file == NULL) {
|
||||||
|
fprintf(stderr, "Could not open keylog file: %s\n", fileName);
|
||||||
|
SetError(KEYLOG_FILE_INVALID, error, NULL, 0);
|
||||||
|
return WOLFSSL_SNIFFER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fscanf(file, "%13s %64s %96s",
|
||||||
|
clientRandomLabel, clientRandomHex, masterSecretHex) == 3) {
|
||||||
|
if (XSTRCMP(clientRandomLabel, CLIENT_RANDOM_LABEL_STR) == 0) {
|
||||||
|
hexToBin(clientRandomHex, clientRandom, CLIENT_RANDOM_LENGTH);
|
||||||
|
hexToBin(masterSecretHex, masterSecret, MASTER_SECRET_LENGTH);
|
||||||
|
ret = addSecretNode(clientRandom, masterSecret, error);
|
||||||
|
if (ret != 0) {
|
||||||
|
fclose(file);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void freeSecretList(void)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
LOCK_SECRET_LIST();
|
||||||
|
|
||||||
|
for (i=0; i<WOLFSSL_SNIFFER_KEYLOGFILE_HASH_TABLE_SIZE; i++)
|
||||||
|
{
|
||||||
|
SecretNode* current = secretHashTable[i];
|
||||||
|
SecretNode * next = NULL;
|
||||||
|
|
||||||
|
while (current != NULL) {
|
||||||
|
next = current->next;
|
||||||
|
XFREE(current, NULL, DYNAMIC_TYPE_SNIFFER_KEYLOG_NODE);
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UNLOCK_SECRET_LIST();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Looks up secret based on client random and copies it to output_secret
|
||||||
|
*/
|
||||||
|
static int snifferSecretCb(unsigned char* client_random,
|
||||||
|
unsigned char* output_secret)
|
||||||
|
{
|
||||||
|
unsigned char* secret = NULL;
|
||||||
|
|
||||||
|
if (client_random == NULL || output_secret == NULL) {
|
||||||
|
return WOLFSSL_SNIFFER_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get secret from secret table based on client random */
|
||||||
|
secret = findMasterSecret(client_random);
|
||||||
|
if (secret != NULL) {
|
||||||
|
XMEMCPY(output_secret, secret, MASTER_SECRET_LENGTH);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* didn't find the secret */
|
||||||
|
return WOLFSSL_SNIFFER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void setSnifferSecretCb(SnifferSession* session)
|
||||||
|
{
|
||||||
|
session->context->useKeyLogFile = 1;
|
||||||
|
session->sslServer->snifferSecretCb = snifferSecretCb;
|
||||||
|
session->sslClient->snifferSecretCb = snifferSecretCb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper function that creates a sniffer server object that can decrypt using
|
||||||
|
* a keylog file, and adds it to the server list
|
||||||
|
*
|
||||||
|
* NOTE: the caller is responsible for locking and unlocking the server list
|
||||||
|
*/
|
||||||
|
static int addKeyLogSnifferServerHelper(const char* address,
|
||||||
|
int port,
|
||||||
|
char* error)
|
||||||
|
{
|
||||||
|
IpAddrInfo serverIp = {0};
|
||||||
|
SnifferServer *sniffer = NULL;
|
||||||
|
|
||||||
|
TraceHeader();
|
||||||
|
TraceSetServer(address, port, NULL);
|
||||||
|
|
||||||
|
serverIp.version = IPV4;
|
||||||
|
serverIp.ip4 = XINET_ADDR(address);
|
||||||
|
if (serverIp.ip4 == XINADDR_NONE) {
|
||||||
|
#ifdef FUSION_RTOS
|
||||||
|
if (XINET_PTON(AF_INET6, address, serverIp.ip6,
|
||||||
|
sizeof(serverIp.ip4)) == 1)
|
||||||
|
#else
|
||||||
|
if (XINET_PTON(AF_INET6, address, serverIp.ip6) == 1)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
serverIp.version = IPV6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sniffer = ServerList;
|
||||||
|
while (sniffer != NULL &&
|
||||||
|
(!MatchAddr(sniffer->server, serverIp) || sniffer->port != port)) {
|
||||||
|
sniffer = sniffer->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sniffer == NULL) {
|
||||||
|
sniffer = (SnifferServer*)XMALLOC(sizeof(SnifferServer),
|
||||||
|
NULL, DYNAMIC_TYPE_SNIFFER_SERVER);
|
||||||
|
if (sniffer == NULL) {
|
||||||
|
SetError(MEMORY_STR, error, NULL, 0);
|
||||||
|
return WOLFSSL_SNIFFER_ERROR;
|
||||||
|
}
|
||||||
|
InitSnifferServer(sniffer);
|
||||||
|
|
||||||
|
XSTRNCPY(sniffer->address, address, MAX_SERVER_ADDRESS-1);
|
||||||
|
sniffer->address[MAX_SERVER_ADDRESS-1] = '\0';
|
||||||
|
sniffer->server = serverIp;
|
||||||
|
sniffer->port = port;
|
||||||
|
|
||||||
|
sniffer->ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
|
||||||
|
if (!sniffer->ctx) {
|
||||||
|
SetError(MEMORY_STR, error, NULL, 0);
|
||||||
|
FreeSnifferServer(sniffer);
|
||||||
|
return WOLFSSL_SNIFFER_ERROR;
|
||||||
|
}
|
||||||
|
#if defined(WOLF_CRYPTO_CB) || defined(WOLFSSL_ASYNC_CRYPT)
|
||||||
|
if (CryptoDeviceId != INVALID_DEVID)
|
||||||
|
wolfSSL_CTX_SetDevId(sniffer->ctx, CryptoDeviceId);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
sniffer->next = ServerList;
|
||||||
|
ServerList = sniffer;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("SESSION ALREADY EXISTS\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tag the new or existing server as requiring keylog support to
|
||||||
|
* decrypt, otherwise it won't be useable */
|
||||||
|
sniffer->useKeyLogFile = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creates a sniffer server that is able to decrypt using secrets from a
|
||||||
|
* keylog file, and adds it to the server list
|
||||||
|
*
|
||||||
|
* If a server at the address and port already exists, it will be marked
|
||||||
|
* for keylog file decryption
|
||||||
|
*/
|
||||||
|
int ssl_CreateKeyLogSnifferServer(const char* address, int port, char* error)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (address == NULL) {
|
||||||
|
SetError(KEYLOG_FILE_INVALID, error, NULL, 0);
|
||||||
|
return WOLFSSL_SNIFFER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCK_SERVER_LIST();
|
||||||
|
|
||||||
|
ret = addKeyLogSnifferServerHelper(address, port, error);
|
||||||
|
|
||||||
|
UNLOCK_SERVER_LIST();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loads secrets to decrypt TLS traffic from a keylog file. Only sniffer
|
||||||
|
* servers registered with ssl_createKeyLogSnifferServer() will be able to
|
||||||
|
* decrypt using these secrets
|
||||||
|
*/
|
||||||
|
int ssl_LoadSecretsFromKeyLogFile(const char* keylogfile, char* error)
|
||||||
|
{
|
||||||
|
if (keylogfile == NULL) {
|
||||||
|
SetError(KEYLOG_FILE_INVALID, error, NULL, 0);
|
||||||
|
return WOLFSSL_SNIFFER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseKeyLogFile(keylogfile, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
|
|
||||||
|
|
||||||
#undef ERROR_OUT
|
#undef ERROR_OUT
|
||||||
|
|
||||||
#endif /* WOLFSSL_SNIFFER */
|
#endif /* WOLFSSL_SNIFFER */
|
||||||
|
13
src/tls.c
13
src/tls.c
@ -516,6 +516,19 @@ int MakeTlsMasterSecret(WOLFSSL* ssl)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
#if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_KEYLOGFILE)
|
||||||
|
/* If this is called from a sniffer session with keylog file support, obtain
|
||||||
|
* the master secret from the callback */
|
||||||
|
if (ssl->snifferSecretCb != NULL) {
|
||||||
|
ret = ssl->snifferSecretCb(ssl->arrays->clientRandom, ssl->arrays->masterSecret);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = DeriveTlsKeys(ssl);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif /* WOLFSSL_SNIFFER && WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
|
|
||||||
#ifdef HAVE_EXTENDED_MASTER
|
#ifdef HAVE_EXTENDED_MASTER
|
||||||
if (ssl->options.haveEMS) {
|
if (ssl->options.haveEMS) {
|
||||||
word32 hashSz = HSHASH_SZ;
|
word32 hashSz = HSHASH_SZ;
|
||||||
|
@ -13729,6 +13729,12 @@ int tls13ShowSecrets(WOLFSSL* ssl, int id, const unsigned char* secret,
|
|||||||
str = "SERVER_TRAFFIC_SECRET_0"; break;
|
str = "SERVER_TRAFFIC_SECRET_0"; break;
|
||||||
case EXPORTER_SECRET:
|
case EXPORTER_SECRET:
|
||||||
str = "EXPORTER_SECRET"; break;
|
str = "EXPORTER_SECRET"; break;
|
||||||
|
default:
|
||||||
|
#ifdef WOLFSSL_SSLKEYLOGFILE_OUTPUT
|
||||||
|
XFCLOSE(fp);
|
||||||
|
#endif
|
||||||
|
return BAD_FUNC_ARG;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(fp, "%s ", str);
|
fprintf(fp, "%s ", str);
|
||||||
|
@ -39,13 +39,18 @@ The STARTTLS option allows the sniffer to receive and ignore plaintext before re
|
|||||||
|
|
||||||
`./configure --enable-sniffer CPPFLAGS=-DSTARTTLS_ALLOWED`
|
`./configure --enable-sniffer CPPFLAGS=-DSTARTTLS_ALLOWED`
|
||||||
|
|
||||||
|
The SSL KeyLog file option enables the sniffer to decrypt TLS traffic using the master secret obtained from a [NSS keylog file](https://web.archive.org/web/20220531072242/https://firefox-source-docs.mozilla.org/security/nss/legacy/key_log_format/index.html). This allows the sniffer to decrypt all TLS traffic, even for TLS connections using ephemeral cipher suites. Currently, sniffer keylog file support is limited to TLSv1.2 traffic. WolfSSL can be configured to export a keylog file using the `-DSHOW_SECRETS -DHAVE_SECRET_CALLBACK -DWOLFSSL_SSLKEYLOGFILE` macros, independently from the sniffer feature (NOTE: never do this in a production environment, as it is inherently insecure). To enable sniffer support for keylog files,
|
||||||
|
use the following configure command line and build as before:
|
||||||
|
|
||||||
|
`./configure --enable-sniffer CPPFLAGS=-DWOLFSSL_SNIFFER_KEYLOGFILE`
|
||||||
|
|
||||||
All options may be enabled with the following configure command line:
|
All options may be enabled with the following configure command line:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
./configure --enable-sniffer \
|
./configure --enable-sniffer \
|
||||||
CPPFLAGS="-DWOLFSSL_SNIFFER_STATS -DWOLFSSL_SNIFFER_WATCH \
|
CPPFLAGS="-DWOLFSSL_SNIFFER_STATS -DWOLFSSL_SNIFFER_WATCH \
|
||||||
-DWOLFSSL_SNIFFER_STORE_DATA_CB -DWOLFSSL_SNIFFER_CHAIN_INPUT \
|
-DWOLFSSL_SNIFFER_STORE_DATA_CB -DWOLFSSL_SNIFFER_CHAIN_INPUT \
|
||||||
-DSTARTTLS_ALLOWED"
|
-DSTARTTLS_ALLOWED -DWOLFSSL_SNIFFER_KEYLOGFILE"
|
||||||
```
|
```
|
||||||
|
|
||||||
To add some other cipher support to the sniffer, you can add options like:
|
To add some other cipher support to the sniffer, you can add options like:
|
||||||
@ -88,7 +93,11 @@ To build with OCTEON III support for a Linux host:
|
|||||||
|
|
||||||
## Command Line Options
|
## 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.
|
The wolfSSL sniffer includes a test application `snifftest` in the `sslSniffer/sslSnifferTest/` directory. The command line application has two sniffing modes: "live" mode and "offline" mode. In "live" mode, the application will prompt the user for network information and other parameters and then actively sniff real network traffic on an interface. In "offline" mode, the user provides the application with a pcap file and other network information via command line arguments, and the sniffer
|
||||||
|
will then decrypt the relevant TLS traffic captured in the pcap file.
|
||||||
|
|
||||||
|
### Live Sniff Mode
|
||||||
|
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:
|
An example startup may look like this:
|
||||||
|
|
||||||
@ -116,41 +125,50 @@ The above example sniffs on the localhost interface (lo0) with the default wolfS
|
|||||||
|
|
||||||
Trace output will be written to a file named `tracefile.txt`.
|
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.
|
### Offline Sniff Mode
|
||||||
|
|
||||||
The following table lists the accepted inputs in saved file mode.
|
Offline mode allows traffic to be decoded from a previously saved pcap file. To run the sniffer in offline mode, you will need to provide the application with some command line arguments, some of which are mandatory and some of which are optional
|
||||||
|
|
||||||
|
The following table lists the accepted inputs in offline mode.
|
||||||
|
|
||||||
Synopsis:
|
Synopsis:
|
||||||
|
|
||||||
`snifftest dumpFile pemKey [server] [port] [password] [threads]`
|
`snifftest -pcap pcap_arg -key key_arg [-password password_arg] [-server server_arg] [-port port_arg] [-keylogfile keylogfile_arg] [-threads threads_arg]`
|
||||||
|
|
||||||
`snifftest` Options Summary:
|
`snifftest` Options Summary:
|
||||||
|
|
||||||
```
|
```
|
||||||
Option Description Default Value
|
Option Description Default Value Mandatory
|
||||||
dumpFile A previously saved pcap file NA
|
pcap_arg A previously saved pcap file NA Y
|
||||||
pemKey The server’s private key in PEM format NA
|
key_arg The server’s private key in PEM format NA Y
|
||||||
server The server’s IP address (v4 or v6) 127.0.0.1
|
password_arg Private Key Password if required NA N
|
||||||
port The server port to sniff 443
|
server_arg The server’s IP address (v4 or v6) 127.0.0.1 N
|
||||||
password Private Key Password if required NA
|
port_arg The server port to sniff 443 N
|
||||||
threads The number of threads to run with 5
|
threads The number of threads to run with 5 N
|
||||||
|
keylogfile_arg Keylog file containing decryption secrets NA N
|
||||||
```
|
```
|
||||||
|
|
||||||
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:
|
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`
|
`./snifftest -pcap test.pcap -key myKey.pem`
|
||||||
|
|
||||||
If the server was on 10.0.1.2 and on port 12345 you could instead use:
|
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`
|
`./snifftest -pcap test.pcap -key myKey.pem -server 10.0.1.2 -port 12345`
|
||||||
|
|
||||||
If the server was on localhost using IPv6 and on port 12345 you could instead use:
|
If the server was on localhost using IPv6 and on port 12345 you could instead use:
|
||||||
|
|
||||||
`./snifftest test.pcap myKey.pem ::1 12345`
|
`./snifftest -pcap test.pcap -key myKey.pem -server ::1 -port 12345`
|
||||||
|
|
||||||
If you wanted to use 15 threads to decode `test.pcap` and your key does not require a password, you could use a dummy password and run:
|
If you wanted to use 15 threads to decode `test.pcap` and your key does not require a password, you could use a dummy password and run:
|
||||||
|
|
||||||
`./snifftest test.pcap myKey.pem 10.0.1.2 12345 pass 15`
|
`./snifftest -pcap test.pcap -key myKey.pem -server 10.0.1.2 -port 12345 -password pass -threads 15`
|
||||||
|
|
||||||
|
If the server exported its secrets in a [NSS keylog file](https://web.archive.org/web/20220531072242/https://firefox-source-docs.mozilla.org/security/nss/legacy/key_log_format/index.html)
|
||||||
|
named "sslkeylog.log", you could decrypt the traffic using:
|
||||||
|
|
||||||
|
`./snifftest -pcap test.pcap -key myKey.pem -server 10.0.1.2 -port 12345 -keylogfile /path/to/sslkeylog.log`
|
||||||
|
|
||||||
|
|
||||||
## API Usage
|
## API Usage
|
||||||
|
|
||||||
@ -164,7 +182,7 @@ Use the include `#include <wolfssl/sniffer.h>`.
|
|||||||
void ssl_InitSniffer(void);
|
void ssl_InitSniffer(void);
|
||||||
```
|
```
|
||||||
|
|
||||||
Initializes the wolfSSL sniffer for use and should be called once per application.
|
Initializes the wolfSSL sniffer for use and should be called once per application.
|
||||||
|
|
||||||
### ssl_FreeSniffer
|
### ssl_FreeSniffer
|
||||||
|
|
||||||
@ -285,8 +303,8 @@ Return Values:
|
|||||||
### ssl_SetEphemeralKey
|
### ssl_SetEphemeralKey
|
||||||
|
|
||||||
```c
|
```c
|
||||||
int ssl_SetEphemeralKey(const char* address, int port,
|
int ssl_SetEphemeralKey(const char* address, int port,
|
||||||
const char* keyFile, int typeKey,
|
const char* keyFile, int typeKey,
|
||||||
const char* password, char* error)
|
const char* password, char* error)
|
||||||
```
|
```
|
||||||
Creates a sniffer session based on the `serverAddress` and `port` inputs using ECC or DH static ephemeral key.
|
Creates a sniffer session based on the `serverAddress` and `port` inputs using ECC or DH static ephemeral key.
|
||||||
@ -300,6 +318,35 @@ Return Values:
|
|||||||
* 0 on success
|
* 0 on success
|
||||||
* -1 if a problem occurred, the string error will hold a message describing the problem
|
* -1 if a problem occurred, the string error will hold a message describing the problem
|
||||||
|
|
||||||
|
### ssl_LoadSecretsFromKeyLogFile
|
||||||
|
|
||||||
|
```c
|
||||||
|
int ssl_LoadSecretsFromKeyLogFile(const char* keylogfile, char* error)
|
||||||
|
```
|
||||||
|
|
||||||
|
Loads secrets to decrypt TLS traffic from a keylog file. Only sniffer servers registered with `ssl_createKeyLogSnifferServer()` will be able to decrypt using these secrets
|
||||||
|
|
||||||
|
This function requires that sniffer keylog file support (`WOLFSSL_SNIFFER_KEYLOGFILE`) is enabled in the build. Keylog file sniffing is only supported for TLS 1.2 traffic.
|
||||||
|
|
||||||
|
Return Values:
|
||||||
|
* 0 on success
|
||||||
|
* -1 if a problem occurred, the string error will hold a message describing the problem
|
||||||
|
|
||||||
|
### ssl_CreateKeyLogSnifferServer
|
||||||
|
|
||||||
|
```c
|
||||||
|
int ssl_CreateKeyLogSnifferServer(const char* address, int port, char* error)
|
||||||
|
```
|
||||||
|
|
||||||
|
Creates a sniffer session based on `serverAddress` and `port`, and uses secrets obtained from a keylog file to decrypt traffic. Keylog files should be loaded using `ssl_LoadSecretsFromKeyLogFile()`.
|
||||||
|
|
||||||
|
This function requires that sniffer keylog file support (`WOLFSSL_SNIFFER_KEYLOGFILE`) is enabled in the build. Keylog file sniffing is only supported for TLS 1.2 traffic.
|
||||||
|
|
||||||
|
Return Values:
|
||||||
|
* 0 on success
|
||||||
|
* -1 if a problem occurred, the string error will hold a message describing the problem
|
||||||
|
|
||||||
|
|
||||||
### ssl_DecodePacket
|
### ssl_DecodePacket
|
||||||
|
|
||||||
```c
|
```c
|
||||||
@ -525,7 +572,7 @@ Return Values:
|
|||||||
### ssl_SetWatchKey_buffer
|
### ssl_SetWatchKey_buffer
|
||||||
|
|
||||||
```c
|
```c
|
||||||
int ssl_SetWatchKey_buffer(void* vSniffer, const unsigned char* key,
|
int ssl_SetWatchKey_buffer(void* vSniffer, const unsigned char* key,
|
||||||
unsigned int keySz, int keyType, char* error);
|
unsigned int keySz, int keyType, char* error);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -144,6 +144,8 @@ enum {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define DEFAULT_SERVER_IP "127.0.0.1"
|
||||||
|
#define DEFAULT_SERVER_PORT (443)
|
||||||
|
|
||||||
#ifdef WOLFSSL_SNIFFER_WATCH
|
#ifdef WOLFSSL_SNIFFER_WATCH
|
||||||
static const byte rsaHash[] = {
|
static const byte rsaHash[] = {
|
||||||
@ -470,20 +472,12 @@ static void show_appinfo(void)
|
|||||||
#ifdef WOLFSSL_STATIC_DH
|
#ifdef WOLFSSL_STATIC_DH
|
||||||
"dh_static "
|
"dh_static "
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef WOLFSSL_SNIFFER_KEYLOGFILE
|
||||||
|
"ssl_keylog_file "
|
||||||
|
#endif /* WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
"\n\n"
|
"\n\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
static void show_usage(void)
|
|
||||||
{
|
|
||||||
printf("usage:\n");
|
|
||||||
printf("\t./snifftest\n");
|
|
||||||
printf("\t\tprompts for options\n");
|
|
||||||
#ifdef THREADED_SNIFFTEST
|
|
||||||
printf("\t./snifftest dump pemKey [server] [port] [password] [threads]\n");
|
|
||||||
#else
|
|
||||||
printf("\t./snifftest dump pemKey [server] [port] [password]\n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct SnifferPacket {
|
typedef struct SnifferPacket {
|
||||||
byte* packet;
|
byte* packet;
|
||||||
@ -955,7 +949,6 @@ int main(int argc, char** argv)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
int hadBadPacket = 0;
|
int hadBadPacket = 0;
|
||||||
int inum = 0;
|
int inum = 0;
|
||||||
int port = 0;
|
|
||||||
int saveFile = 0;
|
int saveFile = 0;
|
||||||
int i = 0, defDev = 0;
|
int i = 0, defDev = 0;
|
||||||
int packetNumber = 0;
|
int packetNumber = 0;
|
||||||
@ -963,9 +956,13 @@ int main(int argc, char** argv)
|
|||||||
char err[PCAP_ERRBUF_SIZE];
|
char err[PCAP_ERRBUF_SIZE];
|
||||||
char filter[32];
|
char filter[32];
|
||||||
const char *keyFilesSrc = NULL;
|
const char *keyFilesSrc = NULL;
|
||||||
|
#ifdef WOLFSSL_SNIFFER_KEYLOGFILE
|
||||||
|
const char *sslKeyLogFile = NULL;
|
||||||
|
#endif /* WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
char keyFilesBuf[MAX_FILENAME_SZ];
|
char keyFilesBuf[MAX_FILENAME_SZ];
|
||||||
char keyFilesUser[MAX_FILENAME_SZ];
|
char keyFilesUser[MAX_FILENAME_SZ];
|
||||||
const char *server = NULL;
|
const char *server = DEFAULT_SERVER_IP;
|
||||||
|
int port = DEFAULT_SERVER_PORT;
|
||||||
const char *sniName = NULL;
|
const char *sniName = NULL;
|
||||||
const char *passwd = NULL;
|
const char *passwd = NULL;
|
||||||
pcap_if_t *d;
|
pcap_if_t *d;
|
||||||
@ -977,18 +974,13 @@ int main(int argc, char** argv)
|
|||||||
workerThreadCount = 1;
|
workerThreadCount = 1;
|
||||||
#else
|
#else
|
||||||
workerThreadCount = 5;
|
workerThreadCount = 5;
|
||||||
if (argc >= 7)
|
|
||||||
workerThreadCount = XATOI(argv[6]);
|
|
||||||
#endif
|
#endif
|
||||||
SnifferWorker workers[workerThreadCount];
|
|
||||||
int used[workerThreadCount];
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
show_appinfo();
|
show_appinfo();
|
||||||
|
|
||||||
signal(SIGINT, sig_handler);
|
signal(SIGINT, sig_handler);
|
||||||
|
|
||||||
|
|
||||||
#ifndef THREADED_SNIFFTEST
|
#ifndef THREADED_SNIFFTEST
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
ssl_InitSniffer(); /* dll load on Windows */
|
ssl_InitSniffer(); /* dll load on Windows */
|
||||||
@ -1140,51 +1132,117 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (argc >= 3) {
|
else {
|
||||||
saveFile = 1;
|
char *pcapFile = NULL;
|
||||||
pcap = pcap_open_offline(argv[1], err);
|
|
||||||
if (pcap == NULL) {
|
|
||||||
printf("pcap_open_offline failed %s\n", err);
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* defaults for server and port */
|
|
||||||
port = 443;
|
|
||||||
server = "127.0.0.1";
|
|
||||||
keyFilesSrc = argv[2];
|
|
||||||
|
|
||||||
if (argc >= 4)
|
for (i = 1; i < argc; i++) {
|
||||||
server = argv[3];
|
if (strcmp(argv[i], "-pcap") == 0 && i + 1 < argc) {
|
||||||
|
pcapFile = argv[++i];
|
||||||
if (argc >= 5)
|
}
|
||||||
port = XATOI(argv[4]);
|
else if (strcmp(argv[i], "-key") == 0 && i + 1 < argc) {
|
||||||
|
keyFilesSrc = argv[++i];
|
||||||
if (argc >= 6)
|
}
|
||||||
passwd = argv[5];
|
else if (strcmp(argv[i], "-server") == 0 && i + 1 < argc) {
|
||||||
|
server = argv[++i];
|
||||||
ret = load_key(NULL, server, port, keyFilesSrc, passwd, err);
|
}
|
||||||
if (ret != 0) {
|
else if (strcmp(argv[i], "-port") == 0 && i + 1 < argc) {
|
||||||
|
port = XATOI(argv[++i]);
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[i], "-password") == 0 && i + 1 < argc) {
|
||||||
|
passwd = argv[++i];
|
||||||
|
}
|
||||||
|
#if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
|
||||||
|
else if (strcmp(argv[i], "-keylogfile") == 0 && i + 1 < argc) {
|
||||||
|
sslKeyLogFile = argv[++i];
|
||||||
|
}
|
||||||
|
#endif /* WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
|
#if defined(THREADED_SNIFFTEST)
|
||||||
|
else if (strcmp(argv[i], "-threads") == 0 && i + 1 < argc) {
|
||||||
|
workerThreadCount = XATOI(argv[++i]);
|
||||||
|
}
|
||||||
|
#endif /* THREADED_SNIFFTEST */
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Invalid option or missing argument: %s\n", argv[i]);
|
||||||
|
fprintf(stderr, "Usage: %s -pcap pcap_arg -key key_arg"
|
||||||
|
" [-password password_arg] [-server server_arg] [-port port_arg]"
|
||||||
|
#if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
|
||||||
|
" [-keylogfile keylogfile_arg]"
|
||||||
|
#endif /* WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
|
#if defined(THREADED_SNIFFTEST)
|
||||||
|
" [-threads threads_arg]"
|
||||||
|
#endif /* THREADED_SNIFFTEST */
|
||||||
|
"\n", argv[0]);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pcapFile) {
|
||||||
|
fprintf(stderr, "Error: -pcap option is required.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
|
||||||
|
/* If we offer keylog support, then user must provide EITHER a pubkey
|
||||||
|
* OR a keylog file but NOT both */
|
||||||
|
if ((!keyFilesSrc && !sslKeyLogFile) || (keyFilesSrc && sslKeyLogFile)) {
|
||||||
|
fprintf(stderr, "Error: either -key OR -keylogfile option required but NOT both.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!keyFilesSrc) {
|
||||||
|
fprintf(stderr, "Error: -key option is required.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
saveFile = 1;
|
||||||
|
pcap = pcap_open_offline(pcapFile , err);
|
||||||
|
if (pcap == NULL) {
|
||||||
|
fprintf(stderr, "pcap_open_offline failed %s\n", err);
|
||||||
|
err_sys(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
|
||||||
|
if (sslKeyLogFile != NULL) {
|
||||||
|
ret = ssl_LoadSecretsFromKeyLogFile(sslKeyLogFile, err);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "ERROR=%d, unable to load secrets from keylog file\n",ret);
|
||||||
|
err_sys(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ssl_CreateKeyLogSnifferServer(server, port, err);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "ERROR=%d, unable to create keylog sniffer server\n",ret);
|
||||||
|
err_sys(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif /* WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
|
{
|
||||||
|
ret = load_key(NULL, server, port, keyFilesSrc, passwd, err);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "Failed to load key\n");
|
||||||
|
err_sys(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Only let through TCP/IP packets */
|
/* Only let through TCP/IP packets */
|
||||||
ret = pcap_compile(pcap, &pcap_fp, "(ip6 or ip) and tcp", 0, 0);
|
ret = pcap_compile(pcap, &pcap_fp, "(ip6 or ip) and tcp", 0, 0);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
printf("pcap_compile failed %s\n", pcap_geterr(pcap));
|
fprintf(stderr, "pcap_compile failed %s\n", pcap_geterr(pcap));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = pcap_setfilter(pcap, &pcap_fp);
|
ret = pcap_setfilter(pcap, &pcap_fp);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
printf("pcap_setfilter failed %s\n", pcap_geterr(pcap));
|
fprintf(stderr, "pcap_setfilter failed %s\n", pcap_geterr(pcap));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
show_usage();
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
err_sys(err);
|
err_sys(err);
|
||||||
@ -1193,6 +1251,9 @@ int main(int argc, char** argv)
|
|||||||
frame = NULL_IF_FRAME_LEN;
|
frame = NULL_IF_FRAME_LEN;
|
||||||
|
|
||||||
#ifdef THREADED_SNIFFTEST
|
#ifdef THREADED_SNIFFTEST
|
||||||
|
SnifferWorker workers[workerThreadCount];
|
||||||
|
int used[workerThreadCount];
|
||||||
|
|
||||||
XMEMSET(used, 0, sizeof(used));
|
XMEMSET(used, 0, sizeof(used));
|
||||||
XMEMSET(&workers, 0, sizeof(workers));
|
XMEMSET(&workers, 0, sizeof(workers));
|
||||||
|
|
||||||
|
@ -279,6 +279,10 @@
|
|||||||
|
|
||||||
#include <wolfssl/wolfcrypt/hpke.h>
|
#include <wolfssl/wolfcrypt/hpke.h>
|
||||||
|
|
||||||
|
#if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_KEYLOGFILE)
|
||||||
|
#include <wolfssl/sniffer.h>
|
||||||
|
#endif /* WOLFSSL_SNIFFER && WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -2204,6 +2208,8 @@ WOLFSSL_LOCAL int ALPN_Select(WOLFSSL* ssl);
|
|||||||
|
|
||||||
WOLFSSL_LOCAL int ChachaAEADEncrypt(WOLFSSL* ssl, byte* out, const byte* input,
|
WOLFSSL_LOCAL int ChachaAEADEncrypt(WOLFSSL* ssl, byte* out, const byte* input,
|
||||||
word16 sz); /* needed by sniffer */
|
word16 sz); /* needed by sniffer */
|
||||||
|
WOLFSSL_LOCAL int ChachaAEADDecrypt(WOLFSSL* ssl, byte* plain, const byte* input,
|
||||||
|
word16 sz); /* needed by sniffer */
|
||||||
|
|
||||||
#ifdef WOLFSSL_TLS13
|
#ifdef WOLFSSL_TLS13
|
||||||
WOLFSSL_LOCAL int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input,
|
WOLFSSL_LOCAL int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input,
|
||||||
@ -5839,6 +5845,11 @@ struct WOLFSSL {
|
|||||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||||
WOLFSSL_EchConfig* echConfigs;
|
WOLFSSL_EchConfig* echConfigs;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_KEYLOGFILE)
|
||||||
|
SSLSnifferSecretCb snifferSecretCb;
|
||||||
|
#endif /* WOLFSSL_SNIFFER && WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -313,6 +313,21 @@ SSL_SNIFFER_API int ssl_PollSniffer(WOLF_EVENT** events, int maxEvents,
|
|||||||
|
|
||||||
#endif /* WOLFSSL_ASYNC_CRYPT */
|
#endif /* WOLFSSL_ASYNC_CRYPT */
|
||||||
|
|
||||||
|
#ifdef WOLFSSL_SNIFFER_KEYLOGFILE
|
||||||
|
|
||||||
|
WOLFSSL_API
|
||||||
|
SSL_SNIFFER_API int ssl_CreateKeyLogSnifferServer(const char* address,
|
||||||
|
int port,
|
||||||
|
char* error);
|
||||||
|
|
||||||
|
WOLFSSL_API
|
||||||
|
SSL_SNIFFER_API int ssl_LoadSecretsFromKeyLogFile(const char* keylogfile,
|
||||||
|
char* error);
|
||||||
|
|
||||||
|
typedef int (*SSLSnifferSecretCb)(unsigned char* client_random,
|
||||||
|
unsigned char* output_secret);
|
||||||
|
|
||||||
|
#endif /* WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -142,6 +142,8 @@
|
|||||||
#define SNIFFER_KEY_SETUP_STR 96
|
#define SNIFFER_KEY_SETUP_STR 96
|
||||||
#define UNSUPPORTED_TLS_VER_STR 97
|
#define UNSUPPORTED_TLS_VER_STR 97
|
||||||
#define KEY_MISMATCH_STR 98
|
#define KEY_MISMATCH_STR 98
|
||||||
|
|
||||||
|
#define KEYLOG_FILE_INVALID 99
|
||||||
/* !!!! also add to msgTable in sniffer.c and .rc file !!!! */
|
/* !!!! also add to msgTable in sniffer.c and .rc file !!!! */
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
STRINGTABLE
|
STRINGTABLE
|
||||||
{
|
{
|
||||||
1, "Out of Memory"
|
1, "Out of Memory"
|
||||||
2, "New SSL Sniffer Server Registered"
|
2, "New SSL Sniffer Server Registered"
|
||||||
@ -60,7 +60,7 @@ STRINGTABLE
|
|||||||
48, "Wrong Protocol type"
|
48, "Wrong Protocol type"
|
||||||
49, "Packet Short for header processing"
|
49, "Packet Short for header processing"
|
||||||
50, "Got Unknown Record Type"
|
50, "Got Unknown Record Type"
|
||||||
|
|
||||||
51, "Can't Open Trace File"
|
51, "Can't Open Trace File"
|
||||||
52, "Session in Fatal Error State"
|
52, "Session in Fatal Error State"
|
||||||
53, "Partial SSL record received"
|
53, "Partial SSL record received"
|
||||||
@ -72,7 +72,7 @@ STRINGTABLE
|
|||||||
58, "Received an Overlap Duplicate Packet"
|
58, "Received an Overlap Duplicate Packet"
|
||||||
59, "Received an Overlap Reassembly Begin Duplicate Packet"
|
59, "Received an Overlap Reassembly Begin Duplicate Packet"
|
||||||
60, "Received an Overlap Reassembly End Duplicate Packet"
|
60, "Received an Overlap Reassembly End Duplicate Packet"
|
||||||
|
|
||||||
61, "Missed the Client Hello Entirely"
|
61, "Missed the Client Hello Entirely"
|
||||||
62, "Got Hello Request msg"
|
62, "Got Hello Request msg"
|
||||||
63, "Got Session Ticket msg"
|
63, "Got Session Ticket msg"
|
||||||
@ -118,4 +118,6 @@ STRINGTABLE
|
|||||||
96, "Setting up keys"
|
96, "Setting up keys"
|
||||||
97, "Unsupported TLS Version"
|
97, "Unsupported TLS Version"
|
||||||
98, "Server Client Key Mismatch"
|
98, "Server Client Key Mismatch"
|
||||||
|
|
||||||
|
99, "Invalid or missing keylog file"
|
||||||
}
|
}
|
||||||
|
@ -1023,7 +1023,8 @@ typedef struct w64wrapper {
|
|||||||
DYNAMIC_TYPE_SNIFFER_PB_BUFFER = 1003,
|
DYNAMIC_TYPE_SNIFFER_PB_BUFFER = 1003,
|
||||||
DYNAMIC_TYPE_SNIFFER_TICKET_ID = 1004,
|
DYNAMIC_TYPE_SNIFFER_TICKET_ID = 1004,
|
||||||
DYNAMIC_TYPE_SNIFFER_NAMED_KEY = 1005,
|
DYNAMIC_TYPE_SNIFFER_NAMED_KEY = 1005,
|
||||||
DYNAMIC_TYPE_SNIFFER_KEY = 1006
|
DYNAMIC_TYPE_SNIFFER_KEY = 1006,
|
||||||
|
DYNAMIC_TYPE_SNIFFER_KEYLOG_NODE = 1007
|
||||||
};
|
};
|
||||||
|
|
||||||
/* max error buffer string size */
|
/* max error buffer string size */
|
||||||
|
Loading…
Reference in New Issue
Block a user