diff options
Diffstat (limited to 't')
-rwxr-xr-x | t/00_testssl_help.t | 63 | ||||
-rwxr-xr-x | t/01_testssl_banner.t | 49 | ||||
-rwxr-xr-x | t/02_clientsim_txt_parsable.t | 27 | ||||
-rwxr-xr-x | t/05_ca_hashes_up_to_date.t | 16 | ||||
-rwxr-xr-x | t/10_baseline_ipv4_http.t | 73 | ||||
-rwxr-xr-x | t/11_baseline_ipv6_http.t.DISABLED | 61 | ||||
-rwxr-xr-x | t/21_baseline_starttls.t | 193 | ||||
-rwxr-xr-x | t/23_client_simulation.t | 79 | ||||
-rwxr-xr-x | t/31_isJSON_valid.t | 88 | ||||
-rwxr-xr-x | t/32_isHTML_valid.t | 92 | ||||
-rwxr-xr-x | t/33_isJSON_severitylevel_valid.t | 69 | ||||
-rwxr-xr-x | t/51_badssl.com.t | 147 | ||||
-rwxr-xr-x | t/59_hpkp.t.tmpDISABLED | 84 | ||||
-rwxr-xr-x | t/61_diff_testsslsh.t | 70 | ||||
-rw-r--r-- | t/Readme.md | 10 | ||||
-rw-r--r-- | t/baseline_data/default_testssl.csvfile | 140 |
16 files changed, 1261 insertions, 0 deletions
diff --git a/t/00_testssl_help.t b/t/00_testssl_help.t new file mode 100755 index 0000000..bedcb8c --- /dev/null +++ b/t/00_testssl_help.t @@ -0,0 +1,63 @@ +#!/usr/bin/env perl + +# Basics: is there a syntax error where already bash hiccups on? + +use strict; +use Test::More; +use File::stat; + +my $tests = 0; +my $fileout=""; +my $prg="./testssl.sh"; +my $out=""; + +# Try to detect remainders from debugging: +my $debug_regexp='^(\s)*set (-|\+)x'; +# Blacklists we use to trigger an error: +my $error_regexp1='(syntax|parse) (e|E)rror'; +my $error_regexp2='testssl.sh: line'; +my $error_regexp3='bash: warning'; +my $error_regexp4='command not found'; +my $error_regexp5='(syntax error|unexpected token)'; + +printf "\n%s\n", "Testing whether just calling \"./testssl.sh\" produces no error ..."; +my $info = stat($prg); +my $retMode = $info->mode; + +is($retMode & 0400, 0400, "Checking \"./testssl.sh\" for read permission"); +$tests++; + +is($retMode & 0100, 0100, "Checking \"./testssl.sh\" for execute permission"); +$tests++; + +$fileout = `timeout 10 bash $prg 2>&1`; +my $retval=$?; + +unlike($fileout, qr/$error_regexp1/, "regex 1"); +$tests++; + +unlike($fileout, qr/$error_regexp2/, "regex 2"); +$tests++; + +unlike($fileout, qr/$error_regexp3/, "regex 3"); +$tests++; + +unlike($fileout, qr/$error_regexp4/, "regex 4"); +$tests++; + +unlike($fileout, qr/$error_regexp5/, "regex 5"); +$tests++; + +is($retval, 0, "return value should be equal zero: \"$retval\""); +$tests++; + +$out=`grep -E "$debug_regexp" $prg`; +unlike($out, qr/$debug_regexp/, "Debug RegEx"); +$tests++; + +printf "\n"; +done_testing($tests); + + +# vim:ts=5:sw=5:expandtab + diff --git a/t/01_testssl_banner.t b/t/01_testssl_banner.t new file mode 100755 index 0000000..032077a --- /dev/null +++ b/t/01_testssl_banner.t @@ -0,0 +1,49 @@ +#!/usr/bin/env perl + +# Basics: is there a syntax error where already bash hiccups on? +# --banner is equal to --version + +use strict; +use Test::More; + +my $tests = 0; +my $fileout=""; +# Blacklists we use to trigger an error: +my $error_regexp1='(syntax|parse) (e|E)rror'; +my $error_regexp2='testssl.sh: line'; +my $error_regexp3='bash: warning'; +my $error_regexp4='command not found'; +my $error_regexp5='(syntax error|unexpected token)'; +my $good_regexp='free software([\s\S]*)USAGE w/o ANY WARRANTY([\s\S]*)OWN RISK([\s\S]*)Using([\s\S]*)ciphers([\s\S]*)built([\s\S]*)platform'; + +printf "\n%s\n", "Testing whether just calling \"./testssl.sh --banner\" produces no error ..."; +$fileout = `timeout 10 bash ./testssl.sh --banner 2>&1`; +my $retval=$?; + +unlike($fileout, qr/$error_regexp1/, "regex 1"); +$tests++; + +unlike($fileout, qr/$error_regexp2/, "regex 2"); +$tests++; + +unlike($fileout, qr/$error_regexp3/, "regex 3"); +$tests++; + +unlike($fileout, qr/$error_regexp4/, "regex 4"); +$tests++; + +unlike($fileout, qr/$error_regexp5/, "regex 5"); +$tests++; + +like($fileout, qr/$good_regexp/, "regex positive"); +$tests++; + +is($retval, 0, "return value should be equal zero: \"$retval\""); +$tests++; + +printf "\n"; +done_testing($tests); + + +# vim:ts=5:sw=5:expandtab + diff --git a/t/02_clientsim_txt_parsable.t b/t/02_clientsim_txt_parsable.t new file mode 100755 index 0000000..4cbfd01 --- /dev/null +++ b/t/02_clientsim_txt_parsable.t @@ -0,0 +1,27 @@ +#!/usr/bin/env perl + +# Just a functional test, whether ~/etc/client-simulation.txt +# doesn't have any syntax errors + +use strict; +use Test::More; + +my $tests = 0; +my $fileout=""; +# Blacklists we use to trigger an error: +my $error_regexp1='(syntax|parse) (e|E)rror'; +my $error_regexp2='client-simulation.txt:'; + +printf "\n%s\n", "Testing whether \"~/etc/client-simulation.txt\" isn't broken ..."; +$fileout = `bash ./etc/client-simulation.txt 2>&1`; +unlike($fileout, qr/$error_regexp1/, "regex 1"); +$tests++; + +unlike($fileout, qr/$error_regexp2/, "regex 2"); +$tests++; + +printf "\n"; +done_testing($tests); + +# vim:ts=5:sw=5:expandtab + diff --git a/t/05_ca_hashes_up_to_date.t b/t/05_ca_hashes_up_to_date.t new file mode 100755 index 0000000..434b7a0 --- /dev/null +++ b/t/05_ca_hashes_up_to_date.t @@ -0,0 +1,16 @@ +#!/usr/bin/env perl + +use strict; +use Test::More; + +printf "\n%s\n", "Testing whether CA certificates are newer their SPKI hashes \"~/etc/ca_hashes.txt\" ..."; + +my $newer_bundles=`find etc/*.pem -newer etc/ca_hashes.txt`; +is($newer_bundles,"","If there's an output with a *.pem file run \"~/utils/create_ca_hashes.sh\""); + +printf "\n"; +done_testing; + + +# vim:ts=5:sw=5:expandtab + diff --git a/t/10_baseline_ipv4_http.t b/t/10_baseline_ipv4_http.t new file mode 100755 index 0000000..c98e6f2 --- /dev/null +++ b/t/10_baseline_ipv4_http.t @@ -0,0 +1,73 @@ +#!/usr/bin/env perl + +# baseline test for testssl, screen and JSON output + +# This is referred by the documentation. + +# We could also inspect the JSON for any problems for +# "id" : "scanProblem" +# "finding" : "Scan interrupted" + +use strict; +use Test::More; +use Data::Dumper; +use JSON; + +my $tests = 0; +my $prg="./testssl.sh"; +my $check2run="-p -s -P --fs -S -h -U -q --ip=one --color 0"; +my $uri="google.com"; +my $socket_out=""; +my $openssl_out=""; +# Blacklists we use to trigger an error: +my $socket_regex_bl='(e|E)rror|\.\/testssl\.sh: line |(f|F)atal|(c|C)ommand not found'; +my $openssl_regex_bl='(e|E)rror|(f|F)atal|\.\/testssl\.sh: line |Oops|s_client connect problem|(c|C)ommand not found'; +my $json_regex_bl='(id".*:\s"scanProblem"|severity".*:\s"FATAL"|"Scan interrupted")'; + +my $socket_json=""; +my $openssl_json=""; +$check2run="--jsonfile tmp.json $check2run"; + +die "Unable to open $prg" unless -f $prg; + +# Provide proper start conditions +unlink "tmp.json"; + +# Title +printf "\n%s\n", "Baseline unit test IPv4 against \"$uri\""; + +#1 +$socket_out = `$prg $check2run $uri 2>&1`; +$socket_json = json('tmp.json'); +unlink "tmp.json"; +unlike($socket_out, qr/$socket_regex_bl/, "via sockets, terminal output"); +$tests++; +unlike($socket_json, qr/$json_regex_bl/, "via sockets JSON output"); +$tests++; + +#2 +$openssl_out = `$prg --ssl-native $check2run $uri 2>&1`; +$openssl_json = json('tmp.json'); +unlink "tmp.json"; +# With Google only we sometimes encounter an error as they return a 0 char with openssl, so we white list this pattern here: +# It should be fixed in the code though so we comment this out +# $openssl_out =~ s/testssl.*warning: command substitution: ignored null byte in input\n//g; +unlike($openssl_out, qr/$openssl_regex_bl/, "via OpenSSL"); +$tests++; +unlike($openssl_json, qr/$json_regex_bl/, "via OpenSSL JSON output"); +$tests++; + +done_testing($tests); +printf "\n"; + + +sub json($) { + my $file = shift; + $file = `cat $file`; + unlink $file; + return from_json($file); +} + + +# vim:ts=5:sw=5:expandtab + diff --git a/t/11_baseline_ipv6_http.t.DISABLED b/t/11_baseline_ipv6_http.t.DISABLED new file mode 100755 index 0000000..affa18a --- /dev/null +++ b/t/11_baseline_ipv6_http.t.DISABLED @@ -0,0 +1,61 @@ +#!/usr/bin/env perl + +# disabled as IPv6 is not supported by Travis, see https://github.com/drwetter/testssl.sh/issues/1177 + +# Just a functional test, whether there are any problems on the client side +# Probably we could also inspect the JSON for any problems for +# "id" : "scanProblem" +# "finding" : "Scan interrupted" + +use strict; +use Test::More; +use Data::Dumper; +# use JSON; +# if we need JSON we need to comment this and the lines below in + +my $tests = 0; +my $prg="./testssl.sh"; +my $check2run ="-p -s -P --fs -S -h -U -q --ip=one --color 0"; +my $uri=""; +my $socket_out=""; +my $openssl_out=""; +# Blacklists we use to trigger an error: +my $socket_regex_bl='(e|E)rror|\.\/testssl\.sh: line |(f|F)atal|(c|C)ommand not found'; +my $openssl_regex_bl='(e|E)rror|(f|F)atal|\.\/testssl\.sh: line |Oops|s_client connect problem|(c|C)ommand not found'; + +# my $socket_json=""; +# my $openssl_json=""; +# $check2run="--jsonfile tmp.json $check2run"; + +die "Unable to open $prg" unless -f $prg; + +$uri="testssl.net"; + +# unlink "tmp.json"; +printf "\n%s\n", "Baseline unit test IPv6 via sockets --> $uri ..."; +$socket_out = `./testssl.sh $check2run -6 $uri 2>&1`; +# $socket_json = json('tmp.json'); +unlike($socket_out, qr/$socket_regex_bl/, ""); +$tests++; + +# unlink "tmp.json"; +printf "\n%s\n", "Baseline unit test IPv6 via OpenSSL --> $uri ..."; +$openssl_out = `./testssl.sh --ssl-native $check2run -6 $uri 2>&1`; +# $openssl_json = json('tmp.json'); +# With Google only we encounter an error as they return a 0 char with openssl, so we white list this pattern here: +$openssl_out =~ s/testssl.*warning: command substitution: ignored null byte in input\n//g; +unlike($openssl_out, qr/$openssl_regex_bl/, ""); +$tests++; + + +done_testing($tests); +unlink "tmp.json"; + + + +sub json($) { + my $file = shift; + $file = `cat $file`; + unlink $file; + return from_json($file); +} diff --git a/t/21_baseline_starttls.t b/t/21_baseline_starttls.t new file mode 100755 index 0000000..8778b98 --- /dev/null +++ b/t/21_baseline_starttls.t @@ -0,0 +1,193 @@ +#!/usr/bin/env perl + +# Just a functional test, whether there are any problems on the client side +# Probably we could also inspect the JSON for any problems for +# "id" : "scanProblem" +# "finding" : "Scan interrupted" + +# Catches: +# - This unit test takes very long +# - Hosts which match the regex patterns should be avoided + +use strict; +use Test::More; +use Data::Dumper; +# use JSON; +# if we need JSON we need to comment this and the lines below in + +my $tests = 0; +my $prg="./testssl.sh"; +my $check2run_smtp="--protocols --standard --fs --server-preference --headers --vulnerable -q --ip=one --color 0"; +my $check2run="-q --ip=one --color 0"; +my $uri=""; +my $socket_out=""; +my $openssl_out=""; +# Blacklists we use to trigger an error: +my $socket_regex_bl='(e|E)rror|\.\/testssl\.sh: line |(f|F)atal|(c|C)ommand not found'; +my $openssl_regex_bl='(e|E)rror|(f|F)atal|\.\/testssl\.sh: line |Oops|s_client connect problem|(c|C)ommand not found'; + +# my $socket_json=""; +# my $openssl_json=""; +# $check2run_smtp="--jsonfile tmp.json $check2run_smtp"; +# $check2run="--jsonfile tmp.json $check2run"; + +die "Unable to open $prg" unless -f $prg; + +$uri="smtp-relay.gmail.com:587"; + +# we will have client simulations later, so we don't need to run everything again: +# unlink "tmp.json"; +printf "\n%s\n", "STARTTLS SMTP unit test via sockets --> $uri ..."; +$socket_out = `./testssl.sh $check2run_smtp -t smtp $uri 2>&1`; +# $socket_json = json('tmp.json'); +unlike($socket_out, qr/$socket_regex_bl/, ""); +$tests++; + +# unlink "tmp.json"; +printf "\n%s\n", "STARTTLS SMTP unit tests via OpenSSL --> $uri ..."; +$openssl_out = `./testssl.sh --ssl-native $check2run_smtp -t smtp $uri 2>&1`; +# $openssl_json = json('tmp.json'); +unlike($openssl_out, qr/$openssl_regex_bl/, ""); +$tests++; + + +$uri="pop.gmx.net:110"; + +# unlink "tmp.json"; +printf "\n%s\n", "STARTTLS POP3 unit tests via sockets --> $uri ..."; +$socket_out = `./testssl.sh $check2run -t pop3 $uri 2>&1`; +# $socket_json = json('tmp.json'); +unlike($socket_out, qr/$socket_regex_bl/, ""); +$tests++; + +printf "\n%s\n", "STARTTLS POP3 unit tests via OpenSSL --> $uri ..."; +$openssl_out = `./testssl.sh --ssl-native $check2run -t pop3 $uri 2>&1`; +# $openssl_json = json('tmp.json'); +unlike($openssl_out, qr/$openssl_regex_bl/, ""); +$tests++; + + +$uri="imap.gmx.net:143"; + +# unlink "tmp.json"; +printf "\n%s\n", "STARTTLS IMAP unit tests via sockets --> $uri ..."; +$socket_out = `./testssl.sh $check2run -t imap $uri 2>&1`; +# $socket_json = json('tmp.json'); +unlike($socket_out, qr/$socket_regex_bl/, ""); +$tests++; + +printf "\n%s\n", "STARTTLS IMAP unit tests via OpenSSL --> $uri ..."; +$openssl_out = `./testssl.sh --ssl-native $check2run -t imap $uri 2>&1`; +# $openssl_json = json('tmp.json'); +unlike($openssl_out, qr/$openssl_regex_bl/, ""); +$tests++; + + +$uri="mail.tigertech.net:4190"; + +# unlink "tmp.json"; +printf "\n%s\n", "STARTTLS MANAGE(SIEVE) unit tests via sockets --> $uri ..."; +$socket_out = `./testssl.sh $check2run -t sieve $uri 2>&1`; +# $socket_json = json('tmp.json'); +unlike($openssl_out, qr/$openssl_regex_bl/, ""); +$tests++; + + +$uri="jabber.org:5222"; + +# unlink "tmp.json"; +printf "\n%s\n", "STARTTLS XMPP unit tests via sockets --> $uri ..."; +$socket_out = `./testssl.sh $check2run -t xmpp $uri 2>&1`; +# $socket_json = json('tmp.json'); +unlike($openssl_out, qr/$openssl_regex_bl/, ""); +$tests++; + +# commented out, bc of travis' limits +# +#printf "\n%s\n", "STARTTLS XMPP unit tests via OpenSSL --> $uri ..."; +#$openssl_out = `./testssl.sh --ssl-native $check2run -t xmpp $uri 2>&1`; +# $openssl_json = json('tmp.json'); +#unlike($openssl_out, qr/$openssl_regex_bl/, ""); +#$tests++; + +# $uri="jabber.ccc.de:5269"; +# printf "\n%s\n", "Quick STARTTLS XMPP S2S unit tests via sockets --> $uri ..."; +# $openssl_out = `./testssl.sh --openssl=/usr/bin/openssl -p $check2run -t xmpp-server $uri 2>&1`; +# # $openssl_json = json('tmp.json'); +# unlike($openssl_out, qr/$openssl_regex_bl/, ""); +# $tests++; + + +$uri="ldap.uni-rostock.de:21"; + +# unlink "tmp.json"; +printf "\n%s\n", "STARTTLS FTP unit tests via sockets --> $uri ..."; +$socket_out = `./testssl.sh $check2run -t ftp $uri 2>&1`; +# $socket_json = json('tmp.json'); +# OCSP stapling fails sometimes with: 'offered, error querying OCSP responder (ERROR: No Status found)' +$socket_out =~ s/ error querying OCSP responder .*\n//g; +unlike($socket_out, qr/$socket_regex_bl/, ""); +$tests++; + +# commented out, bc of travis' limits +# +# printf "\n%s\n", "STARTTLS FTP unit tests via OpenSSL --> $uri ..."; +# $openssl_out = `./testssl.sh --ssl-native $check2run -t ftp $uri 2>&1`; +# $openssl_json = json('tmp.json'); +# OCSP stapling fails sometimes with: 'offered, error querying OCSP responder (ERROR: No Status found)' +# $openssl_out =~ s/ error querying OCSP responder .*\n//g; +# unlike($openssl_out, qr/$openssl_regex_bl/, ""); +# $tests++; + + +# https://ldapwiki.com/wiki/Public%20LDAP%20Servers +$uri="db.debian.org:389"; + +printf "\n%s\n", "STARTTLS LDAP unit tests via sockets --> $uri ..."; +$socket_out = `./testssl.sh $check2run -t ldap $uri 2>&1`; +# $socket_json = json('tmp.json'); +unlike($socket_out, qr/$socket_regex_bl/, ""); +$tests++; + +printf "\n%s\n", "STARTTLS LDAP unit tests via OpenSSL --> $uri ..."; +$openssl_out = `./testssl.sh --ssl-native $check2run -t ldap $uri 2>&1`; +# $openssl_json = json('tmp.json'); +unlike($openssl_out, qr/$openssl_regex_bl/, ""); +$tests++; + + +# For NNTP there doesn't seem to be reliable host out there +#$uri="144.76.182.167:119"; + +#printf "\n%s\n", "STARTTLS NNTP unit tests via sockets --> $uri ..."; +#$socket_out = `./testssl.sh $check2run -t nntp $uri 2>&1`; +#unlike($socket_out, qr/$socket_regex_bl/, ""); +#$tests++; + +# commented out, bc of travis' limits +# +#printf "\n%s\n", "STARTTLS NNTP unit tests via OpenSSL --> $uri ..."; +#$openssl_out = `./testssl.sh --ssl-native $check2run -t nntp $uri 2>&1`; +# $openssl_json = json('tmp.json'); +#unlike($openssl_out, qr/$openssl_regex_bl/, ""); +#$tests++; + + +# IRC: missing +# LTMP, mysql, postgres + + + +done_testing($tests); +# unlink "tmp.json"; + +sub json($) { + my $file = shift; + $file = `cat $file`; + unlink $file; + return from_json($file); +} + + +# vim:ts=5:sw=5:expandtab + diff --git a/t/23_client_simulation.t b/t/23_client_simulation.t new file mode 100755 index 0000000..dc310a7 --- /dev/null +++ b/t/23_client_simulation.t @@ -0,0 +1,79 @@ +#!/usr/bin/env perl + +# Just a functional test, whether there are any problems on the client side +# Probably we could also inspect the JSON for any problems for +# "id" : "scanProblem" +# "finding" : "Scan interrupted" + +use strict; +use Test::More; +use Data::Dumper; +# use JSON; +# if we need JSON we need to comment this and the lines below in + +my $tests = 0; +my $prg="./testssl.sh"; +my $check2run ="--client-simulation -q --ip=one --color 0"; +my $uri=""; +my $socket_out=""; +my $openssl_out=""; +# Blacklists we use to trigger an error: +my $socket_regex_bl='(e|E)rror|\.\/testssl\.sh: line |(f|F)atal|(c|C)ommand not found'; +my $openssl_regex_bl='(e|E)rror|(f|F)atal|\.\/testssl\.sh: line |Oops|s_client connect problem|(c|C)ommand not found'; + +# my $socket_json=""; +# my $openssl_json=""; +# $check2run="--jsonfile tmp.json $check2run"; + +die "Unable to open $prg" unless -f $prg; + +$uri="google.com"; + +# unlink "tmp.json"; +printf "\n%s\n", "Client simulations unit test via sockets --> $uri ..."; +$socket_out = `./testssl.sh $check2run $uri 2>&1`; +# $socket_json = json('tmp.json'); +unlike($socket_out, qr/$socket_regex_bl/, ""); +$tests++; + +# unlink "tmp.json"; +printf "\n%s\n", "Client simulations unit test via OpenSSL --> $uri ..."; +$openssl_out = `./testssl.sh $check2run --ssl-native $uri 2>&1`; +# $openssl_json = json('tmp.json'); +unlike($openssl_out, qr/$openssl_regex_bl/, ""); +$tests++; + + +$uri="smtp-relay.gmail.com:587"; + +# unlink "tmp.json"; +printf "\n%s\n", "STARTTLS: Client simulations unit test via sockets --> $uri ..."; +$socket_out = `./testssl.sh $check2run -t smtp $uri 2>&1`; +# $socket_json = json('tmp.json'); +unlike($socket_out, qr/$socket_regex_bl/, ""); +$tests++; + +# commented out, bc of travis' limits +# +# unlink "tmp.json"; +#printf "\n%s\n", "STARTTLS: Client simulations unit test via OpenSSL --> $uri ..."; +#$openssl_out = `./testssl.sh --ssl-native $check2run -t smtp $uri 2>&1`; +## $openssl_json = json('tmp.json'); +#unlike($openssl_out, qr/$openssl_regex_bl/, ""); +#$tests++; + +done_testing($tests); +unlink "tmp.json"; + + + +sub json($) { + my $file = shift; + $file = `cat $file`; + unlink $file; + return from_json($file); +} + + +# vim:ts=5:sw=5:expandtab + diff --git a/t/31_isJSON_valid.t b/t/31_isJSON_valid.t new file mode 100755 index 0000000..2637ac1 --- /dev/null +++ b/t/31_isJSON_valid.t @@ -0,0 +1,88 @@ +#!/usr/bin/env perl + +# This is more a PoC. Improvements welcome! +# + +use strict; +use Test::More; +use JSON; + +my $tests = 0; +my $prg="./testssl.sh"; +my $check2run ="--ip=one --ids-friendly -q --color 0"; +my $uri=""; +my $json=""; +my $out=""; +# Blacklists we use to trigger an error: +my $socket_regex_bl='(e|E)rror|\.\/testssl\.sh: line |(f|F)atal|(c|C)ommand not found'; +my $openssl_regex_bl='(e|E)rror|(f|F)atal|\.\/testssl\.sh: line |Oops|s_client connect problem|(c|C)ommand not found'; + +die "Unable to open $prg" unless -f $prg; + +my $uri="cloudflare.com"; + +printf "\n%s\n", "Unit testing JSON output ..."; +unlink 'tmp.json'; + +#1 +printf "%s\n", ".. plain JSON --> $uri "; +$out = `./testssl.sh $check2run --jsonfile tmp.json $uri`; +$json = json('tmp.json'); +unlink 'tmp.json'; +my @errors=eval { decode_json($json) }; +is(@errors,0,"no errors"); +$tests++; + +#2 +printf "%s\n", ".. pretty JSON --> $uri "; +$out = `./testssl.sh $check2run --jsonfile-pretty tmp.json $uri`; +$json = json('tmp.json'); +unlink 'tmp.json'; +@errors=eval { decode_json($json) }; +is(@errors,0,"no errors"); +$tests++; + + +#3 +# This testssl.sh run deliberately does NOT work as travis-ci.org blocks port 25 egress. +# but the output should be fine. The idea is to have a unit test for a failed connection. +printf "%s\n", ".. plain JSON for a failed run: '--mx $uri' ..."; +$out = `./testssl.sh --ssl-native --openssl-timeout=10 $check2run --jsonfile tmp.json --mx $uri`; +$json = json('tmp.json'); +unlink 'tmp.json'; +@errors=eval { decode_json($json) }; +is(@errors,0,"no errors"); +$tests++; + +#4 +# Same as above but with pretty JSON +printf "%s\n", ".. pretty JSON for a failed run '--mx $uri' ..."; +$out = `./testssl.sh --ssl-native --openssl-timeout=10 $check2run --jsonfile-pretty tmp.json --mx $uri`; +$json = json('tmp.json'); +unlink 'tmp.json'; +@errors=eval { decode_json($json) }; +is(@errors,0,"no errors"); +$tests++; + +#5 +my $uri = "smtp-relay.gmail.com:587"; +printf "%s\n", " .. plain JSON and STARTTLS --> $uri ..."; +$out = `./testssl.sh --jsonfile tmp.json $check2run -t smtp $uri`; +$json = json('tmp.json'); +unlink 'tmp.json'; +@errors=eval { decode_json($json) }; +is(@errors,0,"no errors"); +$tests++; + +printf "\n"; +done_testing($tests); + +sub json($) { + my $file = shift; + $file = `cat $file`; + return from_json($file); +} + + +# vim:ts=5:sw=5:expandtab + diff --git a/t/32_isHTML_valid.t b/t/32_isHTML_valid.t new file mode 100755 index 0000000..c006329 --- /dev/null +++ b/t/32_isHTML_valid.t @@ -0,0 +1,92 @@ +#!/usr/bin/env perl + +# Checking whether the HTML output is somehow valid +# This could be amended by using HTML::Tidy or HTML::Valid + +use strict; +use Test::More; +use Data::Dumper; +use Text::Diff; + +my $tests = 0; +my $prg="./testssl.sh"; +my $uri="heise.de"; +my $out=""; +my $html=""; +my $debughtml=""; +my $edited_html=""; +my $htmlfile="tmp.html"; +my $check2run="--ip=one --sneaky --ids-friendly --color 0 --htmlfile $htmlfile"; +my $diff=""; +die "Unable to open $prg" unless -f $prg; + +printf "\n%s\n", "Doing HTML output checks"; +unlink $htmlfile; + +#1 +printf "%s\n", " .. running $prg against \"$uri\" to create HTML and terminal outputs (may take ~2 minutes)"; +# specify a TERM_WIDTH so that the two calls to testssl.sh don't create HTML files with different values of TERM_WIDTH +$out = `TERM_WIDTH=120 $prg $check2run $uri`; +$html = `cat $htmlfile`; +# $edited_html will contain the HTML with formatting information removed in order to compare against terminal output +# Start by removing the HTML header. +$edited_html = `tail -n +11 $htmlfile`; +unlink $htmlfile; + +# Remove the HTML footer +$edited_html =~ s/\n\<\/pre\>\n\<\/body\>\n\<\/html\>//; +# Remove any hypertext links for URLs +$edited_html =~ s/<a href=[0-9A-Za-z ";:_&=\/\.\?\-]*>//g; +$edited_html =~ s/<\/a>//g; + +# Replace escaped characters with their original text +$edited_html =~ s/&/&/g; +$edited_html =~ s/</</g; +$edited_html =~ s/>/>/g; +$edited_html =~ s/"/"/g; +$edited_html =~ s/'/'/g; + +cmp_ok($edited_html, "eq", $out, "HTML file matches terminal output"); +$tests++; + +$diff = diff \$edited_html, \$out; +printf "\n%s\n", "$diff"; + + +#2 +printf "\n%s\n", " .. running again $prg against \"$uri\", now with --debug 4 to create HTML output (may take another ~2 minutes)"; +# Redirect stderr to /dev/null in order to avoid some unexplained "date: invalid date" error messages +$out = `TERM_WIDTH=120 $prg $check2run --debug 4 $uri 2> /dev/null`; +$debughtml = `cat $htmlfile`; +unlink $htmlfile; + +# Remove date information from the Start and Done banners in the two HTML files, since they were created at different times +$html =~ s/Start 2[0-9][0-9][0-9]-[0-3][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]/Start XXXX-XX-XX XX:XX:XX/; +$debughtml =~ s/Start 2[0-9][0-9][0-9]-[0-3][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]/Start XXXX-XX-XX XX:XX:XX/; + +$html =~ s/Done 2[0-9][0-9][0-9]-[0-3][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9] \[ *[0-9]*s\]/Done XXXX-XX-XX XX:XX:XX [ Xs]/; +$debughtml =~ s/Done 2[0-9][0-9][0-9]-[0-3][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9] \[ *[0-9]*s\]/Done XXXX-XX-XX XX:XX:XX [ Xs]/; + +# Remove time difference from "HTTP clock skew" line +$html =~ s/HTTP clock skew \+?-?[0-9]* /HTTP clock skew X /; +$debughtml =~ s/HTTP clock skew \+?-?[0-9]* /HTTP clock skew X /; + +$debughtml =~ s/ Pre-test: .*\n//g; +$debughtml =~ s/.*OK: below 825 days.*\n//g; +$debughtml =~ s/.*DEBUG:.*\n//g; +$debughtml =~ s/No engine or GOST support via engine with your.*\n//g; + +cmp_ok($debughtml, "eq", $html, "HTML file created with --debug 4 matches HTML file created without --debug"); +$tests++; + +$diff = diff \$debughtml, \$html; +printf "\n%s\n", "$diff"; + + + +printf "\n"; +done_testing($tests); + + +# vim:ts=5:sw=5:expandtab + diff --git a/t/33_isJSON_severitylevel_valid.t b/t/33_isJSON_severitylevel_valid.t new file mode 100755 index 0000000..00b04a4 --- /dev/null +++ b/t/33_isJSON_severitylevel_valid.t @@ -0,0 +1,69 @@ +#!/usr/bin/env perl + +use strict; +use Test::More; +use Data::Dumper; +use JSON; + +my ( + $out, + $json, + $json_pretty, + $found, + $tests +); + +$tests = 0; + +my $prg="./testssl.sh"; +my $check2run = '-S -e --ids-friendly -U --severity LOW --color 0'; +my $uri = 'badssl.com'; + +printf "\n%s\n", "Doing severity level checks"; + +die "Unable to open $prg" unless -f $prg; +unlink 'tmp.json'; + +#1 +pass(" .. running testssl.sh against $uri to create a JSON report with severity level >= LOW (may take 2~3 minutes)"); $tests++; +$out = `$prg $check2run --jsonfile tmp.json $uri`; +$json = json('tmp.json'); +unlink 'tmp.json'; +$found = 0; +cmp_ok(@$json,'>',0,"At least 1 finding is expected"); $tests++; +foreach my $f ( @$json ) { + if ( $f->{severity} eq "INFO" ) { + $found = 1; + last; + } +} +is($found,0,"We should not have any finding with INFO level"); $tests++; + +#2 +pass(" .. running testssl.sh against $uri to create a JSON-PRETTY report with severity level >= LOW (may take 2~3 minutes)"); $tests++; +$out = `$prg $check2run --jsonfile-pretty tmp.json $uri`; +$json_pretty = json('tmp.json'); +unlink 'tmp.json'; +$found = 0; +my $vulnerabilities = $json_pretty->{scanResult}->[0]->{vulnerabilities}; +foreach my $f ( @$vulnerabilities ) { + if ( $f->{severity} eq "INFO" ) { + $found = 1; + last; + } +} +is($found,0,"We should not have any finding with INFO level"); $tests++; + +printf "\n"; +done_testing($tests); + +sub json($) { + my $file = shift; + $file = `cat $file`; + unlink $file; + return from_json($file); +} + + +# vim:ts=5:sw=5:expandtab + diff --git a/t/51_badssl.com.t b/t/51_badssl.com.t new file mode 100755 index 0000000..40b6e91 --- /dev/null +++ b/t/51_badssl.com.t @@ -0,0 +1,147 @@ +#!/usr/bin/env perl + +use strict; +use Test::More; +use Data::Dumper; +use JSON; + +my $tests = 0; + +my ( + $out, + $json, + $found, +); +# OK +pass("Running testssl.sh against badssl.com to create a baseline (may take 2~3 minutes)"); $tests++; +my $okout = `./testssl.sh -S -e --freak --logjam --drown --rc4 --sweet32 --breach --winshock --crime --jsonfile tmp.json --color 0 badssl.com`; +my $okjson = json('tmp.json'); +unlink 'tmp.json'; +cmp_ok(@$okjson,'>',10,"We have more then 10 findings"); $tests++; + +# Expiration +pass("Running testssl against expired.badssl.com"); $tests++; +$out = `./testssl.sh -S --jsonfile tmp.json --color 0 expired.badssl.com`; +like($out, qr/Chain of trust\s+NOT ok \(expired\)/,"The chain of trust should be expired"); $tests++; +like($out, qr/Certificate Validity \(UTC\)\s+expired/,"The certificate should be expired"); $tests++; +$json = json('tmp.json'); +unlink 'tmp.json'; +$found = 0; +foreach my $f ( @$json ) { + if ( $f->{id} eq "cert_expirationStatus" ) { + $found = 1; + like($f->{finding},qr/^expired/,"Finding reads expired."); $tests++; + is($f->{severity}, "CRITICAL", "Severity should be CRITICAL"); $tests++; + last; + } +} +is($found,1,"We had a finding for this in the JSON output"); $tests++; + +# Self signed and not-expired +pass("Running testssl against self-signed.badssl.com"); $tests++; +$out = `./testssl.sh -S --jsonfile tmp.json --color 0 self-signed.badssl.com`; +unlike($out, qr/Certificate Validity \(UTC\)s+expired/,"The certificate should not be expired"); $tests++; +$json = json('tmp.json'); +unlink 'tmp.json'; +$found = 0; +foreach my $f ( @$json ) { + if ( $f->{id} eq "cert_expirationStatus" ) { + $found = 1; + like($f->{finding},qr/days/,"Finding doesn't read expired."); $tests++; + isnt($f->{severity}, "CRITICAL", "Severity should be OK, MEDIUM or HIGH"); $tests++; + last; + } +} +is($found,1,"We had a finding for this in the JSON output"); $tests++; + +like($out, qr/Chain of trust.*?NOT ok.*\(self signed\)/,"Chain of trust should fail because of self signed"); $tests++; +$found = 0; +foreach my $f ( @$json ) { + if ( $f->{id} eq "cert_chain_of_trust" ) { + $found = 1; + like($f->{finding},qr/^.*self signed/,"Finding says certificate cannot be trusted."); $tests++; + is($f->{severity}, "CRITICAL", "Severity should be CRITICAL"); $tests++; + last; + } +} +is($found,1,"We had a finding for this in the JSON output"); $tests++; + +like($okout, qr/Chain of trust[^\n]*?Ok/,"Chain of trust should be ok"); $tests++; +$found = 0; +foreach my $f ( @$okjson ) { + if ( $f->{id} eq "cert_chain_of_trust" ) { + $found = 1; + like($f->{finding},qr/passed/,"Finding says certificate can be trusted."); $tests++; + # is($f->{finding},"^.*passed.*","Finding says certificate can be trusted."); $tests++; + is($f->{severity}, "OK", "Severity should be OK"); $tests++; + last; + } +} +is($found,1,"We had a finding for this in the JSON output"); $tests++; + +# Wrong host +#pass("Running testssl against wrong.host.badssl.com"); $tests++; +#$out = `./testssl.sh -S --jsonfile tmp.json --color 0 wrong.host.badssl.com`; +#unlike($out, qr/Certificate Expiration\s+expired\!/,"The certificate should not be expired"); $tests++; +#$json = json('tmp.json'); +#unlink 'tmp.json'; +#$found = 0; +#foreach my $f ( @$json ) { +# if ( $f->{id} eq "expiration" ) { +# $found = 1; +# unlike($f->{finding},qr/^Certificate Expiration.*expired\!/,"Finding should not read expired."); $tests++; +# is($f->{severity}, "ok", "Severity should be ok"); $tests++; +# last; +# } +#} +#is($found,1,"We had a finding for this in the JSON output"); $tests++; + +# Incomplete chain +pass("Running testssl against incomplete-chain.badssl.com"); $tests++; +$out = `./testssl.sh -S --jsonfile tmp.json --color 0 incomplete-chain.badssl.com`; +like($out, qr/Chain of trust.*?NOT ok\s+\(chain incomplete\)/,"Chain of trust should fail because of incomplete"); $tests++; +$json = json('tmp.json'); +unlink 'tmp.json'; +$found = 0; +foreach my $f ( @$json ) { + if ( $f->{id} eq "cert_chain_of_trust" ) { + $found = 1; + like($f->{finding},qr/^.*chain incomplete/,"Finding says certificate cannot be trusted."); $tests++; + is($f->{severity}, "CRITICAL", "Severity should be CRITICAL"); $tests++; + last; + } +} +is($found,1,"We had a finding for this in the JSON output"); $tests++; + +# TODO: RSA 8192 + +# TODO: CBC +#pass("Running testssl against cbc.badssl.com"); $tests++; +#$out = `./testssl.sh -e -U --jsonfile tmp.json --color 0 cbc.badssl.com`; +#like($out, qr/Chain of trust.*?NOT ok\s+\(chain incomplete\)/,"Chain of trust should fail because of incomplete"); $tests++; +#$json = json('tmp.json'); +#unlink 'tmp.json'; +#$found = 0; +#foreach my $f ( @$json ) { +# if ( $f->{id} eq "cert_chain_of_trust" ) { +# $found = 1; +# like($f->{finding},qr/^All certificate trust checks failed.*incomplete/,"Finding says certificate cannot be trusted."); $tests++; +# is($f->{severity}, "CRITICAL", "Severity should be CRITICAL"); $tests++; +# last; +# } +#} +#is($found,1,"We had a finding for this in the JSON output"); $tests++; + + +done_testing($tests); + +sub json($) { + my $file = shift; + $file = `cat $file`; + unlink $file; + return from_json($file); +} + + +# vim:ts=5:sw=5:expandtab + diff --git a/t/59_hpkp.t.tmpDISABLED b/t/59_hpkp.t.tmpDISABLED new file mode 100755 index 0000000..94dcea5 --- /dev/null +++ b/t/59_hpkp.t.tmpDISABLED @@ -0,0 +1,84 @@ +#!/usr/bin/env perl + +use strict; +use Test::More; +use Data::Dumper; +use JSON; + +my $tests = 0; + +my ( + $out, + $json, + $found, +); +# OK +pass("Running testssl.sh against ssl.sectionzero.org"); $tests++; +$out = `./testssl.sh --headers --jsonfile tmp.json --color 0 ssl.sectionzero.org`; +$json = json('tmp.json'); +unlink 'tmp.json'; + +# It is better to have findings in a hash +# Look for a host cert match in the process. +my $found = 0; +my %findings; +foreach my $f ( @$json ) { + $findings{$f->{id}} = $f; + if ( $f->{finding} =~ /matches the host certificate/ ) { + $found++; + } +} +is($found,1,"We found 1 'matches the host certificate' finding"); $tests++; +like($out,'/Host cert/',"There is a 'host cert match' in the text output"); $tests++; + +# Sub CA match +ok( exists $findings{"hpkp_YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg"},"We have a finding for SPKI YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg"); $tests++; +like($findings{"hpkp_YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg"}->{finding},'/matches Intermediate CA \'Let\'s Encrypt Authority X3\' pinned in the HPKP header/',"We have our Sub CA finding"); $tests++; +is($findings{"hpkp_YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg"}->{severity}, "OK", "The finding is ok"); $tests++; +like($out,'/Sub CA\: YLh1dUR9y6Kja30RrAn7JKnbQG\/uEtLMkBgFF2Fuihg/',"There is a 'Sub CA match' in the text output"); $tests++; + +# Root CA match Lets encrypt +ok( exists $findings{"hpkp_Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys"},"We have a finding for SPKI Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys"); $tests++; +like($findings{"hpkp_Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys"}->{finding},'/matches Root CA \'DST Root CA X3\' pinned in the HPKP header/',"This is a Root CA finding"); $tests++; +like($findings{"hpkp_Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys"}->{finding},'/DST Root CA X3/',"Correct Root CA"); $tests++; +like($findings{"hpkp_Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys"}->{finding},'/matches Root CA \'DST Root CA X3\' pinned in the HPKP header\. \(Root CA part of the chain\)/',"CA is indeed part of chain"); $tests++; +is($findings{"hpkp_Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys"}->{severity}, "INFO", "The finding is informational"); $tests++; +like($out,'/Root CA\: Vjs8r4z\+80wjNcr1YKepWQboSIRi63WsWXhIMN\+eWys/',"There is a 'Root CA match' in the text output"); $tests++; + +# Root CA StartCom +ok( exists $findings{"hpkp_5C8kvU039KouVrl52D0eZSGf4Onjo4Khs8tmyTlV3nU"},"We have a finding for SPKI 5C8kvU039KouVrl52D0eZSGf4Onjo4Khs8tmyTlV3nU"); $tests++; +like($findings{"hpkp_5C8kvU039KouVrl52D0eZSGf4Onjo4Khs8tmyTlV3nU"}->{finding},'/matches Root CA \'StartCom Certification Authority\' pinned in the HPKP header/',"This is a Root CA finding"); $tests++; +like($findings{"hpkp_5C8kvU039KouVrl52D0eZSGf4Onjo4Khs8tmyTlV3nU"}->{finding},'/StartCom Certification Authority/',"Correct Root CA"); $tests++; +like($findings{"hpkp_5C8kvU039KouVrl52D0eZSGf4Onjo4Khs8tmyTlV3nU"}->{finding},'/matches Root CA \'StartCom Certification Authority\' pinned in the HPKP header\. \(Root backup SPKI\)/',"CA is indeed NOT part of chain"); $tests++; +is($findings{"hpkp_5C8kvU039KouVrl52D0eZSGf4Onjo4Khs8tmyTlV3nU"}->{severity}, "INFO", "The finding is informational"); $tests++; +like($out,'/Backups\: 5C8kvU039KouVrl52D0eZSGf4Onjo4Khs8tmyTlV3nU/',"There is a 'Root CA match' in the text output"); $tests++; + +# Bad PIN +ok( exists $findings{"hpkp_MTIzYmFkMTIzYmFkMTIzYmFkMTIzYmFkMTIzYmFkMTI"},"We have a finding for SPKI MTIzYmFkMTIzYmFkMTIzYmFkMTIzYmFkMTIzYmFkMTI"); $tests++; +like($findings{"hpkp_MTIzYmFkMTIzYmFkMTIzYmFkMTIzYmFkMTIzYmFkMTI"}->{finding},'/doesn\'t match anything/',"It doesn't match indeed"); $tests++; +is($findings{"hpkp_MTIzYmFkMTIzYmFkMTIzYmFkMTIzYmFkMTIzYmFkMTI"}->{severity}, "INFO", "The finding is informational"); $tests++; +like($out,'/MTIzYmFkMTIzYmFkMTIzYmFkMTIzYmFkMTIzYmFkMTI/',"There is an 'unmatched key' in the text output"); $tests++; + +like($findings{hpkp_spkis}->{finding},'/5 keys pinned/',"5 keys pinned in json"); $tests++; +like($out,'/5 keys/',"5 keys pinned in text output"); $tests++; + +like($findings{hpkp_age}->{finding},'/90 days/',"90 days in json"); $tests++; +like($out,'/90 days/',"90 days in text output"); $tests++; + +like($findings{hpkp_subdomains}->{finding},'/this domain only/',"this domain only in json"); $tests++; +like($out,'/just this domain/',"just this domain text output"); $tests++; + +like($findings{hpkp_preload}->{finding},'/NOT marked for/',"no preloading in json"); $tests++; + +done_testing($tests); + +sub json($) { + my $file = shift; + $file = `cat $file`; + unlink $file; + return from_json($file); +} + + +# vim:ts=5:sw=5:expandtab + diff --git a/t/61_diff_testsslsh.t b/t/61_diff_testsslsh.t new file mode 100755 index 0000000..f4070b1 --- /dev/null +++ b/t/61_diff_testsslsh.t @@ -0,0 +1,70 @@ +#!/usr/bin/env perl + +# Baseline diff test against testssl.sh (csv output) +# +# We don't use a full run yet and only the certificate section. +# There we would need to blacklist at least: +# cert_serialNumber, cert_fingerprintSHA1, cert_fingerprintSHA256, cert +# cert_expirationStatus, cert_notBefore, cert_notAfter, cert_caIssuers, intermediate_cert +# +# help is appreciated here + +use strict; +use Test::More; +use Data::Dumper; +use Text::Diff; + +my $tests = 0; +my $prg="./testssl.sh"; +my $master_socket_csv="./t/baseline_data/default_testssl.csvfile"; +my $socket_csv="tmp.csv"; +my $check2run="-p -s -P --fs -h -U -c -q --ip=one --color 0 --csvfile $socket_csv"; +#my $check2run="-p --color 0 --csvfile $socket_csv"; +my $uri="testssl.sh"; +my $diff=""; + +die "Unable to open $prg" unless -f $prg; +die "Unable to open $master_socket_csv" unless -f $master_socket_csv; + + +# Provide proper start conditions +unlink "tmp.csv"; + +# Title +printf "\n%s\n", "Diff unit test IPv4 against \"$uri\""; + +#1 run +`$prg $check2run $uri 2>&1`; + +$diff = diff $socket_csv, $master_socket_csv; + +$socket_csv=`cat tmp.csv`; +$master_socket_csv=`cat $master_socket_csv`; + +# Filter for changes that are allowed to occur +$socket_csv=~ s/HTTP_clock_skew.*\n//g; +$master_socket_csv=~ s/HTTP_clock_skew.*\n//g; + +# DROWN +$socket_csv=~ s/censys.io.*\n//g; +$master_socket_csv=~ s/censys.io.*\n//g; + +# HTTP time +$socket_csv=~ s/HTTP_headerTime.*\n//g; +$master_socket_csv=~ s/HTTP_headerTime.*\n//g; + +# Compare the differences to the master file -- and print differences if there were detected. +# +cmp_ok($socket_csv, "eq", $master_socket_csv, "Check whether CSV output matches master file from $uri") or + diag ("\n%s\n", "$diff"); + +$tests++; + +unlink "tmp.csv"; + +done_testing($tests); +printf "\n"; + + +# vim:ts=5:sw=5:expandtab + diff --git a/t/Readme.md b/t/Readme.md new file mode 100644 index 0000000..272372b --- /dev/null +++ b/t/Readme.md @@ -0,0 +1,10 @@ +### Naming scheme + +* 00-05: Does the bare testssl.sh work at all? +* 10-29: Do scans work fine (client side)? +* 30-39: Does reporting work? +* 50-69: Are the results what I expect (server side)? + +Please help to write Travis/CI tests! Documentation can be found [here](https://perldoc.perl.org/Test/More.html). +You can consult the existing code here. Feel free to use `10_baseline_ipv4_http.t` or `23_client_simulation.t` as a +template. diff --git a/t/baseline_data/default_testssl.csvfile b/t/baseline_data/default_testssl.csvfile new file mode 100644 index 0000000..28118ba --- /dev/null +++ b/t/baseline_data/default_testssl.csvfile @@ -0,0 +1,140 @@ +"id","fqdn/ip","port","severity","finding","cve","cwe" +"service","testssl.sh/81.169.166.184","443","INFO","HTTP","","" +"pre_128cipher","testssl.sh/81.169.166.184","443","INFO","No 128 cipher limit bug","","" +"SSLv2","testssl.sh/81.169.166.184","443","OK","not offered","","" +"SSLv3","testssl.sh/81.169.166.184","443","OK","not offered","","" +"TLS1","testssl.sh/81.169.166.184","443","LOW","offered (deprecated)","","" +"TLS1_1","testssl.sh/81.169.166.184","443","LOW","offered (deprecated)","","" +"TLS1_2","testssl.sh/81.169.166.184","443","OK","offered","","" +"TLS1_3","testssl.sh/81.169.166.184","443","OK","offered with final","","" +"NPN","testssl.sh/81.169.166.184","443","INFO","offered with h2, http/1.1 (advertised)","","" +"ALPN_HTTP2","testssl.sh/81.169.166.184","443","OK","h2","","" +"ALPN","testssl.sh/81.169.166.184","443","INFO","http/1.1","","" +"cipherlist_NULL","testssl.sh/81.169.166.184","443","OK","not offered","","CWE-327" +"cipherlist_aNULL","testssl.sh/81.169.166.184","443","OK","not offered","","CWE-327" +"cipherlist_EXPORT","testssl.sh/81.169.166.184","443","OK","not offered","","CWE-327" +"cipherlist_LOW","testssl.sh/81.169.166.184","443","OK","not offered","","CWE-327" +"cipherlist_3DES_IDEA","testssl.sh/81.169.166.184","443","INFO","not offered","","CWE-310" +"cipherlist_OBSOLETED","testssl.sh/81.169.166.184","443","LOW","offered","","CWE-310" +"cipherlist_STRONG_NOFS","testssl.sh/81.169.166.184","443","OK","offered","","" +"cipherlist_STRONG_FS","testssl.sh/81.169.166.184","443","OK","offered","","" +"cipher_order-tls1","testssl.sh/81.169.166.184","443","OK","server","","" +"cipher-tls1_xc014","testssl.sh/81.169.166.184","443","LOW","TLSv1 xc014 ECDHE-RSA-AES256-SHA ECDH 256 AES 256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA","","" +"cipher-tls1_xc013","testssl.sh/81.169.166.184","443","LOW","TLSv1 xc013 ECDHE-RSA-AES128-SHA ECDH 256 AES 128 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA","","" +"cipher-tls1_x88","testssl.sh/81.169.166.184","443","LOW","TLSv1 x88 DHE-RSA-CAMELLIA256-SHA DH 2048 Camellia 256 TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA","","" +"cipher-tls1_x45","testssl.sh/81.169.166.184","443","LOW","TLSv1 x45 DHE-RSA-CAMELLIA128-SHA DH 2048 Camellia 128 TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA","","" +"cipher-tls1_x39","testssl.sh/81.169.166.184","443","LOW","TLSv1 x39 DHE-RSA-AES256-SHA DH 2048 AES 256 TLS_DHE_RSA_WITH_AES_256_CBC_SHA","","" +"cipher-tls1_x33","testssl.sh/81.169.166.184","443","LOW","TLSv1 x33 DHE-RSA-AES128-SHA DH 2048 AES 128 TLS_DHE_RSA_WITH_AES_128_CBC_SHA","","" +"cipher-tls1_x35","testssl.sh/81.169.166.184","443","LOW","TLSv1 x35 AES256-SHA RSA AES 256 TLS_RSA_WITH_AES_256_CBC_SHA","","" +"cipherorder_TLSv1","testssl.sh/81.169.166.184","443","INFO","ECDHE-RSA-AES256-SHA ECDHE-RSA-AES128-SHA DHE-RSA-CAMELLIA256-SHA DHE-RSA-CAMELLIA128-SHA DHE-RSA-AES256-SHA DHE-RSA-AES128-SHA AES256-SHA","","" +"cipher_order-tls1_1","testssl.sh/81.169.166.184","443","OK","server","","" +"cipher-tls1_1_xc014","testssl.sh/81.169.166.184","443","LOW","TLSv1.1 xc014 ECDHE-RSA-AES256-SHA ECDH 256 AES 256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA","","" +"cipher-tls1_1_xc013","testssl.sh/81.169.166.184","443","LOW","TLSv1.1 xc013 ECDHE-RSA-AES128-SHA ECDH 256 AES 128 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA","","" +"cipher-tls1_1_x88","testssl.sh/81.169.166.184","443","LOW","TLSv1.1 x88 DHE-RSA-CAMELLIA256-SHA DH 2048 Camellia 256 TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA","","" +"cipher-tls1_1_x45","testssl.sh/81.169.166.184","443","LOW","TLSv1.1 x45 DHE-RSA-CAMELLIA128-SHA DH 2048 Camellia 128 TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA","","" +"cipher-tls1_1_x39","testssl.sh/81.169.166.184","443","LOW","TLSv1.1 x39 DHE-RSA-AES256-SHA DH 2048 AES 256 TLS_DHE_RSA_WITH_AES_256_CBC_SHA","","" +"cipher-tls1_1_x33","testssl.sh/81.169.166.184","443","LOW","TLSv1.1 x33 DHE-RSA-AES128-SHA DH 2048 AES 128 TLS_DHE_RSA_WITH_AES_128_CBC_SHA","","" +"cipher-tls1_1_x35","testssl.sh/81.169.166.184","443","LOW","TLSv1.1 x35 AES256-SHA RSA AES 256 TLS_RSA_WITH_AES_256_CBC_SHA","","" +"cipherorder_TLSv1_1","testssl.sh/81.169.166.184","443","INFO","ECDHE-RSA-AES256-SHA ECDHE-RSA-AES128-SHA DHE-RSA-CAMELLIA256-SHA DHE-RSA-CAMELLIA128-SHA DHE-RSA-AES256-SHA DHE-RSA-AES128-SHA AES256-SHA","","" +"cipher_order-tls1_2","testssl.sh/81.169.166.184","443","OK","server","","" +"cipher-tls1_2_xc030","testssl.sh/81.169.166.184","443","OK","TLSv1.2 xc030 ECDHE-RSA-AES256-GCM-SHA384 ECDH 256 AESGCM 256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384","","" +"cipher-tls1_2_xc02f","testssl.sh/81.169.166.184","443","OK","TLSv1.2 xc02f ECDHE-RSA-AES128-GCM-SHA256 ECDH 256 AESGCM 128 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256","","" +"cipher-tls1_2_x9f","testssl.sh/81.169.166.184","443","OK","TLSv1.2 x9f DHE-RSA-AES256-GCM-SHA384 DH 2048 AESGCM 256 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384","","" +"cipher-tls1_2_x9e","testssl.sh/81.169.166.184","443","OK","TLSv1.2 x9e DHE-RSA-AES128-GCM-SHA256 DH 2048 AESGCM 128 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256","","" +"cipher-tls1_2_xc028","testssl.sh/81.169.166.184","443","LOW","TLSv1.2 xc028 ECDHE-RSA-AES256-SHA384 ECDH 256 AES 256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384","","" +"cipher-tls1_2_xc014","testssl.sh/81.169.166.184","443","LOW","TLSv1.2 xc014 ECDHE-RSA-AES256-SHA ECDH 256 AES 256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA","","" +"cipher-tls1_2_xc013","testssl.sh/81.169.166.184","443","LOW","TLSv1.2 xc013 ECDHE-RSA-AES128-SHA ECDH 256 AES 128 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA","","" +"cipher-tls1_2_x88","testssl.sh/81.169.166.184","443","LOW","TLSv1.2 x88 DHE-RSA-CAMELLIA256-SHA DH 2048 Camellia 256 TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA","","" +"cipher-tls1_2_x45","testssl.sh/81.169.166.184","443","LOW","TLSv1.2 x45 DHE-RSA-CAMELLIA128-SHA DH 2048 Camellia 128 TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA","","" +"cipher-tls1_2_x6b","testssl.sh/81.169.166.184","443","LOW","TLSv1.2 x6b DHE-RSA-AES256-SHA256 DH 2048 AES 256 TLS_DHE_RSA_WITH_AES_256_CBC_SHA256","","" +"cipher-tls1_2_x39","testssl.sh/81.169.166.184","443","LOW","TLSv1.2 x39 DHE-RSA-AES256-SHA DH 2048 AES 256 TLS_DHE_RSA_WITH_AES_256_CBC_SHA","","" +"cipher-tls1_2_x67","testssl.sh/81.169.166.184","443","LOW","TLSv1.2 x67 DHE-RSA-AES128-SHA256 DH 2048 AES 128 TLS_DHE_RSA_WITH_AES_128_CBC_SHA256","","" +"cipher-tls1_2_x33","testssl.sh/81.169.166.184","443","LOW","TLSv1.2 x33 DHE-RSA-AES128-SHA DH 2048 AES 128 TLS_DHE_RSA_WITH_AES_128_CBC_SHA","","" +"cipher-tls1_2_x9d","testssl.sh/81.169.166.184","443","OK","TLSv1.2 x9d AES256-GCM-SHA384 RSA AESGCM 256 TLS_RSA_WITH_AES_256_GCM_SHA384","","" +"cipher-tls1_2_x9c","testssl.sh/81.169.166.184","443","OK","TLSv1.2 x9c AES128-GCM-SHA256 RSA AESGCM 128 TLS_RSA_WITH_AES_128_GCM_SHA256","","" +"cipher-tls1_2_x3d","testssl.sh/81.169.166.184","443","LOW","TLSv1.2 x3d AES256-SHA256 RSA AES 256 TLS_RSA_WITH_AES_256_CBC_SHA256","","" +"cipher-tls1_2_x35","testssl.sh/81.169.166.184","443","LOW","TLSv1.2 x35 AES256-SHA RSA AES 256 TLS_RSA_WITH_AES_256_CBC_SHA","","" +"cipherorder_TLSv1_2","testssl.sh/81.169.166.184","443","INFO","ECDHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-SHA384 ECDHE-RSA-AES256-SHA ECDHE-RSA-AES128-SHA DHE-RSA-CAMELLIA256-SHA DHE-RSA-CAMELLIA128-SHA DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA AES256-GCM-SHA384 AES128-GCM-SHA256 AES256-SHA256 AES256-SHA","","" +"cipher_order-tls1_3","testssl.sh/81.169.166.184","443","OK","server","","" +"cipher-tls1_3_x1302","testssl.sh/81.169.166.184","443","OK","TLSv1.3 x1302 TLS_AES_256_GCM_SHA384 ECDH 253 AESGCM 256 TLS_AES_256_GCM_SHA384","","" +"cipher-tls1_3_x1303","testssl.sh/81.169.166.184","443","OK","TLSv1.3 x1303 TLS_CHACHA20_POLY1305_SHA256 ECDH 253 ChaCha20 256 TLS_CHACHA20_POLY1305_SHA256","","" +"cipher-tls1_3_x1301","testssl.sh/81.169.166.184","443","OK","TLSv1.3 x1301 TLS_AES_128_GCM_SHA256 ECDH 253 AESGCM 128 TLS_AES_128_GCM_SHA256","","" +"cipherorder_TLSv1_3","testssl.sh/81.169.166.184","443","INFO","TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256","","" +"prioritize_chacha_TLSv1_3","testssl.sh/81.169.166.184","443","INFO","false","","" +"cipher_order","testssl.sh/81.169.166.184","443","OK","server","","" +"FS","testssl.sh/81.169.166.184","443","OK","offered","","" +"FS_ciphers","testssl.sh/81.169.166.184","443","INFO","TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-SHA384 ECDHE-RSA-AES256-SHA DHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA DHE-RSA-CAMELLIA256-SHA TLS_AES_128_GCM_SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-SHA DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA DHE-RSA-CAMELLIA128-SHA","","" +"FS_ECDHE_curves","testssl.sh/81.169.166.184","443","OK","prime256v1 secp384r1 secp521r1 X25519 X448","","" +"DH_groups","testssl.sh/81.169.166.184","443","OK","Unknown DH group (2048 bits)","","" +"FS_TLS12_sig_algs","testssl.sh/81.169.166.184","443","INFO","RSA-PSS-RSAE+SHA256 RSA-PSS-RSAE+SHA384 RSA-PSS-RSAE+SHA512 RSA+SHA256 RSA+SHA384 RSA+SHA512 RSA+SHA224","","" +"FS_TLS13_sig_algs","testssl.sh/81.169.166.184","443","INFO","RSA-PSS-RSAE+SHA256 RSA-PSS-RSAE+SHA384 RSA-PSS-RSAE+SHA512","","" +"HTTP_status_code","testssl.sh/81.169.166.184","443","INFO","200 OK ('/')","","" +"HTTP_clock_skew","testssl.sh/81.169.166.184","443","INFO","0 seconds from localtime","","" +"HTTP_headerTime","testssl.sh/81.169.166.184","443","INFO","1654006271","","" +"HSTS_time","testssl.sh/81.169.166.184","443","OK","362 days (=31337000 seconds) > 15552000 seconds","","" +"HSTS_subdomains","testssl.sh/81.169.166.184","443","INFO","only for this domain","","" +"HSTS_preload","testssl.sh/81.169.166.184","443","INFO","domain is NOT marked for preloading","","" +"HPKP","testssl.sh/81.169.166.184","443","INFO","No support for HTTP Public Key Pinning","","" +"banner_server","testssl.sh/81.169.166.184","443","INFO","Never trust a banner","","" +"banner_application","testssl.sh/81.169.166.184","443","INFO","X-Powered-By: A portion of humor","","" +"cookie_count","testssl.sh/81.169.166.184","443","INFO","0 at '/'","","" +"X-Frame-Options","testssl.sh/81.169.166.184","443","OK","DENY","","" +"X-Content-Type-Options","testssl.sh/81.169.166.184","443","OK","nosniff","","" +"Content-Security-Policy","testssl.sh/81.169.166.184","443","OK","script-src 'unsafe-inline'; style-src 'unsafe-inline' 'self'; object-src 'self'; base-uri 'none'; form-action 'none'; img-src 'self' ; default-src 'self'; frame-ancestors 'self'; upgrade-insecure-requests;","","" +"banner_reverseproxy","testssl.sh/81.169.166.184","443","INFO","--","","CWE-200" +"heartbleed","testssl.sh/81.169.166.184","443","OK","not vulnerable, no heartbeat extension","CVE-2014-0160","CWE-119" +"CCS","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2014-0224","CWE-310" +"ticketbleed","testssl.sh/81.169.166.184","443","OK","no session ticket extension","CVE-2016-9244","CWE-200" +"ROBOT","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2017-17382 CVE-2017-17427 CVE-2017-17428 CVE-2017-13098 CVE-2017-1000385 CVE-2017-13099 CVE-2016-6883 CVE-2012-5081 CVE-2017-6168","CWE-203" +"secure_renego","testssl.sh/81.169.166.184","443","OK","supported","","CWE-310" +"secure_client_renego","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2011-1473","CWE-310" +"CRIME_TLS","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2012-4929","CWE-310" +"BREACH","testssl.sh/81.169.166.184","443","OK","not vulnerable, no gzip/deflate/compress/br HTTP compression - only supplied '/' tested","CVE-2013-3587","CWE-310" +"POODLE_SSL","testssl.sh/81.169.166.184","443","OK","not vulnerable, no SSLv3","CVE-2014-3566","CWE-310" +"fallback_SCSV","testssl.sh/81.169.166.184","443","OK","supported","","" +"SWEET32","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2016-2183 CVE-2016-6329","CWE-327" +"FREAK","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2015-0204","CWE-310" +"DROWN","testssl.sh/81.169.166.184","443","OK","not vulnerable on this host and port","CVE-2016-0800 CVE-2016-0703","CWE-310" +"DROWN_hint","testssl.sh/81.169.166.184","443","INFO","Make sure you don't use this certificate elsewhere with SSLv2 enabled services, see https://search.censys.io/search?resource=hosts&virtual_hosts=INCLUDE&q=31B44391529821C6A77F3C78B02D716A07F99B8FDB342BF5A78F263C25375968","CVE-2016-0800 CVE-2016-0703","CWE-310" +"LOGJAM","testssl.sh/81.169.166.184","443","OK","not vulnerable, no DH EXPORT ciphers,","CVE-2015-4000","CWE-310" +"LOGJAM-common_primes","testssl.sh/81.169.166.184","443","OK","--","CVE-2015-4000","CWE-310" +"BEAST_CBC_TLS1","testssl.sh/81.169.166.184","443","MEDIUM","ECDHE-RSA-AES256-SHA ECDHE-RSA-AES128-SHA DHE-RSA-CAMELLIA256-SHA DHE-RSA-CAMELLIA128-SHA DHE-RSA-AES256-SHA DHE-RSA-AES128-SHA AES256-SHA","CVE-2011-3389","CWE-20" +"BEAST","testssl.sh/81.169.166.184","443","LOW","VULNERABLE -- but also supports higher protocols TLSv1.1 TLSv1.2 (likely mitigated)","CVE-2011-3389","CWE-20" +"LUCKY13","testssl.sh/81.169.166.184","443","LOW","potentially vulnerable, uses TLS CBC ciphers","CVE-2013-0169","CWE-310" +"winshock","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2014-6321","CWE-94" +"RC4","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2013-2566 CVE-2015-2808","CWE-310" +"clientsimulation-android_60","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256","","" +"clientsimulation-android_70","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384","","" +"clientsimulation-android_81","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384","","" +"clientsimulation-android_90","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-android_X","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-android_11","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-android_12","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-chrome_79_win10","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-chrome_101_win10","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-firefox_66_win81","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-firefox_100_win10","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-ie_6_xp","testssl.sh/81.169.166.184","443","INFO","No connection","","" +"clientsimulation-ie_8_win7","testssl.sh/81.169.166.184","443","INFO","TLSv1.0 ECDHE-RSA-AES256-SHA","","" +"clientsimulation-ie_8_xp","testssl.sh/81.169.166.184","443","INFO","No connection","","" +"clientsimulation-ie_11_win7","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 DHE-RSA-AES256-GCM-SHA384","","" +"clientsimulation-ie_11_win81","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 DHE-RSA-AES256-GCM-SHA384","","" +"clientsimulation-ie_11_winphone81","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-SHA","","" +"clientsimulation-ie_11_win10","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384","","" +"clientsimulation-edge_15_win10","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384","","" +"clientsimulation-edge_101_win10_21h2","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-safari_121_ios_122","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-safari_130_osx_10146","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-safari_154_osx_1231","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-java_7u25","testssl.sh/81.169.166.184","443","INFO","TLSv1.0 ECDHE-RSA-AES128-SHA","","" +"clientsimulation-java_8u161","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384","","" +"clientsimulation-java1102","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-java1703","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-go_1178","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-libressl_283","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384","","" +"clientsimulation-openssl_102e","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384","","" +"clientsimulation-openssl_110l","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384","","" +"clientsimulation-openssl_111d","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-openssl_303","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" +"clientsimulation-apple_mail_16_0","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384","","" +"clientsimulation-thunderbird_91_9","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","","" |