diff --git a/.travis.yml b/.travis.yml
index d1d660b..06f35cd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,6 +7,12 @@ addons:
packages:
- dnsutils
- jsonlint
+before_install:
+ - if ! git diff --name-only $TRAVIS_COMMIT_RANGE | grep -qvE '(.md)|(.pem)|(.pdf)|(.html)|^(LICENSE)|^(docs)|^(utils)|^(bin)|(Dockerfile)'
+ then
+ echo "no code was updated, not running the CI."
+ exit
+ fi
install:
- cpanm --notest Test::More
- cpanm --notest Data::Dumper
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cdbd545..1e0d9f2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -27,7 +27,10 @@
* Added environment variable for amount of attempts for ssl renegotiation check
* Added --user-agent argument to support using a custom User Agent
* Added --overwrite argument to support overwriting output files without warning
-* Headerflag X-XSS-Protection is labeled as INFO
+* Headerflag X-XSS-Protection is now labeled as INFO
+* Client simulation runs in wide mode which is even better readable
+* Added --reqheader to support custom headers in HTTP requests
+
### Features implemented / improvements in 3.0
diff --git a/CREDITS.md b/CREDITS.md
index beee57a..de826d5 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -42,6 +42,7 @@ Full contribution, see git log.
* Jim Blankendaal
- maximum certificate lifespan of 398 days
- ssl renegotiation amount variable
+ - custom http request headers
* Frank Breedijk
- Detection of insecure redirects
@@ -181,4 +182,3 @@ Probably more I forgot to mention which did give me feedback, bug reports and he
* Ivan Ristic/Qualys for the liberal license which made it possible to make partly use of the client data
* My family for supporting me doing this work
-
diff --git a/Dockerfile.md b/Dockerfile.md
index bbdf371..1eed4e3 100644
--- a/Dockerfile.md
+++ b/Dockerfile.md
@@ -1,6 +1,21 @@
-## Usage:
+## Usage
+
+### From git directory
+
+```
+docker build .
+```
+
+Catch is when you run without image tags you need to catch the ID when building
+
+```
+[..]
+---> 889fa2f99933
+Successfully built 889fa2f99933
+```
+
+More comfortable is
-(in git directory):
```
docker build -t mytestssl .
docker run --rm -t mytestssl example.com
@@ -13,22 +28,22 @@ docker run -t mytestssl --help
docker run --rm -t mytestssl -p --header example.com
```
-or pull the image from dockerhub and run:
+### From dockerhub
+
+You can pull the image from dockerhub and run:
```
-docker run --rm -t drwetter/testssl.sh --pfs example.com
+docker run --rm -t drwetter/testssl.sh --fs example.com
```
-Tags supported are: ``latest``, ``stable`` which _for now_ are all the same and point to ``3.0``.
+Supported tages are: ``3.1dev`` and ``latest`, which are the same, i.e. the rolling release. ``3.0`` is the latest stable version from git which might have a few improvements (see git log) over the released version 3.0.X.
``docker run --rm -t drwetter/testssl.sh:stable example.com``.
-And for the indomitable users who prefer to run old stuff you can use the tag ``2.9.5``. Please note ``2.9dev`` should not be used anymore.
-
-Keep in mind that any output file (--log, --html, --json etc.) will be created in the container. If you wish to have this created in a local directory you can mount a volume into the container and change the output prefix where the container user has write access to, e.g.:
+Keep in mind that any output file (--log, --html, --json etc.) will be created within the container. If you wish to have this created in a local directory on your host you can mount a volume into the container and change the output prefix where the container user has write access to, e.g.:
```
docker run --rm -t -v /tmp:/data drwetter/testssl.sh --htmlfile /data/ example.com
```
-which writes the output to ``/tmp/example.com_p443--
+
--reqheader <header> This can be used to add additional HTTP request headers in the correct format Headername: headercontent. This parameter can be called multiple times if required. For example: --reqheader 'Proxy-Authorization: Basic dGVzdHNzbDpydWxlcw==' --reqheader 'ClientID: 0xDEADBEAF'. REQHEADER is the corresponding environment variable.
+
SPECIAL INVOCATIONS
-t <protocol>, --starttls <protocol> does a default run against a STARTTLS enabled protocol. protocol must be one of ftp, smtp, pop3, imap, xmpp, xmpp-server, telnet, ldap, irc, lmtp, nntp, postgres, mysql. For the latter four you need e.g. the supplied OpenSSL or OpenSSL version 1.1.1. Please note: MongoDB doesn't offer a STARTTLS connection, LDAP currently only works with --ssl-native. telnet and irc is WIP.
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index 9a9ee34..e395736 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -110,6 +110,8 @@ The same can be achieved by setting the environment variable `WARNINGS`.
`--basicauth ` This can be set to provide HTTP basic auth credentials which are used during checks for security headers. BASICAUTH is the ENV variable you can use instead.
+`--reqheader ` This can be used to add additional HTTP request headers in the correct format `Headername: headercontent`. This parameter can be called multiple times if required. For example: `--reqheader 'Proxy-Authorization: Basic dGVzdHNzbDpydWxlcw==' --reqheader 'ClientID: 0xDEADBEAF'`. REQHEADER is the corresponding environment variable.
+
### SPECIAL INVOCATIONS
diff --git a/etc/README.md b/etc/README.md
index 3550ac5..51f1d1d 100644
--- a/etc/README.md
+++ b/etc/README.md
@@ -28,6 +28,8 @@ If you want to check trust against e.g. a company internal CA you need to use ``
* ``cipher-mapping.txt`` contains information about all of the cipher suites defined for SSL/TLS
+* ``curves-mapping.txt`` contains information about all of the eliptic curves defined by IANA
+
* ``ca_hashes.txt`` is used for HPKP test in order to have a fast comparison with known CAs. Use
``~/utils/create_ca_hashes.sh`` for an update
diff --git a/etc/client-simulation.wiresharked.md b/etc/client-simulation.wiresharked.md
index 60c66d9..6ed28a4 100644
--- a/etc/client-simulation.wiresharked.md
+++ b/etc/client-simulation.wiresharked.md
@@ -14,7 +14,7 @@ The whole process is done manually.
* Retrieve "handshakebytes" by marking the Record Layer --> Copy --> As a hex stream.
* Figure out "protos" and "tlsvers" by looking at the supported_versions TLS extension (43=0x002b). May work only on modern clients. Be careful as some do not list all TLS versions here (OpenSSL 1.1.1 lists only TLS 1.2/1.3 here)
* Adjust "lowest_protocol" and "highest_protocol" accordingly.
-* Get "curves" from at the supported groups TLS extension 10 = 0x00a. Omit any GREASE.
+* For "curves" mark the supported groups TLS extension --> Copy --> As a hex stream, remove any leading GREASE ciphers (?a?a) and supply it to `~/utils/hexstream2curves.sh`
* Retrieve "alpn" by looking at the alpn TLS extension 16 (=0x0010).
* Review TLS extension 13 (=0x000d) whether any SHA1 signature algorithm is listed. If not "requiresSha2" is true
* Leave "maxDhBits"/"minDhBits" and "minRsaBits"/"maxRsaBits" at -1, unless you know for sure what the client can handle
diff --git a/etc/curves-mapping.txt b/etc/curves-mapping.txt
new file mode 100644
index 0000000..1b348ec
--- /dev/null
+++ b/etc/curves-mapping.txt
@@ -0,0 +1,47 @@
+ 0x00,0x00 - NULL TPM_ECC_NONE
+ 0x00,0x01 - sect163k1 sect163k1
+ 0x00,0x02 - sect163r1 sect163r1
+ 0x00,0x03 - sect163r2 sect163r2
+ 0x00,0x04 - sect193r1 sect193r1
+ 0x00,0x05 - sect193r2 sect193r2
+ 0x00,0x06 - sect233k1 sect233k1
+ 0x00,0x07 - sect233r1 sect233r1
+ 0x00,0x08 - sect239k1 sect239k1
+ 0x00,0x09 - sect283k1 sect283k1
+ 0x00,0x0a - sect283r1 sect283r1
+ 0x00,0x0b - sect409k1 sect409k1
+ 0x00,0x0c - sect409r1 sect409r1
+ 0x00,0x0d - sect571k1 sect571k1
+ 0x00,0x0e - sect571r1 sect571r1
+ 0x00,0x0f - secp160k1 secp160k1
+ 0x00,0x10 - secp160r1 secp160r1
+ 0x00,0x11 - secp160r2 secp160r2
+ 0x00,0x12 - secp192k1 secp192k1
+ 0x00,0x13 - secp192r1 secp192r1
+ 0x00,0x14 - secp224k1 secp224k1
+ 0x00,0x15 - secp224r1 secp224r1
+ 0x00,0x16 - secp256k1 secp256k1
+ 0x00,0x17 - secp256r1 secp256r1
+ 0x00,0x18 - secp384r1 secp384r1
+ 0x00,0x19 - secp521r1 secp521r1
+ 0x00,0x1a - brainpoolP256r1 brainpoolP256r1
+ 0x00,0x1b - brainpoolP384r1 brainpoolP384r1
+ 0x00,0x1c - brainpoolP512r1 brainpoolP512r1
+ 0x00,0x1d - x25519 x25519
+ 0x00,0x1e - x448 x448
+ 0x00,0x1f - brainpoolP256r1tls13 brainpoolP256r1tls13
+ 0x00,0x20 - brainpoolP384r1tls13 brainpoolP384r1tls13
+ 0x00,0x21 - brainpoolP512r1tls13 brainpoolP512r1tls13
+ 0x00,0x22 - GC256A GC256A
+ 0x00,0x23 - GC256B GC256B
+ 0x00,0x24 - GC256C GC256C
+ 0x00,0x25 - GC256D GC256D
+ 0x00,0x26 - GC512A GC512A
+ 0x00,0x27 - GC512B GC512B
+ 0x00,0x28 - GC512C GC512C
+ 0x00,0x29 - curveSM2 curveSM2
+ 0x00,0x100 - ffdhe2048 ffdhe2048
+ 0x00,0x101 - ffdhe3072 ffdhe3072
+ 0x00,0x102 - ffdhe4096 ffdhe4096
+ 0x00,0x103 - ffdhe6144 ffdhe6144
+ 0x00,0x104 - ffdhe8192 ffdhe8192
diff --git a/t/20_baseline_ipv4_http.t b/t/10_baseline_ipv4_http.t
similarity index 92%
rename from t/20_baseline_ipv4_http.t
rename to t/10_baseline_ipv4_http.t
index 575a262..06d61ad 100755
--- a/t/20_baseline_ipv4_http.t
+++ b/t/10_baseline_ipv4_http.t
@@ -20,8 +20,8 @@ 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';
-my $openssl_regex_bl='(e|E)rror|(f|F)atal|\.\/testssl\.sh: line |Oops|s_client connect problem';
+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="";
diff --git a/t/21_baseline_ipv6_http.t.DISABLED b/t/11_baseline_ipv6_http.t.DISABLED
similarity index 92%
rename from t/21_baseline_ipv6_http.t.DISABLED
rename to t/11_baseline_ipv6_http.t.DISABLED
index 2043f50..e8253f8 100755
--- a/t/21_baseline_ipv6_http.t.DISABLED
+++ b/t/11_baseline_ipv6_http.t.DISABLED
@@ -20,8 +20,8 @@ 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';
-my $openssl_regex_bl='(e|E)rror|(f|F)atal|\.\/testssl\.sh: line |Oops|s_client connect problem';
+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="";
diff --git a/t/25_baseline_starttls.t b/t/21_baseline_starttls.t
similarity index 78%
rename from t/25_baseline_starttls.t
rename to t/21_baseline_starttls.t
index efb795e..57c3663 100755
--- a/t/25_baseline_starttls.t
+++ b/t/21_baseline_starttls.t
@@ -17,14 +17,14 @@ use Data::Dumper;
my $tests = 0;
my $prg="./testssl.sh";
-my $check2run_smtp="--protocols --standard --fs --server-preference --headers --vulnerable --each-cipher -q --ip=one --color 0";
+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';
-my $openssl_regex_bl='(e|E)rror|(f|F)atal|\.\/testssl\.sh: line |Oops|s_client connect problem';
+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="";
@@ -60,12 +60,14 @@ $socket_out = `./testssl.sh $check2run -t pop3 $uri 2>&1`;
unlike($socket_out, qr/$socket_regex_bl/, "");
$tests++;
+# commented out, bc of travis' limits
+#
+#printf "\n%s\n", "STARTTLS POP3 unit tests via OpenSSL --> $uri ...";
# unlink "tmp.json";
-printf "\n%s\n", "STARTTLS POP3 unit tests via OpenSSL --> $uri ...";
-$openssl_out = `./testssl.sh --ssl-native $check2run -t pop3 $uri 2>&1`;
+#$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++;
+#unlike($openssl_out, qr/$openssl_regex_bl/, "");
+#$tests++;
$uri="imap.gmx.net:143";
@@ -93,11 +95,13 @@ $socket_out = `./testssl.sh $check2run -t xmpp $uri 2>&1`;
unlike($openssl_out, qr/$openssl_regex_bl/, "");
$tests++;
-printf "\n%s\n", "STARTTLS XMPP unit tests via OpenSSL --> $uri ...";
-$openssl_out = `./testssl.sh --ssl-native $check2run -t xmpp $uri 2>&1`;
+# 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++;
+#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 ...";
@@ -118,13 +122,15 @@ $socket_out =~ s/ error querying OCSP responder .*\n//g;
unlike($socket_out, qr/$socket_regex_bl/, "");
$tests++;
-printf "\n%s\n", "STARTTLS FTP unit tests via OpenSSL --> $uri ...";
-$openssl_out = `./testssl.sh --ssl-native $check2run -t ftp $uri 2>&1`;
+# 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++;
+# $openssl_out =~ s/ error querying OCSP responder .*\n//g;
+# unlike($openssl_out, qr/$openssl_regex_bl/, "");
+# $tests++;
# https://ldapwiki.com/wiki/Public%20LDAP%20Servers
@@ -146,11 +152,13 @@ $socket_out = `./testssl.sh $check2run -t nntp $uri 2>&1`;
unlike($socket_out, qr/$socket_regex_bl/, "");
$tests++;
-printf "\n%s\n", "STARTTLS NNTP unit tests via OpenSSL --> $uri ...";
-$openssl_out = `./testssl.sh --ssl-native $check2run -t nntp $uri 2>&1`;
+# 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++;
+#unlike($openssl_out, qr/$openssl_regex_bl/, "");
+#$tests++;
# IRC: missing
diff --git a/t/23_client_simulation.t b/t/23_client_simulation.t
index 60ab990..c241132 100755
--- a/t/23_client_simulation.t
+++ b/t/23_client_simulation.t
@@ -18,8 +18,8 @@ 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';
-my $openssl_regex_bl='(e|E)rror|(f|F)atal|\.\/testssl\.sh: line |Oops|s_client connect problem';
+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="";
@@ -53,12 +53,14 @@ $socket_out = `./testssl.sh $check2run -t smtp $uri 2>&1`;
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++;
+#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";
diff --git a/t/07_isJSON_valid.t b/t/31_isJSON_valid.t
similarity index 87%
rename from t/07_isJSON_valid.t
rename to t/31_isJSON_valid.t
index 26814b8..5a84bed 100755
--- a/t/07_isJSON_valid.t
+++ b/t/31_isJSON_valid.t
@@ -9,13 +9,13 @@ use JSON;
my $tests = 0;
my $prg="./testssl.sh";
-my $check2run ="--ip=one -q --color 0";
+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';
-my $openssl_regex_bl='(e|E)rror|(f|F)atal|\.\/testssl\.sh: line |Oops|s_client connect problem';
+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;
@@ -44,7 +44,7 @@ $tests++;
#3
-# This testss.sh run deliberately does NOT work as travis-ci.org blocks port 25 egress.
+# 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`;
diff --git a/t/08_isHTML_valid.t b/t/32_isHTML_valid.t
similarity index 97%
rename from t/08_isHTML_valid.t
rename to t/32_isHTML_valid.t
index 294661a..a1aa819 100755
--- a/t/08_isHTML_valid.t
+++ b/t/32_isHTML_valid.t
@@ -15,7 +15,7 @@ my $out="";
my $html="";
my $debughtml="";
my $edited_html="";
-my $check2run="--ip=one --color 0 --htmlfile tmp.html";
+my $check2run="--ip=one --ids-friendly --color 0 --htmlfile tmp.html";
my $diff="";
die "Unable to open $prg" unless -f $prg;
diff --git a/t/09_isJSON_severitylevel_valid.t b/t/33_isJSON_severitylevel_valid.t
similarity index 65%
rename from t/09_isJSON_severitylevel_valid.t
rename to t/33_isJSON_severitylevel_valid.t
index e39d6ab..9f17de8 100755
--- a/t/09_isJSON_severitylevel_valid.t
+++ b/t/33_isJSON_severitylevel_valid.t
@@ -15,13 +15,18 @@ my (
$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 badssl.com to create a JSON report with severity level equal greater than LOW (may take 2~3 minutes)"); $tests++;
-$out = `./testssl.sh -S -e -U --jsonfile tmp.json --severity LOW --color 0 badssl.com`;
+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;
@@ -35,8 +40,8 @@ foreach my $f ( @$json ) {
is($found,0,"We should not have any finding with INFO level"); $tests++;
#2
-pass(" .. running testssl.sh against badssl.com to create a JSON-PRETTY report with severity level equal greater than LOW (may take 2~3 minutes)"); $tests++;
-$out = `./testssl.sh -S -e -U --jsonfile-pretty tmp.json --severity LOW --color 0 badssl.com`;
+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;
diff --git a/t/51_badssl.com.t b/t/51_badssl.com.t
index 16c5aed..b66f756 100755
--- a/t/51_badssl.com.t
+++ b/t/51_badssl.com.t
@@ -14,7 +14,7 @@ my (
);
# 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 --crime --jsonfile tmp.json --color 0 badssl.com`;
+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++;
diff --git a/t/61_diff_testsslsh.t b/t/61_diff_testsslsh.t
new file mode 100755
index 0000000..f7afe79
--- /dev/null
+++ b/t/61_diff_testsslsh.t
@@ -0,0 +1,64 @@
+#!/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 apreciated 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 now only HTTP_clock_skew
+$socket_csv=~ s/HTTP_clock_skew.*\n//g;
+$master_socket_csv=~ s/HTTP_clock_skew.*\n//g;
+
+# Compare the differences to the master file -- and print differences if there were detected.
+# Filtering takes place later, so if there will be a difference detected it'll also show HTTP_clock_skew :-(
+#
+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:tw=95:ts=5:sw=5:et
+
diff --git a/t/Readme.md b/t/Readme.md
index 56ba9c5..272372b 100644
--- a/t/Readme.md
+++ b/t/Readme.md
@@ -1,10 +1,10 @@
### Naming scheme
* 00-05: Does the bare testssl.sh work at all?
-* 06-09: Does the reporting work at all?
-* 20-39: Do scans work fine (client side)?
+* 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 `20_baseline_ipv4_http.t` or `23_client_simulation.t` as a
+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..9c89f61
--- /dev/null
+++ b/t/baseline_data/default_testssl.csvfile
@@ -0,0 +1,137 @@
+"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_AVERAGE","testssl.sh/81.169.166.184","443","LOW","offered","","CWE-310"
+"cipherlist_GOOD","testssl.sh/81.169.166.184","443","OK","offered","",""
+"cipherlist_STRONG","testssl.sh/81.169.166.184","443","OK","offered","",""
+"cipher_order","testssl.sh/81.169.166.184","443","OK","server","",""
+"protocol_negotiated","testssl.sh/81.169.166.184","443","OK","Default protocol TLS1.3","",""
+"cipher_negotiated","testssl.sh/81.169.166.184","443","OK","TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)","",""
+"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-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-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-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","",""
+"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)","",""
+"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","",""
+"HSTS_time","testssl.sh/81.169.166.184","443","OK","362 days (=31337000 seconds) > 15465600 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'; default-src 'self' ; child-src 'none'; object-src 'self'; frame-ancestors 'self'; upgrade-insecure-requests","",""
+"Expect-CT","testssl.sh/81.169.166.184","443","OK","max-age=86400, enforce","",""
+"X-XSS-Protection","testssl.sh/81.169.166.184","443","INFO","1; mode=block","",""
+"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://censys.io/ipv4?q=B95B85E87BA020CD25A95DF53CDD16C7DCEA96EFE7FEF9411529D511B39015B3","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_442","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384","",""
+"clientsimulation-android_500","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256","",""
+"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-chrome_74_win10","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-firefox_66_win81","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","",""
+"clientsimulation-firefox_71_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_17_win10","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384","",""
+"clientsimulation-opera_66_win10","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","",""
+"clientsimulation-safari_9_ios9","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384","",""
+"clientsimulation-safari_9_osx1011","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384","",""
+"clientsimulation-safari_10_osx1012","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-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-apple_ats_9_ios9","testssl.sh/81.169.166.184","443","INFO","TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384","",""
+"clientsimulation-java_6u45","testssl.sh/81.169.166.184","443","INFO","No connection","",""
+"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-java1201","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_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-thunderbird_68_3_1","testssl.sh/81.169.166.184","443","INFO","TLSv1.3 TLS_AES_256_GCM_SHA384","",""
diff --git a/testssl.sh b/testssl.sh
index e0cc3ea..38c4f0c 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -162,6 +162,7 @@ QUIET=${QUIET:-false} # don't output the banner. By doing this
SSL_NATIVE=${SSL_NATIVE:-false} # we do per default bash sockets where possible "true": switch back to "openssl native"
ASSUME_HTTP=${ASSUME_HTTP:-false} # in seldom cases (WAF, old servers, grumpy SSL) service detection fails. "True" enforces HTTP checks
BASICAUTH=${BASICAUTH:-""} # HTTP basic auth credentials can be set here like user:pass
+REQHEADER=${REQHEADER:-""} # HTTP custom request header can be set here like Header: content. Can be used multiple times.
BUGS=${BUGS:-""} # -bugs option from openssl, needed for some BIG IP F5
WARNINGS=${WARNINGS:-""} # can be either off or batch
DEBUG=${DEBUG:-0} # 1: normal output the files in /tmp/ are kept for further debugging purposes
@@ -382,6 +383,7 @@ TLS_NOW="" # Similar
TLS_DIFFTIME_SET=false # Tells TLS functions to measure the TLS difftime or not
NOW_TIME=""
HTTP_TIME=""
+REQHEADERS=()
GET_REQ11=""
START_TIME=0 # time in epoch when the action started
END_TIME=0 # .. ended
@@ -893,6 +895,15 @@ is_ipv6addr() {
return 1
}
+join_by() {
+ # joins an array using a custom delimiter https://web.archive.org/web/20201222183540/https://stackoverflow.com/questions/1527049/how-can-i-join-elements-of-an-array-in-bash/17841619#17841619
+ local d=$1
+ shift
+ local f=$1
+ shift
+ printf %s "$f" "${@/#/$d}";
+}
+
###### END universal helper function definitions ######
###### START ServerHello/OpenSSL/F5 function definitions ######
@@ -4822,21 +4833,19 @@ run_client_simulation() {
outln
debugme echo
- if "$WIDE"; then
- if [[ "$DISPLAY_CIPHERNAMES" =~ openssl ]]; then
- out " Browser Protocol Cipher Suite Name (OpenSSL) "
- ( "$using_sockets" || "$HAS_DH_BITS") && out "Forward Secrecy"
- outln
- out "--------------------------------------------------------------------------"
- else
- out " Browser Protocol Cipher Suite Name (IANA/RFC) "
- ( "$using_sockets" || "$HAS_DH_BITS") && out "Forward Secrecy"
- outln
- out "------------------------------------------------------------------------------------------"
- fi
- ( "$using_sockets" || "$HAS_DH_BITS") && out "----------------------"
+ if [[ "$DISPLAY_CIPHERNAMES" =~ openssl ]]; then
+ out " Browser Protocol Cipher Suite Name (OpenSSL) "
+ ( "$using_sockets" || "$HAS_DH_BITS") && out "Forward Secrecy"
outln
+ out "--------------------------------------------------------------------------"
+ else
+ out " Browser Protocol Cipher Suite Name (IANA/RFC) "
+ ( "$using_sockets" || "$HAS_DH_BITS") && out "Forward Secrecy"
+ outln
+ out "------------------------------------------------------------------------------------------"
fi
+ ( "$using_sockets" || "$HAS_DH_BITS") && out "----------------------"
+ outln
if ! "$using_sockets"; then
# We can't use the connectivity checker here as of now the openssl reply is always empty (reason??)
save_max_ossl_fail=$MAX_OSSL_FAIL
@@ -4946,27 +4955,23 @@ run_client_simulation() {
cipher="$(openssl2rfc "$cipher")"
[[ -z "$cipher" ]] && cipher=$(get_cipher $TMPFILE)
fi
- out "$proto "
- "$WIDE" && out " "
+ out "$proto "
if [[ "$COLOR" -le 2 ]]; then
out "$cipher"
else
pr_cipher_quality "$cipher"
fi
- if "$WIDE"; then
- if [[ "$DISPLAY_CIPHERNAMES" =~ openssl ]]; then
- for (( j=${#cipher}; j < 34; j++ )); do
- out " "
- done
- else
- for (( j=${#cipher}; j < 50; j++ )); do
- out " "
- done
- fi
+ if [[ "$DISPLAY_CIPHERNAMES" =~ openssl ]]; then
+ for (( j=${#cipher}; j < 34; j++ )); do
+ out " "
+ done
+ else
+ for (( j=${#cipher}; j < 50; j++ )); do
+ out " "
+ done
fi
if [[ -n "$what_dh" ]]; then
[[ -n "$curve" ]] && curve="($curve)"
- "$WIDE" || out ", "
if [[ "$what_dh" == ECDH ]]; then
pr_ecdh_quality "$bits" "$(printf -- "%-12s" "$bits bit $what_dh") $curve"
else
@@ -4974,7 +4979,6 @@ run_client_simulation() {
fi
else
if "$HAS_DH_BITS" || ( "$using_sockets" && [[ -n "${handshakebytes[i]}" ]] ); then
- "$WIDE" || out ", "
out "No FS"
fi
fi
@@ -19354,6 +19358,7 @@ tuning / connect options (most also can be preset via environment variables):
--phone-out allow to contact external servers for CRL download and querying OCSP responder
--add-ca path to with *.pem or a comma separated list of CA files to include in trust check
--basicauth provide HTTP basic auth information.
+ --reqheader add custom http request headers
output options (can also be preset via environment variables):
--quiet don't output the banner. By doing this you acknowledge usage terms normally appearing in the banner
@@ -19509,6 +19514,7 @@ SHOW_EACH_C: $SHOW_EACH_C
SSL_NATIVE: $SSL_NATIVE
ASSUME_HTTP $ASSUME_HTTP
BASICAUTH: $BASICAUTH
+REQHEADER: $REQHEADER
SNEAKY: $SNEAKY
OFFENSIVE: $OFFENSIVE
PHONE_OUT: $PHONE_OUT
@@ -20634,6 +20640,7 @@ determine_service() {
local ua
local protocol
local basicauth_header=""
+ local reqheader=""
# Check if we can connect to $NODEIP:$PORT. Attention: This ALWAYS uses sockets. Thus timeouts for --ssl-=native do not apply
if ! fd_socket 5; then
@@ -20661,7 +20668,10 @@ determine_service() {
if [[ -n "$BASICAUTH" ]]; then
basicauth_header="Authorization: Basic $(safe_echo "$BASICAUTH" | $OPENSSL base64 2>/dev/null)\r\n"
fi
- GET_REQ11="GET $URL_PATH HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $ua\r\n${basicauth_header}Accept-Encoding: identity\r\nAccept: text/*\r\nConnection: Close\r\n\r\n"
+ if [[ -n "$REQHEADERS" ]]; then
+ reqheader="$(join_by "\r\n" "${REQHEADERS[@]}")\r\n" #Add all required custom http headers to one string with newlines
+ fi
+ GET_REQ11="GET $URL_PATH HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $ua\r\n${basicauth_header}${reqheader}Accept-Encoding: identity\r\nAccept: text/*\r\nConnection: Close\r\n\r\n"
# returns always 0:
service_detection $OPTIMAL_PROTO
else # STARTTLS
@@ -22326,6 +22336,11 @@ parse_cmd_line() {
BASICAUTH="$(parse_opt_equal_sign "$1" "$2")"
[[ $? -eq 0 ]] && shift
;;
+ --reqheader|--reqheader=*)
+ REQHEADER="$(parse_opt_equal_sign "$1" "$2")"
+ [[ $? -eq 0 ]] && shift
+ REQHEADERS+=("$REQHEADER")
+ ;;
(--) shift
break
;;
diff --git a/utils/hexstream2curves.sh b/utils/hexstream2curves.sh
new file mode 100755
index 0000000..f62e154
--- /dev/null
+++ b/utils/hexstream2curves.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+hs="$1"
+len=${#hs}
+echo "# curves: $((len/4))"
+
+mapfile="etc/curves-mapping.txt"
+[ -s $mapfile ] || mapfile="../$mapfile"
+[ -s $mapfile ] || exit 255
+
+cur=""
+first=true
+
+for ((i=0; i $grepstr --> "
+ cur=$(grep -i -E "^ *${grepstr}" $mapfile | awk '{ print $3 }')
+ if [[ $grepstr == 0x00,0xff ]]; then
+ echo TPM_ECC_NONE
+ else
+ echo $cur
+ fi
+ if "$first"; then
+ curves="$cur"
+ first=false
+ else
+ curves="$curves:$cur"
+ fi
+done
+
+echo
+# remove leading : because of GREASE, and trailing because of TPM_ECC_NONE
+curves="${curves%:}"
+echo ${curves#:}