From 385485d39b096f21347c9aea3dfa6820c59d8b37 Mon Sep 17 00:00:00 2001
From: Dirk Wetter 2) standard cipher categories to give you upfront an idea for the ciphers supported 3) checks (perfect) forward secrecy: ciphers and elliptical curves 3) checks forward secrecy: ciphers and elliptical curves 4) server preferences (server order)./bin/
-f, --pfs, --fs,--nsa
Checks robust (perfect) forward secrecy key exchange. "Robust" means that ciphers having intrinsic severe weaknesses like Null Authentication or Encryption, 3DES and RC4 won't be considered here. There shouldn't be the wrong impression that a secure key exchange has been taking place and everything is fine when in reality the encryption sucks. Also this section lists the available elliptical curves and Diffie Hellman groups, as well as FFDHE groups (TLS 1.2 and TLS 1.3).
-f, --fs, --nsa, --forward-secrecy
Checks robust forward secrecy key exchange. "Robust" means that ciphers having intrinsic severe weaknesses like Null Authentication or Encryption, 3DES and RC4 won't be considered here. There shouldn't be the wrong impression that a secure key exchange has been taking place and everything is fine when in reality the encryption sucks. Also this section lists the available elliptical curves and Diffie Hellman groups, as well as FFDHE groups (TLS 1.2 and TLS 1.3).
-p, --protocols
checks TLS/SSL protocols SSLv2, SSLv3, TLS 1.0 through TLS 1.3 and for HTTP: SPDY (NPN) and ALPN, a.k.a. HTTP/2. For TLS 1.3 several drafts (from 18 on) and final are supported and being tested for.
-q, --quiet
Normally testssl.sh displays a banner on stdout with several version information, usage rights and a warning. This option suppresses it. Please note that by choosing this option you acknowledge usage terms and the warning normally appearing in the banner.
--wide
Except the "each cipher output" all tests displays the single cipher name (scheme see below). This option enables testssl.sh to display also for the following sections the same output as for testing each ciphers: BEAST, PFS, RC4. The client simulation has also a wide mode. The difference here is restricted to a column aligned output and a proper headline. The environment variable WIDE
can be used instead.
--wide
Except the "each cipher output" all tests displays the single cipher name (scheme see below). This option enables testssl.sh to display also for the following sections the same output as for testing each ciphers: BEAST, FS, RC4. The client simulation has also a wide mode. The difference here is restricted to a column aligned output and a proper headline. The environment variable WIDE
can be used instead.
--mapping <openssl|iana|no-openssl|no-iana>
testssl.sh testssl.sh
-does a default run on https://testssl.sh (protocols, standard cipher lists, PFS, server preferences, server defaults, vulnerabilities, testing all known 370 ciphers, client simulation.
+does a default run on https://testssl.sh (protocols, standard cipher lists, FS, server preferences, server defaults, vulnerabilities, testing all known 370 ciphers, client simulation.
testssl.sh testssl.net:443
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index d2756b6..f347c20 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -42,7 +42,7 @@ linked OpenSSL binaries for major operating systems are supplied in `./bin/`.
2) standard cipher categories to give you upfront an idea for the ciphers supported
-3) checks (perfect) forward secrecy: ciphers and elliptical curves
+3) checks forward secrecy: ciphers and elliptical curves
4) server preferences (server order)
@@ -164,7 +164,7 @@ Any single check switch supplied as an argument prevents testssl.sh from doing a
* `Average grade Ciphers`: 'HIGH:MEDIUM:AES:CAMELLIA:ARIA:!IDEA:!CHACHA20:!3DES:!RC2:!RC4:!AESCCM8:!AESCCM:!AESGCM:!ARIAGCM:!aNULL'
* `Strong grade Ciphers` (AEAD): 'AESGCM:CHACHA20:AESGCM:CamelliaGCM:AESCCM8:AESCCM'
-`-f, --pfs, --fs,--nsa ` Checks robust (perfect) forward secrecy key exchange. "Robust" means that ciphers having intrinsic severe weaknesses like Null Authentication or Encryption, 3DES and RC4 won't be considered here. There shouldn't be the wrong impression that a secure key exchange has been taking place and everything is fine when in reality the encryption sucks. Also this section lists the available elliptical curves and Diffie Hellman groups, as well as FFDHE groups (TLS 1.2 and TLS 1.3).
+`-f, --fs, --nsa, --forward-secrecy` Checks robust forward secrecy key exchange. "Robust" means that ciphers having intrinsic severe weaknesses like Null Authentication or Encryption, 3DES and RC4 won't be considered here. There shouldn't be the wrong impression that a secure key exchange has been taking place and everything is fine when in reality the encryption sucks. Also this section lists the available elliptical curves and Diffie Hellman groups, as well as FFDHE groups (TLS 1.2 and TLS 1.3).
`-p, --protocols` checks TLS/SSL protocols SSLv2, SSLv3, TLS 1.0 through TLS 1.3 and for HTTP: SPDY (NPN) and ALPN, a.k.a. HTTP/2. For TLS 1.3 several drafts (from 18 on) and final are supported and being tested for.
@@ -258,7 +258,7 @@ Also for multiple server certificates are being checked for as well as for the c
`-q, --quiet` Normally testssl.sh displays a banner on stdout with several version information, usage rights and a warning. This option suppresses it. Please note that by choosing this option you acknowledge usage terms and the warning normally appearing in the banner.
-`--wide` Except the "each cipher output" all tests displays the single cipher name (scheme see below). This option enables testssl.sh to display also for the following sections the same output as for testing each ciphers: BEAST, PFS, RC4. The client simulation has also a wide mode. The difference here is restricted to a column aligned output and a proper headline. The environment variable `WIDE` can be used instead.
+`--wide` Except the "each cipher output" all tests displays the single cipher name (scheme see below). This option enables testssl.sh to display also for the following sections the same output as for testing each ciphers: BEAST, FS, RC4. The client simulation has also a wide mode. The difference here is restricted to a column aligned output and a proper headline. The environment variable `WIDE` can be used instead.
`--mapping /etc/hosts
. The use of the switch is only useful if you either
--phone-out
Checking for revoked certificates via CRL and OCSP is not done per default. This switch instructs testssl.sh to query external -- in a sense of the current run -- URIs. By using this switch you acknowledge that the check might have privacy issues, a download of several megabytes (CRL file) may happen and there may be network connectivity problems while contacting the endpoint which testssl.sh doesn't handle. PHONE_OUT is the environment variable for this which needs to be set to true if you want this.
--add-ca <cafile>
enables you to add your own CA(s) for trust chain checks. cafile
can be a single path or multiple paths as a comma separated list of root CA files. Internally they will be added during runtime to all CA stores. This is (only) useful for internal hosts whose certificates is issued by internal CAs. Alternatively
-ADDITIONAL_CA_FILES is the environment variable for this.
For the trust chain check 5 certificate stores are provided. If the test against one of the trust stores failed, the one is being identified and the reason for the failure is displayed - in addition the ones which succeeded are displayed too.
-You can configure your own CA via ADDITIONAL_CA_FILES, see section FILES
below. If the server provides no matching record in Subject Alternative Name (SAN) but in Common Name (CN), it will be indicated as this is deprecated.
+You can configure your own CA via ADDTL_CA_FILES, see section FILES
below. If the server provides no matching record in Subject Alternative Name (SAN) but in Common Name (CN), it will be indicated as this is deprecated.
Also for multiple server certificates are being checked for as well as for the certificate reply to a non-SNI (Server Name Indication) client hello to the IP address. Regarding the TLS clock skew: it displays the time difference to the client. Only a few TLS stacks nowadays still support this and return the local clock gmt_unix_time
, e.g. IIS, openssl < 1.0.1f. In addition to the HTTP date you could e.g. derive that there are different hosts where your TLS and your HTTP request ended -- if the time deltas differ significantly.
-x <pattern>, --single-cipher <pattern>
tests matched pattern
of ciphers against a server. Patterns are similar to -V pattern , --local pattern
, see above about matching.
./bin/
2) standard cipher categories to give you upfront an idea for the ciphers supported
-3) checks forward secrecy: ciphers and elliptical curves
+3) server's cipher preferences (server order)
-4) server preferences (server order)
+4) forward secrecy: ciphers and elliptical curves
5) server defaults (certificate info, TLS extensions, session information)
@@ -133,9 +133,7 @@ linked OpenSSL binaries for major operating systems are supplied in ./bin/
7) vulnerabilities
-8) testing each of 370 preconfigured ciphers
-
-9) client simulation
+8) client simulation
OPTIONS AND PARAMETERS
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index 8f29a92..ac54ec4 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -42,9 +42,9 @@ linked OpenSSL binaries for major operating systems are supplied in `./bin/`.
2) standard cipher categories to give you upfront an idea for the ciphers supported
-3) checks forward secrecy: ciphers and elliptical curves
+3) server's cipher preferences (server order?)
-4) server preferences (server order)
+4) forward secrecy: ciphers and elliptical curves
5) server defaults (certificate info, TLS extensions, session information)
@@ -52,9 +52,7 @@ linked OpenSSL binaries for major operating systems are supplied in `./bin/`.
7) vulnerabilities
-8) testing each of 370 preconfigured ciphers
-
-9) client simulation
+8) client simulation
## OPTIONS AND PARAMETERS
From 50d10d00f7afabc81ec142d1a56d9a0bcecea244 Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Mon, 27 Apr 2020 19:19:19 +0200
Subject: [PATCH 055/211] Add latest changes
including the one since 3.0
---
CHANGELOG.md | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 289f81a..675f757 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,20 @@
## Change Log
+### Features implemented / improvements in 3.1dev
+
+* Extend Server (cipher) preference: always now in wide mode instead of running all ciphers in the end (per default)
+* Improved compatibility with OpenSSL 3.0
+* Renamed PFS/perfect forward secrecy --> FS/forward secrecy
+* Improved mass testing
+* Align better colors of ciphers with standard cipherlists
+* Added several ciphers to colored ciphers
+* Percent output char problem fixed
+* Several display/output fixes
+* Security fix: DNS input
+* Don't use external pwd anymore
+* Rating (pending)
+
### Features implemented / improvements in 3.0
* Full support of TLS 1.3, shows also drafts supported
From 88c04f534525685da43f6d301e0be2f1a030274c Mon Sep 17 00:00:00 2001
From: Dirk
Date: Tue, 28 Apr 2020 10:06:29 +0200
Subject: [PATCH 056/211] Relax the possible GPL license contradiction
... see also #1590
---
Readme.md | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/Readme.md b/Readme.md
index 7454f79..071828e 100644
--- a/Readme.md
+++ b/Readme.md
@@ -30,9 +30,12 @@ cryptographic flaws.
### License
This software is free. You can use it under the terms of GPLv2, see LICENSE.
-In addition starting from version 3.0rc1 if you're offering a scanner based on testssl.sh
-as a public and / or paid service in the internet you need to mention to your audience that you're using
-this program and where to get this program from.
+
+Attribution is important for the future of this project -- also in the
+internet. Thus if you're offering a scanner based on testssl.sh as a public and/or
+paid service in the internet you are strongly encouraged to mention to your audience
+that you're using this program and where to get this program from. That helps us
+to get bugfixes, other feedback and more contributions.
### Compatibility
From 13a76bc7198577f72cfb8f91306ef745489ac9c1 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Tue, 28 Apr 2020 13:35:24 +0200
Subject: [PATCH 057/211] (try to) resolve merge conflict
---
CHANGELOG.md | 14 +++++++++++---
doc/testssl.1.md | 8 ++++----
2 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 26c1e23..2b2a34b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,11 +1,19 @@
## Change Log
-### Features implemented / improvements in 3.1
-* Renamed PFS into FS
+### Features implemented / improvements in 3.1dev
+
+* Extend Server (cipher) preference: always now in wide mode instead of running all ciphers in the end (per default)
+* Improved compatibility with OpenSSL 3.0
+* Renamed PFS/perfect forward secrecy --> FS/forward secrecy
* Improved mass testing
+* Align better colors of ciphers with standard cipherlists
+* Added several ciphers to colored ciphers
+* Percent output char problem fixed
+* Several display/output fixes
* Security fix: DNS input
-* Rating
+* Don't use external pwd anymore
+* Rating (via SSL Labs)
### Features implemented / improvements in 3.0
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index 1006684..e81ae78 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -40,9 +40,9 @@ linked OpenSSL binaries for major operating systems are supplied in `./bin/`.
1) SSL/TLS protocol check
-2) standard cipher categories to give you upfront an idea for the ciphers supported
+2) checks forward secrecy: ciphers and elliptical curves
-3) checks forward secrecy: ciphers and elliptical curves
+3) standard cipher categories to give you upfront an idea for the ciphers supported
4) server preferences (server order)
@@ -54,9 +54,9 @@ linked OpenSSL binaries for major operating systems are supplied in `./bin/`.
8) testing each of 370 preconfigured ciphers
-9) client simulation
+8) client simulation
-10) Result of script in form of a grade
+9) Result of script in form of a grade
## OPTIONS AND PARAMETERS
From db84e5c87c853758e7af7ac1689f94d423952692 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Tue, 28 Apr 2020 13:38:23 +0200
Subject: [PATCH 058/211] Add grade cap reasons and warnings to JSON/CSV
---
testssl.sh | 28 +++++++++-------------------
1 file changed, 9 insertions(+), 19 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 75fbd7a..3971364 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -20541,7 +20541,7 @@ run_rating() {
local c1_score c2_score c3_score c1_wscore c2_wscore c3_wscore
local c1_worst c1_best
local c3_worst c3_best c3_worst_cb c3_best_cb
- local old_ifs=$IFS sorted_reasons sorted_warnings reason_loop=0 warning_loop=0
+ local old_ifs=$IFS sorted_reasons sorted_warnings reason_nr=0 warning_nr=0
outln "\n";
pr_headlineln " Rating (experimental) "
@@ -20705,35 +20705,25 @@ run_rating() {
# Pretty print - again, it's just nicer to read
for reason in "${sorted_reasons[@]}"; do
- if [[ $reason_loop -eq 0 ]]; then
+ if [[ $reason_nr -eq 0 ]]; then
pr_bold " Grade cap reasons "; outln "$reason"
- let reason_loop++
else
outln " $reason"
fi
+ let reason_nr++
+ fileout "grade_cap_reason_${reason_nr}" "INFO" "$reason"
done
for warning in "${sorted_warnings[@]}"; do
- if [[ $warning_loop -eq 0 ]]; then
- pr_bold " Grade warning "; prln_svrty_medium "$warning"
- let warning_loop++
+ if [[ $warning_nr -eq 0 ]]; then
+ pr_bold " Grade warning "; prln_svrty_medium "$warning"
else
- prln_svrty_medium " $warning"
+ prln_svrty_medium " $warning"
fi
+ let warning_nr++
+ fileout "grade_cap_warning_${warning_nr}" "INFO" "$warning"
done
- case $GRADE_CAP in
- # A-E: WIP
- A) fileout "grade_cap_reasons" "INFO" "" ;;
- B) fileout "grade_cap_reasons" "INFO" "" ;;
- C) fileout "grade_cap_reasons" "INFO" "" ;;
- D) fileout "grade_cap_reasons" "INFO" "" ;;
- E) fileout "grade_cap_reasons" "INFO" "" ;;
- M) fileout "grade_cap_reasons" "INFO" "SAN / CN mismatch" ;;
- F) fileout "grade_cap_reasons" "INFO" "Severe vulnerability or cryptographic problem" ;;
- T) fileout "grade_cap_reasons" "INFO" "Issue with certificate" ;;
- esac
-
return 0
}
From 97ac4c452e441b2e7f34bc573f19c60d8b8b0b5d Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Thu, 23 Apr 2020 11:20:46 +0200
Subject: [PATCH 060/211] Update documentation (ADDITIONAL_CA_FILES ->
ADDTL_CA_FILES)
which happened in d44a643fab6be6755a917f85ed491c38990d15ae in
testssl.sh .
This fixes it in the related files. See also #1581
---
Coding_Convention.md | 2 +-
doc/testssl.1 | 4 ++--
doc/testssl.1.html | 4 ++--
doc/testssl.1.md | 5 +++--
etc/README.md | 2 +-
5 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/Coding_Convention.md b/Coding_Convention.md
index 933b30c..03122d1 100644
--- a/Coding_Convention.md
+++ b/Coding_Convention.md
@@ -65,7 +65,7 @@ Bash is actually quite powerful -- not only with respect to sockets. It's not as
### Misc
-* If you're implementing a new feature a cmd line switch, there has to be also a global ENV variable which can be used without the switch (see e.g. `SNEAKY`, `ASSUME_HTTP` or `ADDITIONAL_CA_FILES`)
+* If you're implementing a new feature a cmd line switch, there has to be also a global ENV variable which can be used without the switch (see e.g. `SNEAKY`, `ASSUME_HTTP` or `ADDTL_CA_FILES`)
* Test before doing a PR! Best if you check with two bad and two good examples which should then work as expected. Maybe compare results e.g. with SSLlabs.
* Unit tests are done automatically done with Perl using Travis. The trigger is `~/.travis.yml`. The general documentation for [Test::More](https://perldoc.perl.org/Test/More.html) is a good start. You are encouraged to write own checks. You can use e.g. `t/20_baseline_ipv4_http.t` as an example.
* If it's an OpenSSL feature you want to use and it could be not available for older OpenSSL versions testssl.sh needs to find out whether OpenSSL has that feature. Best do this with OpenSSL itself and not by checking the version as some vendors do backports. See the examples for `HAS_SSL2` or proxy option check of OpenSSL in `check_proxy()`.
diff --git a/doc/testssl.1 b/doc/testssl.1
index 9c0f684..a8e8626 100644
--- a/doc/testssl.1
+++ b/doc/testssl.1
@@ -176,7 +176,7 @@ Please note that \fBfname\fR has to be in Unix format\. DOS carriage returns won
\fB\-\-phone\-out\fR Checking for revoked certificates via CRL and OCSP is not done per default\. This switch instructs testssl\.sh to query external \-\- in a sense of the current run \-\- URIs\. By using this switch you acknowledge that the check might have privacy issues, a download of several megabytes (CRL file) may happen and there may be network connectivity problems while contacting the endpoint which testssl\.sh doesn\'t handle\. PHONE_OUT is the environment variable for this which needs to be set to true if you want this\.
.
.P
-\fB\-\-add\-ca \fR enables you to add your own CA(s) for trust chain checks\. \fBcafile\fR can be a single path or multiple paths as a comma separated list of root CA files\. Internally they will be added during runtime to all CA stores\. This is (only) useful for internal hosts whose certificates is issued by internal CAs\. Alternatively ADDITIONAL_CA_FILES is the environment variable for this\.
+\fB\-\-add\-ca \fR enables you to add your own CA(s) for trust chain checks\. \fBcafile\fR can be a single path or multiple paths as a comma separated list of root CA files\. Internally they will be added during runtime to all CA stores\. This is (only) useful for internal hosts whose certificates is issued by internal CAs\. Alternatively ADDTL_CA_FILES is the environment variable for this\.
.
.SS "SINGLE CHECK OPTIONS"
Any single check switch supplied as an argument prevents testssl\.sh from doing a default run\. It just takes this and if supplied other options and runs them \- in the order they would also appear in the default run\.
@@ -282,7 +282,7 @@ Certificate Transparency info (if provided by server)\.
.IP "" 0
.
.P
-For the trust chain check 5 certificate stores are provided\. If the test against one of the trust stores failed, the one is being identified and the reason for the failure is displayed \- in addition the ones which succeeded are displayed too\. You can configure your own CA via ADDITIONAL_CA_FILES, see section \fBFILES\fR below\. If the server provides no matching record in Subject Alternative Name (SAN) but in Common Name (CN), it will be indicated as this is deprecated\. Also for multiple server certificates are being checked for as well as for the certificate reply to a non\-SNI (Server Name Indication) client hello to the IP address\. Regarding the TLS clock skew: it displays the time difference to the client\. Only a few TLS stacks nowadays still support this and return the local clock \fBgmt_unix_time\fR, e\.g\. IIS, openssl < 1\.0\.1f\. In addition to the HTTP date you could e\.g\. derive that there are different hosts where your TLS and your HTTP request ended \-\- if the time deltas differ significantly\.
+For the trust chain check 5 certificate stores are provided\. If the test against one of the trust stores failed, the one is being identified and the reason for the failure is displayed \- in addition the ones which succeeded are displayed too\. You can configure your own CA via ADDTL_CA_FILES, see section \fBFILES\fR below\. If the server provides no matching record in Subject Alternative Name (SAN) but in Common Name (CN), it will be indicated as this is deprecated\. Also for multiple server certificates are being checked for as well as for the certificate reply to a non\-SNI (Server Name Indication) client hello to the IP address\. Regarding the TLS clock skew: it displays the time difference to the client\. Only a few TLS stacks nowadays still support this and return the local clock \fBgmt_unix_time\fR, e\.g\. IIS, openssl < 1\.0\.1f\. In addition to the HTTP date you could e\.g\. derive that there are different hosts where your TLS and your HTTP request ended \-\- if the time deltas differ significantly\.
.
.P
\fB\-x , \-\-single\-cipher \fR tests matched \fBpattern\fR of ciphers against a server\. Patterns are similar to \fB\-V pattern , \-\-local pattern\fR, see above about matching\.
diff --git a/doc/testssl.1.html b/doc/testssl.1.html
index e7f3c34..5a6c392 100644
--- a/doc/testssl.1.html
+++ b/doc/testssl.1.html
@@ -221,7 +221,7 @@ in /etc/hosts
. The use of the switch is only useful if you either
--phone-out
Checking for revoked certificates via CRL and OCSP is not done per default. This switch instructs testssl.sh to query external -- in a sense of the current run -- URIs. By using this switch you acknowledge that the check might have privacy issues, a download of several megabytes (CRL file) may happen and there may be network connectivity problems while contacting the endpoint which testssl.sh doesn't handle. PHONE_OUT is the environment variable for this which needs to be set to true if you want this.
--add-ca <cafile>
enables you to add your own CA(s) for trust chain checks. cafile
can be a single path or multiple paths as a comma separated list of root CA files. Internally they will be added during runtime to all CA stores. This is (only) useful for internal hosts whose certificates is issued by internal CAs. Alternatively
-ADDITIONAL_CA_FILES is the environment variable for this.
+ADDTL_CA_FILES is the environment variable for this.
SINGLE CHECK OPTIONS
@@ -278,7 +278,7 @@ ADDITIONAL_CA_FILES is the environment variable for this.
For the trust chain check 5 certificate stores are provided. If the test against one of the trust stores failed, the one is being identified and the reason for the failure is displayed - in addition the ones which succeeded are displayed too.
-You can configure your own CA via ADDITIONAL_CA_FILES, see section FILES
below. If the server provides no matching record in Subject Alternative Name (SAN) but in Common Name (CN), it will be indicated as this is deprecated.
+You can configure your own CA via ADDTL_CA_FILES, see section FILES
below. If the server provides no matching record in Subject Alternative Name (SAN) but in Common Name (CN), it will be indicated as this is deprecated.
Also for multiple server certificates are being checked for as well as for the certificate reply to a non-SNI (Server Name Indication) client hello to the IP address. Regarding the TLS clock skew: it displays the time difference to the client. Only a few TLS stacks nowadays still support this and return the local clock gmt_unix_time
, e.g. IIS, openssl < 1.0.1f. In addition to the HTTP date you could e.g. derive that there are different hosts where your TLS and your HTTP request ended -- if the time deltas differ significantly.
-x <pattern>, --single-cipher <pattern>
tests matched pattern
of ciphers against a server. Patterns are similar to -V pattern , --local pattern
, see above about matching.
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index e81ae78..96a774c 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -144,7 +144,8 @@ in `/etc/hosts`. The use of the switch is only useful if you either can't or ar
`--phone-out` Checking for revoked certificates via CRL and OCSP is not done per default. This switch instructs testssl.sh to query external -- in a sense of the current run -- URIs. By using this switch you acknowledge that the check might have privacy issues, a download of several megabytes (CRL file) may happen and there may be network connectivity problems while contacting the endpoint which testssl.sh doesn't handle. PHONE_OUT is the environment variable for this which needs to be set to true if you want this.
-`--add-ca ` enables you to add your own CA(s) for trust chain checks. `cafile` can be a single path or multiple paths as a comma separated list of root CA files. Internally they will be added during runtime to all CA stores. This is (only) useful for internal hosts whose certificates is issued by internal CAs. Alternatively ADDITIONAL_CA_FILES is the environment variable for this.
+`--add-ca ` enables you to add your own CA(s) for trust chain checks. `cafile` can be a single path or multiple paths as a comma separated list of root CA files. Internally they will be added during runtime to all CA stores. This is (only) useful for internal hosts whose certificates is issued by internal CAs. Alternatively
+ADDTL_CA_FILES is the environment variable for this.
### SINGLE CHECK OPTIONS
@@ -192,7 +193,7 @@ Any single check switch supplied as an argument prevents testssl.sh from doing a
- Certificate Transparency info (if provided by server).
For the trust chain check 5 certificate stores are provided. If the test against one of the trust stores failed, the one is being identified and the reason for the failure is displayed - in addition the ones which succeeded are displayed too.
-You can configure your own CA via ADDITIONAL_CA_FILES, see section `FILES` below. If the server provides no matching record in Subject Alternative Name (SAN) but in Common Name (CN), it will be indicated as this is deprecated.
+You can configure your own CA via ADDTL_CA_FILES, see section `FILES` below. If the server provides no matching record in Subject Alternative Name (SAN) but in Common Name (CN), it will be indicated as this is deprecated.
Also for multiple server certificates are being checked for as well as for the certificate reply to a non-SNI (Server Name Indication) client hello to the IP address. Regarding the TLS clock skew: it displays the time difference to the client. Only a few TLS stacks nowadays still support this and return the local clock `gmt_unix_time`, e.g. IIS, openssl < 1.0.1f. In addition to the HTTP date you could e.g. derive that there are different hosts where your TLS and your HTTP request ended -- if the time deltas differ significantly.
`-x , --single-cipher ` tests matched `pattern` of ciphers against a server. Patterns are similar to `-V pattern , --local pattern`, see above about matching.
diff --git a/etc/README.md b/etc/README.md
index 3437195..fc619cc 100644
--- a/etc/README.md
+++ b/etc/README.md
@@ -18,7 +18,7 @@ The certificate trust stores were retrieved from
Google Chromium uses basically the trust stores above, see https://www.chromium.org/Home/chromium-security/root-ca-policy.
-If you want to check trust against e.g. a company internal CA you need to use ``./testssl.sh --add-ca companyCA1.pem,companyCA2.pem `` or ``ADDITIONAL_CA_FILES=companyCA1.pem,companyCA2.pem ./testssl.sh ``.
+If you want to check trust against e.g. a company internal CA you need to use ``./testssl.sh --add-ca companyCA1.pem,companyCA2.pem `` or ``ADDTL_CA_FILES=companyCA1.pem,companyCA2.pem ./testssl.sh ``.
#### Further files
From a9d28949fe27605e2bb365b2dd855d9cf4c8eb08 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Tue, 28 Apr 2020 21:13:36 +0200
Subject: [PATCH 061/211] Clarify responsilility for rating
---
doc/testssl.1.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index 96a774c..1f5be5d 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -390,9 +390,9 @@ Except the environment variables mentioned above which can replace command line
### RATING
This program has a near-complete implementation of SSL Labs's '[SSL Server Rating Guide](https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide)'.
-This is *not* a reimplementation of the [SS LLab's SSL Server Test](https://www.ssllabs.com/ssltest/analyze.html), but a implementation of the above rating specification, slight discrepancies might occur!
+This is *not* a 100% reimplementation of the [SSL Lab's SSL Server Test](https://www.ssllabs.com/ssltest/analyze.html), but an implementation of the above rating specification, slight discrepancies may occur. Please note that for now we stick to the SSL Labs rating as good as possible. We are not responsible for their rating. Before filing issues please inspect their Rating Guide.
-Disclaimer: Having a good grade does **NOT** necessary equal to having good security! Never rely solely on a good rating!
+Disclaimer: Having a good grade is **NOT** necessarily equal to having good security! Don't start a competition for the best grade, at least not without monitoring the client handshakes and not without adding a portion of good sense to it.
As of writing, these checks are missing:
* GOLDENDOODLE - should be graded **F** if vulnerable
@@ -435,7 +435,7 @@ When a new revision of the rating specification comes around, the following has
testssl.sh testssl.sh
-does a default run on https://testssl.sh (protocols, standard cipher lists, FS, server preferences, server defaults, vulnerabilities, testing all known 370 ciphers, client simulation, and rating.
+does a default run on https://testssl.sh (protocols, standard cipher lists, server's cipher preferences, FS, server defaults, vulnerabilities, client simulation, and rating.
testssl.sh testssl.net:443
From 3db9d74c2162f334023ab49b7401e83204faefa9 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Wed, 29 Apr 2020 10:13:22 -0400
Subject: [PATCH 062/211] Ticketbleed and TLS 1.3
run_ticketbleed() and sub_session_ticket_tls() each include one call to "$OPENSSL s_client". For each of these calls the expected response is a TLS 1.2 or earlier ServerHello. However, if $OPENSSL supports TLS 1.3, then a TLS 1.3 ClientHello will be sent.
This commit fixes this problem in two ways. For the call in run_ticketbleed(), "-no_tls1_3" is added to the command line if "$OPENSSL" supports TLS 1.3. For the call in sub_session_ticket_tls(), this commit changes the function so that the same ClientHello version is sent as will sent by run_ticketbleed() via sockets.
---
testssl.sh | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 995196f..b7f60ee 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -15134,13 +15134,14 @@ run_ccs_injection(){
}
sub_session_ticket_tls() {
+ local tls_proto="$1"
local sessticket_tls=""
#FIXME: we likely have done this already before (either @ run_server_defaults() or at least the output
# from a previous handshake) --> would save 1x connect. We have TLS_TICKET but not yet the ticket itself #FIXME
#ATTENTION: we DO NOT use SNI here as we assume ticketbleed is a vulnerability of the TLS stack. If we'd do SNI here, we'd also need
# it in the ClientHello of run_ticketbleed() otherwise the ticket will be different and the whole thing won't work!
#
- sessticket_tls="$($OPENSSL s_client $(s_client_options "$BUGS $OPTIMAL_PROTO $PROXY -connect $NODEIP:$PORT") $ERRFILE | awk '/TLS session ticket:/,/^$/' | awk '!/TLS session ticket/')"
+ sessticket_tls="$($OPENSSL s_client $(s_client_options "$BUGS $tls_proto $PROXY -connect $NODEIP:$PORT") $ERRFILE | awk '/TLS session ticket:/,/^$/' | awk '!/TLS session ticket/')"
sessticket_tls="$(sed -e 's/^.* - /x/g' -e 's/ .*$//g' <<< "$sessticket_tls" | tr '\n' ',')"
sed -e 's/ /,x/g' -e 's/-/,x/g' <<< "$sessticket_tls"
@@ -15149,6 +15150,7 @@ sub_session_ticket_tls() {
# see https://blog.filippo.io/finding-ticketbleed/ | https://filippo.io/ticketbleed/
run_ticketbleed() {
+ local tls_hexcode tls_proto=""
local session_tckt_tls=""
local -i len_ch=300 # fixed len of prepared clienthello below
local sid="x00,x0B,xAD,xC0,xDE,x00," # some abitratry bytes
@@ -15186,25 +15188,26 @@ run_ticketbleed() {
fi
if [[ 0 -eq $(has_server_protocol tls1) ]]; then
- tls_hexcode="x03, x01"
+ tls_hexcode="x03, x01"; tls_proto="-tls1"
elif [[ 0 -eq $(has_server_protocol tls1_1) ]]; then
- tls_hexcode="x03, x02"
+ tls_hexcode="x03, x02"; tls_proto="-tls1_1"
elif [[ 0 -eq $(has_server_protocol tls1_2) ]]; then
- tls_hexcode="x03, x03"
+ tls_hexcode="x03, x03"; tls_proto="-tls1_2"
elif [[ 0 -eq $(has_server_protocol ssl3) ]]; then
- tls_hexcode="x03, x00"
+ tls_hexcode="x03, x00"; tls_proto="-ssl3"
else # no protocol for some reason defined, determine TLS versions offered with a new handshake
- $OPENSSL s_client $(s_client_options "$STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY") >$TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE
Date: Thu, 30 Apr 2020 10:26:56 -0400
Subject: [PATCH 063/211] Use $HAS_X25519 and $HAS_X448
generate_key_share_extension() and prepare_tls_clienthello() currently check the $OPENSSL version number to determine whether X25519 and X448 are supported. The commit changes these functions to use $HAS_X25519 and $HAS_X448.
---
testssl.sh | 25 +++++--------------------
1 file changed, 5 insertions(+), 20 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index b7f60ee..a8a4bf4 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -13835,26 +13835,13 @@ generate_key_share_extension() {
# with X25519 keys, so don't include the X25519 key share
# if the server's response needs to be decrypted and an
# older version of OpenSSL is being used.
- if [[ $i -gt 12 ]] && [[ $group -eq 29 ]] && [[ "$2" == all ]]; then
- [[ "$OSSL_NAME" =~ LibreSSL ]] && continue
- if [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR != 1.1.0* ]] && \
- [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR != 1.1.1* ]] && \
- [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR != 3.0.0* ]]; then
- continue
- fi
- fi
+ [[ $i -gt 12 ]] && [[ $group -eq 29 ]] && [[ "$2" == all ]] && ! "$HAS_X25519" && continue
# Versions of OpenSSL prior to 1.1.1 cannot perform operations
# with X448 keys, so don't include the X448 key share
# if the server's response needs to be decrypted and an
# older version of OpenSSL is being used.
- if [[ $i -gt 12 ]] && [[ $group -eq 30 ]] && [[ "$2" == all ]]; then
- [[ "$OSSL_NAME" =~ LibreSSL ]] && continue
- if [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR != 1.1.1* ]] && \
- [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR != 3.0.0* ]]; then
- continue
- fi
- fi
+ [[ $i -gt 12 ]] && [[ $group -eq 30 ]] && [[ "$2" == all ]] && ! "$HAS_X448" && continue
# NOTE: The public keys could be extracted from the private keys
# (TLS13_KEY_SHARES) using $OPENSSL, but only OpenSSL 1.1.0 and newer can
@@ -14016,9 +14003,7 @@ prepare_tls_clienthello() {
00, 01, 00, 02, 00, 03, 00, 0f, 00, 10, 00, 11"
elif [[ 0x$tls_low_byte -gt 0x03 ]]; then
# Supported Groups Extension
- if [[ ! "$process_full" =~ all ]] || ( [[ ! "$OSSL_NAME" =~ LibreSSL ]] && \
- ( [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == 1.1.1* ]] || \
- [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == 3.0.0* ]] ) ); then
+ if [[ ! "$process_full" =~ all ]] || ( "$HAS_X25519" && "$HAS_X448" ); then
extension_supported_groups="
00,0a, # Type: Supported Groups, see RFC 8446
00,10, 00,0e, # lengths
@@ -14027,13 +14012,13 @@ prepare_tls_clienthello() {
# OpenSSL prior to 1.1.1 does not support X448, so list it as the least
# preferred option if the response needs to be decrypted, and do not
# list it at all if the response MUST be decrypted.
- elif [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == 1.1.0* ]] && [[ "$process_full" == all+ ]]; then
+ elif "$HAS_X25519" && [[ "$process_full" == all+ ]]; then
extension_supported_groups="
00,0a, # Type: Supported Groups, see RFC 8446
00,0e, 00,0c, # lengths
00,1d, 00,17, 00,18, 00,19,
01,00, 01,01"
- elif [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == "1.1.0"* ]]; then
+ elif "$HAS_X25519"; then
extension_supported_groups="
00,0a, # Type: Supported Groups, see RFC 8446
00,10, 00,0e, # lengths
From cb67d9141786656002682d1780122c221e1aa4b6 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Thu, 30 Apr 2020 10:37:12 -0400
Subject: [PATCH 064/211] Improve compatibility with LibreSSL 3.0.2 and earlier
This commit addresses two compatibility issues with LibreSSL.
First, with LibreSSL, "$OPENSSL s_client" does not support the "-curves" option, so the "-groups" option needs to be used instead. Note that with LibreSSL, the command line "$OPENSSL s_client -groups $curve -connect invalid." will not work, as it will complain "no port defined," but will not indicate whether the specified curve is supported. Adding a port number fixes that problem. (There does not seem to be a need to include a port number for other tests, such as whether the "-curves" option itself is supported.)
Second, including "-out -" in the command line for "$OPENSSL genpkey" causes LibreSSL to create a file with the name "-" if the algorithm is supported. This is not an issue at the moment, since LibreSSL's genpkey does not support X25519 or X448. However, both genpkey with both OpenSSL and LibreSSL uses stdout as the default output if no "-out" is specified, so the "-out -" is not necessary.
---
testssl.sh | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index b7f60ee..3125688 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -297,6 +297,7 @@ OSSL_VER_MINOR=0
OSSL_VER_APPENDIX="none"
CLIENT_PROB_NO=1
HAS_DH_BITS=${HAS_DH_BITS:-false} # initialize openssl variables
+HAS_CURVES=false
OSSL_SUPPORTED_CURVES=""
HAS_SSL2=false
HAS_SSL3=false
@@ -2034,6 +2035,7 @@ s_client_options() {
# (e.g. client simulations) we replace it with the name which OpenSSL understands
# This shouldn't be needed. We have this here as a last resort
if [[ "$1" =~ " -curves " ]]; then
+ ! "$HAS_CURVES" && options="${options// -curves / -groups }"
[[ "$1" =~ secp192r1 ]] && options="${options//secp192r1/prime192v1}"
[[ "$1" =~ secp256r1 ]] && options="${options//secp256r1/prime256v1}"
fi
@@ -18035,6 +18037,7 @@ find_openssl_binary() {
HAS_CIPHERSUITES=false
HAS_COMP=false
HAS_NO_COMP=false
+ HAS_CURVES=false
OSSL_SUPPORTED_CURVES=""
HAS_PKEY=false
HAS_PKUTIL=false
@@ -18067,10 +18070,10 @@ find_openssl_binary() {
$OPENSSL s_client -tls1_3 -connect invalid. 2>&1 | grep -aiq "unknown option" || \
HAS_TLS13=true
- $OPENSSL genpkey -algorithm X448 -out - 2>&1 | grep -aq "not found" || \
+ $OPENSSL genpkey -algorithm X448 2>&1 | grep -aq "not found" || \
HAS_X448=true
- $OPENSSL genpkey -algorithm X25519 -out - 2>&1 | grep -aq "not found" || \
+ $OPENSSL genpkey -algorithm X25519 2>&1 | grep -aq "not found" || \
HAS_X25519=true
$OPENSSL s_client -no_ssl2 -connect invalid. 2>&1 | grep -aiq "unknown option" || \
@@ -18090,10 +18093,18 @@ find_openssl_binary() {
OPENSSL_NR_CIPHERS=$(count_ciphers "$(actually_supported_osslciphers 'ALL:COMPLEMENTOFALL' 'ALL')")
- for curve in "${curves_ossl[@]}"; do
- $OPENSSL s_client -curves $curve -connect invalid. 2>&1 | grep -Eiaq "Error with command|unknown option"
- [[ $? -ne 0 ]] && OSSL_SUPPORTED_CURVES+=" $curve "
- done
+ if $OPENSSL s_client -curves "${curves_ossl[0]}" -connect invalid. 2>&1 | grep -aiq "unknown option"; then
+ for curve in "${curves_ossl[@]}"; do
+ $OPENSSL s_client -groups $curve -connect invalid.:8443 2>&1 | grep -Eiaq "Error with command|unknown option|Failed to set groups"
+ [[ $? -ne 0 ]] && OSSL_SUPPORTED_CURVES+=" $curve "
+ done
+ else
+ HAS_CURVES=true
+ for curve in "${curves_ossl[@]}"; do
+ $OPENSSL s_client -curves $curve -connect invalid. 2>&1 | grep -Eiaq "Error with command|unknown option"
+ [[ $? -ne 0 ]] && OSSL_SUPPORTED_CURVES+=" $curve "
+ done
+ fi
$OPENSSL pkey -help 2>&1 | grep -q Error || \
HAS_PKEY=true
@@ -18423,6 +18434,7 @@ OSSL_VER_PLATFORM: $OSSL_VER_PLATFORM
OPENSSL_NR_CIPHERS: $OPENSSL_NR_CIPHERS
OPENSSL_CONF: $OPENSSL_CONF
+HAS_CURVES: $HAS_CURVES
OSSL_SUPPORTED_CURVES: $OSSL_SUPPORTED_CURVES
HAS_IPv6: $HAS_IPv6
From a5a28d2457b6aa9ab2944057dec8adf2beded14a Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Thu, 30 Apr 2020 10:54:41 -0400
Subject: [PATCH 065/211] Improve LibreSSL 3.1.0 compatibility
This commit addresses two compatibility issues with LibreSSL 3.1.0, which has added client support for TLS 1.3.
The first issue is that LibreSSL has named the TLS 1.3 ciphers that it supports AEAD-AES256-GCM-SHA384, AEAD-CHACHA20-POLY1305-SHA256, and AEAD-AES128-GCM-SHA256, rather than using the OpenSSL names, which are TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, and TLS_AES_128_GCM_SHA256. (Draft versions of OpenSSL 1.1.1 names these ciphers TLS13-AES-256-GCM-SHA384, TLS13-CHACHA20-POLY1305-SHA256, TLS13-AES-128-GCM-SHA256.) There are several places where testssl.sh checks whether a cipher suite is a TLS 1.3 cipher by checking whether its OpenSSL name begins with "TLS_" (or "TLS13"). In order to work with LibreSSL 3.1.0, these checks also need to consider names that begin with "AEAD-" to be TLS 1.3 ciphers.
Second, in sub_session_resumption() there is code that adds "-no_ssl2" to the "$OPENSSL s_client" command line if that option is supported. If "-no_ssl2" is not supported, then other protocol information is added to the command line. I believe this code was written with the assumption that any version of OpenSSL that supports "-no_ssl2" does not support TLS 1.3. However, LibreSSL 3.1.0 supports both. So, this commit changes the code to add the "-no_ssl2" option only if TLS 1.3 is not supported.
---
testssl.sh | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index b7f60ee..05515fa 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -3575,7 +3575,7 @@ run_cipher_match(){
tls13_ciphers_to_test=""
for (( i=bundle*bundle_size; i < end_of_bundle; i++ )); do
if ! "${ciphers_found2[i]}"; then
- if [[ "${ciph2[i]}" == TLS13* ]] || [[ "${ciph2[i]}" == TLS_* ]]; then
+ if [[ "${ciph2[i]}" == TLS13* ]] || [[ "${ciph2[i]}" == TLS_* ]] || [[ "${ciph2[i]}" == AEAD-* ]]; then
tls13_ciphers_to_test+=":${ciph2[i]}"
else
ciphers_to_test+=":${ciph2[i]}"
@@ -3593,7 +3593,7 @@ run_cipher_match(){
[[ $i -eq $end_of_bundle ]] && break
i=${index[i]}
ciphers_found[i]=true
- if [[ "$cipher" == TLS13* ]] || [[ "$cipher" == TLS_* ]]; then
+ if [[ "$cipher" == TLS13* ]] || [[ "$cipher" == TLS_* ]] || [[ "$cipher" == AEAD-* ]]; then
kx[i]="$(read_dhtype_from_file $TMPFILE)"
fi
if [[ ${kx[i]} == "Kx=ECDH" ]] || [[ ${kx[i]} == "Kx=DH" ]] || [[ ${kx[i]} == "Kx=EDH" ]]; then
@@ -3849,7 +3849,7 @@ run_allciphers() {
tls13_ciphers_to_test=""
for (( i=bundle*bundle_size; i < end_of_bundle; i++ )); do
if ! "${ciphers_found2[i]}"; then
- if [[ "${ciph2[i]}" == TLS13* ]] || [[ "${ciph2[i]}" == TLS_* ]]; then
+ if [[ "${ciph2[i]}" == TLS13* ]] || [[ "${ciph2[i]}" == TLS_* ]] || [[ "${ciph2[i]}" == AEAD-* ]]; then
tls13_ciphers_to_test+=":${ciph2[i]}"
else
ciphers_to_test+=":${ciph2[i]}"
@@ -3867,7 +3867,7 @@ run_allciphers() {
[[ $i -eq $end_of_bundle ]] && break
i=${index[i]}
ciphers_found[i]=true
- if [[ "$cipher" == TLS13* ]] || [[ "$cipher" == TLS_* ]]; then
+ if [[ "$cipher" == TLS13* ]] || [[ "$cipher" == TLS_* ]] || [[ "$cipher" == AEAD-* ]]; then
kx[i]="$(read_dhtype_from_file $TMPFILE)"
fi
if [[ ${kx[i]} == Kx=ECDH ]] || [[ ${kx[i]} == Kx=DH ]] || [[ ${kx[i]} == Kx=EDH ]]; then
@@ -4055,9 +4055,9 @@ ciphers_by_strength() {
fi
while read hexc n ciph[nr_ciphers] sslvers kx[nr_ciphers] auth enc[nr_ciphers] mac export2[nr_ciphers]; do
if [[ "$proto" == -tls1_3 ]]; then
- [[ "${ciph[nr_ciphers]}" == TLS13* ]] || [[ "${ciph[nr_ciphers]}" == TLS_* ]] || continue
+ [[ "${ciph[nr_ciphers]}" == TLS13* ]] || [[ "${ciph[nr_ciphers]}" == TLS_* ]] || [[ "${ciph[nr_ciphers]}" == AEAD-* ]] || continue
elif [[ "$proto" == -tls1_2 ]]; then
- if [[ "${ciph[nr_ciphers]}" == TLS13* ]] || [[ "${ciph[nr_ciphers]}" == TLS_* ]]; then
+ if [[ "${ciph[nr_ciphers]}" == TLS13* ]] || [[ "${ciph[nr_ciphers]}" == TLS_* ]] || [[ "${ciph[nr_ciphers]}" == AEAD-* ]]; then
continue
fi
elif [[ "${ciph[nr_ciphers]}" == *-SHA256 ]] || [[ "${ciph[nr_ciphers]}" == *-SHA384 ]] || \
@@ -6203,7 +6203,7 @@ sub_session_resumption() {
fi
fi
"$CLIENT_AUTH" && return 6
- if "$HAS_NO_SSL2"; then
+ if ! "$HAS_TLS13" && "$HAS_NO_SSL2"; then
addcmd+=" -no_ssl2"
else
protocol=${protocol/\./_}
@@ -9586,7 +9586,7 @@ run_fs() {
tls13_ciphers_to_test=""
for (( i=0; i < nr_supported_ciphers; i++ )); do
if ! "${ciphers_found[i]}" && "${ossl_supported[i]}"; then
- if [[ "${ciph[i]}" == TLS13* ]] || [[ "${ciph[i]}" == TLS_* ]]; then
+ if [[ "${ciph[i]}" == TLS13* ]] || [[ "${ciph[i]}" == TLS_* ]] || [[ "${ciph[i]}" == AEAD-* ]]; then
tls13_ciphers_to_test+=":${ciph[i]}"
else
ciphers_to_test+=":${ciph[i]}"
@@ -9603,7 +9603,7 @@ run_fs() {
done
[[ $i -eq $nr_supported_ciphers ]] && break
ciphers_found[i]=true
- if [[ "$fs_cipher" == TLS13* ]] || [[ "$fs_cipher" == TLS_* ]]; then
+ if [[ "$fs_cipher" == TLS13* ]] || [[ "$fs_cipher" == TLS_* ]] || [[ "$fs_cipher" == AEAD-* ]]; then
fs_tls13_offered=true
"$WIDE" && kx[i]="$(read_dhtype_from_file $TMPFILE)"
fi
@@ -9662,11 +9662,12 @@ run_fs() {
fi
fs_ciphers+="$fs_cipher "
- if [[ "${ciph[i]}" == ECDHE-* ]] || [[ "${ciph[i]}" == TLS13* ]] || [[ "${ciph[i]}" == TLS_* ]] || ( "$using_sockets" && [[ "${rfc_ciph[i]}" == TLS_ECDHE_* ]] ); then
+ if [[ "${ciph[i]}" == ECDHE-* ]] || [[ "${ciph[i]}" == TLS13* ]] || [[ "${ciph[i]}" == TLS_* ]] || \
+ [[ "${ciph[i]}" == AEAD-* ]] || ( "$using_sockets" && [[ "${rfc_ciph[i]}" == TLS_ECDHE_* ]] ); then
ecdhe_offered=true
ecdhe_cipher_list_hex+=", ${hexcode[i]}"
if [[ "${ciph[i]}" != "-" ]]; then
- if [[ "${ciph[i]}" == TLS13* ]] || [[ "${ciph[i]}" == TLS_* ]]; then
+ if [[ "${ciph[i]}" == TLS13* ]] || [[ "${ciph[i]}" == TLS_* ]] || [[ "${ciph[i]}" == AEAD-* ]]; then
tls13_cipher_list+=":$fs_cipher"
else
ecdhe_cipher_list+=":$fs_cipher"
@@ -9676,7 +9677,7 @@ run_fs() {
if [[ "${ciph[i]}" == "DHE-"* ]] || ( "$using_sockets" && [[ "${rfc_ciph[i]}" == "TLS_DHE_"* ]] ); then
ffdhe_offered=true
ffdhe_cipher_list_hex+=", ${hexcode[i]}"
- elif [[ "${ciph[i]}" == TLS13* ]] || [[ "${ciph[i]}" == TLS_* ]]; then
+ elif [[ "${ciph[i]}" == TLS13* ]] || [[ "${ciph[i]}" == TLS_* ]] || [[ "${ciph[i]}" == AEAD-* ]]; then
ffdhe_cipher_list_hex+=", ${hexcode[i]}"
fi
fi
From 4daf20585d74af79415843ea482775be2e77e014 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Sch=C3=A4fer?=
Date: Tue, 20 Aug 2019 18:48:06 +0200
Subject: [PATCH 066/211] STARTTLS: add support for xmpp-server
XMPP client-to-server and server-to-server links historically use
different XML namespaces. Some server implementations are strict
about this and will not proceed with the connection attempt when
the client namespace (`jabber:client`) is used on a
server-to-server link.
openssl s_client also supports `xmpp-server`.
---
doc/testssl.1 | 2 +-
testssl.sh | 15 +++++++++------
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/doc/testssl.1 b/doc/testssl.1
index 9c0f684..9d6decb 100644
--- a/doc/testssl.1
+++ b/doc/testssl.1
@@ -134,7 +134,7 @@ Please note that \fBfname\fR has to be in Unix format\. DOS carriage returns won
\fB\-\-basicauth \fR 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\.
.
.SS "SPECIAL INVOCATIONS"
-\fB\-t , \-\-starttls \fR does a default run against a STARTTLS enabled \fBprotocol\fR\. \fBprotocol\fR must be one of \fBftp\fR, \fBsmtp\fR, \fBpop3\fR, \fBimap\fR, \fBxmpp\fR, \fBtelnet\fR, \fBldap\fR, \fBirc\fR, \fBlmtp\fR, \fBnntp\fR, \fBpostgres\fR, \fBmysql\fR\. 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 \fB\-\-ssl\-native\fR\. \fBtelnet\fR and \fBirc\fR is WIP\.
+\fB\-t , \-\-starttls \fR does a default run against a STARTTLS enabled \fBprotocol\fR\. \fBprotocol\fR must be one of \fBftp\fR, \fBsmtp\fR, \fBpop3\fR, \fBimap\fR, \fBxmpp\fR, \fBxmpp-server\fR, \fBtelnet\fR, \fBldap\fR, \fBirc\fR, \fBlmtp\fR, \fBnntp\fR, \fBpostgres\fR, \fBmysql\fR\. 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 \fB\-\-ssl\-native\fR\. \fBtelnet\fR and \fBirc\fR is WIP\.
.
.P
\fB\-\-xmpphost \fR is an additional option for STARTTLS enabled XMPP: It expects the jabber domain as a parameter\. This is only needed if the domain is different from the URI supplied\.
diff --git a/testssl.sh b/testssl.sh
index d5d7ee7..19e0031 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -10296,7 +10296,10 @@ starttls_xmpp_dialog() {
debugme echo "=== starting xmpp STARTTLS dialog ==="
[[ -z $XMPP_HOST ]] && XMPP_HOST="$NODE"
- starttls_io "" 'starttls(.*)features' 1 &&
+ namespace="jabber:client"
+ [[ "$STARTTLS_PROTOCOL" == xmpp-server ]] && namespace="jabber:server"
+
+ starttls_io "" 'starttls(.*)features' 1 &&
starttls_io " " '", where [options] is:
-t, --starttls Does a default run against a STARTTLS enabled
+ protocol is
--xmpphost For STARTTLS enabled XMPP it supplies the XML stream to-'' domain -- sometimes needed
--mx Tests MX records from high to low priority (STARTTLS, port 25)
--file/-iL Mass testing option: Reads one testssl.sh command line per line from .
@@ -19646,9 +19649,9 @@ determine_service() {
fi
case "$protocol" in
- ftp|smtp|lmtp|pop3|imap|xmpp|telnet|ldap|postgres|mysql|nntp)
+ ftp|smtp|lmtp|pop3|imap|xmpp|xmpp-server|telnet|ldap|postgres|mysql|nntp)
STARTTLS="-starttls $protocol"
- if [[ "$protocol" == xmpp ]]; then
+ if [[ "$protocol" == xmpp ]] || [[ "$protocol" == xmpp-server ]]; then
# for XMPP, openssl has a problem using -connect $NODEIP:$PORT. thus we use -connect $NODE:$PORT instead!
NODEIP="$NODE"
if [[ -n "$XMPP_HOST" ]]; then
@@ -20591,7 +20594,7 @@ parse_cmd_line() {
STARTTLS_PROTOCOL="$(parse_opt_equal_sign "$1" "$2")"
[[ $? -eq 0 ]] && shift
case $STARTTLS_PROTOCOL in
- ftp|smtp|lmtp|pop3|imap|xmpp|telnet|ldap|irc|nntp|postgres|mysql) ;;
+ ftp|smtp|lmtp|pop3|imap|xmpp|xmpp-server|telnet|ldap|irc|nntp|postgres|mysql) ;;
ftps|smtps|lmtps|pop3s|imaps|xmpps|telnets|ldaps|ircs|nntps|mysqls) ;;
*) tmln_magenta "\nunrecognized STARTTLS protocol \"$1\", see help" 1>&2
help 1 ;;
From 53ee37b046cffa5ed74e28e8369c071f3e41ba3c Mon Sep 17 00:00:00 2001
From: Dirk
Date: Fri, 1 May 2020 18:03:19 +0200
Subject: [PATCH 067/211] XMPP server
---
CHANGELOG.md | 1 +
CREDITS.md | 3 +++
2 files changed, 4 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 31f0325..36d0236 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@
* Several display/output fixes
* Security fix: DNS input
* Don't use external pwd anymore
+* STARTTLS: XMPP server support
* Rating (SSL Labs, not complete)
### Features implemented / improvements in 3.0
diff --git a/CREDITS.md b/CREDITS.md
index 884d8dd..3c0cd24 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -143,6 +143,9 @@ Full contribution, see git log.
* Dmitri S
- inspiration & help for Darwin port
+* Jonas Schäfer
+ - XMPP server patch
+
* Marcin Szychowski
- Quick'n'dirty client certificate support
From 0e6fb44bd34ece23f610d12e55ec748bb85e1565 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Fri, 1 May 2020 18:31:35 +0200
Subject: [PATCH 068/211] add xmpp-server
---
doc/testssl.1.html | 2 +-
doc/testssl.1.md | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/doc/testssl.1.html b/doc/testssl.1.html
index 662cfae..37fb4dc 100644
--- a/doc/testssl.1.html
+++ b/doc/testssl.1.html
@@ -189,7 +189,7 @@ The same can be achieved by setting the environment variable WARNINGSSPECIAL INVOCATIONS
--t <protocol>, --starttls <protocol>
does a default run against a STARTTLS enabled protocol
. protocol
must be one of ftp
, smtp
, pop3
, imap
, xmpp
, 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.
+-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.
--xmpphost <jabber_domain>
is an additional option for STARTTLS enabled XMPP: It expects the jabber domain as a parameter. This is only needed if the domain is different from the URI supplied.
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index 4cce65b..63cfa88 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -113,7 +113,7 @@ The same can be achieved by setting the environment variable `WARNINGS`.
### SPECIAL INVOCATIONS
-`-t , --starttls ` does a default run against a STARTTLS enabled `protocol`. `protocol` must be one of `ftp`, `smtp`, `pop3`, `imap`, `xmpp`, `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.
+`-t , --starttls ` 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.
`--xmpphost ` is an additional option for STARTTLS enabled XMPP: It expects the jabber domain as a parameter. This is only needed if the domain is different from the URI supplied.
From 1d7adebb4e882949d457c3a8b3b7f1f99a741185 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Fri, 1 May 2020 18:32:22 +0200
Subject: [PATCH 069/211] Add HAS_XMPP_SERVER
... see also #1575
---
testssl.sh | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/testssl.sh b/testssl.sh
index d5888d7..6520366 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -317,6 +317,7 @@ HAS_NPN=false
HAS_FALLBACK_SCSV=false
HAS_PROXY=false
HAS_XMPP=false
+HAS_XMPP_SERVER=false
HAS_POSTGRES=false
HAS_MYSQL=false
HAS_LMTP=false
@@ -18214,6 +18215,7 @@ find_openssl_binary() {
HAS_FALLBACK_SCSV=false
HAS_PROXY=false
HAS_XMPP=false
+ HAS_XMPP_SERVER=false
HAS_POSTGRES=false
HAS_MYSQL=false
HAS_LMTP=false
@@ -18298,9 +18300,12 @@ find_openssl_binary() {
grep -q '\-proxy' $s_client_has && \
HAS_PROXY=true
- grep -q '\-xmpp' $s_client_has && \
+ grep -q 'xmpp' $s_client_starttls_has && \
HAS_XMPP=true
+ grep -q 'xmpp-server' $s_client_starttls_has && \
+ HAS_XMPP_SERVER=true
+
grep -q 'postgres' $s_client_starttls_has && \
HAS_POSTGRES=true
@@ -18623,6 +18628,7 @@ HAS_PKEY: $HAS_PKEY
HAS_PKUTIL: $HAS_PKUTIL
HAS_PROXY: $HAS_PROXY
HAS_XMPP: $HAS_XMPP
+HAS_XMPP_SERVER: $HAS_XMPP_SERVER
HAS_POSTGRES: $HAS_POSTGRES
HAS_MYSQL: $HAS_MYSQL
HAS_LMTP: $HAS_LMTP
@@ -19811,6 +19817,9 @@ determine_service() {
fi
fi
fi
+ if [[ "$protocol" == xmpp-server ]] && ! "$HAS_XMPP_SERVER"; then
+ fatal "Your $OPENSSL does not support the \"-xmpphost\" option" $ERR_OSSLBIN
+ fi
elif [[ "$protocol" == postgres ]]; then
# Check if openssl version supports postgres.
if ! "$HAS_POSTGRES"; then
From 191c69fbdde8cd90aa33f5cf914e071e3e0d1d8c Mon Sep 17 00:00:00 2001
From: Dirk
Date: Fri, 1 May 2020 18:39:36 +0200
Subject: [PATCH 070/211] Minor probe for STARTTLS xmpp-server
... don't know whether this gets through -- depends on the
version openssl used (1.0.2 doesn't have that)
---
t/25_baseline_starttls.t | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/t/25_baseline_starttls.t b/t/25_baseline_starttls.t
index 0179e4a..18c9e27 100755
--- a/t/25_baseline_starttls.t
+++ b/t/25_baseline_starttls.t
@@ -99,6 +99,14 @@ $openssl_out = `./testssl.sh --ssl-native $check2run -t xmpp $uri 2>&1`;
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";
From 9e61d6605e87309f4ff6dfb8f92a9c264af4c55f Mon Sep 17 00:00:00 2001
From: Dirk
Date: Fri, 1 May 2020 19:17:58 +0200
Subject: [PATCH 071/211] Perl needs a semicolon ;-/
---
t/25_baseline_starttls.t | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/t/25_baseline_starttls.t b/t/25_baseline_starttls.t
index 18c9e27..9537604 100755
--- a/t/25_baseline_starttls.t
+++ b/t/25_baseline_starttls.t
@@ -99,7 +99,7 @@ $openssl_out = `./testssl.sh --ssl-native $check2run -t xmpp $uri 2>&1`;
unlike($openssl_out, qr/$openssl_regex_bl/, "");
$tests++;
-uri="jabber.ccc.de:5269"
+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');
From 5da54b9ce8cdf1e49cde3de284820a458e911d4e Mon Sep 17 00:00:00 2001
From: Dirk
Date: Fri, 1 May 2020 21:42:41 +0200
Subject: [PATCH 072/211] fix var declaration
---
t/25_baseline_starttls.t | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/t/25_baseline_starttls.t b/t/25_baseline_starttls.t
index 9537604..0902b4c 100755
--- a/t/25_baseline_starttls.t
+++ b/t/25_baseline_starttls.t
@@ -99,7 +99,7 @@ $openssl_out = `./testssl.sh --ssl-native $check2run -t xmpp $uri 2>&1`;
unlike($openssl_out, qr/$openssl_regex_bl/, "");
$tests++;
-uri="jabber.ccc.de:5269";
+$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');
From 485bcc1888e717b059166521a3d9d6fa874112f0 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Sat, 2 May 2020 18:34:10 +0200
Subject: [PATCH 073/211] Change Travis/CI environment to bionic
... as it comes with openssl 1.1.1 and we can check also XMPP S2S
protocol
---
.travis.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.travis.yml b/.travis.yml
index 950e14b..d1d660b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,5 @@
language: perl
+dist: bionic
perl:
- "5.26"
addons:
From 05c90d4c3ad5f63776fe227ed2f0e3a330f64603 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Sat, 2 May 2020 18:37:02 +0200
Subject: [PATCH 074/211] remove add_tls_offered
---
testssl.sh | 2 --
1 file changed, 2 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 6520366..ba67b8e 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -5182,7 +5182,6 @@ run_protocols() {
5) prln_svrty_high "CVE-2015-3197: $supported_no_ciph2";
fileout "$jsonID" "HIGH" "offered, no cipher" "CVE-2015-3197" "CWE-310"
add_proto_offered ssl2 yes
- add_tls_offered ssl2 yes
set_grade_cap "F" "SSLv2 is offered"
;;
7) prln_local_problem "$OPENSSL doesn't support \"s_client -ssl2\""
@@ -5211,7 +5210,6 @@ run_protocols() {
latest_supported_string="SSLv3"
fi
add_proto_offered ssl3 yes
- add_tls_offered ssl3 yes
set_grade_cap "B" "SSLv3 is offered"
;;
1) prln_svrty_best "not offered (OK)"
From 7981a238a5c7016833c40cbeb4ee029b7d3679e5 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Sat, 2 May 2020 19:40:45 +0200
Subject: [PATCH 075/211] Comment out S2S XMPP server test for now
---
t/25_baseline_starttls.t | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/t/25_baseline_starttls.t b/t/25_baseline_starttls.t
index 0902b4c..efb795e 100755
--- a/t/25_baseline_starttls.t
+++ b/t/25_baseline_starttls.t
@@ -99,13 +99,12 @@ $openssl_out = `./testssl.sh --ssl-native $check2run -t xmpp $uri 2>&1`;
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="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";
From 381fdfa985ea4a891c2de82c4b0fa1a4cf81019f Mon Sep 17 00:00:00 2001
From: Dirk
Date: Sat, 2 May 2020 19:49:01 +0200
Subject: [PATCH 076/211] Fix typo in docs: Strong grade Ciphers / AEAD
---
doc/testssl.1 | 2 +-
doc/testssl.1.html | 2 +-
doc/testssl.1.md | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/doc/testssl.1 b/doc/testssl.1
index fb6cb33..05cbe3d 100644
--- a/doc/testssl.1
+++ b/doc/testssl.1
@@ -212,7 +212,7 @@ Any single check switch supplied as an argument prevents testssl\.sh from doing
\fBAverage grade Ciphers\fR: \'HIGH:MEDIUM:AES:CAMELLIA:ARIA:!IDEA:!CHACHA20:!3DES:!RC2:!RC4:!AESCCM8:!AESCCM:!AESGCM:!ARIAGCM:!aNULL\'
.
.IP "\(bu" 4
-\fBStrong grade Ciphers\fR (AEAD): \'AESGCM:CHACHA20:AESGCM:CamelliaGCM:AESCCM8:AESCCM\'
+\fBStrong grade Ciphers\fR (AEAD): \'AESGCM:CHACHA20:CamelliaGCM:AESCCM\'
.
.IP "" 0
.
diff --git a/doc/testssl.1.html b/doc/testssl.1.html
index 37fb4dc..2609c6f 100644
--- a/doc/testssl.1.html
+++ b/doc/testssl.1.html
@@ -240,7 +240,7 @@ ADDTL_CA_FILES is the environment variable for this.
LOW
(64 Bit + DES ciphers, without EXPORT ciphers): 'LOW:DES:RC2:RC4:!ADH:!EXP:!NULL:!eNULL'
3DES + IDEA Ciphers
: '3DES:IDEA:!aNULL:!ADH'
Average grade Ciphers
: 'HIGH:MEDIUM:AES:CAMELLIA:ARIA:!IDEA:!CHACHA20:!3DES:!RC2:!RC4:!AESCCM8:!AESCCM:!AESGCM:!ARIAGCM:!aNULL'
-Strong grade Ciphers
(AEAD): 'AESGCM:CHACHA20:AESGCM:CamelliaGCM:AESCCM8:AESCCM'
+Strong grade Ciphers
(AEAD): 'AESGCM:CHACHA20:CamelliaGCM:AESCCM8:AESCCM'
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index 63cfa88..536762e 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -165,7 +165,7 @@ Any single check switch supplied as an argument prevents testssl.sh from doing a
* `LOW` (64 Bit + DES ciphers, without EXPORT ciphers): 'LOW:DES:RC2:RC4:!ADH:!EXP:!NULL:!eNULL'
* `3DES + IDEA Ciphers`: '3DES:IDEA:!aNULL:!ADH'
* `Average grade Ciphers`: 'HIGH:MEDIUM:AES:CAMELLIA:ARIA:!IDEA:!CHACHA20:!3DES:!RC2:!RC4:!AESCCM8:!AESCCM:!AESGCM:!ARIAGCM:!aNULL'
-* `Strong grade Ciphers` (AEAD): 'AESGCM:CHACHA20:AESGCM:CamelliaGCM:AESCCM8:AESCCM'
+* `Strong grade Ciphers` (AEAD): 'AESGCM:CHACHA20:CamelliaGCM:AESCCM8:AESCCM'
`-f, --fs, --nsa, --forward-secrecy` Checks robust forward secrecy key exchange. "Robust" means that ciphers having intrinsic severe weaknesses like Null Authentication or Encryption, 3DES and RC4 won't be considered here. There shouldn't be the wrong impression that a secure key exchange has been taking place and everything is fine when in reality the encryption sucks. Also this section lists the available elliptical curves and Diffie Hellman groups, as well as FFDHE groups (TLS 1.2 and TLS 1.3).
From ae8a056afe2a1129e02cf5dd0c9115d1d72c158a Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Mon, 4 May 2020 14:29:13 -0400
Subject: [PATCH 077/211] Check server's response
There is code at the beginning of parse_tls_serverhello() that checks whether the server's response appears to consist of a sequence of messages of the form . However, at the moment the check is only performed if "$do_starttls" is false. This commit changes parse_tls_serverhello() so that the check is always performed.
---
testssl.sh | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/testssl.sh b/testssl.sh
index ba67b8e..ccbe7a6 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -12793,7 +12793,8 @@ parse_tls_serverhello() {
[[ $DEBUG -ge 1 ]] && tmpfile_handle ${FUNCNAME[0]}.txt
return 3
fi
- elif [[ $tls_content_type != 14 ]] && [[ $tls_content_type != 15 ]] && \
+ fi
+ if [[ $tls_content_type != 14 ]] && [[ $tls_content_type != 15 ]] && \
[[ $tls_content_type != 16 ]] && [[ $tls_content_type != 17 ]]; then
debugme tmln_warning "Content type other than alert, handshake, change cipher spec, or application data detected."
[[ $DEBUG -ge 1 ]] && tmpfile_handle ${FUNCNAME[0]}.txt
From cdc1a088198e9210f4bdd6d74fbca01b012abfc1 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Mon, 4 May 2020 20:34:32 +0200
Subject: [PATCH 078/211] Address further potential license restriction
.. see https://github.com/drwetter/testssl.sh/issues/1590#issuecomment-623526604
Added some formatting and verbal improvements in the intruductory comment section.
---
testssl.sh | 30 ++++++++++++++++--------------
1 file changed, 16 insertions(+), 14 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index ba67b8e..b86432a 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -3,23 +3,25 @@
# vim:ts=5:sw=5:expandtab
# we have a spaces softtab, that ensures readability with other editors too
-# testssl.sh is a program for spotting weak SSL encryption, ciphers, version and some
-# vulnerabilities or features
+# testssl.sh is a program for spotting weak SSL/TLS encryption, ciphers, protocols and some
+# vulnerabilities or features. It may or may be not distributed by your distribution.
+# The upstream versions are available (please leave the links intact):
#
-# Devel version is available from https://github.com/drwetter/testssl.sh
-# Stable version from https://testssl.sh
-# Please file bugs at github! https://github.com/drwetter/testssl.sh/issues
+# Development version https://github.com/drwetter/testssl.sh
+# Stable version https://testssl.sh
+# File bugs at github https://github.com/drwetter/testssl.sh/issues
#
# Project lead and initiator: Dirk Wetter, copyleft: 2007-today, contributions so far see CREDITS.md
# Main contributions from David Cooper
+# Project lead and initiator: Dirk Wetter, copyleft: 2007-today.
+# Main contributions from David Cooper. Further contributors see CREDITS.md .
#
-# License: GPLv2, see https://opensource.org/licenses/gpl-2.0.php
-# and accompanying license "LICENSE.txt". Redistribution + modification under this
+# License: GPLv2, see https://opensource.org/licenses/gpl-2.0.php and
+# ccompanying license "LICENSE.txt". Redistribution + modification under this
# license permitted.
-# If you enclose this script or parts of it in your software, it has to
-# be accompanied by the same license (see link) and the place where to get
-# the recent version of this program. Do not violate the license and if
-# you do not agree to all of these terms, do not use it in the first place.
+# If you enclose this program or parts of it in your software, it has to be
+# accompanied by the same license (see link). Do not violate the license.
+# If you do not agree to these terms, do not use it in the first place!
#
# OpenSSL, which is being used and maybe distributed via one of this projects'
# web sites, is subject to their licensing: https://www.openssl.org/source/license.txt
@@ -30,13 +32,13 @@
#
# Please note: USAGE WITHOUT ANY WARRANTY, THE SOFTWARE IS PROVIDED "AS IS".
# USE IT AT your OWN RISK!
-# Seriously! The threat is you run this code on your computer and input could be /
-# is being supplied via untrusted sources.
+# Seriously! The threat is you run this code on your computer and untrusted input e.g.
+# could be supplied from a server you are querying.
#
# HISTORY:
# Back in 2006 it all started with a few openssl commands...
# That's because openssl is a such a good swiss army knife (see e.g.
-# wiki.openssl.org/index.php/Command_Line_Utilities) that it was difficult to resist
+# https://wiki.openssl.org/index.php/Command_Line_Utilities) that it was difficult to resist
# wrapping some shell commands around it, which I used for my pen tests. This is how
# everything started.
# Now it has grown up, it has bash socket support for most features, which has been basically
From d949b305c016607cb18df9cda0c3b2d54ba21b6b Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Mon, 4 May 2020 22:38:02 +0200
Subject: [PATCH 079/211] Fix STARTTLS pretests, improve XMPP handshakes
There was a empty variable in determine_optimal_proto() which prevented to save
STARTTLS_OPTIMAL_PROTO. This is fixed.
The buffers and return codes for XMPP in starttls_io() were under not every
circumstances correct. This fixes those cases and making that in general more
robust (hopefully). (There's still code commented out which I'll leave it for
now).
When openssl did not support -starttls xmpp-server there was a copy
and paste error saying that -xmpphost option was not supported.
---
testssl.sh | 39 +++++++++++++++++++++++----------------
1 file changed, 23 insertions(+), 16 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index ba67b8e..4915eae 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -5038,8 +5038,9 @@ run_prototest_openssl() {
# arg1: protocol
# arg2: available (yes) or not (no)
add_proto_offered() {
+ # the ":" is mandatory here (and @ other places), otherwise e.g. tls1 will match tls1_2
if [[ "$PROTOS_OFFERED" =~ $1: ]]; then
- # the ":" is mandatory here (and @ other places), otherwise e.g. tls1 will match tls1_2
+ # we got that protcol already
:
else
PROTOS_OFFERED+="${1}:$2 "
@@ -10231,12 +10232,13 @@ run_alpn() {
return $ret
}
-# arg1: string to send
-# arg2: possible success strings a egrep pattern, needed!
-# arg3: wait in seconds
+# arg1: send string
+# arg2: success string: an egrep pattern
+# arg3: number of loops we should read from the buffer (optional, otherwise STARTTLS_SLEEP)
starttls_io() {
- local waitsleep=$STARTTLS_SLEEP
+ local nr_waits=$STARTTLS_SLEEP
local buffer=""
+ local -i i
[[ -n "$3" ]] && waitsleep=$3
[[ -z "$2" ]] && echo "FIXME $((LINENO))"
@@ -10244,27 +10246,31 @@ starttls_io() {
# If there's a sending part it's IO. Postgres sends via socket and replies via
# strings "S". So there's no I part of IO ;-)
if [[ -n "$1" ]]; then
- debugme echo -en "C: \"$1\""
+ debugme echo -en "C: $1"
echo -en "$1" >&5
fi
+ if [[ "$2" == JUSTSEND ]]; then
+ debugme echo -e "\n (only sent)\n"
+ dd of=/dev/null bs=512 count=1 <&5 2>/dev/null &
+ return 0
+ fi
# This seems a bit dangerous but works. No blockings yet. "if=nonblock" doesn't work on BSDs
buffer="$(dd bs=512 count=1 <&5 2>/dev/null)"
- [[ "$DEBUG" -ge 2 ]] && echo -en "\nS: " && echo $buffer
- for ((i=1; i < $waitsleep; i++ )); do
+ for ((i=1; i < $nr_waits; i++ )); do
+ [[ "$DEBUG" -ge 2 ]] && echo -en "\nS: " && echo $buffer
if [[ "$buffer" =~ $2 ]]; then
debugme echo " ---> reply matched \"$2\""
# the fd sometimes still seem to contain chars which confuses the following TLS handshake, trying to empty:
- dd of=/dev/null bs=512 count=1 <&5 2>/dev/null
+ # dd of=/dev/null bs=512 count=1 <&5 2>/dev/null
return 0
else
# no match yet, more reading from fd helps.
buffer+=$(dd bs=512 count=1 <&5 2>/dev/null)
fi
- sleep 0.5
done
- return 0
+ return 1
}
@@ -10413,8 +10419,9 @@ starttls_xmpp_dialog() {
namespace="jabber:client"
[[ "$STARTTLS_PROTOCOL" == xmpp-server ]] && namespace="jabber:server"
- starttls_io "" 'starttls(.*)features' 1 &&
+ starttls_io "" 'starttls(.*)features' 1 &&
starttls_io " " '" 'JUSTSEND' 2
local ret=$?
debugme echo "=== finished xmpp STARTTLS dialog with ${ret} ==="
return $ret
@@ -19640,7 +19647,7 @@ determine_optimal_proto() {
$OPENSSL s_client $(s_client_options "$STARTTLS_OPTIMAL_PROTO $BUGS -connect "$NODEIP:$PORT" $PROXY -msg $STARTTLS $SNI") $TMPFILE 2>>$ERRFILE
if sclient_auth $? $TMPFILE; then
all_failed=false
- add_proto_offered "${proto/-/}" yes
+ add_proto_offered "${STARTTLS_OPTIMAL_PROTO/-/}" yes
break
fi
done
@@ -19747,7 +19754,7 @@ determine_optimal_proto() {
}
-# arg1 (optional): ftp smtp, lmtp, pop3, imap, xmpp, telnet, ldap, postgres, mysql, irc, nntp (maybe with trailing s)
+# arg1 (optional): ftp smtp, lmtp, pop3, imap, xmpp, xmpp-server, telnet, ldap, postgres, mysql, irc, nntp (maybe with trailing s)
#
determine_service() {
local ua
@@ -19816,7 +19823,7 @@ determine_service() {
fi
fi
if [[ "$protocol" == xmpp-server ]] && ! "$HAS_XMPP_SERVER"; then
- fatal "Your $OPENSSL does not support the \"-xmpphost\" option" $ERR_OSSLBIN
+ fatal "Your $OPENSSL does not support the \"-starttls xmpp-server\" option" $ERR_OSSLBIN
fi
elif [[ "$protocol" == postgres ]]; then
# Check if openssl version supports postgres.
@@ -19850,7 +19857,7 @@ determine_service() {
outln
;;
*) outln
- fatal "momentarily only ftp, smtp, lmtp, pop3, imap, xmpp, telnet, ldap, nntp, postgres and mysql allowed" $ERR_CMDLINE
+ fatal "momentarily only ftp, smtp, lmtp, pop3, imap, xmpp, xmpp-server, telnet, ldap, nntp, postgres and mysql allowed" $ERR_CMDLINE
;;
esac
fi
From 918d358e952e80bd2b084c5987ad1731425c6c9f Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Tue, 5 May 2020 13:37:58 +0200
Subject: [PATCH 080/211] Add X-TYPO3-Parsetime
---
testssl.sh | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/testssl.sh b/testssl.sh
index 5778047..a30973b 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -2865,6 +2865,7 @@ emphasize_stuff_in_headers(){
-e "s/CentOS/${yellow}CentOS${off}/g" \
-e "s/Via/${yellow}Via${off}/g" \
-e "s/X-Forwarded/${yellow}X-Forwarded${off}/g" \
+ -e "s/X-TYPO3-Parsetime/${yellow}X-TYPO3-Parsetime${off}/g" \
-e "s/Liferay-Portal/${yellow}Liferay-Portal${off}/g" \
-e "s/X-Cache-Lookup/${yellow}X-Cache-Lookup${off}/g" \
-e "s/X-Cache/${yellow}X-Cache${off}/g" \
@@ -2912,6 +2913,7 @@ emphasize_stuff_in_headers(){
-e "s/CentOS/${html_yellow}CentOS${html_off}/g" \
-e "s/Via/${html_yellow}Via${html_off}/g" \
-e "s/X-Forwarded/${html_yellow}X-Forwarded${html_off}/g" \
+ -e "s/X-TYPO3-Parsetime/${yellow}X-TYPO3-Parsetime${html_off}/g" \
-e "s/Liferay-Portal/${html_yellow}Liferay-Portal${html_off}/g" \
-e "s/X-Cache-Lookup/${html_yellow}X-Cache-Lookup${html_off}/g" \
-e "s/X-Cache/${html_yellow}X-Cache${html_off}/g" \
@@ -2991,7 +2993,7 @@ run_appl_banner() {
run_http_header "$1" || return 1
fi
pr_bold " Application banner "
- grep -Eai '^X-Powered-By|^X-AspNet-Version|^X-Version|^Liferay-Portal|^X-OWA-Version^|^MicrosoftSharePointTeamServices' $HEADERFILE >$TMPFILE
+ grep -Eai '^X-Powered-By|^X-AspNet-Version|^X-Version|^Liferay-Portal|^X-TYPO3-Parsetime|^X-OWA-Version^|^MicrosoftSharePointTeamServices' $HEADERFILE >$TMPFILE
if [[ $? -ne 0 ]]; then
outln "--"
fileout "$jsonID" "INFO" "No application banner found"
From 908975380d0e595afd6c63babc15563e78856ab4 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Wed, 6 May 2020 09:17:42 +0200
Subject: [PATCH 081/211] Amendment to "Relax the possible GPL license
contradiction"
fix it also in the man pages. See #1590 / #1593
---
doc/testssl.1 | 11 ++++++++---
doc/testssl.1.html | 16 ++++++++++++----
doc/testssl.1.md | 13 +++++++++----
3 files changed, 29 insertions(+), 11 deletions(-)
diff --git a/doc/testssl.1 b/doc/testssl.1
index 05cbe3d..6aea659 100644
--- a/doc/testssl.1
+++ b/doc/testssl.1
@@ -79,7 +79,7 @@ Options are either short or long options\. Any long or short option requiring a
\fB\-\-help\fR (or no arg) display command line help
.
.P
-\fB\-b, \-\-banner\fR displays testssl\.sh banner, including license, usage conditions, version of testssl\.sh, detected openssl version, its path to it, # of ciphers of openssl, its build date and the architecture
+\fB\-b, \-\-banner\fR displays testssl\.sh banner, including license, usage conditions, version of testssl\.sh, detected openssl version, its path to it, # of ciphers of openssl, its build date and the architecture\.
.
.P
\fB\-v, \-\-version\fR same as before
@@ -902,10 +902,15 @@ TLSWG Draft: The Transport Layer Security (TLS) Protocol Version 1\.3
Developed by Dirk Wetter, David Cooper and many others, see CREDITS\.md \.
.
.SH "COPYRIGHT"
-Copyright © 2012 Dirk Wetter\. License GPLv2: Free Software Foundation, Inc\. This is free software: you are free to change and redistribute it under the terms of the license\. Usage WITHOUT ANY WARRANTY\. USE at your OWN RISK!
+Copyright © 2012 Dirk Wetter\. License GPLv2: Free Software Foundation, Inc\. This is free software: you are free to change and redistribute it under the terms of the license, see LICENSE\.
+.P
+Attribution is important for the future of this project - also in the internet\. Thus if you\'re offering a scanner based on testssl\.sh as a public
+and/or paid service in the internet you are strongly encouraged to mention to your audience that you\'re using this program and where to get this program
+from\. That helps us to get bugfixes, other feedback and more contributions\.
.
.P
-If you\'re offering testssl\.sh as a public and / or paid service in the internet you need to mention to your audience that you\'re using this program and where to get this program from\.
+Usage WITHOUT ANY WARRANTY\. USE at your OWN RISK!
+.
.
.SH "LIMITATION"
All native Windows platforms emulating Linux are known to be slow\.
diff --git a/doc/testssl.1.html b/doc/testssl.1.html
index 2609c6f..8422223 100644
--- a/doc/testssl.1.html
+++ b/doc/testssl.1.html
@@ -147,7 +147,7 @@ linked OpenSSL binaries for major operating systems are supplied in ./bin/
--help
(or no arg) display command line help
--b, --banner
displays testssl.sh banner, including license, usage conditions, version of testssl.sh, detected openssl version, its path to it, # of ciphers of openssl, its build date and the architecture
+-b, --banner
displays testssl.sh banner, including license, usage conditions, version of testssl.sh, detected openssl version, its path to it, # of ciphers of openssl, its build date and the architecture.
-v, --version
same as before
@@ -638,10 +638,18 @@ This is to prevent giving out a misleading or wrong grade.
COPYRIGHT
Copyright © 2012 Dirk Wetter. License GPLv2: Free Software Foundation, Inc.
- This is free software: you are free to change and redistribute it under the terms of the license. Usage WITHOUT ANY WARRANTY. USE at your OWN RISK!
+ This is free software: you are free to change and redistribute it under the terms of the license, see LICENSE.
+
+
+Attribution is important for the future of this project - also in the
+internet. Thus if you're offering a scanner based on testssl.sh as a public
+and/or paid service in the internet you are strongly encouraged to mention to
+your audience that you're using this program and where to get this program
+from. That helps us to get bugfixes, other feedback and more contributions.
+
+
+ Usage WITHOUT ANY WARRANTY. USE at your OWN RISK!
-If you're offering testssl.sh as a public and / or paid service in the internet you need to mention to your audience that you're using this program and
-where to get this program from.
LIMITATION
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index 536762e..a63fb26 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -70,7 +70,7 @@ Options are either short or long options. Any long or short option requiring a v
`--help` (or no arg) display command line help
-`-b, --banner` displays testssl.sh banner, including license, usage conditions, version of testssl.sh, detected openssl version, its path to it, # of ciphers of openssl, its build date and the architecture
+`-b, --banner` displays testssl.sh banner, including license, usage conditions, version of testssl.sh, detected openssl version, its path to it, # of ciphers of openssl, its build date and the architecture.
`-v, --version` same as before
@@ -536,10 +536,15 @@ Developed by Dirk Wetter, David Cooper and many others, see CREDITS.md .
## COPYRIGHT
Copyright © 2012 Dirk Wetter. License GPLv2: Free Software Foundation, Inc.
- This is free software: you are free to change and redistribute it under the terms of the license. Usage WITHOUT ANY WARRANTY. USE at your OWN RISK!
+ This is free software: you are free to change and redistribute it under the terms of the license, see LICENSE.
-If you're offering testssl.sh as a public and / or paid service in the internet you need to mention to your audience that you're using this program and
-where to get this program from.
+Attribution is important for the future of this project - also in the
+internet. Thus if you're offering a scanner based on testssl.sh as a public
+and/or paid service in the internet you are strongly encouraged to mention to
+your audience that you're using this program and where to get this program
+from. That helps us to get bugfixes, other feedback and more contributions.
+
+Usage WITHOUT ANY WARRANTY. USE at your OWN RISK!
## LIMITATION
From 84a82dbddc1bfac50d86e82afd476924b35f888a Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Wed, 6 May 2020 08:31:09 -0400
Subject: [PATCH 082/211] tls_sockets() return value
There is one place in parse_tls_serverhello() that returns 8 if the server's response is not well-formed TLS. However, there is no code in testssl.sh that is prepared to handle this return value. Every function except run_protocols() only distinguishes between 0, 2, and everything else. run_protocols(), however, gets confused if tls_sockets() returns a value that it is not expecting. So, this commit changes parse_tls_serverhello() to return 1 whenever the server's response can not be parsed.
---
testssl.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/testssl.sh b/testssl.sh
index a30973b..b83eb41 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -12809,7 +12809,7 @@ parse_tls_serverhello() {
[[ $tls_content_type != 16 ]] && [[ $tls_content_type != 17 ]]; then
debugme tmln_warning "Content type other than alert, handshake, change cipher spec, or application data detected."
[[ $DEBUG -ge 1 ]] && tmpfile_handle ${FUNCNAME[0]}.txt
- return 8
+ return 1
elif [[ "${tls_protocol:0:2}" != 03 ]]; then
debugme tmln_warning "Protocol record_version.major is not 03."
[[ $DEBUG -ge 1 ]] && tmpfile_handle ${FUNCNAME[0]}.txt
From 329ba95d5bae296495eb15d0e4c142d899b5d9f8 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Wed, 6 May 2020 08:43:13 -0400
Subject: [PATCH 083/211] Fix #1433
This commit fixes #1433 by adding "@SECLEVEL=0" to the "$OPENSSL s_client" and "$OPENSSL ciphers" command lines if that option is supported. Adding this option configures OpenSSL to support some weak ciphers that it would not use in the default configuration.
---
testssl.sh | 31 ++++++++++++++++++++++++-------
1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index a30973b..8055fbe 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -312,6 +312,7 @@ HAS_PKEY=false
HAS_NO_SSL2=false
HAS_NOSERVERNAME=false
HAS_CIPHERSUITES=false
+HAS_SECLEVEL=false
HAS_COMP=false
HAS_NO_COMP=false
HAS_ALPN=false
@@ -870,15 +871,17 @@ is_ipv6addr() {
#arg2: TLS 1.3 ciphers
#arg3: options (e.g., -V)
actually_supported_osslciphers() {
+ local ciphers="$1"
local tls13_ciphers="$TLS13_OSSL_CIPHERS"
[[ "$2" != ALL ]] && tls13_ciphers="$2"
+ "$HAS_SECLEVEL" && [[ -n "$ciphers" ]] && ciphers="@SECLEVEL=0:$1"
if "$HAS_CIPHERSUITES"; then
- $OPENSSL ciphers $3 $OSSL_CIPHERS_S -ciphersuites "$tls13_ciphers" "$1" 2>/dev/null || echo ""
+ $OPENSSL ciphers $3 $OSSL_CIPHERS_S -ciphersuites "$tls13_ciphers" "$ciphers" 2>/dev/null || echo ""
elif [[ -n "$tls13_ciphers" ]]; then
- $OPENSSL ciphers $3 $OSSL_CIPHERS_S "$tls13_ciphers:$1" 2>/dev/null || echo ""
+ $OPENSSL ciphers $3 $OSSL_CIPHERS_S "$tls13_ciphers:$ciphers" 2>/dev/null || echo ""
else
- $OPENSSL ciphers $OSSL_CIPHERS_S $3 "$1" 2>/dev/null || echo ""
+ $OPENSSL ciphers $OSSL_CIPHERS_S $3 "$ciphers" 2>/dev/null || echo ""
fi
}
@@ -2121,6 +2124,13 @@ s_client_options() {
options+=" -no_tls1_3"
fi
+ if "$HAS_SECLEVEL"; then
+ if [[ "$ciphers" == notpresent ]]; then
+ [[ ! " $options " =~ \ -tls1_3\ ]] && ciphers="@SECLEVEL=0:ALL:COMPLEMENTOFALL"
+ else
+ ciphers="@SECLEVEL=0:$ciphers"
+ fi
+ fi
if [[ "$ciphers" != notpresent ]] || [[ "$tls13_ciphers" != notpresent ]]; then
if ! "$HAS_CIPHERSUITES"; then
[[ "$ciphers" == notpresent ]] && ciphers=""
@@ -5717,15 +5727,17 @@ run_protocols() {
listciphers() {
local -i ret
local debugname=""
+ local ciphers="$1"
local tls13_ciphers="$TLS13_OSSL_CIPHERS"
[[ "$2" != ALL ]] && tls13_ciphers="$2"
+ "$HAS_SECLEVEL" && [[ -n "$ciphers" ]] && ciphers="@SECLEVEL=0:$1"
if "$HAS_CIPHERSUITES"; then
- $OPENSSL ciphers $OSSL_CIPHERS_S $3 -ciphersuites "$tls13_ciphers" "$1" &>$TMPFILE
+ $OPENSSL ciphers $OSSL_CIPHERS_S $3 -ciphersuites "$tls13_ciphers" "$ciphers" &>$TMPFILE
elif [[ -n "$tls13_ciphers" ]]; then
- $OPENSSL ciphers $OSSL_CIPHERS_S $3 "$tls13_ciphers:$1" &>$TMPFILE
+ $OPENSSL ciphers $OSSL_CIPHERS_S $3 "$tls13_ciphers:$ciphers" &>$TMPFILE
else
- $OPENSSL ciphers $OSSL_CIPHERS_S $3 "$1" &>$TMPFILE
+ $OPENSSL ciphers $OSSL_CIPHERS_S $3 "$ciphers" &>$TMPFILE
fi
ret=$?
debugme cat $TMPFILE
@@ -16080,7 +16092,7 @@ run_ssl_poodle() {
nr_cbc_ciphers=$(count_ciphers $cbc_ciphers)
nr_supported_ciphers=$(count_ciphers $(actually_supported_osslciphers $cbc_ciphers))
# SNI not needed as SSLv3 has none:
- $OPENSSL s_client -ssl3 $STARTTLS $BUGS -cipher $cbc_ciphers -connect $NODEIP:$PORT $PROXY >$TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE &1 | grep -aiq "unknown option" || \
HAS_CIPHERSUITES=true
+ $OPENSSL ciphers @SECLEVEL=0:ALL > /dev/null 2> /dev/null
+ [[ $? -eq 0 ]] && HAS_SECLEVEL=true
+
$OPENSSL s_client -comp -connect invalid. 2>&1 | grep -aiq "unknown option" || \
HAS_COMP=true
@@ -18634,6 +18650,7 @@ HAS_FALLBACK_SCSV: $HAS_FALLBACK_SCSV
HAS_COMP: $HAS_COMP
HAS_NO_COMP: $HAS_NO_COMP
HAS_CIPHERSUITES: $HAS_CIPHERSUITES
+HAS_SECLEVEL: $HAS_SECLEVEL
HAS_PKEY: $HAS_PKEY
HAS_PKUTIL: $HAS_PKUTIL
HAS_PROXY: $HAS_PROXY
From 9dba2a8c9cf3bf29c609c051d9c7223d81ea84d3 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Wed, 6 May 2020 12:16:15 -0400
Subject: [PATCH 084/211] Fix #1576
This commit adds additional information to the "Server key size" line for a certificate if the subject public key is RSA, ECDSA, or DH.
For RSA it show the public exponent. For ECDSA, it shows the curve. For DH, it shows the group used, if it is a common prime.
---
testssl.sh | 89 ++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 67 insertions(+), 22 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index dfb976f..9daae5a 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -8290,7 +8290,10 @@ certificate_info() {
local sni_used="${10}"
local ct="${11}"
local certificate_list_ordering_problem="${12}"
- local cert_sig_algo cert_sig_hash_algo cert_key_algo cert_keyusage cert_ext_keyusage short_keyAlgo
+ local cert_sig_algo cert_sig_hash_algo cert_key_algo cert_spki_info
+ local common_primes_file="$TESTSSL_INSTALL_DIR/etc/common-primes.txt"
+ local -i lineno_matched=0
+ local cert_keyusage cert_ext_keyusage short_keyAlgo
local outok=true
local expire days2expire secs2warn ocsp_uri crl
local startdate enddate issuer_CN issuer_C issuer_O issuer sans san all_san="" cn
@@ -8308,6 +8311,7 @@ certificate_info() {
local -i ret=0
local json_postfix="" # string to place at the end of JSON IDs when there is more than one certificate
local jsonID="" # string to place at beginning of JSON IDs
+ local json_rating json_msg
local indent=""
local days2warn2=$DAYS2WARN2
local days2warn1=$DAYS2WARN1
@@ -8476,51 +8480,51 @@ certificate_info() {
if [[ $cert_key_algo =~ ecdsa ]] || [[ $cert_key_algo =~ ecPublicKey ]]; then
if [[ "$cert_keysize" -le 110 ]]; then # a guess
pr_svrty_critical "$cert_keysize"
- fileout "${jsonID}${json_postfix}" "CRITICAL" "$short_keyAlgo $cert_keysize bits"
+ json_rating="CRITICAL"; json_msg="$short_keyAlgo $cert_keysize bits"
elif [[ "$cert_keysize" -le 123 ]]; then # a guess
pr_svrty_high "$cert_keysize"
- fileout "${jsonID}${json_postfix}" "HIGH" "$short_keyAlgo $cert_keysize bits"
+ json_rating="HIGH"; json_msg="$short_keyAlgo $cert_keysize bits"
elif [[ "$cert_keysize" -le 163 ]]; then
pr_svrty_medium "$cert_keysize"
- fileout "${jsonID}${json_postfix}" "MEDIUM" "$short_keyAlgo $cert_keysize bits"
+ json_rating="MEDIUM"; json_msg="$short_keyAlgo $cert_keysize bits"
elif [[ "$cert_keysize" -le 224 ]]; then
out "$cert_keysize"
- fileout "${jsonID}${json_postfix}" "INFO" "$short_keyAlgo $cert_keysize bits"
+ json_rating="INFO"; json_msg="$short_keyAlgo $cert_keysize bits"
elif [[ "$cert_keysize" -le 533 ]]; then
pr_svrty_good "$cert_keysize"
- fileout "${jsonID}${json_postfix}" "OK" "$short_keyAlgo $cert_keysize bits"
+ json_rating="OK"; json_msg="$short_keyAlgo $cert_keysize bits"
else
out "keysize: $cert_keysize (not expected, FIXME)"
- fileout "${jsonID}${json_postfix}" "DEBUG" " $cert_keysize bits (not expected)"
+ json_rating="DEBUG"; json_msg=" $cert_keysize bits (not expected)"
((ret++))
fi
- outln " bits"
+ out " bits"
set_key_str_score "$short_keyAlgo" "$cert_keysize" # TODO: should be $dh_param_size
elif [[ $cert_key_algo =~ RSA ]] || [[ $cert_key_algo =~ rsa ]] || [[ $cert_key_algo =~ dsa ]] || \
[[ $cert_key_algo =~ dhKeyAgreement ]] || [[ $cert_key_algo == X9.42\ DH ]]; then
if [[ "$cert_keysize" -le 512 ]]; then
pr_svrty_critical "$cert_keysize"
- outln " bits"
- fileout "${jsonID}${json_postfix}" "CRITICAL" "$short_keyAlgo $cert_keysize bits"
+ out " bits"
+ json_rating="CRITICAL"; json_msg="$short_keyAlgo $cert_keysize bits"
elif [[ "$cert_keysize" -le 768 ]]; then
pr_svrty_high "$cert_keysize"
- outln " bits"
- fileout "${jsonID}${json_postfix}" "HIGH" "$short_keyAlgo $cert_keysize bits"
+ out " bits"
+ json_rating="HIGH"; json_msg="$short_keyAlgo $cert_keysize bits"
elif [[ "$cert_keysize" -le 1024 ]]; then
pr_svrty_medium "$cert_keysize"
- outln " bits"
- fileout "${jsonID}${json_postfix}" "MEDIUM" "$short_keyAlgo $cert_keysize bits"
+ out " bits"
+ json_rating="MEDIUM"; json_msg="$short_keyAlgo $cert_keysize bits"
elif [[ "$cert_keysize" -le 2048 ]]; then
- outln "$cert_keysize bits"
- fileout "${jsonID}${json_postfix}" "INFO" "$short_keyAlgo $cert_keysize bits"
+ out "$cert_keysize bits"
+ json_rating="INFO"; json_msg="$short_keyAlgo $cert_keysize bits"
elif [[ "$cert_keysize" -le 4096 ]]; then
pr_svrty_good "$cert_keysize"
- fileout "${jsonID}${json_postfix}" "OK" "$short_keyAlgo $cert_keysize bits"
- outln " bits"
+ json_rating="OK"; json_msg="$short_keyAlgo $cert_keysize bits"
+ out " bits"
else
- pr_warning "weird key size: $cert_keysize bits"; outln " (could cause compatibility problems)"
- fileout "${jsonID}${json_postfix}" "WARN" "$cert_keysize bits (Odd)"
+ pr_warning "weird key size: $cert_keysize bits"; out " (could cause compatibility problems)"
+ json_rating="WARN"; json_msg="$cert_keysize bits (Odd)"
((ret++))
fi
@@ -8528,12 +8532,53 @@ certificate_info() {
else
out "$cert_key_algo + $cert_keysize bits ("
pr_warning "FIXME: can't tell whether this is good or not"
- outln ")"
- fileout "${jsonID}${json_postfix}" "WARN" "Server keys $cert_keysize bits, unknown public key algorithm $cert_key_algo"
+ out ")"
+ json_rating="WARN"; json_msg="Server keys $cert_keysize bits, unknown public key algorithm $cert_key_algo"
((ret++))
fi
fi
+ case "$short_keyAlgo" in
+ "RSA") cert_spki_info="${cert_txt##*Subject Public Key Info:}"
+ cert_spki_info="${cert_spki_info##*Public Key Algorithm:}"
+ cert_spki_info="${cert_spki_info#*Exponent:}"
+ cert_spki_info="$(strip_leading_space "$cert_spki_info")"
+ cert_spki_info="${cert_spki_info%%[[:space:]]*}"
+ if [[ -n "$cert_spki_info" ]]; then
+ out " (exponent is $cert_spki_info)"
+ json_msg+=" (exponent is $cert_spki_info)"
+ fi
+ ;;
+ "EC") cert_spki_info="${cert_txt##*Subject Public Key Info:}"
+ cert_spki_info="${cert_spki_info##*Public Key Algorithm:}"
+ cert_spki_info="${cert_spki_info##*ASN1 OID: }"
+ [[ "$cert_spki_info" =~ NIST\ CURVE:\ ]] && cert_spki_info="${cert_spki_info##*NIST CURVE: }"
+ cert_spki_info="${cert_spki_info%%[[:space:]]*}"
+ cert_spki_info="$(strip_lf "$(strip_spaces "$cert_spki_info")")"
+ if [[ -n "$cert_spki_info" ]]; then
+ out " (curve $cert_spki_info)"
+ json_msg+=" (curve $cert_spki_info)"
+ fi
+ ;;
+ "DH") if [[ -s "$common_primes_file" ]]; then
+ cert_spki_info="${cert_txt##*Subject Public Key Info:}"
+ cert_spki_info="${cert_spki_info##*Public Key Algorithm:}"
+ cert_spki_info="$(awk '/prime:|prime P:/,/generator:|generator G:/' <<< "$cert_spki_info" | grep -Ev "prime|generator")"
+ cert_spki_info="$(strip_spaces "$(colon_to_spaces "$(newline_to_spaces "$cert_spki_info")")")"
+ [[ "${cert_spki_info:0:2}" == 00 ]] && cert_spki_info="${cert_spki_info:2}"
+ cert_spki_info="$(toupper "$cert_spki_info")"
+ lineno_matched=$(grep -n "$cert_spki_info" "$common_primes_file" 2>/dev/null | awk -F':' '{ print $1 }')
+ if [[ "$lineno_matched" -ne 0 ]]; then
+ cert_spki_info="$(awk "NR == $lineno_matched-1" "$common_primes_file" | awk -F'"' '{ print $2 }')"
+ out " ($cert_spki_info)"
+ json_msg+=" ($cert_spki_info)"
+ fi
+ fi
+ ;;
+ esac
+ outln
+ fileout "${jsonID}${json_postfix}" "$json_rating" "$json_msg"
+
out "$indent"; pr_bold " Server key usage ";
outok=true
jsonID="cert_keyUsage"
From a8c9133fc6632f7a758c7b950d6fc0443384dbe2 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Wed, 6 May 2020 14:25:59 -0400
Subject: [PATCH 085/211] Check for RSA exponent of 1
As suggested in #1576, set the grade cap to F if the RSA key has an exponent of 1.
---
testssl.sh | 1 +
1 file changed, 1 insertion(+)
diff --git a/testssl.sh b/testssl.sh
index 9daae5a..099dcfd 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -8547,6 +8547,7 @@ certificate_info() {
if [[ -n "$cert_spki_info" ]]; then
out " (exponent is $cert_spki_info)"
json_msg+=" (exponent is $cert_spki_info)"
+ [[ $cert_spki_info -eq 1 ]] && set_grade_cap "F" "RSA certificate uses exponent of 1"
fi
;;
"EC") cert_spki_info="${cert_txt##*Subject Public Key Info:}"
From 46bf8c90acd59eaa75c1f7c9d905c00ae3968ecd Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Wed, 6 May 2020 14:30:44 -0400
Subject: [PATCH 086/211] Improve key exchange grading
This commit makes a couple of improvements to set_key_str_score().
It rates (finite-field) DH keys the same as RSA and DSA keys.
Second, in the case of a server that has more than one certificate, the current code sets $KEY_EXCH_SCORE based on the length of the public key in the last certificate that is parsed. This commit changes set_key_str_score() so that $KEY_EXCH_SCORE is set based on the weakest public key.
Note that there is still the issue that the key exchange score does not take into account any ephemeral keys used. However, that needs to be addressed by callling set_key_str_score() from run_fs() and run_logjam(), as certificate_info() cannot provide information about ephemeral keys.
---
testssl.sh | 30 ++++++++++--------------------
1 file changed, 10 insertions(+), 20 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index dfb976f..954a6c3 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -382,7 +382,7 @@ HEX_CIPHER="" # "
GRADE_CAP="" # Keeps track of the current grading cap
GRADE_CAP_REASONS=() # Keeps track of all the reasons why grades are capped
GRADE_WARNINGS=() # Keeps track of all the grade warnings
-KEY_EXCH_SCORE=0 # Keeps track of the score for category 2 "Key Exchange Strength"
+KEY_EXCH_SCORE=100 # Keeps track of the score for category 2 "Key Exchange Strength"
CIPH_STR_BEST=0 # Keeps track of the best bit size for category 3 "Cipher Strength"
CIPH_STR_WORST=100000 # Keeps track of the worst bit size for category 3 "Cipher Strength"
# Intentionally set very high, so it can be set to 0, if necessary
@@ -1039,41 +1039,31 @@ set_key_str_score() {
# TODO: We need to get the size of DH params (follows the same table as the "else" clause)
# For now, verifying the key size will do...
- if [[ $type == EC || $type == DH ]]; then
- if [[ $size -lt 110 ]]; then
+ if [[ $type == EC ]]; then
+ if [[ $size -lt 110 ]] && [[ $KEY_EXCH_SCORE -gt 20 ]]; then
let KEY_EXCH_SCORE=20
set_grade_cap "F" "Using an insecure key"
- elif [[ $size -lt 123 ]]; then
+ elif [[ $size -lt 123 ]] && [[ $KEY_EXCH_SCORE -gt 40 ]]; then
let KEY_EXCH_SCORE=40
set_grade_cap "F" "Using an insecure key"
- elif [[ $size -lt 163 ]]; then
+ elif [[ $size -lt 163 ]] && [[ $KEY_EXCH_SCORE -gt 80 ]]; then
let KEY_EXCH_SCORE=80
set_grade_cap "B" "Using a weak key"
- elif [[ $size -lt 225 ]]; then
+ elif [[ $size -lt 225 ]] && [[ $KEY_EXCH_SCORE -gt 90 ]]; then
let KEY_EXCH_SCORE=90
- elif [[ $size -ge 225 ]]; then
- let KEY_EXCH_SCORE=100
- else
- let KEY_EXCH_SCORE=0
- set_grade_cap "F" "Using an insecure key"
fi
else
- if [[ $size -lt 512 ]]; then
+ if [[ $size -lt 512 ]] && [[ $KEY_EXCH_SCORE -gt 20 ]]; then
let KEY_EXCH_SCORE=20
set_grade_cap "F" "Using an insecure key"
- elif [[ $size -lt 1024 ]]; then
+ elif [[ $size -lt 1024 ]] && [[ $KEY_EXCH_SCORE -gt 40 ]]; then
let KEY_EXCH_SCORE=40
set_grade_cap "F" "Using an insecure key"
- elif [[ $size -lt 2048 ]]; then
+ elif [[ $size -lt 2048 ]] && [[ $KEY_EXCH_SCORE -gt 80 ]]; then
let KEY_EXCH_SCORE=80
set_grade_cap "B" "Using a weak key"
- elif [[ $size -lt 4096 ]]; then
+ elif [[ $size -lt 4096 ]] && [[ $KEY_EXCH_SCORE -gt 90 ]]; then
let KEY_EXCH_SCORE=90
- elif [[ $size -ge 4096 ]]; then
- let KEY_EXCH_SCORE=100
- else
- let KEY_EXCH_SCORE=0
- set_grade_cap "F" "Using an insecure key"
fi
fi
return 0
From 7b3adf8195f2490bfa7472f3017cc2a36ce50847 Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Thu, 7 May 2020 10:50:41 +0200
Subject: [PATCH 087/211] Labelling, look @ 3.0.2
* label 3.1dev it as a ~rolling release
* outlook to 3.0.2 (~tomorrow)
---
Readme.md | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/Readme.md b/Readme.md
index 071828e..6267975 100644
--- a/Readme.md
+++ b/Readme.md
@@ -17,11 +17,9 @@ cryptographic flaws.
* Machine readable output (CSV, two JSON formats)
* No need to install or to configure something. No gems, CPAN, pip or the like.
* Works out of the box: Linux, OSX/Darwin, FreeBSD, NetBSD, MSYS2/Cygwin, WSL (bash on Windows). Only OpenBSD needs bash.
-* A Dockerfile is provided, there's also an offical container @ dockerhub.
-* Flexibility: You can test any SSL/TLS enabled and STARTTLS service, not
- only web servers at port 443.
-* Toolbox: Several command line options help you to run *your* test and
- configure *your* output.
+* A Dockerfile is provided, there's also an offical container build @ dockerhub.
+* Flexibility: You can test any SSL/TLS enabled and STARTTLS service, not only web servers at port 443.
+* Toolbox: Several command line options help you to run *your* test and configure *your* output.
* Reliability: features are tested thoroughly.
* Privacy: It's only you who sees the result, not a third party.
* Freedom: It's 100% open source. You can look at the code, see what's going on.
@@ -51,18 +49,20 @@ Update notification here or @ [twitter](https://twitter.com/drwetter).
### Installation
-You can download testssl.sh by cloning this git repository:
+You can download testssl.sh version 3.1dev by cloning this git repository:
git clone --depth 1 https://github.com/drwetter/testssl.sh.git
-Or help yourself downloading the 3.0 ZIP archive [https://github.com/drwetter/testssl.sh/archive/3.0.1.zip](https://github.com/drwetter/testssl.sh/archive/3.0.1.zip). Just ``cd`` to the directory created (=INSTALLDIR) and run it off there.
+Think of 3.1dev like a rolling release, see below. For the stable version help yourself by downloading the [ZIP](https://github.com/drwetter/testssl.sh/archive/3.0.2.zip) or [tar.gz](https://github.com/drwetter/testssl.sh/archive/3.0.2.zip) archive. Just ``cd`` to the directory created (=INSTALLDIR) and run it off there.
#### Docker
Testssl.sh has minimal requirements. As stated you don't have to install or build anything. You can just run it from the pulled/cloned directory. Still if you don't want to pull the github repo to your directory of choice you can pull a container from dockerhub and run it:
+
```
-docker run --rm -ti drwetter/testssl.sh
+docker run --rm -ti drwetter/testssl.sh:3.1dev
```
+
Or if you have cloned this repo you also can just ``cd`` to the INSTALLDIR and run
```
docker build .
@@ -77,10 +77,9 @@ Successfully built 889fa2f99933
### Status
-We're currently in the developement pase of 3.1dev. That means **occasionally** things can break. But we plan to keep it usable, think more of a rolling development. For missing critical purposes or when you don't like changes you should wait a bit until we're in the release phase. As soon as we reach that or the "dev" disappears in the branch you should rather use this version.
-
-Support for 2.9.5 has been dropped. Supported is 3.0 only.
+We're currently in the development phase, version 3.1dev. 3.1dev will eventually become 3.2. Bigger features are developed in a seperate branch before merged into 3.1dev to avoid hiccups or inconsitencies. Albeit we try to keep 3.1dev as solid as possible things will certainly change in 3.1dev. So if you need stability the 3.0 branch is better for you. Think of the 3.1dev branch like a rolling release.
+Support for 2.9.5 has been dropped. Supported is 3.0.x only.
### Documentation
From 6fa82ea2f70d7557d9817ee6c05507e6837fb048 Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Thu, 7 May 2020 17:15:11 +0200
Subject: [PATCH 088/211] Fix typos
---
Readme.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Readme.md b/Readme.md
index 6267975..fe16248 100644
--- a/Readme.md
+++ b/Readme.md
@@ -37,7 +37,7 @@ to get bugfixes, other feedback and more contributions.
### Compatibility
-testssl.sh is working on every Linux/BSD distribution out of the box. Latest by 2.9dev
+Testssl.sh is working on every Linux/BSD distribution out of the box. Latest by 2.9dev
most of the limitations of disabled features from the openssl client are gone
due to bash-socket-based checks. As a result you can also use e.g. LibreSSL or OpenSSL >=
1.1.1 . testssl.sh also works on other unixoid system out of the box, supposed they have
@@ -49,7 +49,7 @@ Update notification here or @ [twitter](https://twitter.com/drwetter).
### Installation
-You can download testssl.sh version 3.1dev by cloning this git repository:
+You can download testssl.sh branch 3.1dev just by cloning this git repository:
git clone --depth 1 https://github.com/drwetter/testssl.sh.git
@@ -77,7 +77,7 @@ Successfully built 889fa2f99933
### Status
-We're currently in the development phase, version 3.1dev. 3.1dev will eventually become 3.2. Bigger features are developed in a seperate branch before merged into 3.1dev to avoid hiccups or inconsitencies. Albeit we try to keep 3.1dev as solid as possible things will certainly change in 3.1dev. So if you need stability the 3.0 branch is better for you. Think of the 3.1dev branch like a rolling release.
+We're currently in the development phase, version 3.1dev. 3.1dev will eventually become 3.2. Bigger features are developed in a separate branch before merged into 3.1dev to avoid hiccups or inconsistencies. Albeit we try to keep 3.1dev as solid as possible things will certainly change in 3.1dev. So if you need stability the 3.0 branch is better for you. Think of the 3.1dev branch like a rolling release.
Support for 2.9.5 has been dropped. Supported is 3.0.x only.
@@ -85,7 +85,7 @@ Support for 2.9.5 has been dropped. Supported is 3.0.x only.
* .. it is there for reading. Please do so :-) -- at least before asking questions. See man page in groff, html and markdown format in `~/doc/`.
* [https://testssl.sh/](https://testssl.sh/) will help to get you started.
-* Will Hunt provides a longer, good [description](https://www.4armed.com/blog/doing-your-own-ssl-tls-testing/) for the (older) version 2.8, including useful background info.
+* For the (older) version 2.8 will Hunt provides a longer, good [description](https://www.4armed.com/blog/doing-your-own-ssl-tls-testing/), including useful background info.
### Contributing
From 8697e3417a2843840e7703883985453fab3a13f4 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Thu, 7 May 2020 12:30:40 -0400
Subject: [PATCH 089/211] Fix copy and paste error
This commit fixes a bug that was introduced by an accidental copy and paste.
---
testssl.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/testssl.sh b/testssl.sh
index dfb976f..813f6b1 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -9276,7 +9276,7 @@ run_server_defaults() {
if [[ -z "${ciphers_to_test[n+1]}" ]]; then
ciphers_to_test[n+1]="${ciphers_to_test[n]/aDSS/}"
ciphers_to_test[n+1]="${ciphers_to_test[n+1]/::/:}"
- [[ "${ciphe-S 127.0.0.1rs_to_test[n+1]:0:1}" == : ]] && ciphers_to_test[n+1]="${ciphers_to_test[n+1]:1}"
+ [[ "${ciphers_to_test[n+1]:0:1}" == : ]] && ciphers_to_test[n+1]="${ciphers_to_test[n+1]:1}"
fi
ciphers_to_test[n]="aDSS"
elif [[ "$ciph" == TLS_DH_* ]]; then
From cde2ecdc5d35961bffd11fb12ef4c59688efa119 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Fri, 8 May 2020 08:23:14 -0400
Subject: [PATCH 090/211] Rate RSA e=1 as CRITICAL
PR #1619 set the grade cap to 'F' is the server has a certificate with an RSA with e=1, however, it did not change the rating in the JSON/CSV output. This commit changes the cert_keySize rating to CRITICAL for an RSA key with e=1, regardless of the size of the modulus. It also uses pr_svrty_critical() to print the exponent in this case.
---
testssl.sh | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 7f3bfb9..91e1f3e 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -8535,9 +8535,14 @@ certificate_info() {
cert_spki_info="$(strip_leading_space "$cert_spki_info")"
cert_spki_info="${cert_spki_info%%[[:space:]]*}"
if [[ -n "$cert_spki_info" ]]; then
- out " (exponent is $cert_spki_info)"
+ if [[ $cert_spki_info -eq 1 ]]; then
+ out " (exponent is "; pr_svrty_critical "$cert_spki_info"; out ")"
+ json_rating="CRITICAL"
+ set_grade_cap "F" "RSA certificate uses exponent of 1"
+ else
+ out " (exponent is $cert_spki_info)"
+ fi
json_msg+=" (exponent is $cert_spki_info)"
- [[ $cert_spki_info -eq 1 ]] && set_grade_cap "F" "RSA certificate uses exponent of 1"
fi
;;
"EC") cert_spki_info="${cert_txt##*Subject Public Key Info:}"
From ec4feb52e78081035be41a60e48e722888dae995 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Fri, 8 May 2020 16:13:30 -0400
Subject: [PATCH 091/211] Fix "local problem" output in ciher_pref_check()
When cipher_pref_check() is called in "--ssl-native" mode and the specified protocol is not supported, the message indicating a "local problem" is not properly formatted.
---
testssl.sh | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 91e1f3e..a4451de 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -6825,11 +6825,11 @@ cipher_pref_check() {
order=""; ciphers_found_with_sockets=false
if [[ $proto == ssl3 ]] && ! "$HAS_SSL3" && ! "$using_sockets"; then
- out "\n SSLv3: "; pr_local_problem "$OPENSSL doesn't support \"s_client -ssl3\"";
+ prln_local_problem "$OPENSSL doesn't support \"s_client -ssl3\"";
return 0
fi
if [[ $proto == tls1_3 ]] && ! "$HAS_TLS13" && ! "$using_sockets"; then
- out "\n TLSv1.3 "; pr_local_problem "$OPENSSL doesn't support \"s_client -tls1_3\"";
+ prln_local_problem "$OPENSSL doesn't support \"s_client -tls1_3\"";
return 0
fi
From 4f802502a0a985fb55a58edb5dbb10af9cec97f0 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Fri, 8 May 2020 16:15:32 -0400
Subject: [PATCH 092/211] Implement $HAS_SIGALGS
The "-sigalgs" option is used in get_server_certificate() to obtain certificates the server uses with TLS 1.3. get_server_certificate() is currently designed to use $OPENSSL, if $OPENSSL supports TLS 1.3.
LibreSSL 3.1.{0,1} has added client support for TLS 1.3, but does not support the "-sigalgs" option. So, this commit determines whether the "-sigalgs" option is supported, and if it isn't, then uses tls_sockets().
---
testssl.sh | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/testssl.sh b/testssl.sh
index 91e1f3e..1ed9088 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -307,6 +307,7 @@ HAS_SSL3=false
HAS_TLS13=false
HAS_X448=false
HAS_X25519=false
+HAS_SIGALGS=false
HAS_PKUTIL=false
HAS_PKEY=false
HAS_NO_SSL2=false
@@ -7542,7 +7543,7 @@ get_server_certificate() {
CERTIFICATE_LIST_ORDERING_PROBLEM=false
if [[ "$1" =~ "tls1_3" ]]; then
[[ $(has_server_protocol "tls1_3") -eq 1 ]] && return 1
- if "$HAS_TLS13"; then
+ if "$HAS_TLS13" && "$HAS_SIGALGS"; then
if [[ "$1" =~ "tls1_3_RSA" ]]; then
$OPENSSL s_client $(s_client_options "$STARTTLS $BUGS -showcerts -connect $NODEIP:$PORT $PROXY $SNI -tls1_3 -tlsextdebug -status -msg -sigalgs PSS+SHA256:PSS+SHA384") $ERRFILE >$TMPFILE
elif [[ "$1" =~ "tls1_3_ECDSA" ]]; then
@@ -18264,6 +18265,7 @@ find_openssl_binary() {
HAS_TLS13=false
HAS_X448=false
HAS_X25519=false
+ HAS_SIGALGS=false
HAS_NO_SSL2=false
HAS_NOSERVERNAME=false
HAS_CIPHERSUITES=false
@@ -18310,6 +18312,10 @@ find_openssl_binary() {
$OPENSSL genpkey -algorithm X25519 2>&1 | grep -aq "not found" || \
HAS_X25519=true
+ if "$HAS_TLS13"; then
+ $OPENSSL s_client -tls1_3 -sigalgs PSS+SHA256:PSS+SHA384 -connect invalid. 2>&1 | grep -aiq "unknown option" || \
+ HAS_SIGALGS=true
+ fi
$OPENSSL s_client -no_ssl2 -connect invalid. 2>&1 | grep -aiq "unknown option" || \
HAS_NO_SSL2=true
@@ -18684,6 +18690,7 @@ HAS_SSL3: $HAS_SSL3
HAS_TLS13: $HAS_TLS13
HAS_X448: $HAS_X448
HAS_X25519: $HAS_X25519
+HAS_SIGALGS: $HAS_SIGALGS
HAS_NO_SSL2: $HAS_NO_SSL2
HAS_SPDY: $HAS_SPDY
HAS_ALPN: $HAS_ALPN
From 871db32fb557ebf4fdec914d6b3fd787bff8bcf5 Mon Sep 17 00:00:00 2001
From: Unit 193
Date: Fri, 8 May 2020 22:48:20 -0400
Subject: [PATCH 093/211] Fix a couple typos.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
enviroment → environment
ususally → usually
---
doc/testssl.1 | 4 ++--
doc/testssl.1.html | 4 ++--
doc/testssl.1.md | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/doc/testssl.1 b/doc/testssl.1
index 6aea659..38bbfed 100644
--- a/doc/testssl.1
+++ b/doc/testssl.1
@@ -128,7 +128,7 @@ Please note that \fBfname\fR has to be in Unix format\. DOS carriage returns won
\fB\-\-warnings \fR\. The warnings parameter determines how testssl\.sh will deal with situations where user input normally will be necessary\. There are two options\. \fBbatch\fR doesn\'t wait for a confirming keypress when a client\- or server\-side probem is encountered\. As of 3\.0 it just then terminates the particular scan\. This is automatically chosen for mass testing (\fB\-\-file\fR)\. \fBoff\fR just skips the warning, the confirmation but continues the scan, independent whether it makes sense or not\. Please note that there are conflicts where testssl\.sh will still ask for confirmation which are the ones which otherwise would have a drastic impact on the results\. Almost any other decision will be made in the future as a best guess by testssl\.sh\. The same can be achieved by setting the environment variable \fBWARNINGS\fR\.
.
.P
-\fB\-\-connect\-timeout \fR This is useful for socket TCP connections to a node\. If the node does not complete a TCP handshake (e\.g\. because it is down or behind a firewall or there\'s an IDS or a tarpit) testssl\.sh may ususally hang for around 2 minutes or even much more\. This parameter instructs testssl\.sh to wait at most \fBseconds\fR for the handshake to complete before giving up\. This option only works if your OS has a timeout binary installed\. CONNECT_TIMEOUT is the corresponding enviroment variable\.
+\fB\-\-connect\-timeout \fR This is useful for socket TCP connections to a node\. If the node does not complete a TCP handshake (e\.g\. because it is down or behind a firewall or there\'s an IDS or a tarpit) testssl\.sh may usually hang for around 2 minutes or even much more\. This parameter instructs testssl\.sh to wait at most \fBseconds\fR for the handshake to complete before giving up\. This option only works if your OS has a timeout binary installed\. CONNECT_TIMEOUT is the corresponding environment variable\.
.
.P
\fB\-\-openssl\-timeout \fR This is especially useful for all connects using openssl and practically useful for mass testing\. It avoids the openssl connect to hang for ~2 minutes\. The expected parameter \fBseconds\fR instructs testssl\.sh to wait before the openssl connect will be terminated\. The option is only available if your OS has a timeout binary installed\. As there are different implementations of \fBtimeout\fR: It automatically calls the binary with the right parameters\. OPENSSL_TIMEOUT is the equivalent environment variable\.
@@ -167,7 +167,7 @@ Please note that \fBfname\fR has to be in Unix format\. DOS carriage returns won
\fB\-\-assuming\-http\fR testssl\.sh normally does upfront an application protocol detection\. In cases where HTTP cannot be automatically detected you may want to use this option\. It enforces testssl\.sh not to skip HTTP specific tests (HTTP header) and to run a browser based client simulation\. Please note that sometimes also the severity depends on the application protocol, e\.g\. SHA1 signed certificates, the lack of any SAN matches and some vulnerabilities will be punished harder when checking a web server as opposed to a mail server\.
.
.P
-\fB\-n, \-\-nodns \fR tells testssl\.sh which DNS lookups should be performed\. \fBmin\fR uses only forward DNS resolution (A and AAAA record or MX record) and skips CAA lookups and PTR records from the IP address back to a DNS name\. \fBnone\fR performs no DNS lookups at all\. For the latter you either have to supply the IP address as a target, to use \fB\-\-ip\fR or have the IP address in \fB/etc/hosts\fR\. The use of the switch is only useful if you either can\'t or are not willing to perform DNS lookups\. The latter can apply e\.g\. to some pentests\. In general this option could e\.g\. help you to avoid timeouts by DNS lookups\. \fBNODNS\fR is the enviroment variable for this\.
+\fB\-n, \-\-nodns \fR tells testssl\.sh which DNS lookups should be performed\. \fBmin\fR uses only forward DNS resolution (A and AAAA record or MX record) and skips CAA lookups and PTR records from the IP address back to a DNS name\. \fBnone\fR performs no DNS lookups at all\. For the latter you either have to supply the IP address as a target, to use \fB\-\-ip\fR or have the IP address in \fB/etc/hosts\fR\. The use of the switch is only useful if you either can\'t or are not willing to perform DNS lookups\. The latter can apply e\.g\. to some pentests\. In general this option could e\.g\. help you to avoid timeouts by DNS lookups\. \fBNODNS\fR is the environment variable for this\.
.
.P
\fB\-\-sneaky\fR For HTTP header checks testssl\.sh uses normally the server friendly HTTP user agent \fBTLS tester from ${URL}\fR\. With this option your traces are less verbose and a Firefox user agent is being used\. Be aware that it doesn\'t hide your activities\. That is just not possible (environment preset via \fBSNEAKY=true\fR)\.
diff --git a/doc/testssl.1.html b/doc/testssl.1.html
index 8422223..8290958 100644
--- a/doc/testssl.1.html
+++ b/doc/testssl.1.html
@@ -181,7 +181,7 @@ host.example.com:631
--warnings <batch|off>
. The warnings parameter determines how testssl.sh will deal with situations where user input normally will be necessary. There are two options. batch
doesn't wait for a confirming keypress when a client- or server-side probem is encountered. As of 3.0 it just then terminates the particular scan. This is automatically chosen for mass testing (--file
). off
just skips the warning, the confirmation but continues the scan, independent whether it makes sense or not. Please note that there are conflicts where testssl.sh will still ask for confirmation which are the ones which otherwise would have a drastic impact on the results. Almost any other decision will be made in the future as a best guess by testssl.sh.
The same can be achieved by setting the environment variable WARNINGS
.
---connect-timeout <seconds>
This is useful for socket TCP connections to a node. If the node does not complete a TCP handshake (e.g. because it is down or behind a firewall or there's an IDS or a tarpit) testssl.sh may ususally hang for around 2 minutes or even much more. This parameter instructs testssl.sh to wait at most seconds
for the handshake to complete before giving up. This option only works if your OS has a timeout binary installed. CONNECT_TIMEOUT is the corresponding enviroment variable.
+--connect-timeout <seconds>
This is useful for socket TCP connections to a node. If the node does not complete a TCP handshake (e.g. because it is down or behind a firewall or there's an IDS or a tarpit) testssl.sh may usually hang for around 2 minutes or even much more. This parameter instructs testssl.sh to wait at most seconds
for the handshake to complete before giving up. This option only works if your OS has a timeout binary installed. CONNECT_TIMEOUT is the corresponding environment variable.
--openssl-timeout <seconds>
This is especially useful for all connects using openssl and practically useful for mass testing. It avoids the openssl connect to hang for ~2 minutes. The expected parameter seconds
instructs testssl.sh to wait before the openssl connect will be terminated. The option is only available if your OS has a timeout binary installed. As there are different implementations of timeout
: It automatically calls the binary with the right parameters. OPENSSL_TIMEOUT is the equivalent environment variable.
@@ -212,7 +212,7 @@ The same can be achieved by setting the environment variable WARNINGS--assuming-http
testssl.sh normally does upfront an application protocol detection. In cases where HTTP cannot be automatically detected you may want to use this option. It enforces testssl.sh not to skip HTTP specific tests (HTTP header) and to run a browser based client simulation. Please note that sometimes also the severity depends on the application protocol, e.g. SHA1 signed certificates, the lack of any SAN matches and some vulnerabilities will be punished harder when checking a web server as opposed to a mail server.
-n, --nodns <min|none>
tells testssl.sh which DNS lookups should be performed. min
uses only forward DNS resolution (A and AAAA record or MX record) and skips CAA lookups and PTR records from the IP address back to a DNS name. none
performs no DNS lookups at all. For the latter you either have to supply the IP address as a target, to use --ip
or have the IP address
-in /etc/hosts
. The use of the switch is only useful if you either can't or are not willing to perform DNS lookups. The latter can apply e.g. to some pentests. In general this option could e.g. help you to avoid timeouts by DNS lookups. NODNS
is the enviroment variable for this.
+in /etc/hosts
. The use of the switch is only useful if you either can't or are not willing to perform DNS lookups. The latter can apply e.g. to some pentests. In general this option could e.g. help you to avoid timeouts by DNS lookups. NODNS
is the environment variable for this.
--sneaky
For HTTP header checks testssl.sh uses normally the server friendly HTTP user agent TLS tester from ${URL}
. With this option your traces are less verbose and a Firefox user agent is being used. Be aware that it doesn't hide your activities. That is just not possible (environment preset via SNEAKY=true
).
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index a63fb26..b695822 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -104,7 +104,7 @@ Please note that `fname` has to be in Unix format. DOS carriage returns won't be
`--warnings `. The warnings parameter determines how testssl.sh will deal with situations where user input normally will be necessary. There are two options. `batch` doesn't wait for a confirming keypress when a client- or server-side probem is encountered. As of 3.0 it just then terminates the particular scan. This is automatically chosen for mass testing (`--file`). `off` just skips the warning, the confirmation but continues the scan, independent whether it makes sense or not. Please note that there are conflicts where testssl.sh will still ask for confirmation which are the ones which otherwise would have a drastic impact on the results. Almost any other decision will be made in the future as a best guess by testssl.sh.
The same can be achieved by setting the environment variable `WARNINGS`.
-`--connect-timeout ` This is useful for socket TCP connections to a node. If the node does not complete a TCP handshake (e.g. because it is down or behind a firewall or there's an IDS or a tarpit) testssl.sh may ususally hang for around 2 minutes or even much more. This parameter instructs testssl.sh to wait at most `seconds` for the handshake to complete before giving up. This option only works if your OS has a timeout binary installed. CONNECT_TIMEOUT is the corresponding enviroment variable.
+`--connect-timeout ` This is useful for socket TCP connections to a node. If the node does not complete a TCP handshake (e.g. because it is down or behind a firewall or there's an IDS or a tarpit) testssl.sh may usually hang for around 2 minutes or even much more. This parameter instructs testssl.sh to wait at most `seconds` for the handshake to complete before giving up. This option only works if your OS has a timeout binary installed. CONNECT_TIMEOUT is the corresponding environment variable.
`--openssl-timeout ` This is especially useful for all connects using openssl and practically useful for mass testing. It avoids the openssl connect to hang for ~2 minutes. The expected parameter `seconds` instructs testssl.sh to wait before the openssl connect will be terminated. The option is only available if your OS has a timeout binary installed. As there are different implementations of `timeout`: It automatically calls the binary with the right parameters. OPENSSL_TIMEOUT is the equivalent environment variable.
@@ -137,7 +137,7 @@ The same can be achieved by setting the environment variable `WARNINGS`.
`--assuming-http` testssl.sh normally does upfront an application protocol detection. In cases where HTTP cannot be automatically detected you may want to use this option. It enforces testssl.sh not to skip HTTP specific tests (HTTP header) and to run a browser based client simulation. Please note that sometimes also the severity depends on the application protocol, e.g. SHA1 signed certificates, the lack of any SAN matches and some vulnerabilities will be punished harder when checking a web server as opposed to a mail server.
`-n, --nodns ` tells testssl.sh which DNS lookups should be performed. `min` uses only forward DNS resolution (A and AAAA record or MX record) and skips CAA lookups and PTR records from the IP address back to a DNS name. `none` performs no DNS lookups at all. For the latter you either have to supply the IP address as a target, to use `--ip` or have the IP address
-in `/etc/hosts`. The use of the switch is only useful if you either can't or are not willing to perform DNS lookups. The latter can apply e.g. to some pentests. In general this option could e.g. help you to avoid timeouts by DNS lookups. `NODNS` is the enviroment variable for this.
+in `/etc/hosts`. The use of the switch is only useful if you either can't or are not willing to perform DNS lookups. The latter can apply e.g. to some pentests. In general this option could e.g. help you to avoid timeouts by DNS lookups. `NODNS` is the environment variable for this.
`--sneaky` For HTTP header checks testssl.sh uses normally the server friendly HTTP user agent `TLS tester from ${URL}`. With this option your traces are less verbose and a Firefox user agent is being used. Be aware that it doesn't hide your activities. That is just not possible (environment preset via `SNEAKY=true`).
From d065bda3b8538ba8bc9cd4f077685536d2a95dd1 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Sat, 9 May 2020 13:17:02 +0200
Subject: [PATCH 094/211] Better Dockerfile: doesn't require "git clone"
.. see also #1559.
It "mkdirs" the needed etc and bin directories first, then copies
stuff over. It also reduces a few layers.
Also it corrects a mistake in the Readme.md (docker exec --> run)
Thanks for the discussion @Alex131089
---
Dockerfile | 17 ++++++++++-------
Readme.md | 2 +-
2 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index 11e2759..42a6941 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,16 +1,19 @@
FROM alpine:3.11
-RUN apk update && apk upgrade && apk add --no-cache bash procps drill git coreutils libidn curl
-
-RUN addgroup testssl
-RUN adduser -G testssl -g "testssl user" -s /bin/bash -D testssl
-
-RUN ln -s /home/testssl/testssl.sh /usr/local/bin/
+RUN apk update && \
+ apk upgrade && \
+ apk add --no-cache bash procps drill git coreutils libidn curl && \
+ addgroup testssl && \
+ adduser -G testssl -g "testssl user" -s /bin/bash -D testssl && \
+ ln -s /home/testssl/testssl.sh /usr/local/bin/ && \
+ mkdir -m 755 -p /home/testssl/etc /home/testssl/bin
USER testssl
WORKDIR /home/testssl/
-RUN git clone --depth=1 https://github.com/drwetter/testssl.sh.git .
+COPY --chown=testssl:testssl etc/. /home/testssl/etc/
+COPY --chown=testssl:testssl bin/. /home/testssl/bin/
+COPY --chown=testssl:testssl testssl.sh /home/testssl/
ENTRYPOINT ["testssl.sh"]
diff --git a/Readme.md b/Readme.md
index fe16248..bc1dca3 100644
--- a/Readme.md
+++ b/Readme.md
@@ -68,7 +68,7 @@ Or if you have cloned this repo you also can just ``cd`` to the INSTALLDIR and r
docker build .
```
-followed by ``docker exec -ti `` where ``ID`` is the identifier in the last line from the build command like
+followed by ``docker run -ti `` where ``ID`` is the identifier in the last line from the build command like
```
---> 889fa2f99933
From 825cbf7b1deafe89f6a05e80bad5b2d88db3bf0a Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Mon, 11 May 2020 10:41:48 +0200
Subject: [PATCH 095/211] Improve compression detection for BREACH
This commit tries to enummerate through all possible compressions
instead of just raising the arm because of the first one detected.
As far as the performance is concerned there's room for improvements
which subsequent commits will address.
---
testssl.sh | 67 +++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 46 insertions(+), 21 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 39c67e3..6c61516 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -15887,6 +15887,7 @@ run_crime() {
# BREACH is a HTTP-level compression & an attack which works against any cipher suite and is agnostic
# to the version of TLS/SSL, more: http://www.breachattack.com/ . Foreign referrers are the important thing here!
# Mitigation: see https://community.qualys.com/message/20360
+# Any URL can be vulnerable. Here only the given URL is tested. See also $when_makesense
#
run_breach() {
local header
@@ -15899,8 +15900,10 @@ run_breach() {
local when_makesense=" Can be ignored for static pages or if no secrets in the page"
local cve="CVE-2013-3587"
local cwe="CWE-310"
- local hint=""
+ local hint="" c=""
local jsonID="BREACH"
+ local compressions="gzip deflate compress br"
+ local has_compression=()
[[ $SERVICE != HTTP ]] && ! "$CLIENT_AUTH" && return 7
@@ -15925,33 +15928,55 @@ run_breach() {
[[ "$NODE" =~ google ]] && referer="https://yandex.ru/" # otherwise we have a false positive for google.com
useragent="$UA_STD"
$SNEAKY && useragent="$UA_SNEAKY"
- tm_out "GET $url HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $useragent\r\nReferer: $referer\r\nConnection: Close\r\nAccept-encoding: gzip,deflate,compress\r\nAccept: text/*\r\n\r\n" | $OPENSSL s_client $(s_client_options "$OPTIMAL_PROTO $BUGS -quiet -ign_eof -connect $NODEIP:$PORT $PROXY $SNI") 1>$TMPFILE 2>$ERRFILE &
- wait_kill $! $HEADER_MAXSLEEP
- was_killed=$? # !=0 was killed
- result=$(awk '/^Content-Encoding/ { print $2 }' $TMPFILE)
- result=$(strip_lf "$result")
- debugme grep '^Content-Encoding' $TMPFILE
- if [[ ! -s $TMPFILE ]]; then
- pr_warning "failed (HTTP header request stalled or empty return"
- if [[ $was_killed -ne 0 ]]; then
- pr_warning " and was terminated"
- fileout "$jsonID" "WARN" "Test failed as HTTP request stalled and was terminated" "$cve" "$cwe"
+ for c in $compressions; do
+ tm_out "GET $url HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $useragent\r\nReferer: $referer\r\nConnection: Close\r\nAccept-encoding: $c\r\nAccept: text/*\r\n\r\n" | $OPENSSL s_client $(s_client_options "$OPTIMAL_PROTO $BUGS -quiet -ign_eof -connect $NODEIP:$PORT $PROXY $SNI") 1>$TMPFILE 2>$ERRFILE &
+ wait_kill $! $HEADER_MAXSLEEP
+ was_killed=$? # !=0 was killed
+ result=$(grep -ia ^Content-Encoding: $TMPFILE)
+ debugme echo "$result"
+ result="$(strip_lf "$result")"
+ result="${result#*:}"
+ result="$(strip_spaces "$result")"
+ if [[ ! -s $TMPFILE ]]; then
+ if [[ $was_killed -ne 0 ]]; then
+ has_compression+=("$c:warn_stalled")
+ else
+ has_compression+=("$c:warn_empty")
+ fi
+ ret+=1
+ elif [[ -z $result ]]; then
+ has_compression+=("$c:no")
else
- fileout "$jsonID" "WARN" "Test failed as HTTP response was empty" "$cve" "$cwe"
+ has_compression+=("$c:yes")
fi
- prln_warning ") "
- ret=1
- elif [[ -z $result ]]; then
- pr_svrty_best "no HTTP compression (OK) "
+ done
+
+ result=""
+ if [[ ! ${has_compression[@]} =~ yes ]] && [[ ! ${has_compression[@]} =~ warn ]]; then
+ pr_svrty_best "no gzip/deflate/compress/br HTTP compression (OK) "
outln "$disclaimer"
- fileout "$jsonID" "OK" "not vulnerable, no HTTP compression $disclaimer" "$cve" "$cwe"
+ fileout "$jsonID" "OK" "not vulnerable, no gzip/deflate/compress/br HTTP compression $disclaimer" "$cve" "$cwe"
+ elif [[ ${has_compression[@]} =~ warn_stalled ]]; then
+ pr_warning "At least 1/4 checks failed (HTTP header request stalled and was terminated"
+ out ", debug: ${has_compression[@]})"
+ fileout "$jsonID" "WARN" "Test failed as HTTP request stalled and was terminated" "$cve" "$cwe"
+ elif [[ ${has_compression[@]} =~ warn_empty ]]; then
+ pr_warning "At least 1/4 checks failed (HTTP header request was empty, debug: ${has_compression[@]}"
+ out ", debug: ${has_compression[@]})"
+ fileout "$jsonID" "WARN" "Test failed as HTTP response was empty, debug: ${has_compression[@]}" "$cve" "$cwe"
else
- pr_svrty_high "potentially NOT ok, uses $result HTTP compression."
+ for c in ${has_compression[@]}; do
+ if [[ $c =~ yes ]]; then
+ result+="${c%:*} "
+ fi
+ done
+ result="$(strip_trailing_space "$result")"
+ pr_svrty_high "potentially NOT ok, \"$result\" HTTP compression detected."
outln "$disclaimer"
outln "$spaces$when_makesense"
- fileout "$jsonID" "HIGH" "potentially VULNERABLE, uses $result HTTP compression $disclaimer" "$cve" "$cwe" "$hint"
+ fileout "$jsonID" "HIGH" "potentially VULNERABLE, $result HTTP compression detected $disclaimer" "$cve" "$cwe" "$hint"
fi
- # Any URL can be vulnerable. I am testing now only the given URL!
+ debugme echo "has_compression: ${has_compression[@]}"
tmpfile_handle ${FUNCNAME[0]}.txt
return $ret
From 25f87455a4bc4ce442396b6bdd2afd005dede07b Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Mon, 11 May 2020 13:57:50 +0200
Subject: [PATCH 096/211] Amendment for compression detection (BREACH)
This commit saves more or less time for a detection of the compression.
First it assembles the GET command with all available compressions and send them all.
If the result is negative: we can just tell the finding and return. If it's
positive: We already have identified 1x compression. Then we cycle through the
remaining compressions with single GET requests.
In order to not duplicate code we introduced a helper function sub_breach_helper()
which takes care sending the request and analysis the result.
We treat now failed requests differently: When the first fails we don't
continue anymore.
---
testssl.sh | 167 +++++++++++++++++++++++++++++++++++------------------
1 file changed, 110 insertions(+), 57 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 6c61516..13c633d 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -15884,15 +15884,48 @@ run_crime() {
}
-# BREACH is a HTTP-level compression & an attack which works against any cipher suite and is agnostic
-# to the version of TLS/SSL, more: http://www.breachattack.com/ . Foreign referrers are the important thing here!
+
+# As the name says. It expects as arg1 a GET command string. It returns 1
+# when GET command was stalled or killed (which is no not always used)
+# and echos "warn_*". It return 0 when everything went ok and echos the
+# compression if any.
+sub_breach_helper() {
+ local get_command="$1"
+ local detected_compression=""
+ local -i was_killed=0
+
+ safe_echo "$get_command" | $OPENSSL s_client $(s_client_options "$OPTIMAL_PROTO $BUGS -quiet -ign_eof -connect $NODEIP:$PORT $PROXY $SNI") 1>$TMPFILE 2>$ERRFILE &
+ wait_kill $! $HEADER_MAXSLEEP
+ was_killed=$? # !=0 when it was killed
+ detected_compression=$(grep -ia ^Content-Encoding: $TMPFILE)
+ detected_compression="$(strip_lf "$detected_compression")"
+ detected_compression="${detected_compression#*:}"
+ detected_compression="$(strip_spaces "$detected_compression")"
+ if [[ ! -s $TMPFILE ]]; then
+ if [[ $was_killed -eq 0 ]]; then
+ echo "warn_stalled"
+ else
+ echo "warn_killed"
+ fi
+ return 1
+ elif [[ -z $detected_compression ]]; then
+ echo "no_compression"
+ else
+ echo "$detected_compression"
+ fi
+ return 0
+}
+
+
+
+# BREACH is a HTTP-level compression & an attack which works against any cipher suite and is agnostic to the
+# version of TLS/SSL, more: http://www.breachattack.com/ . External referrers are the important thing here!
# Mitigation: see https://community.qualys.com/message/20360
# Any URL can be vulnerable. Here only the given URL is tested. See also $when_makesense
#
run_breach() {
local header
local -i ret=0
- local -i was_killed=0
local referer useragent
local url="$1"
local spaces=" "
@@ -15904,6 +15937,8 @@ run_breach() {
local jsonID="BREACH"
local compressions="gzip deflate compress br"
local has_compression=()
+ local detected_compression=""
+ local get_command=""
[[ $SERVICE != HTTP ]] && ! "$CLIENT_AUTH" && return 7
@@ -15914,13 +15949,6 @@ run_breach() {
fileout "$jsonID" "INFO" "was not tested, server side requires x509 authentication" "$cve" "$cwe"
fi
- # if [[ $NR_HEADER_FAIL -ge $MAX_HEADER_FAIL ]]; then
- # pr_warning "Retrieving HTTP header failed before. Skipping."
- # fileout "$jsonID" "WARN" "HTTP response was wampty before" "$cve" "$cwe"
- # outln
- # return 1
- # fi
-
[[ -z "$url" ]] && url="/"
disclaimer=" - only supplied \"$url\" tested"
@@ -15928,55 +15956,80 @@ run_breach() {
[[ "$NODE" =~ google ]] && referer="https://yandex.ru/" # otherwise we have a false positive for google.com
useragent="$UA_STD"
$SNEAKY && useragent="$UA_SNEAKY"
- for c in $compressions; do
- tm_out "GET $url HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $useragent\r\nReferer: $referer\r\nConnection: Close\r\nAccept-encoding: $c\r\nAccept: text/*\r\n\r\n" | $OPENSSL s_client $(s_client_options "$OPTIMAL_PROTO $BUGS -quiet -ign_eof -connect $NODEIP:$PORT $PROXY $SNI") 1>$TMPFILE 2>$ERRFILE &
- wait_kill $! $HEADER_MAXSLEEP
- was_killed=$? # !=0 was killed
- result=$(grep -ia ^Content-Encoding: $TMPFILE)
- debugme echo "$result"
- result="$(strip_lf "$result")"
- result="${result#*:}"
- result="$(strip_spaces "$result")"
- if [[ ! -s $TMPFILE ]]; then
- if [[ $was_killed -ne 0 ]]; then
- has_compression+=("$c:warn_stalled")
- else
- has_compression+=("$c:warn_empty")
- fi
- ret+=1
- elif [[ -z $result ]]; then
- has_compression+=("$c:no")
- else
- has_compression+=("$c:yes")
- fi
- done
- result=""
- if [[ ! ${has_compression[@]} =~ yes ]] && [[ ! ${has_compression[@]} =~ warn ]]; then
- pr_svrty_best "no gzip/deflate/compress/br HTTP compression (OK) "
- outln "$disclaimer"
- fileout "$jsonID" "OK" "not vulnerable, no gzip/deflate/compress/br HTTP compression $disclaimer" "$cve" "$cwe"
- elif [[ ${has_compression[@]} =~ warn_stalled ]]; then
- pr_warning "At least 1/4 checks failed (HTTP header request stalled and was terminated"
- out ", debug: ${has_compression[@]})"
- fileout "$jsonID" "WARN" "Test failed as HTTP request stalled and was terminated" "$cve" "$cwe"
- elif [[ ${has_compression[@]} =~ warn_empty ]]; then
- pr_warning "At least 1/4 checks failed (HTTP header request was empty, debug: ${has_compression[@]}"
- out ", debug: ${has_compression[@]})"
- fileout "$jsonID" "WARN" "Test failed as HTTP response was empty, debug: ${has_compression[@]}" "$cve" "$cwe"
- else
- for c in ${has_compression[@]}; do
- if [[ $c =~ yes ]]; then
- result+="${c%:*} "
+ # Assemble the GET command with all available compressions and send them all, initially.
+ # If the result is negative: we can just tell the finding and return. If it's
+ # positive: We already have identified 1x compression
+ get_command="GET $url HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $useragent\r\nReferer: $referer\r\nConnection: Close\r\nAccept-encoding: ${compressions// /,}\r\nAccept: text/*\r\n\r\n"
+ detected_compression=$(sub_breach_helper "$get_command")
+ case "$detected_compression" in
+ warn_stalled)
+ pr_warning "First request failed (HTTP header request stalled and was terminated)"
+ fileout "$jsonID" "WARN" "Test failed as first HTTP request stalled and was terminated" "$cve" "$cwe"
+ ret=1
+ ;;
+ warn_failed)
+ pr_warning "First request failed (HTTP header request was empty)"
+ fileout "$jsonID" "WARN" "Test failed as first HTTP response was empty" "$cve" "$cwe"
+ ret=1
+ ;;
+ no_compression)
+ pr_svrty_best "no gzip/deflate/compress/br HTTP compression (OK) "
+ outln "$disclaimer"
+ fileout "$jsonID" "OK" "not vulnerable, no gzip/deflate/compress/br HTTP compression $disclaimer" "$cve" "$cwe"
+ ret=0
+ ;;
+ *) # Now assemble the remaining compressions in $compressions and loop through them
+ has_compression+=("$detected_compression:yes")
+ compressions="${compressions//$detected_compression/}"
+ for c in $compressions; do
+ get_command="GET $url HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $useragent\r\nReferer: $referer\r\nConnection: Close\r\nAccept-encoding: ${c}\r\nAccept: text/*\r\n\r\n"
+ detected_compression=$(sub_breach_helper "$get_command")
+ if [[ $? -ne 0 ]]; then
+ # This failure unlikely here. The initial request must have succeeded and this one then
+ # failed but we'd rather treat this correctly (e.d. IDS which triggers later). Not also
+ # we exit on the first stalled request. So if the first one with all compressions failed,
+ # we don't get here. It seems very unlikely the first failed and subsequent will succeed.
+ has_compression+=("$c:$compressions")
+ elif [[ "$detected_compression" =~ no_compression ]]; then
+ has_compression+=("$c:no")
+ debugme echo "has_compression: $c: no"
+ elif [[ -n "detected_compression" ]]; then
+ has_compression+=("$c:yes")
+ debugme echo "has_compression: $c: yes"
+ else
+ prln_fixme "strange reply around line $((LINENO)) from sub_breach_helper()"
+ fi
+ done
+
+ # Final verdict (if not happened preemptively before). We reuse $detected_compression here
+ detected_compression=""
+ if [[ ${has_compression[@]} =~ warn ]]; then
+ # warn_empty / warn_stalled
+ if [[ ${has_compression[@]} =~ warn_empty ]]; then
+ pr_warning "At least 1/4 checks failed (HTTP header request was empty, debug: ${has_compression[@]}"
+ out ", debug: ${has_compression[@]})"
+ fileout "$jsonID" "WARN" "Test failed as HTTP response was empty, debug: ${has_compression[@]}" "$cve" "$cwe"
+ else # warn_stalled
+ pr_warning "At least 1/4 checks failed (HTTP header request stalled and was terminated"
+ out ", debug: ${has_compression[@]})"
+ fileout "$jsonID" "WARN" "Test failed as HTTP request stalled and was terminated" "$cve" "$cwe"
+ fi
+ else
+ for c in ${has_compression[@]}; do
+ if [[ $c =~ yes ]]; then
+ detected_compression+="${c%:*} "
+ fi
+ done
+ detected_compression="$(strip_trailing_space "$detected_compression")"
+ pr_svrty_high "potentially NOT ok, \"$detected_compression\" HTTP compression detected."
+ outln "$disclaimer"
+ outln "${spaces}${when_makesense}"
+ fileout "$jsonID" "HIGH" "potentially VULNERABLE, $detected_compression HTTP compression detected $disclaimer" "$cve" "$cwe" "$hint"
fi
- done
- result="$(strip_trailing_space "$result")"
- pr_svrty_high "potentially NOT ok, \"$result\" HTTP compression detected."
- outln "$disclaimer"
- outln "$spaces$when_makesense"
- fileout "$jsonID" "HIGH" "potentially VULNERABLE, $result HTTP compression detected $disclaimer" "$cve" "$cwe" "$hint"
- fi
- debugme echo "has_compression: ${has_compression[@]}"
+ debugme outln "${spaces}has_compression: ${has_compression[@]}"
+ ;;
+ esac
tmpfile_handle ${FUNCNAME[0]}.txt
return $ret
From 78a95d73c8608cd2db559d45955b5e9b912e4c70 Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Mon, 11 May 2020 14:07:02 +0200
Subject: [PATCH 097/211] Add BREACH extension
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 36d0236..6641957 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@
* Added several ciphers to colored ciphers
* Percent output char problem fixed
* Several display/output fixes
+* BREACH check: list all compression methods and add brotli
* Security fix: DNS input
* Don't use external pwd anymore
* STARTTLS: XMPP server support
From 6119d8538e5e486acb3681c3ba793cce6f04a814 Mon Sep 17 00:00:00 2001
From: Magnus Larsen <[]>
Date: Mon, 11 May 2020 15:20:16 +0200
Subject: [PATCH 098/211] proper rating of dh group length
---
doc/testssl.1.md | 3 +--
testssl.sh | 22 +++++++---------------
2 files changed, 8 insertions(+), 17 deletions(-)
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index b695822..efbd11e 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -145,7 +145,7 @@ in `/etc/hosts`. The use of the switch is only useful if you either can't or ar
`--phone-out` Checking for revoked certificates via CRL and OCSP is not done per default. This switch instructs testssl.sh to query external -- in a sense of the current run -- URIs. By using this switch you acknowledge that the check might have privacy issues, a download of several megabytes (CRL file) may happen and there may be network connectivity problems while contacting the endpoint which testssl.sh doesn't handle. PHONE_OUT is the environment variable for this which needs to be set to true if you want this.
-`--add-ca ` enables you to add your own CA(s) for trust chain checks. `cafile` can be a single path or multiple paths as a comma separated list of root CA files. Internally they will be added during runtime to all CA stores. This is (only) useful for internal hosts whose certificates is issued by internal CAs. Alternatively
+`--add-ca ` enables you to add your own CA(s) for trust chain checks. `cafile` can be a single path or multiple paths as a comma separated list of root CA files. Internally they will be added during runtime to all CA stores. This is (only) useful for internal hosts whose certificates is issued by internal CAs. Alternatively
ADDTL_CA_FILES is the environment variable for this.
@@ -404,7 +404,6 @@ As of writing, these checks are missing:
* Zombie POODLE - should be graded **F** if vulnerable
* All remaining old Symantec PKI certificates are distrusted - should be graded **T**
* Symantec certificates issued before June 2016 are distrusted - should be graded **T**
-* ! A reading of DH params - should give correct points in `set_key_str_score()`
* Anonymous key exchange - should give **0** points in `set_key_str_score()`
* Exportable key exchange - should give **40** points in `set_key_str_score()`
* Weak key (Debian OpenSSL Flaw) - should give **0** points in `set_key_str_score()`
diff --git a/testssl.sh b/testssl.sh
index 39c67e3..8ef3c5d 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -1030,7 +1030,7 @@ set_grade_warning() {
}
# Sets the score for Category 2 (Key Exchange Strength)
-# arg1: Short key algorithm ("EC", "DH", "RSA", ...) # Can die, when we get DH_PARAMs
+# arg1: Short key algorithm ("EC", "DH", "RSA", ...), or "DHE" for ephemeral key size
# arg2: key size (number of bits)
set_key_str_score() {
local type=$1
@@ -1038,13 +1038,8 @@ set_key_str_score() {
"$do_rating" || return 0
- # TODO: We need to get the size of DH params (follows the same table as the "else" clause)
- # For now, verifying the key size will do...
if [[ $type == EC ]]; then
- if [[ $size -lt 110 ]] && [[ $KEY_EXCH_SCORE -gt 20 ]]; then
- let KEY_EXCH_SCORE=20
- set_grade_cap "F" "Using an insecure key"
- elif [[ $size -lt 123 ]] && [[ $KEY_EXCH_SCORE -gt 40 ]]; then
+ if [[ $size -lt 123 ]] && [[ $KEY_EXCH_SCORE -gt 40 ]]; then
let KEY_EXCH_SCORE=40
set_grade_cap "F" "Using an insecure key"
elif [[ $size -lt 163 ]] && [[ $KEY_EXCH_SCORE -gt 80 ]]; then
@@ -1054,15 +1049,12 @@ set_key_str_score() {
let KEY_EXCH_SCORE=90
fi
else
- if [[ $size -lt 512 ]] && [[ $KEY_EXCH_SCORE -gt 20 ]]; then
- let KEY_EXCH_SCORE=20
- set_grade_cap "F" "Using an insecure key"
- elif [[ $size -lt 1024 ]] && [[ $KEY_EXCH_SCORE -gt 40 ]]; then
+ if [[ $size -lt 1024 ]] && [[ $KEY_EXCH_SCORE -gt 40 ]]; then
let KEY_EXCH_SCORE=40
- set_grade_cap "F" "Using an insecure key"
+ set_grade_cap "F" "Using an insecure key / DH key exchange parameters"
elif [[ $size -lt 2048 ]] && [[ $KEY_EXCH_SCORE -gt 80 ]]; then
let KEY_EXCH_SCORE=80
- set_grade_cap "B" "Using a weak key"
+ set_grade_cap "B" "Using a weak key / DH key exchange parameters"
elif [[ $size -lt 4096 ]] && [[ $KEY_EXCH_SCORE -gt 90 ]]; then
let KEY_EXCH_SCORE=90
fi
@@ -16677,7 +16669,6 @@ run_logjam() {
if "$vuln_exportdh_ciphers"; then
pr_svrty_high "VULNERABLE (NOT ok):"; out " uses DH EXPORT ciphers"
fileout "$jsonID" "HIGH" "VULNERABLE, uses DH EXPORT ciphers" "$cve" "$cwe" "$hint"
- set_grade_cap "B" "Uses weak DH key exchange parameters (vulnerable to LOGJAM)"
if [[ $subret -eq 3 ]]; then
out ", no DH key detected with <= TLS 1.2"
fileout "$jsonID2" "OK" "no DH key detected with <= TLS 1.2"
@@ -16693,7 +16684,6 @@ run_logjam() {
else
if [[ $subret -eq 1 ]]; then
out_common_prime "$jsonID2" "$cve" "$cwe"
- set_grade_cap "A" "Uses known DH key exchange parameters"
if ! "$openssl_no_expdhciphers"; then
outln ","
out "${spaces}but no DH EXPORT ciphers${addtl_warning}"
@@ -16726,6 +16716,8 @@ run_logjam() {
fi
fi
+ [[ $DH_GROUP_LEN_P -gt 0 ]] && set_key_str_score "DHE" $DH_GROUP_LEN_P
+
outln
tmpfile_handle ${FUNCNAME[0]}.txt
return $ret
From 8b74d41487ceb4d39d27b870e60382654490bc25 Mon Sep 17 00:00:00 2001
From: Magnus Larsen <[]>
Date: Mon, 11 May 2020 15:22:51 +0200
Subject: [PATCH 099/211] unintended linebreak
---
doc/testssl.1.md | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index efbd11e..5198def 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -145,8 +145,7 @@ in `/etc/hosts`. The use of the switch is only useful if you either can't or ar
`--phone-out` Checking for revoked certificates via CRL and OCSP is not done per default. This switch instructs testssl.sh to query external -- in a sense of the current run -- URIs. By using this switch you acknowledge that the check might have privacy issues, a download of several megabytes (CRL file) may happen and there may be network connectivity problems while contacting the endpoint which testssl.sh doesn't handle. PHONE_OUT is the environment variable for this which needs to be set to true if you want this.
-`--add-ca ` enables you to add your own CA(s) for trust chain checks. `cafile` can be a single path or multiple paths as a comma separated list of root CA files. Internally they will be added during runtime to all CA stores. This is (only) useful for internal hosts whose certificates is issued by internal CAs. Alternatively
-ADDTL_CA_FILES is the environment variable for this.
+`--add-ca ` enables you to add your own CA(s) for trust chain checks. `cafile` can be a single path or multiple paths as a comma separated list of root CA files. Internally they will be added during runtime to all CA stores. This is (only) useful for internal hosts whose certificates is issued by internal CAs. Alternatively ADDTL_CA_FILES is the environment variable for this.
### SINGLE CHECK OPTIONS
From d5671a0352d15ed20e09dcba52fcdc75f44d6014 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Mon, 11 May 2020 10:09:02 -0400
Subject: [PATCH 100/211] Fix $SHOW_SIGALGO
This commit fixes two issues related to $SHOW_SIGALGO.
First, cipher_pref_check() does not show the signature algorithm if any of the ciphers were found using tls_sockets(), since the call to tls_sockets() does not specify that the server's certificate should be extracted.
Second, in run_beast() the call to tls_sockets() indicates that the server's certificate should be extracted if "$SHOW_SIGALGO" is true, even if "$WIDE" is false. While this does not cause any problems, extracting the certificate is a waste of effort if "$WIDE" is false, since the signature algorithm is not shown in that case.
---
testssl.sh | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 39c67e3..3570521 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -6993,7 +6993,11 @@ cipher_pref_check() {
! "${ciphers_found2[i]}" && ciphers_to_test+=", ${hexcode[i]}"
done
[[ -z "$ciphers_to_test" ]] && break
- tls_sockets "$proto_hex" "${ciphers_to_test:2}, 00,ff" "ephemeralkey"
+ if "$wide" && "$SHOW_SIGALGO"; then
+ tls_sockets "$proto_hex" "${ciphers_to_test:2}, 00,ff" "all"
+ else
+ tls_sockets "$proto_hex" "${ciphers_to_test:2}, 00,ff" "ephemeralkey"
+ fi
[[ $? -ne 0 ]] && break
cipher=$(get_cipher "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt")
for (( i=0; i < nr_ciphers; i++ )); do
@@ -17006,7 +17010,7 @@ run_beast(){
! "${ciphers_found[i]}" && ciphers_to_test+=", ${hexcode[i]}"
done
[[ -z "$ciphers_to_test" ]] && break
- if "$SHOW_SIGALGO"; then
+ if "$WIDE" && "$SHOW_SIGALGO"; then
tls_sockets "$proto_hex" "${ciphers_to_test:2}, 00,ff" "all"
else
tls_sockets "$proto_hex" "${ciphers_to_test:2}, 00,ff" "ephemeralkey"
From df42eeb8b4b1510a8550b55702f25ef4d1af6ff6 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Thu, 14 May 2020 14:42:08 -0400
Subject: [PATCH 101/211] Extract server's signature algorithm
PR #1519 requested that testssl.sh show the signature algorithm that the server uses during the TLS handshake. In TLS 1.3, this appears in the CertificateVerify message. In TLS 1.2 it appears in the ServerKeyExchange message when the chosen cipher suite uses an ephemeral (DH or ECDH) key, except in the case of cipher suites that provide no authentication. This information is not present in TLS 1.1 and earlier, as the hash algorithm to use in these earlier versions of the protocol is hard coded into the specification.
This commit takes a first step towards being able to show the signature algorithm by extending parse_tls_serverhello() to extract the signature algorithm when it is present. Matching the output produced by OpenSSL, it output two separate lines, the "Peer signature type" (RSA, RSA-PSS, DSA, ECDSA, Ed25519, or Ed448) and the "Peer signing digest" (MD5, SHA1, SHA224, SHA256, SHA384, or SHA512). This will allow the same function to extract the signature algorithm and digest, whether the handshake was performed using "$OPENSSL s_client" or tls_sockets().
---
testssl.sh | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 87 insertions(+), 3 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index ebf8389..e29bda3 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -12800,6 +12800,7 @@ parse_tls_serverhello() {
local len1 len2 len3 key_bitstring="" pem_certificate
local dh_p dh_param ephemeral_param rfc7919_param
local -i dh_p_len dh_param_len
+ local peering_signing_digest=0 peer_signature_type=0
DETECTED_TLS_VERSION=""
[[ $DEBUG -ge 1 ]] && echo > $TMPFILE
@@ -13033,6 +13034,14 @@ parse_tls_serverhello() {
fi
tls_serverkeyexchange_ascii="${tls_handshake_ascii:i:msg_len}"
tls_serverkeyexchange_ascii_len=$msg_len
+ elif [[ "$tls_msg_type" == 0F ]]; then
+ if [[ $msg_len -lt 4 ]]; then
+ debugme tmln_warning "Response contained malformed certificate_verify message."
+ return 1
+ fi
+ # Extract just the SignatureAndHashAlgorithm from the CertificateVerify message.
+ peering_signing_digest="${tls_handshake_ascii:i:2}"
+ peer_signature_type="${tls_handshake_ascii:$((i+2)):2}"
elif [[ "$process_full" =~ all ]] && [[ "$tls_msg_type" == 16 ]]; then
if [[ -n "$tls_certificate_status_ascii" ]]; then
debugme tmln_warning "Response contained more than one certificate_status handshake message."
@@ -13811,12 +13820,24 @@ parse_tls_serverhello() {
29) dh_bits=253 ; named_curve_str="X25519" ;;
30) dh_bits=448 ; named_curve_str="X448" ;;
esac
+ if [[ "$DETECTED_TLS_VERSION" == 0303 ]]; then
+ # Skip over the public key to get to the SignatureAndHashAlgorithm
+ # This is TLS 1.2-only, as this field does not appear in earlier versions.
+ len1=2*$(hex2dec "${tls_serverkeyexchange_ascii:6:2}")
+ offset=$((len1+8))
+ if [[ $tls_serverkeyexchange_ascii_len -ge $((offset+4)) ]]; then
+ # The SignatureAndHashAlgorithm won't be present in an anonymous
+ # key exhange.
+ peering_signing_digest="${tls_serverkeyexchange_ascii:offset:2}"
+ peer_signature_type="${tls_serverkeyexchange_ascii:$((offset+2)):2}"
+ fi
+ fi
fi
if [[ $dh_bits -ne 0 ]] && [[ $named_curve -ne 29 ]] && [[ $named_curve -ne 30 ]]; then
- [[ $DEBUG -ge 3 ]] && echo -e " dh_bits: ECDH, $named_curve_str, $dh_bits bits\n"
+ [[ $DEBUG -ge 3 ]] && echo -e " dh_bits: ECDH, $named_curve_str, $dh_bits bits"
echo "Server Temp Key: ECDH, $named_curve_str, $dh_bits bits" >> $TMPFILE
elif [[ $dh_bits -ne 0 ]]; then
- [[ $DEBUG -ge 3 ]] && echo -e " dh_bits: $named_curve_str, $dh_bits bits\n"
+ [[ $DEBUG -ge 3 ]] && echo -e " dh_bits: $named_curve_str, $dh_bits bits"
echo "Server Temp Key: $named_curve_str, $dh_bits bits" >> $TMPFILE
fi
elif [[ $rfc_cipher_suite =~ TLS_DHE_ ]] || [[ $rfc_cipher_suite =~ TLS_DH_anon ]] || \
@@ -13875,10 +13896,73 @@ parse_tls_serverhello() {
[[ "$ephemeral_param" != "$rfc7919_param" ]] && named_curve_str=""
fi
- [[ $DEBUG -ge 3 ]] && [[ $dh_bits -ne 0 ]] && echo -e " dh_bits: DH,$named_curve_str $dh_bits bits\n"
+ [[ $DEBUG -ge 3 ]] && [[ $dh_bits -ne 0 ]] && echo -e " dh_bits: DH,$named_curve_str $dh_bits bits"
[[ $dh_bits -ne 0 ]] && echo "Server Temp Key: DH,$named_curve_str $dh_bits bits" >> $TMPFILE
+ if [[ "$DETECTED_TLS_VERSION" == 0303 ]]; then
+ # Skip over the public key (P, G, Y) to get to the SignatureAndHashAlgorithm
+ # This is TLS 1.2-only, as this field does not appear in earlier versions.
+ offset=$((dh_p_len+4))
+ if [[ $tls_serverkeyexchange_ascii_len -lt $((offset+4)) ]]; then
+ debugme echo "Malformed ServerKeyExchange Handshake message in ServerHello."
+ tmpfile_handle ${FUNCNAME[0]}.txt
+ return 1
+ fi
+ len1=2*$(hex2dec "${tls_serverkeyexchange_ascii:offset:4}")
+ offset+=$((len1+4))
+ if [[ $tls_serverkeyexchange_ascii_len -lt $((offset+4)) ]]; then
+ debugme echo "Malformed ServerKeyExchange Handshake message in ServerHello."
+ tmpfile_handle ${FUNCNAME[0]}.txt
+ return 1
+ fi
+ len1=2*$(hex2dec "${tls_serverkeyexchange_ascii:offset:4}")
+ offset+=$((len1+4))
+ if [[ $tls_serverkeyexchange_ascii_len -ge $((offset+4)) ]]; then
+ # The SignatureAndHashAlgorithm won't be present in an anonymous
+ # key exhange.
+ peering_signing_digest="${tls_serverkeyexchange_ascii:offset:2}"
+ peer_signature_type="${tls_serverkeyexchange_ascii:$((offset+2)):2}"
+ fi
+ fi
fi
fi
+ if [[ 0x$peering_signing_digest -eq 8 ]] && \
+ [[ 0x$peer_signature_type -ge 4 ]] && [[ 0x$peer_signature_type -le 11 ]]; then
+ case $peer_signature_type in
+ 04) peering_signing_digest="SHA256"; peer_signature_type="RSA-PSS" ;;
+ 05) peering_signing_digest="SHA384"; peer_signature_type="RSA-PSS" ;;
+ 06) peering_signing_digest="SHA512"; peer_signature_type="RSA-PSS" ;;
+ 07) peering_signing_digest=""; peer_signature_type="Ed25519" ;;
+ 08) peering_signing_digest=""; peer_signature_type="Ed448" ;;
+ 09) peering_signing_digest="SHA256"; peer_signature_type="RSA-PSS" ;;
+ 0A) peering_signing_digest="SHA384"; peer_signature_type="RSA-PSS" ;;
+ 0B) peering_signing_digest="SHA512"; peer_signature_type="RSA-PSS" ;;
+ esac
+ if [[ -n "$peering_signing_digest" ]]; then
+ echo "Peer signing digest: $peering_signing_digest" >> $TMPFILE
+ [[ $DEBUG -ge 3 ]] && echo -e " Peer signing digest: $peering_signing_digest"
+ fi
+ echo "Peer signature type: $peer_signature_type" >> $TMPFILE
+ [[ $DEBUG -ge 3 ]] && echo -e " Peer signature type: $peer_signature_type\n"
+ elif [[ 0x$peering_signing_digest -ge 1 ]] && [[ 0x$peering_signing_digest -le 6 ]] && \
+ [[ 0x$peer_signature_type -ge 1 ]] && [[ 0x$peer_signature_type -le 3 ]]; then
+ case $peering_signing_digest in
+ 01) peering_signing_digest="MD5" ;;
+ 02) peering_signing_digest="SHA1" ;;
+ 03) peering_signing_digest="SHA224" ;;
+ 04) peering_signing_digest="SHA256" ;;
+ 05) peering_signing_digest="SHA384" ;;
+ 06) peering_signing_digest="SHA512" ;;
+ esac
+ case $peer_signature_type in
+ 01) peer_signature_type="RSA" ;;
+ 02) peer_signature_type="DSA" ;;
+ 03) peer_signature_type="ECDSA" ;;
+ esac
+ echo "Peer signing digest: $peering_signing_digest" >> $TMPFILE
+ [[ $DEBUG -ge 3 ]] && echo -e " Peer signing digest: $peering_signing_digest"
+ echo "Peer signature type: $peer_signature_type" >> $TMPFILE
+ [[ $DEBUG -ge 3 ]] && echo -e " Peer signature type: $peer_signature_type\n"
+ fi
tmpfile_handle ${FUNCNAME[0]}.txt
TLS_SERVER_HELLO="02$(printf "%06x" $(( tls_serverhello_ascii_len/2)) )${tls_serverhello_ascii}"
From 3ae48931fb0aebc9132dd3fc88d142b09a84b7f0 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Thu, 14 May 2020 14:55:48 -0400
Subject: [PATCH 102/211] Support EdDSA
This commit adds support for EdDSA (Ed25519 and Ed448). In particular:
* It modifies prepare_tls_clienthello() to include Ed25519 and Ed448 in the signature_algorithms extension of the TLS 1.2 and earlier ClientHello (RFC 8422).
* It modifies run_server_defaults() and get_server_certificate() to check whether the server offers EdDSA certificates with TLS 1.3.
* It modifies certificate_info() to handle certificates signed with EdDSA or with EdDSA public keys, even if $OPENSSL does not support pretty printing such keys and signatures.
* It modifies read_sigalg_from_file() to recognize EdDSA signatures even if $OPENSSL does not.
---
CHANGELOG.md | 1 +
testssl.sh | 70 +++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 54 insertions(+), 17 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6641957..7ada38e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@
* Don't use external pwd anymore
* STARTTLS: XMPP server support
* Rating (SSL Labs, not complete)
+* Added support for certificates with EdDSA signatures and pubilc keys
### Features implemented / improvements in 3.0
diff --git a/testssl.sh b/testssl.sh
index e29bda3..3f410d5 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -1040,7 +1040,7 @@ set_key_str_score() {
# TODO: We need to get the size of DH params (follows the same table as the "else" clause)
# For now, verifying the key size will do...
- if [[ $type == EC ]]; then
+ if [[ $type == EC || $type == EdDSA ]]; then
if [[ $size -lt 110 ]] && [[ $KEY_EXCH_SCORE -gt 20 ]]; then
let KEY_EXCH_SCORE=20
set_grade_cap "F" "Using an insecure key"
@@ -6249,7 +6249,15 @@ read_dhtype_from_file() {
# arg1: certificate file
read_sigalg_from_file() {
- $OPENSSL x509 -noout -text -in "$1" 2>/dev/null | awk -F':' '/Signature Algorithm/ { print $2; exit; }'
+ local sig_alg
+
+ sig_alg="$(strip_leading_space "$($OPENSSL x509 -noout -text -in "$1" 2>/dev/null | awk -F':' '/Signature Algorithm/ { print $2; exit; }')")"
+ case "$sig_alg" in
+ 1.3.101.112|ED25519) tm_out "Ed25519" ;;
+ 1.3.101.113|ED448) tm_out "Ed448" ;;
+ *) tm_out "$sig_alg" ;;
+ esac
+
}
@@ -7547,7 +7555,7 @@ get_server_certificate() {
CERTIFICATE_LIST_ORDERING_PROBLEM=false
if [[ "$1" =~ "tls1_3" ]]; then
[[ $(has_server_protocol "tls1_3") -eq 1 ]] && return 1
- if "$HAS_TLS13" && "$HAS_SIGALGS"; then
+ if "$HAS_TLS13" && "$HAS_SIGALGS" && [[ ! "$1" =~ "tls1_3_EdDSA" ]]; then
if [[ "$1" =~ "tls1_3_RSA" ]]; then
$OPENSSL s_client $(s_client_options "$STARTTLS $BUGS -showcerts -connect $NODEIP:$PORT $PROXY $SNI -tls1_3 -tlsextdebug -status -msg -sigalgs PSS+SHA256:PSS+SHA384") $ERRFILE >$TMPFILE
elif [[ "$1" =~ "tls1_3_ECDSA" ]]; then
@@ -7568,6 +7576,8 @@ get_server_certificate() {
tls_sockets "04" "$TLS13_CIPHER" "all" "00,12,00,00, 00,05,00,05,01,00,00,00,00, 00,0d,00,10,00,0e,08,04,08,05,08,06,04,01,05,01,06,01,02,01"
elif [[ "$1" =~ "tls1_3_ECDSA" ]]; then
tls_sockets "04" "$TLS13_CIPHER" "all" "00,12,00,00, 00,05,00,05,01,00,00,00,00, 00,0d,00,0a,00,08,04,03,05,03,06,03,02,03"
+ elif [[ "$1" =~ "tls1_3_EdDSA" ]]; then
+ tls_sockets "04" "$TLS13_CIPHER" "all" "00,12,00,00, 00,05,00,05,01,00,00,00,00, 00,0d,00,06,00,04,08,07,08,08"
else
return 1
fi
@@ -8332,8 +8342,16 @@ certificate_info() {
GOOD_CA_BUNDLE=""
cert_sig_algo="$(awk -F':' '/Signature Algorithm/ { print $2; if (++Match >= 1) exit; }' <<< "$cert_txt")"
cert_sig_algo="${cert_sig_algo// /}"
+ case "$cert_sig_algo" in
+ 1.3.101.112|ED25519) cert_sig_algo="Ed25519" ;;
+ 1.3.101.113|ED448) cert_sig_algo="Ed448" ;;
+ esac
cert_key_algo="$(awk -F':' '/Public Key Algorithm:/ { print $2; if (++Match >= 1) exit; }' <<< "$cert_txt")"
cert_key_algo="${cert_key_algo// /}"
+ case "$cert_key_algo" in
+ 1.3.101.112|E[Dd]25519) cert_key_algo="Ed25519"; cert_keysize=253 ;;
+ 1.3.101.113|E[Dd]448) cert_key_algo="Ed448"; cert_keysize=456 ;;
+ esac
out "$indent" ; pr_bold " Signature Algorithm "
jsonID="cert_signatureAlgorithm"
@@ -8441,6 +8459,10 @@ certificate_info() {
fileout "${jsonID}${json_postfix}" "CRITICAL" "MD5"
set_grade_cap "F" "Supports a insecure signature (MD5)"
;;
+ Ed25519|Ed448)
+ prln_svrty_good "$cert_sig_algo"
+ fileout "${jsonID}${json_postfix}" "OK" "$cert_sig_algo"
+ ;;
*)
out "$cert_sig_algo ("
pr_warning "FIXME: can't tell whether this is good or not"
@@ -8461,6 +8483,7 @@ certificate_info() {
case $cert_key_algo in
*RSA*|*rsa*) short_keyAlgo="RSA";;
*ecdsa*|*ecPublicKey) short_keyAlgo="EC";;
+ *Ed25519*|*Ed448*) short_keyAlgo="EdDSA";;
*DSA*|*dsa*) short_keyAlgo="DSA";;
*GOST*|*gost*) short_keyAlgo="GOST";;
*dh*|*DH*) short_keyAlgo="DH" ;;
@@ -8523,6 +8546,10 @@ certificate_info() {
((ret++))
fi
+ set_key_str_score "$short_keyAlgo" "$cert_keysize"
+ elif [[ $cert_key_algo == Ed* ]]; then
+ pr_svrty_good "$cert_key_algo"
+ json_rating="OK"; json_msg="$short_keyAlgo $cert_key_algo"
set_key_str_score "$short_keyAlgo" "$cert_keysize"
else
out "$cert_key_algo + $cert_keysize bits ("
@@ -8586,7 +8613,7 @@ certificate_info() {
cert_keyusage="$(strip_leading_space "$(awk '/X509v3 Key Usage:/ { getline; print $0 }' <<< "$cert_txt")")"
if [[ -n "$cert_keyusage" ]]; then
outln "$cert_keyusage"
- if ( [[ " $cert_type " =~ " RSASig " ]] || [[ " $cert_type " =~ " DSA " ]] || [[ " $cert_type " =~ " ECDSA " ]] ) && \
+ if ( [[ " $cert_type " =~ " RSASig " ]] || [[ " $cert_type " =~ " DSA " ]] || [[ " $cert_type " =~ " ECDSA " ]] || [[ " $cert_type " =~ " EdDSA " ]] ) && \
[[ ! "$cert_keyusage" =~ "Digital Signature" ]]; then
prln_svrty_high "$indent Certificate incorrectly used for digital signatures"
fileout "${jsonID}${json_postfix}" "HIGH" "Certificate incorrectly used for digital signatures: \"$cert_keyusage\""
@@ -9257,27 +9284,28 @@ run_server_defaults() {
ciphers_to_test[7]=""
ciphers_to_test[8]="tls1_3_RSA"
ciphers_to_test[9]="tls1_3_ECDSA"
+ ciphers_to_test[10]="tls1_3_EdDSA"
certificate_type[1]="" ; certificate_type[2]=""
certificate_type[3]=""; certificate_type[4]=""
certificate_type[5]="" ; certificate_type[6]=""
certificate_type[7]="" ; certificate_type[8]="RSASig"
- certificate_type[9]="ECDSA"
+ certificate_type[9]="ECDSA" ; certificate_type[10]="EdDSA"
- for (( n=1; n <= 16 ; n++ )); do
+ for (( n=1; n <= 17 ; n++ )); do
# Some servers use a different certificate if the ClientHello
# specifies TLSv1.1 and doesn't include a server name extension.
# So, for each public key type for which a certificate was found,
# try again, but only with TLSv1.1 and without SNI.
if [[ $n -ne 1 ]] && [[ "$OPTIMAL_PROTO" == -ssl2 ]]; then
ciphers_to_test[n]=""
- elif [[ $n -ge 10 ]]; then
+ elif [[ $n -ge 11 ]]; then
ciphers_to_test[n]=""
- [[ ${success[n-9]} -eq 0 ]] && [[ $(has_server_protocol "tls1_1") -ne 1 ]] && \
- ciphers_to_test[n]="${ciphers_to_test[n-9]}" && certificate_type[n]="${certificate_type[n-9]}"
+ [[ ${success[n-10]} -eq 0 ]] && [[ $(has_server_protocol "tls1_1") -ne 1 ]] && \
+ ciphers_to_test[n]="${ciphers_to_test[n-10]}" && certificate_type[n]="${certificate_type[n-10]}"
fi
if [[ -n "${ciphers_to_test[n]}" ]]; then
- if [[ $n -ge 10 ]]; then
+ if [[ $n -ge 11 ]]; then
sni="$SNI"
SNI=""
get_server_certificate "${ciphers_to_test[n]}" "tls1_1"
@@ -9288,7 +9316,7 @@ run_server_defaults() {
success[n]=$?
fi
if [[ ${success[n]} -eq 0 ]] && [[ -s "$HOSTCERT" ]]; then
- [[ $n -ge 10 ]] && [[ ! -e $HOSTCERT.nosni ]] && cp $HOSTCERT $HOSTCERT.nosni
+ [[ $n -ge 11 ]] && [[ ! -e $HOSTCERT.nosni ]] && cp $HOSTCERT $HOSTCERT.nosni
cp "$TEMPDIR/$NODEIP.get_server_certificate.txt" $TMPFILE
>$ERRFILE
if [[ -z "$sessticket_lifetime_hint" ]]; then
@@ -9370,7 +9398,7 @@ run_server_defaults() {
fi
i=$((i + 1))
done
- if ! "$match_found" && [[ $n -ge 10 ]] && [[ $certs_found -ne 0 ]]; then
+ if ! "$match_found" && [[ $n -ge 11 ]] && [[ $certs_found -ne 0 ]]; then
# A new certificate was found using TLSv1.1 without SNI.
# Check to see if the new certificate should be displayed.
# It should be displayed if it is either a match for the
@@ -9427,7 +9455,7 @@ run_server_defaults() {
[[ -n "${previous_intermediates[certs_found]}" ]] && [[ -r $TEMPDIR/hostcert_issuer.pem ]] && \
previous_hostcert_issuer[certs_found]=$(cat $TEMPDIR/hostcert_issuer.pem)
previous_ordering_problem[certs_found]=$CERTIFICATE_LIST_ORDERING_PROBLEM
- [[ $n -ge 10 ]] && sni_used[certs_found]="" || sni_used[certs_found]="$SNI"
+ [[ $n -ge 11 ]] && sni_used[certs_found]="" || sni_used[certs_found]="$SNI"
tls_version[certs_found]="$DETECTED_TLS_VERSION"
previous_hostcert_type[certs_found]=" ${certificate_type[n]}"
if [[ $DEBUG -ge 1 ]]; then
@@ -10738,7 +10766,15 @@ get_pub_key_size() {
"$HAS_PKEY" || return 1
# OpenSSL displays the number of bits for RSA and ECC
- pubkeybits=$($OPENSSL x509 -noout -pubkey -in $HOSTCERT 2>>$ERRFILE | $OPENSSL pkey -pubin -text 2>>$ERRFILE | awk -F'(' '/Public-Key/ { print $2 }')
+ pubkeybits=$($OPENSSL x509 -noout -pubkey -in $HOSTCERT 2>>$ERRFILE | $OPENSSL pkey -pubin -text 2>>$ERRFILE)
+ if [[ "$pubkeybits" =~ E[Dd]25519 ]]; then
+ echo "Server public key is 253 bit" >> $TMPFILE
+ return 0
+ elif [[ "$pubkeybits" =~ E[Dd]448 ]]; then
+ echo "Server public key is 456 bit" >> $TMPFILE
+ return 0
+ fi
+ pubkeybits=$(awk -F'(' '/Public-Key/ { print $2 }' <<< "$pubkeybits")
if [[ -n $pubkeybits ]]; then
# remainder e.g. "256 bit)"
pubkeybits="${pubkeybits//\)/}"
@@ -14279,10 +14315,10 @@ prepare_tls_clienthello() {
if [[ 0x$tls_low_byte -le 0x03 ]]; then
extension_signature_algorithms="
- 00, 0d, # Type: signature_algorithms , see RFC 5246
- 00, 20, 00,1e, # lengths
+ 00, 0d, # Type: signature_algorithms , see RFC 5246 and RFC 8422
+ 00, 24, 00,22, # lengths
06,01, 06,02, 06,03, 05,01, 05,02, 05,03, 04,01, 04,02, 04,03,
- 03,01, 03,02, 03,03, 02,01, 02,02, 02,03"
+ 03,01, 03,02, 03,03, 02,01, 02,02, 02,03, 08,07, 08,08"
else
extension_signature_algorithms="
00, 0d, # Type: signature_algorithms , see RFC 8446
From 37ffabf8d52a77cbb6da03ade93b53d063392d4a Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Mon, 18 May 2020 07:38:49 -0400
Subject: [PATCH 103/211] Remove some unnecessary quotation marks
---
testssl.sh | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 3f410d5..c0ed0b4 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -7553,12 +7553,12 @@ get_server_certificate() {
"$SSL_NATIVE" && using_sockets=false
CERTIFICATE_LIST_ORDERING_PROBLEM=false
- if [[ "$1" =~ "tls1_3" ]]; then
+ if [[ "$1" =~ tls1_3 ]]; then
[[ $(has_server_protocol "tls1_3") -eq 1 ]] && return 1
- if "$HAS_TLS13" && "$HAS_SIGALGS" && [[ ! "$1" =~ "tls1_3_EdDSA" ]]; then
- if [[ "$1" =~ "tls1_3_RSA" ]]; then
+ if "$HAS_TLS13" && "$HAS_SIGALGS" && [[ ! "$1" =~ tls1_3_EdDSA ]]; then
+ if [[ "$1" =~ tls1_3_RSA ]]; then
$OPENSSL s_client $(s_client_options "$STARTTLS $BUGS -showcerts -connect $NODEIP:$PORT $PROXY $SNI -tls1_3 -tlsextdebug -status -msg -sigalgs PSS+SHA256:PSS+SHA384") $ERRFILE >$TMPFILE
- elif [[ "$1" =~ "tls1_3_ECDSA" ]]; then
+ elif [[ "$1" =~ tls1_3_ECDSA ]]; then
$OPENSSL s_client $(s_client_options "$STARTTLS $BUGS -showcerts -connect $NODEIP:$PORT $PROXY $SNI -tls1_3 -tlsextdebug -status -msg -sigalgs ECDSA+SHA256:ECDSA+SHA384") $ERRFILE >$TMPFILE
else
return 1
@@ -7572,11 +7572,11 @@ get_server_certificate() {
# For STARTTLS protcols not being implemented yet via sockets this is a bypass otherwise it won't be usable at all (e.g. LDAP)
if ( [[ "$STARTTLS" =~ ldap ]] || [[ "$STARTTLS" =~ irc ]] ); then
return 1
- elif [[ "$1" =~ "tls1_3_RSA" ]]; then
+ elif [[ "$1" =~ tls1_3_RSA ]]; then
tls_sockets "04" "$TLS13_CIPHER" "all" "00,12,00,00, 00,05,00,05,01,00,00,00,00, 00,0d,00,10,00,0e,08,04,08,05,08,06,04,01,05,01,06,01,02,01"
- elif [[ "$1" =~ "tls1_3_ECDSA" ]]; then
+ elif [[ "$1" =~ tls1_3_ECDSA ]]; then
tls_sockets "04" "$TLS13_CIPHER" "all" "00,12,00,00, 00,05,00,05,01,00,00,00,00, 00,0d,00,0a,00,08,04,03,05,03,06,03,02,03"
- elif [[ "$1" =~ "tls1_3_EdDSA" ]]; then
+ elif [[ "$1" =~ tls1_3_EdDSA ]]; then
tls_sockets "04" "$TLS13_CIPHER" "all" "00,12,00,00, 00,05,00,05,01,00,00,00,00, 00,0d,00,06,00,04,08,07,08,08"
else
return 1
@@ -8613,19 +8613,19 @@ certificate_info() {
cert_keyusage="$(strip_leading_space "$(awk '/X509v3 Key Usage:/ { getline; print $0 }' <<< "$cert_txt")")"
if [[ -n "$cert_keyusage" ]]; then
outln "$cert_keyusage"
- if ( [[ " $cert_type " =~ " RSASig " ]] || [[ " $cert_type " =~ " DSA " ]] || [[ " $cert_type " =~ " ECDSA " ]] || [[ " $cert_type " =~ " EdDSA " ]] ) && \
- [[ ! "$cert_keyusage" =~ "Digital Signature" ]]; then
+ if ( [[ " $cert_type " =~ \ RSASig\ ]] || [[ " $cert_type " =~ \ DSA\ ]] || [[ " $cert_type " =~ \ ECDSA\ ]] || [[ " $cert_type " =~ \ EdDSA\ ]] ) && \
+ [[ ! "$cert_keyusage" =~ Digital\ Signature ]]; then
prln_svrty_high "$indent Certificate incorrectly used for digital signatures"
fileout "${jsonID}${json_postfix}" "HIGH" "Certificate incorrectly used for digital signatures: \"$cert_keyusage\""
outok=false
fi
- if [[ " $cert_type " =~ " RSAKMK " ]] && [[ ! "$cert_keyusage" =~ "Key Encipherment" ]]; then
+ if [[ " $cert_type " =~ \ RSAKMK\ ]] && [[ ! "$cert_keyusage" =~ Key\ Encipherment ]]; then
prln_svrty_high "$indent Certificate incorrectly used for key encipherment"
fileout "${jsonID}${json_postfix}" "HIGH" "Certificate incorrectly used for key encipherment: \"$cert_keyusage\""
outok=false
fi
- if ( [[ " $cert_type " =~ " DH " ]] || [[ " $cert_type " =~ " ECDH " ]] ) && \
- [[ ! "$cert_keyusage" =~ "Key Agreement" ]]; then
+ if ( [[ " $cert_type " =~ \ DH\ ]] || [[ " $cert_type " =~ \ ECDH\ ]] ) && \
+ [[ ! "$cert_keyusage" =~ Key\ Agreement ]]; then
prln_svrty_high "$indent Certificate incorrectly used for key agreement"
fileout "${jsonID}${json_postfix}" "HIGH" "Certificate incorrectly used for key agreement: \"$cert_keyusage\""
outok=false
From a4ae05c90c70063cd2eb9d4a3e25b60a4ec764b5 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Mon, 25 May 2020 13:23:49 +0200
Subject: [PATCH 104/211] Add get_txt_record(), fix variable declaration in
get_mx_record()
This commit adds a function for querying the TXT DNS record, so
that subsequently we'll can build on top of that a function for
checking MTA-STS, see #1073.
Also it modifies a local variable mxs in get_mx_record() which
was declared as mx but mxs was used. (That is pending an backport
to 3.0.)
---
testssl.sh | 40 ++++++++++++++++++++++++++++++++++------
1 file changed, 34 insertions(+), 6 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index c0ed0b4..2b34e85 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -19557,7 +19557,7 @@ get_caa_rr_record() {
return 0
}
-# watch out: $1 can also be a cname! --> all checked
+# arg1: domain to check for. Returned will be the MX record as a string
get_mx_record() {
local mx=""
local saved_openssl_conf="$OPENSSL_CONF"
@@ -19567,21 +19567,49 @@ get_mx_record() {
OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134
# we need the last two columns here
if "$HAS_HOST"; then
- mxs="$(host -t MX "$1" 2>/dev/null | awk '/is handled by/ { print $(NF-1), $NF }')"
+ mx="$(host -t MX "$1" 2>/dev/null | awk '/is handled by/ { print $(NF-1), $NF }')"
elif "$HAS_DIG"; then
- mxs="$(dig +short $noidnout -t MX "$1" 2>/dev/null | awk '/^[0-9]/ { print $1" "$2 }')"
+ mx="$(dig +short $noidnout -t MX "$1" 2>/dev/null | awk '/^[0-9]/ { print $1" "$2 }')"
elif "$HAS_DRILL"; then
- mxs="$(drill mx $1 | awk '/IN[ \t]MX[ \t]+/ { print $(NF-1), $NF }')"
+ mx="$(drill mx $1 | awk '/IN[ \t]MX[ \t]+/ { print $(NF-1), $NF }')"
elif "$HAS_NSLOOKUP"; then
- mxs="$(strip_lf "$(nslookup -type=MX "$1" 2>/dev/null | awk '/mail exchanger/ { print $(NF-1), $NF }')")"
+ mx="$(strip_lf "$(nslookup -type=MX "$1" 2>/dev/null | awk '/mail exchanger/ { print $(NF-1), $NF }')")"
else
# shouldn't reach this, as we checked in the top
fatal "No dig, host, drill or nslookup" $ERR_DNSBIN
fi
OPENSSL_CONF="$saved_openssl_conf"
- echo "$mxs"
+ echo "$mx"
}
+# arg1: domain / hostname. Returned will be the TXT record as a string which can be multilined
+# (one entry per line), for e.g. non-MTA-STS records.
+# Is supposed to be used by MTA STS in the future like get_txt_record _mta-sts.DOMAIN.TLD
+get_txt_record() {
+ local record=""
+ local saved_openssl_conf="$OPENSSL_CONF"
+ local noidnout=""
+
+ "$HAS_DIG_NOIDNOUT" && noidnout="+noidnout"
+ OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134
+ # we need the last two columns here and strip any remaining double quotes later
+ if "$HAS_HOST"; then
+ record="$(host -t TXT "$1" 2>/dev/null | awk -F\" '/descriptive text/ { print $(NF-1) }')"
+ elif "$HAS_DIG"; then
+ record="$(dig +short $noidnout -t TXT "$1" 2>/dev/null)"
+ elif "$HAS_DRILL"; then
+ record="$(drill txt $1 | awk -F\" '/^[a-z0-9].*TXT/ { print $(NF-1) }')"
+ elif "$HAS_NSLOOKUP"; then
+ record="$(strip_lf "$(nslookup -type=MX "$1" 2>/dev/null | awk -F= '/text/ { print $(NF-1), $NF }')")"
+ else
+ # shouldn't reach this, as we checked in the top
+ fatal "No dig, host, drill or nslookup" $ERR_DNSBIN
+ fi
+ OPENSSL_CONF="$saved_openssl_conf"
+ echo "${record//\"/}"
+}
+
+
# set IPADDRs and IP46ADDRs
#
From e6150a2348141687eb3aea46c94c3b03ba9686f3 Mon Sep 17 00:00:00 2001
From: Magnus Larsen <[]>
Date: Thu, 28 May 2020 20:33:17 +0200
Subject: [PATCH 105/211] Missed todo comment fix; cleanup output
---
testssl.sh | 25 +++++++++----------------
1 file changed, 9 insertions(+), 16 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index ff6c232..28ec6fb 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -1035,36 +1035,29 @@ set_grade_warning() {
set_key_str_score() {
local type=$1
local size=$2
+ local type_output
"$do_rating" || return 0
-<<<<<<< HEAD
- if [[ $type == EC ]]; then
- if [[ $size -lt 123 ]] && [[ $KEY_EXCH_SCORE -gt 40 ]]; then
-=======
- # TODO: We need to get the size of DH params (follows the same table as the "else" clause)
- # For now, verifying the key size will do...
+ [[ $type == DHE ]] && type_output="DH key exchange parameters" || type_output="key"
+
if [[ $type == EC || $type == EdDSA ]]; then
- if [[ $size -lt 110 ]] && [[ $KEY_EXCH_SCORE -gt 20 ]]; then
- let KEY_EXCH_SCORE=20
- set_grade_cap "F" "Using an insecure key"
- elif [[ $size -lt 123 ]] && [[ $KEY_EXCH_SCORE -gt 40 ]]; then
->>>>>>> upstream/3.1dev
+ if [[ $size -lt 123 ]] && [[ $KEY_EXCH_SCORE -gt 40 ]]; then
let KEY_EXCH_SCORE=40
- set_grade_cap "F" "Using an insecure key"
+ set_grade_cap "F" "Using an insecure $type_output"
elif [[ $size -lt 163 ]] && [[ $KEY_EXCH_SCORE -gt 80 ]]; then
let KEY_EXCH_SCORE=80
- set_grade_cap "B" "Using a weak key"
+ set_grade_cap "B" "Using a weak $type_output"
elif [[ $size -lt 225 ]] && [[ $KEY_EXCH_SCORE -gt 90 ]]; then
let KEY_EXCH_SCORE=90
fi
else
if [[ $size -lt 1024 ]] && [[ $KEY_EXCH_SCORE -gt 40 ]]; then
let KEY_EXCH_SCORE=40
- set_grade_cap "F" "Using an insecure key / DH key exchange parameters"
+ set_grade_cap "F" "Using an insecure $type_output"
elif [[ $size -lt 2048 ]] && [[ $KEY_EXCH_SCORE -gt 80 ]]; then
let KEY_EXCH_SCORE=80
- set_grade_cap "B" "Using a weak key / DH key exchange parameters"
+ set_grade_cap "B" "Using a weak $type_output"
elif [[ $size -lt 4096 ]] && [[ $KEY_EXCH_SCORE -gt 90 ]]; then
let KEY_EXCH_SCORE=90
fi
@@ -8520,7 +8513,7 @@ certificate_info() {
fi
out " bits"
- set_key_str_score "$short_keyAlgo" "$cert_keysize" # TODO: should be $dh_param_size
+ set_key_str_score "$short_keyAlgo" "$cert_keysize"
elif [[ $cert_key_algo =~ RSA ]] || [[ $cert_key_algo =~ rsa ]] || [[ $cert_key_algo =~ dsa ]] || \
[[ $cert_key_algo =~ dhKeyAgreement ]] || [[ $cert_key_algo == X9.42\ DH ]]; then
if [[ "$cert_keysize" -le 512 ]]; then
From dca50fc49ab8aaafd8973a41f71a477f0baa1b4d Mon Sep 17 00:00:00 2001
From: Magnus Larsen <[]>
Date: Thu, 28 May 2020 21:00:45 +0200
Subject: [PATCH 106/211] allow multiple equal key sizes
---
testssl.sh | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 28ec6fb..94b6f9f 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -1039,26 +1039,26 @@ set_key_str_score() {
"$do_rating" || return 0
- [[ $type == DHE ]] && type_output="DH key exchange parameters" || type_output="key"
+ [[ $type == DHE ]] && type_output="temporal DH key (DH parameters)" || type_output="key"
if [[ $type == EC || $type == EdDSA ]]; then
- if [[ $size -lt 123 ]] && [[ $KEY_EXCH_SCORE -gt 40 ]]; then
+ if [[ $size -lt 123 ]] && [[ $KEY_EXCH_SCORE -ge 40 ]]; then
let KEY_EXCH_SCORE=40
set_grade_cap "F" "Using an insecure $type_output"
- elif [[ $size -lt 163 ]] && [[ $KEY_EXCH_SCORE -gt 80 ]]; then
+ elif [[ $size -lt 163 ]] && [[ $KEY_EXCH_SCORE -ge 80 ]]; then
let KEY_EXCH_SCORE=80
set_grade_cap "B" "Using a weak $type_output"
- elif [[ $size -lt 225 ]] && [[ $KEY_EXCH_SCORE -gt 90 ]]; then
+ elif [[ $size -lt 225 ]] && [[ $KEY_EXCH_SCORE -ge 90 ]]; then
let KEY_EXCH_SCORE=90
fi
else
- if [[ $size -lt 1024 ]] && [[ $KEY_EXCH_SCORE -gt 40 ]]; then
+ if [[ $size -lt 1024 ]] && [[ $KEY_EXCH_SCORE -ge 40 ]]; then
let KEY_EXCH_SCORE=40
set_grade_cap "F" "Using an insecure $type_output"
- elif [[ $size -lt 2048 ]] && [[ $KEY_EXCH_SCORE -gt 80 ]]; then
+ elif [[ $size -lt 2048 ]] && [[ $KEY_EXCH_SCORE -ge 80 ]]; then
let KEY_EXCH_SCORE=80
set_grade_cap "B" "Using a weak $type_output"
- elif [[ $size -lt 4096 ]] && [[ $KEY_EXCH_SCORE -gt 90 ]]; then
+ elif [[ $size -lt 4096 ]] && [[ $KEY_EXCH_SCORE -ge 90 ]]; then
let KEY_EXCH_SCORE=90
fi
fi
From 30d571076808eaa2244a701aab7a680e7815b311 Mon Sep 17 00:00:00 2001
From: Magnus Larsen <[]>
Date: Thu, 28 May 2020 21:12:14 +0200
Subject: [PATCH 107/211] ephemeral is the word
---
testssl.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/testssl.sh b/testssl.sh
index 94b6f9f..02bb7e5 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -1039,7 +1039,7 @@ set_key_str_score() {
"$do_rating" || return 0
- [[ $type == DHE ]] && type_output="temporal DH key (DH parameters)" || type_output="key"
+ [[ $type == DHE ]] && type_output="ephemeral DH key (DH parameters)" || type_output="key"
if [[ $type == EC || $type == EdDSA ]]; then
if [[ $size -lt 123 ]] && [[ $KEY_EXCH_SCORE -ge 40 ]]; then
From edefce5998181cbbfe073b7238ceaeedc087dc75 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Mon, 1 Jun 2020 15:31:01 -0400
Subject: [PATCH 108/211] Fix Shellcheck SC2034 issues
This commit fixes several issues related to Shellcheck issue SC2034: unused variables.
In most cases variables are declared in a function, but are referenced later. The exceptions are:
* SESS_RESUMPTION is declared and values are assigned to it, but it us never used. (Same applies for not_new_reused in sub_seession_resumption().)
* In run_cipherlists(), there is a typo in the declaration of sslv2_tdes_ciphers.
* In get_caa_rr_record(), "hash", "len", and "line" are used but not declared.
---
testssl.sh | 51 +++++++++++++++++----------------------------------
1 file changed, 17 insertions(+), 34 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 2b34e85..ca5ae4a 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -266,7 +266,6 @@ V2_HELLO_CIPHERSPEC_LENGTH=0
declare -r NPN_PROTOs="spdy/4a2,spdy/3,spdy/3.1,spdy/2,spdy/1,http/1.1"
# alpn_protos needs to be space-separated, not comma-seperated, including odd ones observed @ facebook and others, old ones like h2-17 omitted as they could not be found
declare -r ALPN_PROTOs="h2 spdy/3.1 http/1.1 grpc-exp h2-fb spdy/1 spdy/2 spdy/3 stun.turn stun.nat-discovery webrtc c-webrtc ftp"
-declare -a SESS_RESUMPTION
TEMPDIR=""
TMPFILE=""
ERRFILE=""
@@ -1687,7 +1686,7 @@ http_get() {
# There the environment variable is used automatically
# Currently it is being used by check_pwnedkeys() only.
http_get_header() {
- local proto z
+ local proto
local node="" query=""
local dl="$2"
local useragent="$UA_STD"
@@ -5932,7 +5931,7 @@ run_cipherlists() {
local ossl_anon_ciphers anon_ciphers sslv2_anon_ciphers
local ossl_exp_ciphers exp_ciphers sslv2_exp_ciphers
local ossl_low_ciphers low_ciphers sslv2_low_ciphers
- local ossl_tdes_ciphers tdes_ciphers sslv2_tdes_cipher
+ local ossl_tdes_ciphers tdes_ciphers sslv2_tdes_ciphers
local ossl_obsoleted_ciphers obsoleted_ciphers
local strong_ciphers
local cwe="CWE-327"
@@ -6341,7 +6340,6 @@ sub_session_resumption() {
local tmpfile=$(mktemp $TEMPDIR/session_resumption.$NODEIP.XXXXXX)
local sess_data=$(mktemp $TEMPDIR/sub_session_data_resumption.$NODEIP.XXXXXX)
local -a rw_line
- local not_new_reused=false
local protocol="$1"
if [[ "$2" == ID ]]; then
@@ -6401,7 +6399,6 @@ sub_session_resumption() {
new_sid=true
else
debugme echo -n "Problem with 2nd ServerHello "
- not_new_reused=true
fi
# Now get the line and compare the numbers "read" and "written" as a second criteria.
# If the "read" number is bigger: a new session ID was probably used
@@ -6823,7 +6820,6 @@ cipher_pref_check() {
local using_sockets="$4"
local wide="$5" # at the moment always = true
local tested_cipher cipher order rfc_cipher rfc_order
- local overflow_probe_cipherlist="ALL:-ECDHE-RSA-AES256-GCM-SHA384:-AES128-SHA:-DES-CBC3-SHA"
local -i i nr_ciphers nr_nonossl_ciphers num_bundles bundle_size bundle end_of_bundle success
local -i nr_ciphers_found
local hexc ciphers_to_test
@@ -8198,7 +8194,6 @@ certificate_transparency() {
local tls_version="$6"
local sni=""
local ciphers=""
- local hexc n ciph sslver kx auth enc mac export
local extra_extns=""
local -i success
# Cipher suites that use a certifiate with an RSA (signature) public key
@@ -9562,25 +9557,20 @@ run_server_defaults() {
jsonID="sessionresumption_ticket"
sub_session_resumption "$sessticket_proto"
case $? in
- 0) SESS_RESUMPTION[2]="ticket=yes"
- out "Tickets: yes, "
+ 0) out "Tickets: yes, "
fileout "$jsonID" "INFO" "supported"
;;
- 1) SESS_RESUMPTION[2]="ticket=no"
- out "Tickets no, "
+ 1) out "Tickets no, "
fileout "$jsonID" "INFO" "not supported"
;;
- 5) SESS_RESUMPTION[2]="ticket=noclue"
- pr_warning "Ticket resumption test failed, pls report / "
+ 5) pr_warning "Ticket resumption test failed, pls report / "
fileout "$jsonID" "WARN" "check failed, pls report"
((ret++))
;;
- 6) SESS_RESUMPTION[2]="ticket=clientauth"
- pr_warning "Client Auth: Ticket resumption test not supported / "
+ 6) pr_warning "Client Auth: Ticket resumption test not supported / "
fileout "$jsonID" "WARN" "check couldn't be performed because of client authentication"
;;
- 7) SESS_RESUMPTION[2]="ticket=unsuccessful"
- pr_warning "Connect problem: Ticket resumption test not possible / "
+ 7) pr_warning "Connect problem: Ticket resumption test not possible / "
fileout "$jsonID" "WARN" "check failed because of connect problem"
((ret++))
;;
@@ -9588,32 +9578,25 @@ run_server_defaults() {
jsonID="sessionresumption_ID"
if "$NO_SSL_SESSIONID"; then
- SESS_RESUMPTION[1]="ID=no"
outln "ID: no"
fileout "$jsonID" "INFO" "No Session ID, no resumption"
else
sub_session_resumption "$sessticket_proto" ID
case $? in
- 0) SESS_RESUMPTION[1]="ID=yes"
- outln "ID: yes"
+ 0) outln "ID: yes"
fileout "$jsonID" "INFO" "supported"
;;
- 1|2) SESS_RESUMPTION[1]="ID=no"
- outln "ID: no"
+ 1|2) outln "ID: no"
fileout "$jsonID" "INFO" "not supported"
;;
- 5) SESS_RESUMPTION[1]="ID=noclue"
- prln_warning "ID resumption test failed, pls report"
+ 5) prln_warning "ID resumption test failed, pls report"
fileout "$jsonID" "WARN" "check failed, pls report"
((ret++))
;;
- 6) SESS_RESUMPTION[1]="ID=clientauth"
- # [[ ${SESS_RESUMPTION[2]} =~ clientauth ]] || pr_warning "Client Auth: "
- prln_warning "Client Auth: ID resumption test not supported"
+ 6) prln_warning "Client Auth: ID resumption test not supported"
fileout "$jsonID" "WARN" "check couldn't be performed because of client authentication"
;;
- 7) SESS_RESUMPTION[1]="ID=unsuccessful"
- prln_warning "ID resumption test failed"
+ 7) prln_warning "ID resumption test failed"
fileout "$jsonID" "WARN" "check failed because of connect problem"
((ret++))
;;
@@ -10565,7 +10548,6 @@ starttls_mysql_dialog() {
# returns 6 if opening the socket caused a problem, 1 if STARTTLS handshake failed, 0: all ok
#
fd_socket() {
- local jabber=""
local proyxline=""
local nodeip="$(tr -d '[]' <<< $NODEIP)" # sockets do not need the square brackets we have of IPv6 addresses
# we just need do it here, that's all!
@@ -14238,7 +14220,7 @@ prepare_tls_clienthello() {
local len_client_hello_word len_all_word
local ecc_cipher_suite_found=false
local extension_signature_algorithms extension_heartbeat session_id
- local extension_session_ticket extension_next_protocol extension_padding
+ local extension_session_ticket extension_next_protocol
local extension_supported_groups="" extension_supported_point_formats=""
local extensions_key_share="" extn_type supported_groups_c2n="" extn_psk_mode=""
local extra_extensions extra_extensions_list="" extension_supported_versions=""
@@ -14656,11 +14638,11 @@ prepare_tls_clienthello() {
resend_if_hello_retry_request() {
local original_clienthello="$1"
local tls_hello_ascii="$2"
- local msg_type tls_low_byte server_version cipher_suite rfc_cipher_suite
+ local msg_type server_version cipher_suite rfc_cipher_suite
local key_share="" new_key_share="" cookie="" second_clienthello data=""
local -i i j msg_len tls_hello_ascii_len sid_len
- local -i extns_offset hrr_extns_len extra_extensions_len len_extn
- local extra_extensions extn_type part2 new_extra_extns=""
+ local -i extns_offset hrr_extns_len len_extn
+ local extn_type
local sha256_hrr="CF21AD74E59A6111BE1D8C021E65B891C2A211167ABB8C5E079E09E2C8A8339C"
tls_hello_ascii_len=${#tls_hello_ascii}
@@ -19480,6 +19462,7 @@ get_aaaa_record() {
# arg1: domain to check for
get_caa_rr_record() {
local raw_caa=""
+ local hash len line
local -i len_caa_property
local caa_property_name
local caa_property_value
From cce7566dc8eac7ba459f3609feb5cad96cb27ce2 Mon Sep 17 00:00:00 2001
From: Magnus Larsen
Date: Tue, 2 Jun 2020 16:26:55 +0200
Subject: [PATCH 109/211] Moved grade_caps to run_rating() function; added
KEY_EXCH_SCORE=20 back again
---
testssl.sh | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 02bb7e5..37c329b 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -1039,25 +1039,23 @@ set_key_str_score() {
"$do_rating" || return 0
- [[ $type == DHE ]] && type_output="ephemeral DH key (DH parameters)" || type_output="key"
-
if [[ $type == EC || $type == EdDSA ]]; then
- if [[ $size -lt 123 ]] && [[ $KEY_EXCH_SCORE -ge 40 ]]; then
+ if [[ $size -lt 110 ]] && [[ $KEY_EXCH_SCORE -gt 20 ]]; then
+ let KEY_EXCH_SCORE=20
+ elif [[ $size -lt 123 ]] && [[ $KEY_EXCH_SCORE -ge 40 ]]; then
let KEY_EXCH_SCORE=40
- set_grade_cap "F" "Using an insecure $type_output"
elif [[ $size -lt 163 ]] && [[ $KEY_EXCH_SCORE -ge 80 ]]; then
let KEY_EXCH_SCORE=80
- set_grade_cap "B" "Using a weak $type_output"
elif [[ $size -lt 225 ]] && [[ $KEY_EXCH_SCORE -ge 90 ]]; then
let KEY_EXCH_SCORE=90
fi
else
- if [[ $size -lt 1024 ]] && [[ $KEY_EXCH_SCORE -ge 40 ]]; then
+ if [[ $size -lt 512 ]] && [[ $KEY_EXCH_SCORE -ge 20 ]]; then
+ let KEY_EXCH_SCORE=20
+ elif [[ $size -lt 1024 ]] && [[ $KEY_EXCH_SCORE -ge 40 ]]; then
let KEY_EXCH_SCORE=40
- set_grade_cap "F" "Using an insecure $type_output"
elif [[ $size -lt 2048 ]] && [[ $KEY_EXCH_SCORE -ge 80 ]]; then
let KEY_EXCH_SCORE=80
- set_grade_cap "B" "Using a weak $type_output"
elif [[ $size -lt 4096 ]] && [[ $KEY_EXCH_SCORE -ge 90 ]]; then
let KEY_EXCH_SCORE=90
fi
@@ -20880,6 +20878,12 @@ run_rating() {
pr_bold " Protocol Support "; out "(weighted) "; outln "$c1_score ($c1_wscore)"
## Category 2
+ if [[ $KEY_EXCH_SCORE -le 40 ]]; then
+ set_grade_cap "F" "Using an insecure public key and/or ephemeral key"
+ elif [[ $KEY_EXCH_SCORE -le 80 ]]; then
+ set_grade_cap "B" "Using a weak public key and/or ephemeral key"
+ fi
+
let c2_score=$KEY_EXCH_SCORE
let c2_wscore=$c2_score*30/100
From 55bbb98a024b818ac2a3a38f055b1078825947b9 Mon Sep 17 00:00:00 2001
From: Magnus Larsen
Date: Tue, 2 Jun 2020 16:28:24 +0200
Subject: [PATCH 110/211] small fixes
---
testssl.sh | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 37c329b..a4a401f 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -1035,12 +1035,11 @@ set_grade_warning() {
set_key_str_score() {
local type=$1
local size=$2
- local type_output
"$do_rating" || return 0
if [[ $type == EC || $type == EdDSA ]]; then
- if [[ $size -lt 110 ]] && [[ $KEY_EXCH_SCORE -gt 20 ]]; then
+ if [[ $size -lt 110 ]] && [[ $KEY_EXCH_SCORE -ge 20 ]]; then
let KEY_EXCH_SCORE=20
elif [[ $size -lt 123 ]] && [[ $KEY_EXCH_SCORE -ge 40 ]]; then
let KEY_EXCH_SCORE=40
@@ -1064,7 +1063,7 @@ set_key_str_score() {
}
# Sets the best and worst bit size key, used to grade Category 3 (Cipher Strength)
-# This function itself doesn't actually set a score; its just in the name to keep it logical (score == grading function)
+# This function itself doesn't actually set a score; its just in the name to keep it logical (score == rating function)
# arg1: a bit size
set_ciph_str_score() {
local size=$1
From fe87192a80ac356e4affa39ba83ccc16db0b576d Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Mon, 8 Jun 2020 13:54:36 -0400
Subject: [PATCH 111/211] Fix missing spaces
In some cases when the Trust finding is printed, there is no space between the results when SNI is used and the results without SNI (which appear in paraenthesis). This commit adds the missing space.
---
testssl.sh | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index bd53b08..0a3056d 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -8862,24 +8862,24 @@ certificate_info() {
fi
elif [[ $trust_nosni -eq 4 ]] || [[ $trust_nosni -eq 8 ]] || [[ $trust_sni -eq 4 ]] || [[ $trust_sni -eq 8 ]]; then
case $trust_nosni in
- 1) trustfinding_nosni="(w/o SNI: Ok via SAN)" ;;
- 2) trustfinding_nosni="(w/o SNI: Ok via SAN wildcard)" ;;
+ 1) trustfinding_nosni=" (w/o SNI: Ok via SAN)" ;;
+ 2) trustfinding_nosni=" (w/o SNI: Ok via SAN wildcard)" ;;
4) if "$has_dns_sans_nosni"; then
- trustfinding_nosni="(w/o SNI: via CN, but not SAN)"
+ trustfinding_nosni=" (w/o SNI: via CN, but not SAN)"
else
- trustfinding_nosni="(w/o SNI: via CN only)"
+ trustfinding_nosni=" (w/o SNI: via CN only)"
fi
;;
- 5) trustfinding_nosni="(w/o SNI: Ok via SAN and CN)" ;;
- 6) trustfinding_nosni="(w/o SNI: Ok via SAN wildcard and CN)" ;;
+ 5) trustfinding_nosni=" (w/o SNI: Ok via SAN and CN)" ;;
+ 6) trustfinding_nosni=" (w/o SNI: Ok via SAN wildcard and CN)" ;;
8) if "$has_dns_sans_nosni"; then
- trustfinding_nosni="(w/o SNI: via CN wildcard, but not SAN)"
+ trustfinding_nosni=" (w/o SNI: via CN wildcard, but not SAN)"
else
- trustfinding_nosni="(w/o SNI: via CN (wildcard) only)"
+ trustfinding_nosni=" (w/o SNI: via CN (wildcard) only)"
fi
;;
- 9) trustfinding_nosni="(w/o SNI: Ok via CN wildcard and SAN)" ;;
- 10) trustfinding_nosni="(w/o SNI: Ok via SAN wildcard and CN wildcard)" ;;
+ 9) trustfinding_nosni=" (w/o SNI: Ok via CN wildcard and SAN)" ;;
+ 10) trustfinding_nosni=" (w/o SNI: Ok via SAN wildcard and CN wildcard)" ;;
esac
elif [[ $trust_sni -ne 0 ]]; then
trustfinding_nosni=" (works w/o SNI)"
From a6c2168cd9d3ea166761cc4265aefa9c661cd497 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Mon, 8 Jun 2020 13:57:00 -0400
Subject: [PATCH 112/211] Fix and enhance CN matching
PR #1373 changed get_cn_from_cert() to handle certificate subject names that include more than one CN attribute. It did this by converting newline characters to spaces. It seems that this resulted in a space character being added to the end of the string returned by get_cn_from_cert() even in the case that the subject name only included one CN attribute. The presence of the space character in returned value caused compare_server_name_to_cert() to determine that the CN attribute did not contain a DNS name (since DNS names cannot include spaces), and so compare_server_name_to_cert() reports that the server name does not match against the CN in the subject. This may be the reason for the problem noted in #1555.
This commit fixes the above problem and also enhances the matching of the CN in the subject name against the server's name. Currently, compare_server_name_to_cert() assumes that the subject field contains at most one CN attribute. However, as noted in #1373, some certificates include subject names with more than one CN attribute, and RFC 6125 (Section 6.2.2) indicates that the certificate subject name include more than one CN, with each specifying a different DNS name.
So, in addition to fixing the problem with the space character, this commit also enhances the CN matching to work even if the certificate includes more than one CN attribute in the subject name.
---
testssl.sh | 30 +++++++++++++++++-------------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index bd53b08..584955c 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -7804,9 +7804,9 @@ wildcard_match()
compare_server_name_to_cert() {
local cert="$1"
- local servername cn dns_sans ip_sans san dercert tag
+ local servername cns cn dns_sans ip_sans san dercert tag
local srv_id="" xmppaddr=""
- local -i i len len1
+ local -i i len len1 cn_match=0
local -i subret=0 # no error condition, passing results
HAS_DNS_SANS=false
@@ -7960,19 +7960,23 @@ compare_server_name_to_cert() {
done <<< "$dns_sans"
fi
- cn="$(get_cn_from_cert "$cert")"
+ # Get every CN from the subject field and compare against the server name.
+ cns="$($OPENSSL x509 -in $1 -noout -subject -nameopt multiline,-align,sname,-esc_msb,utf8,-space_eq 2>>$ERRFILE | awk -F'=' '/CN=/ { print $2 }')"
+ while read cn; do
+ # If the CN contains any characters that are not valid for a DNS name,
+ # then assume it does not contain a DNS name.
+ [[ -n $(sed 's/^[_\.a-zA-Z0-9*\-]*//' <<< "$cn") ]] && continue
- # If the CN contains any characters that are not valid for a DNS name,
- # then assume it does not contain a DNS name.
- [[ -n $(sed 's/^[_\.a-zA-Z0-9*\-]*//' <<< "$cn") ]] && return $subret
+ # Check whether the CN matches the servername
+ [[ $(toupper "$cn") == "$servername" ]] && cn_match=4 && break
- # Check whether the CN in the certificate matches the servername
- [[ $(toupper "$cn") == "$servername" ]] && subret+=4 && return $subret
-
- # Check whether the CN in the certificate is a wildcard name that matches
- # the servername
- wildcard_match "$servername" "$cn"
- [[ $? -eq 0 ]] && subret+=8
+ # Check whether the CN is a wildcard name that matches the servername
+ # NOTE: Don't stop loop on a wildcard match in case there is another CN
+ # that is an exact match.
+ wildcard_match "$servername" "$cn"
+ [[ $? -eq 0 ]] && cn_match=8
+ done <<< "$cns"
+ subret+=$cn_match
return $subret
}
From 21208f46cd683966f50ce89861d7096441f93b31 Mon Sep 17 00:00:00 2001
From: Magnus Larsen
Date: Thu, 18 Jun 2020 21:15:28 +0200
Subject: [PATCH 113/211] Clearer grade cap reason regarding certificate errors
---
testssl.sh | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index a4a401f..5bcd5a1 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -7204,7 +7204,7 @@ determine_trust() {
out "$code"
fi
fileout "${jsonID}${json_postfix}" "CRITICAL" "failed $code. $addtl_warning"
- set_grade_cap "T" "Issues with certificate $code"
+ set_grade_cap "T" "Issues with the chain of trust $code"
else
# is one ok and the others not ==> display the culprit store
if "$some_ok"; then
@@ -7223,7 +7223,7 @@ determine_trust() {
out "$code"
fi
notok_was="${certificate_file[i]} $code $notok_was"
- set_grade_cap "T" "Issues with certificate $code"
+ set_grade_cap "T" "Issues with chain of trust $code"
fi
done
#pr_svrty_high "$notok_was "
From de14ec9f8111fa905467b965b7026e8817ffabb3 Mon Sep 17 00:00:00 2001
From: Magnus Larsen
Date: Fri, 19 Jun 2020 21:21:43 +0200
Subject: [PATCH 114/211] STARTTLS rating styling
---
testssl.sh | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 926e282..9c64829 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -20802,14 +20802,7 @@ run_rating() {
pr_headlineln " Rating (experimental) "
outln
- if [[ -n "$STARTTLS_PROTOCOL" ]]; then
- pr_bold " Grade "; pr_svrty_critical "T"
- outln " - STARTTLS encryption is opportunistic"
- outln " (Further details would lead to a false sense of security)"
- fileout "grade" "CRITICAL" "T"
- fileout "grade_cap_reasons" "INFO" "No more details shown as it would lead to a false sense of security"
- return 0
- fi
+ [[ -n "$STARTTLS_PROTOCOL" ]] && set_grade_warning "STARTTLS encryption is opportunistic. The grade is very insignificant"
# Sort the reasons. This is just nicer to read in genereal
IFS=$'\n' sorted_reasons=($(sort -ru <<<"${GRADE_CAP_REASONS[*]}"))
@@ -20912,7 +20905,7 @@ run_rating() {
pr_bold " Final Score "; outln $final_score
- # get score, and somehow do something about the GRADE_CAP
+ # Calculate the pre-cap grade
if [[ $final_score -ge 80 ]]; then
pre_cap_grade="A"
elif [[ $final_score -ge 65 ]]; then
From 2bff63b7db8a289acca2d88e1669ed3e85b9ef17 Mon Sep 17 00:00:00 2001
From: Magnus Larsen
Date: Mon, 22 Jun 2020 19:14:25 +0200
Subject: [PATCH 115/211] Add a comment about STARTTLS connections in the docs
---
doc/testssl.1.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index 5198def..227ffbd 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -407,6 +407,10 @@ As of writing, these checks are missing:
* Exportable key exchange - should give **40** points in `set_key_str_score()`
* Weak key (Debian OpenSSL Flaw) - should give **0** points in `set_key_str_score()`
+#### STARTTLS
+This program rates STARTTLS connections, exactly according to the specification. However, this program adds a grade warning about STARTTLS is being used. This is not apart of the rating specification, and limits the grade a STARTTLS connection can have, to a maximum of `A-`.
+
+
#### Implementing new grades caps or -warnings
To implement a new grading cap, simply call the `set_grade_cap()` function, with the grade and a reason:
```bash
From 069c5ae917709f2fd1540cc4ce6bd4334e0db47b Mon Sep 17 00:00:00 2001
From: Magnus Larsen
Date: Mon, 22 Jun 2020 19:16:20 +0200
Subject: [PATCH 116/211] Spelling
---
doc/testssl.1.md | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index 227ffbd..c15f3ee 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -410,7 +410,6 @@ As of writing, these checks are missing:
#### STARTTLS
This program rates STARTTLS connections, exactly according to the specification. However, this program adds a grade warning about STARTTLS is being used. This is not apart of the rating specification, and limits the grade a STARTTLS connection can have, to a maximum of `A-`.
-
#### Implementing new grades caps or -warnings
To implement a new grading cap, simply call the `set_grade_cap()` function, with the grade and a reason:
```bash
@@ -423,14 +422,14 @@ set_grade_warning "Documentation is always right"
#### Implementing a new check which contains grade caps
When implementing a new check (be it vulnerability or not) that sets grade caps, the `set_rating_state()` has to be updated (i.e. the `$do_mycheck` variable-name has to be added to the loop, and `$nr_enabled` if-statement has to be incremented)
-The `set_rating_state()` automatically disables ratinng, if all the required checks are *not* enabled.
+The `set_rating_state()` automatically disables rating, if all the required checks are *not* enabled.
This is to prevent giving out a misleading or wrong grade.
#### Implementing a new revision
When a new revision of the rating specification comes around, the following has to be done:
* New grade caps has to be either:
1. Added to the script wherever relevant, or
- 2. Added to the above list of missing checks (if *i.* is not possible)
+ 2. Added to the above list of missing checks (if above is not possible)
* New grade warnings has to be added wherever relevant
* The revision output in `run_rating()` function has to updated
From 82e939f2bdd1ea977224ecd742ce514578a6fbd7 Mon Sep 17 00:00:00 2001
From: Christoph Settgast
Date: Tue, 23 Jun 2020 15:26:31 +0200
Subject: [PATCH 117/211] Add wiresharked Android 7.0 (native)
After being bitten by https://stackoverflow.com/questions/39133437/sslhandshakeexception-handshake-failed-on-android-n-7-0
I add a wiresharked Android 7.0 to reflect that bug in Android 7.0.
---
etc/client-simulation.txt | 9 +++++----
etc/client-simulation.wiresharked.txt | 22 ++++++++++++++++++++++
2 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/etc/client-simulation.txt b/etc/client-simulation.txt
index ed2c3bc..b81a934 100644
--- a/etc/client-simulation.txt
+++ b/etc/client-simulation.txt
@@ -174,24 +174,25 @@
requiresSha2+=(false)
current+=(true)
- names+=("Android 7.0")
+ names+=("Android 7.0 (native)")
short+=("android_70")
- ch_ciphers+=("ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305-OLD:ECDHE-RSA-CHACHA20-POLY1305-OLD:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA:DES-CBC3-SHA")
+ ch_ciphers+=("ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA")
ciphersuites+=("")
ch_sni+=("$SNI")
warning+=("")
- handshakebytes+=("16030100e4010000e0030366285fd01ec41e6b9c032a373d4607a6349c509d8a1b142cecc6820364d6eab42024c69f1c56165106d550c4c72135be8c3fe21f72843d19e663602d6476babc090022cca9cca8cc14cc13c02bc02fc02cc030c009c013c00ac014009c009d002f0035000a01000075ff0100010000000014001200000f6465762e73736c6c6162732e636f6d0017000000230000000d00120010060106030501050304010403020102030005000501000000000012000000100017001502683208737064792f332e3108687474702f312e31000b00020100000a00080006001d00170018")
+ handshakebytes+=("160301009d0100009903036cea0f867ae9fdd087adedaa810119e62971b36c0486d44fb3099e51403c8a1e000018c02bc02ccca9c02fc030cca8c013c014009c009d002f003501000058ff010001000000000d000b00000873796e6f642e696d0017000000230000000d0016001406010603050105030401040303010303020102030010000e000c02683208687474702f312e31000b00020100000a000400020017")
protos+=("-no_ssl3 -no_ssl2")
tlsvers+=("-tls1_2 -tls1_1 -tls1")
lowest_protocol+=("0x0301")
highest_protocol+=("0x0303")
+ alpn+=("h2,http/1.1")
service+=("HTTP,FTP")
minDhBits+=(-1)
maxDhBits+=(-1)
minRsaBits+=(-1)
maxRsaBits+=(-1)
minEcdsaBits+=(-1)
- curves+=("X25519:prime256v1:secp384r1")
+ curves+=("prime256v1")
requiresSha2+=(false)
current+=(true)
diff --git a/etc/client-simulation.wiresharked.txt b/etc/client-simulation.wiresharked.txt
index e399707..255c724 100644
--- a/etc/client-simulation.wiresharked.txt
+++ b/etc/client-simulation.wiresharked.txt
@@ -5,6 +5,28 @@
#
# Instructions how to add a client simulation see file "client-simulation.wiresharked.md".
+ names+=("Android 7.0 (native)")
+ short+=("android_70")
+ ch_ciphers+=("ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA")
+ ciphersuites+=("")
+ ch_sni+=("$SNI")
+ warning+=("")
+ handshakebytes+=("160301009d0100009903036cea0f867ae9fdd087adedaa810119e62971b36c0486d44fb3099e51403c8a1e000018c02bc02ccca9c02fc030cca8c013c014009c009d002f003501000058ff010001000000000d000b00000873796e6f642e696d0017000000230000000d0016001406010603050105030401040303010303020102030010000e000c02683208687474702f312e31000b00020100000a000400020017")
+ protos+=("-no_ssl3 -no_ssl2")
+ tlsvers+=("-tls1_2 -tls1_1 -tls1")
+ lowest_protocol+=("0x0301")
+ highest_protocol+=("0x0303")
+ alpn+=("h2,http/1.1")
+ service+=("HTTP,FTP")
+ minDhBits+=(-1)
+ maxDhBits+=(-1)
+ minRsaBits+=(-1)
+ maxRsaBits+=(-1)
+ minEcdsaBits+=(-1)
+ curves+=("prime256v1")
+ requiresSha2+=(false)
+ current+=(true)
+
names+=("Android 8.1 (native)")
short+=("android_81")
ch_ciphers+=("ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA")
From f647ae8264d274067706b2b3272e7b930cbf16c0 Mon Sep 17 00:00:00 2001
From: Magnus Larsen
Date: Tue, 23 Jun 2020 19:24:24 +0200
Subject: [PATCH 118/211] Change to grade cap
---
doc/testssl.1.md | 3 ---
testssl.sh | 2 +-
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index c15f3ee..a866739 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -407,9 +407,6 @@ As of writing, these checks are missing:
* Exportable key exchange - should give **40** points in `set_key_str_score()`
* Weak key (Debian OpenSSL Flaw) - should give **0** points in `set_key_str_score()`
-#### STARTTLS
-This program rates STARTTLS connections, exactly according to the specification. However, this program adds a grade warning about STARTTLS is being used. This is not apart of the rating specification, and limits the grade a STARTTLS connection can have, to a maximum of `A-`.
-
#### Implementing new grades caps or -warnings
To implement a new grading cap, simply call the `set_grade_cap()` function, with the grade and a reason:
```bash
diff --git a/testssl.sh b/testssl.sh
index 9c64829..d5b3c3b 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -20802,7 +20802,7 @@ run_rating() {
pr_headlineln " Rating (experimental) "
outln
- [[ -n "$STARTTLS_PROTOCOL" ]] && set_grade_warning "STARTTLS encryption is opportunistic. The grade is very insignificant"
+ [[ -n "$STARTTLS_PROTOCOL" ]] && set_grade_cap "T" "Encryption via STARTTLS is not mandatory (opportunistic). This leads to a false sense of security"
# Sort the reasons. This is just nicer to read in genereal
IFS=$'\n' sorted_reasons=($(sort -ru <<<"${GRADE_CAP_REASONS[*]}"))
From b2d41330e0f0636eb35ebfc6fc0eb747519514dc Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Thu, 25 Jun 2020 13:05:47 +0200
Subject: [PATCH 119/211] port typo fixes to html and roff doc
---
doc/testssl.1 | 4 ++--
doc/testssl.1.html | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/doc/testssl.1 b/doc/testssl.1
index 38bbfed..1b7a9f3 100644
--- a/doc/testssl.1
+++ b/doc/testssl.1
@@ -650,10 +650,10 @@ To implement a new grading cap, simply call the \fBset_grade_cap()\fR function,
When implementing a new check (be it vulnerability or not) that sets grade caps, the \fBset_rating_state()\fR has to be updated (i\.e\. the \fB$do_mycheck\fR variable\-name has to be added to the loop, and \fB$nr_enabled\fR if\-statement has to be incremented)
.
.P
-The \fBset_rating_state()\fR automatically disables ratinng, if all the required checks are \fInot\fR enabled\. This is to prevent giving out a misleading or wrong grade\.
+The \fBset_rating_state()\fR automatically disables rating, if all the required checks are \fInot\fR enabled\. This is to prevent giving out a misleading or wrong grade\.
.
.P
-When a new revision of the rating specification comes around, the following has to be done: * New grade caps has to be either: 1\. Added to the script wherever relevant, or 2\. Added to the above list of missing checks (if \fIi\.\fR is not possible) * New grade warnings has to be added wherever relevant * The revision output in \fBrun_rating()\fR function has to updated
+When a new revision of the rating specification comes around, the following has to be done: * New grade caps has to be either: 1\. Added to the script wherever relevant, or 2\. Added to the above list of missing checks (if above is not possible) * New grade warnings has to be added wherever relevant * The revision output in \fBrun_rating()\fR function has to updated
.
.SH "EXAMPLES"
.
diff --git a/doc/testssl.1.html b/doc/testssl.1.html
index 8290958..38067d1 100644
--- a/doc/testssl.1.html
+++ b/doc/testssl.1.html
@@ -515,7 +515,7 @@ set_grade_warning "Documentation is always right"
When implementing a new check (be it vulnerability or not) that sets grade caps, the set_rating_state()
has to be updated (i.e. the $do_mycheck
variable-name has to be added to the loop, and $nr_enabled
if-statement has to be incremented)
-The set_rating_state()
automatically disables ratinng, if all the required checks are not enabled.
+
The set_rating_state()
automatically disables rating, if all the required checks are not enabled.
This is to prevent giving out a misleading or wrong grade.
Implementing a new revision
@@ -523,7 +523,7 @@ This is to prevent giving out a misleading or wrong grade.
When a new revision of the rating specification comes around, the following has to be done:
* New grade caps has to be either:
1. Added to the script wherever relevant, or
- 2. Added to the above list of missing checks (if i. is not possible)
+ 2. Added to the above list of missing checks (if above is not possible)
* New grade warnings has to be added wherever relevant
* The revision output in run_rating()
function has to updated
From 91ceaca1e94df11578d0f637bb46cc9e99b81f38 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Thu, 25 Jun 2020 07:31:50 -0400
Subject: [PATCH 120/211] Fix #1662
This commit fixes #1662 by changing the fileout to use the value of $cert_ext_keyusage rather than the string "cert_ext_keyusage".
---
testssl.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/testssl.sh b/testssl.sh
index faebe83..86a9ce5 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -8647,7 +8647,7 @@ certificate_info() {
outok=false
fi
if "$outok"; then
- fileout "${jsonID}${json_postfix}" "INFO" "cert_ext_keyusage"
+ fileout "${jsonID}${json_postfix}" "INFO" "$cert_ext_keyusage"
fi
out "$indent"; pr_bold " Serial / Fingerprints "
From 1f2b4a3f40fe68f401ae9f93dd8079501a9f9344 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Thu, 25 Jun 2020 13:18:28 -0400
Subject: [PATCH 121/211] Fix #1665
This commit fixes #1665 by adding the certificate number to the JSON identifier for cert_eTLS.
---
testssl.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/testssl.sh b/testssl.sh
index 7a161b0..b750190 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -8942,7 +8942,7 @@ certificate_info() {
out "$indent"; pr_bold " ETS/\"eTLS\""
out ", visibility info "
jsonID="cert_eTLS"
- etsi_etls_visibility_info "$jsonID" "$spaces" "$HOSTCERT" "$cert_txt"
+ etsi_etls_visibility_info "${jsonID}${json_postfix}" "$spaces" "$HOSTCERT" "$cert_txt"
# *Currently* this is even listed as a vulnerability (CWE-310, CVE-2019-919), see
# https://nvd.nist.gov/vuln/detail/CVE-2019-9191, https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9191
# For now we leave this here. We may want to change that later or add infos to other sections (FS & vulnerability)
From 288223c70760a534712d2cc68a57486f281820fe Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Thu, 25 Jun 2020 20:47:51 +0200
Subject: [PATCH 122/211] Polish STARTTLS rating output
Moved the sentence ~i "A grade better than T would lead to a false sense of security"
to the documentation. No reason for excuses in the output. ;-) Explanation fits
better in the doc.
See also #1657
---
doc/testssl.1 | 2 +-
doc/testssl.1.html | 2 +-
doc/testssl.1.md | 3 ++-
testssl.sh | 3 ++-
4 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/doc/testssl.1 b/doc/testssl.1
index 1b7a9f3..834d339 100644
--- a/doc/testssl.1
+++ b/doc/testssl.1
@@ -638,7 +638,7 @@ This program has a near\-complete implementation of SSL Labs\'s \'SSL Server Rat
This is \fInot\fR a 100% reimplementation of the SSL Lab\'s SSL Server Test \fIhttps://www\.ssllabs\.com/ssltest/analyze\.html\fR, but an implementation of the above rating specification, slight discrepancies may occur\. Please note that for now we stick to the SSL Labs rating as good as possible\. We are not responsible for their rating\. Before filing issues please inspect their Rating Guide\.
.
.P
-Disclaimer: Having a good grade is \fBNOT\fR necessarily equal to having good security! Don\'t start a competition for the best grade, at least not without monitoring the client handshakes and not without adding a portion of good sense to it\.
+Disclaimer: Having a good grade is \fBNOT\fR necessarily equal to having good security! Don\'t start a competition for the best grade, at least not without monitoring the client handshakes and not without adding a portion of good sense to it\. Please note STARTTLS always results in a grade cap to T\. Anything else would lead to a false sense of security \- at least until we test for DANE or MTA-STS\.
.
.P
As of writing, these checks are missing: * GOLDENDOODLE \- should be graded \fBF\fR if vulnerable * Insecure renegotiation \- should be graded \fBF\fR if vulnerable * Padding oracle in AES\-NI CBC MAC check (CVE\-2016\-2107) \- should be graded \fBF\fR if vulnerable * Sleeping POODLE \- should be graded \fBF\fR if vulnerable * Zero Length Padding Oracle (CVE\-2019\-1559) \- should be graded \fBF\fR if vulnerable * Zombie POODLE \- should be graded \fBF\fR if vulnerable * All remaining old Symantec PKI certificates are distrusted \- should be graded \fBT\fR * Symantec certificates issued before June 2016 are distrusted \- should be graded \fBT\fR * ! A reading of DH params \- should give correct points in \fBset_key_str_score()\fR * Anonymous key exchange \- should give \fB0\fR points in \fBset_key_str_score()\fR * Exportable key exchange \- should give \fB40\fR points in \fBset_key_str_score()\fR * Weak key (Debian OpenSSL Flaw) \- should give \fB0\fR points in \fBset_key_str_score()\fR
diff --git a/doc/testssl.1.html b/doc/testssl.1.html
index 38067d1..af08013 100644
--- a/doc/testssl.1.html
+++ b/doc/testssl.1.html
@@ -484,7 +484,7 @@ Rating automatically gets disabled, to not give a wrong or misleading grade, whe
This is not a 100% reimplementation of the SSL Lab's SSL Server Test, but an implementation of the above rating specification, slight discrepancies may occur. Please note that for now we stick to the SSL Labs rating as good as possible. We are not responsible for their rating. Before filing issues please inspect their Rating Guide.
-Disclaimer: Having a good grade is NOT necessarily equal to having good security! Don't start a competition for the best grade, at least not without monitoring the client handshakes and not without adding a portion of good sense to it.
+Disclaimer: Having a good grade is NOT necessarily equal to having good security! Don't start a competition for the best grade, at least not without monitoring the client handshakes and not without adding a portion of good sense to it. Please note STARTTLS always results in a grade cap to T. Anything else would lead to a false sense of security - at least until we test for DANE or MTA-STS.
As of writing, these checks are missing:
* GOLDENDOODLE - should be graded F if vulnerable
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index a866739..6755235 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -392,7 +392,8 @@ This program has a near-complete implementation of SSL Labs's '[SSL Server Ratin
This is *not* a 100% reimplementation of the [SSL Lab's SSL Server Test](https://www.ssllabs.com/ssltest/analyze.html), but an implementation of the above rating specification, slight discrepancies may occur. Please note that for now we stick to the SSL Labs rating as good as possible. We are not responsible for their rating. Before filing issues please inspect their Rating Guide.
-Disclaimer: Having a good grade is **NOT** necessarily equal to having good security! Don't start a competition for the best grade, at least not without monitoring the client handshakes and not without adding a portion of good sense to it.
+Disclaimer: Having a good grade is **NOT** necessarily equal to having good security! Don't start a competition for the best grade, at least not without monitoring the client handshakes and not without adding a portion of good sense to it. Please note STARTTLS always results in a grade cap to T. Anything else
+would lead to a false sense of security - at least until we test for DANE or MTA-STS.
As of writing, these checks are missing:
* GOLDENDOODLE - should be graded **F** if vulnerable
diff --git a/testssl.sh b/testssl.sh
index d5b3c3b..fe021e6 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -20797,12 +20797,13 @@ run_rating() {
local c1_worst c1_best
local c3_worst c3_best c3_worst_cb c3_best_cb
local old_ifs=$IFS sorted_reasons sorted_warnings reason_nr=0 warning_nr=0
+ local spaces=" "
outln "\n";
pr_headlineln " Rating (experimental) "
outln
- [[ -n "$STARTTLS_PROTOCOL" ]] && set_grade_cap "T" "Encryption via STARTTLS is not mandatory (opportunistic). This leads to a false sense of security"
+ [[ -n "$STARTTLS_PROTOCOL" ]] && set_grade_cap "T" "Encryption via STARTTLS is not mandatory (opportunistic)."
# Sort the reasons. This is just nicer to read in genereal
IFS=$'\n' sorted_reasons=($(sort -ru <<<"${GRADE_CAP_REASONS[*]}"))
From 7c759937469892e5eaf2621acfbf33c7e5f38fef Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Thu, 25 Jun 2020 20:54:43 +0200
Subject: [PATCH 123/211] remove unused spaces var
---
testssl.sh | 1 -
1 file changed, 1 deletion(-)
diff --git a/testssl.sh b/testssl.sh
index fe021e6..716da8f 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -20797,7 +20797,6 @@ run_rating() {
local c1_worst c1_best
local c3_worst c3_best c3_worst_cb c3_best_cb
local old_ifs=$IFS sorted_reasons sorted_warnings reason_nr=0 warning_nr=0
- local spaces=" "
outln "\n";
pr_headlineln " Rating (experimental) "
From 919064095f7115a67795c70306452c8d03b51c36 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Mon, 6 Jul 2020 15:45:36 -0400
Subject: [PATCH 124/211] Separate pr_cipher_quality() into two functions
This commit separates pr_cipher_quality() into two functions, one that returns the quality of a cipher as a numeric rating (get_cipher_quality()) and one that prints a cipher based on its quality (pr_cipher_quality()). This separation allows get_cipher_quality() to be used to determine how good a cipher is without having to print anything. Having this ability would be helpful in implementing the changes suggested in #1311.
---
testssl.sh | 54 ++++++++++++++++++++++++++++++------------------------
1 file changed, 30 insertions(+), 24 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 135613f..416080d 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -6108,8 +6108,7 @@ pr_ecdh_curve_quality() {
pr_ecdh_quality "$bits" "$curve"
}
-# Print $2 based on the quality of the cipher in $1. If $2 is empty, just print $1.
-# The return value is an indicator of the quality of the cipher in $1:
+# Return a value that is an indicator of the quality of the cipher in $1:
# 0 = $1 is empty
# 1 = pr_svrty_critical, 2 = pr_svrty_high, 3 = pr_svrty_medium, 4 = pr_svrty_low
# 5 = neither good nor bad, 6 = pr_svrty_good, 7 = pr_svrty_best
@@ -6119,13 +6118,11 @@ pr_ecdh_curve_quality() {
# Hint: find out by "grep etc/cipher-mapping.txt" but it' might be be easier
# to look out Enc= and Au= or Mac=
#
-pr_cipher_quality() {
+get_cipher_quality() {
local cipher="$1"
- local text="$2"
local ossl_cipher
[[ -z "$1" ]] && return 0
- [[ -z "$text" ]] && text="$cipher"
if [[ "$cipher" != TLS_* ]] && [[ "$cipher" != SSL_* ]]; then
# This must be the OpenSSL name for a cipher or for TLS 1.3 ($TLS13_OSSL_CIPHERS)
@@ -6135,46 +6132,36 @@ pr_cipher_quality() {
# the case, see "prepare_arrays()" and "./etc/cipher-mapping.txt"
case "$cipher" in
*NULL*|EXP*|ADH*|AECDH*|*anon*)
- pr_svrty_critical "$text"
return 1
;;
*RC4*|*RC2*|*MD5|*M1)
- pr_svrty_high "$text"
return 2
;;
AES256-GCM-SHA384|AES128-GCM-SHA256|AES256-CCM*|AES128-CCM*|ARIA256-GCM-SHA384|ARIA128-GCM-SHA256)
# RSA kx and e.g. GCM isn't certainly the best
- pr_svrty_good "$text"
return 6
;;
*CBC3*|*3DES*|*IDEA*)
- pr_svrty_medium "$text"
return 3
;;
*DES*)
- pr_svrty_high "$text"
return 2
;;
PSK-*GCM*|PSK-*CCM*|RSA-PSK-*GCM*|RSA-PSK-CHACHA20-POLY1305|PSK-CHACHA20-POLY1305)
# PSK kx and e.g. GCM isn't certainly the best
- pr_svrty_good "$text"
return 6
;;
DH-*GCM*|ECDH-*GCM*)
# static DH or ECDH kx and GCM isn't certainly the best
- pr_svrty_good "$text"
return 6
;;
*GCM*|*CCM*|*CHACHA20*)
- pr_svrty_best "$text"
return 7
;; #best ones
*AES*SHA*|*CAMELLIA*SHA*|*SEED*SHA*|*CBC*|*GOST*)
- pr_svrty_low "$text"
return 4
;;
*)
- out "$text"
return 5
;;
esac
@@ -6187,45 +6174,64 @@ pr_cipher_quality() {
# Now we look at the RFC cipher names. The sequence matters - as above.
case "$cipher" in
*NULL*|*EXP*|*_DES40_*|*anon*)
- pr_svrty_critical "$text"
return 1
;;
*RC4*|*RC2*|*MD5|*MD5_1)
- pr_svrty_high "$text"
return 2
;;
*_DES_*)
if [[ "$cipher" =~ EDE3 ]]; then
- pr_svrty_medium "$text" # 3DES
return 3
fi
- pr_svrty_high "$text"
return 2
;;
*CBC3*|*3DES*|*IDEA*)
- pr_svrty_medium "$text"
return 3
;;
*CBC*|*GOST*)
- pr_svrty_low "$text"
return 4
;;
TLS_RSA_*|TLS_DH_*|TLS_ECDH_*|TLS_PSK_WITH_*)
- pr_svrty_good "$text"
# RSA, or static DH, ECDH, or PSK kx and e.g. GCM isn't certainly the best
return 6
;;
*GCM*|*CCM*|*CHACHA20*)
- pr_svrty_best "$text"
return 7
;;
*)
- out "$text"
return 5
;;
esac
}
+# Print $2 based on the quality of the cipher in $1. If $2 is empty, just print $1.
+# The return value is an indicator of the quality of the cipher in $1:
+# 0 = $1 is empty
+# 1 = pr_svrty_critical, 2 = pr_svrty_high, 3 = pr_svrty_medium, 4 = pr_svrty_low
+# 5 = neither good nor bad, 6 = pr_svrty_good, 7 = pr_svrty_best
+#
+pr_cipher_quality() {
+ local cipher="$1"
+ local text="$2"
+ local -i quality
+
+ [[ -z "$1" ]] && return 0
+ [[ -z "$text" ]] && text="$cipher"
+
+ get_cipher_quality "$cipher"
+ quality=$?
+ case $quality in
+ 1) pr_svrty_critical "$text" ;;
+ 2) pr_svrty_high "$text" ;;
+ 3) pr_svrty_medium "$text" ;;
+ 4) pr_svrty_low "$text" ;;
+ 5) out "$text" ;;
+ 6) pr_svrty_good "$text" ;;
+ 7) pr_svrty_best "$text" ;;
+ esac
+ return $quality
+}
+
# arg1: file with input for grepping the type of ephemeral DH key (DH ECDH)
read_dhtype_from_file() {
local temp kx
From 45eafd239f5ecc96a9735833362d452662797a25 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Tue, 7 Jul 2020 07:30:48 -0400
Subject: [PATCH 125/211] Fix printing of unrecognized option
When testssl.sh is called with an unknown option it prints something like:
0: unrecognized option "--option"
It should be printing the name of the program rather than "0". This commit fixes that.
---
testssl.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/testssl.sh b/testssl.sh
index 416080d..fe3ef22 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -21693,7 +21693,7 @@ parse_cmd_line() {
(--) shift
break
;;
- (-*) tmln_warning "0: unrecognized option \"$1\"" 1>&2;
+ (-*) tmln_warning "$0: unrecognized option \"$1\"" 1>&2;
help 1
;;
(*) break
From 6c8df4529cc0bc672a076bf7b082e2bef5fd264e Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Tue, 7 Jul 2020 12:01:23 -0400
Subject: [PATCH 126/211] Include cipher quality in JSON and CSV
run_cipherlists() checks for support for different groups of ciphers, but does not indicate which ciphers in each group are supported. So, for example, if the JSON file indicates that there is a problem with severity level "HIGH" because the "LOW" ciphers are available, there is no clear indication of which of these ciphers are supported by the server.
If run_server_preference() is run with "--color 3", then there will be a visual indication (via color) of the ciphers the server supports that are considered bad, but this information does not appear in the JSON (or CSV) output. The JSON (or CSV) output will include information about every cipher that is supported, but the severity level is always "INFO".
This commit addresses this problem by changing the fileout() calls in ciphers_by_strength() and cipher_pref_check() that output each supported cipher individually so that the "severity" argument is an indication of the quality of the cipher. With this, information about which bad ciphers are supported can easily be found in the JSON/CSV output.
---
testssl.sh | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index fe3ef22..c18299c 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -4378,7 +4378,7 @@ ciphers_by_strength() {
outln "${sigalg[i]}"
id="cipher$proto"
id+="_${normalized_hexcode[i]}"
- fileout "$id" "INFO" "$proto_text $(neat_list "${normalized_hexcode[i]}" "${ciph[i]}" "${kx[i]}" "${enc[i]}" "${export2[i]}") $available"
+ fileout "$id" "$(get_cipher_quality_severity "${ciph[i]}")" "$proto_text $(neat_list "${normalized_hexcode[i]}" "${ciph[i]}" "${kx[i]}" "${enc[i]}" "${export2[i]}") $available"
fi
done
@@ -6204,6 +6204,26 @@ get_cipher_quality() {
esac
}
+# Output the severity level associated with the cipher in $1.
+get_cipher_quality_severity() {
+ local cipher="$1"
+ local -i quality
+
+ [[ -z "$1" ]] && return 0
+
+ get_cipher_quality "$cipher"
+ quality=$?
+ case $quality in
+ 1) tm_out "CRITICAL" ;;
+ 2) tm_out "HIGH" ;;
+ 3) tm_out "MEDIUM" ;;
+ 4) tm_out "LOW" ;;
+ 5) tm_out "INFO" ;;
+ 6|7) tm_out "OK" ;;
+ esac
+ return $quality
+}
+
# Print $2 based on the quality of the cipher in $1. If $2 is empty, just print $1.
# The return value is an indicator of the quality of the cipher in $1:
# 0 = $1 is empty
@@ -7051,7 +7071,7 @@ cipher_pref_check() {
neat_list "${normalized_hexcode[i]}" "${ciph[i]}" "${kx[i]}" "${enc[i]}" "${export2[i]}" "true"
outln "${sigalg[i]}"
id="cipher-${proto}_${normalized_hexcode[i]}"
- fileout "$id" "INFO" "$proto_text $(neat_list "${normalized_hexcode[i]}" "${ciph[i]}" "${kx[i]}" "${enc[i]}" "${export2[i]}")"
+ fileout "$id" "$(get_cipher_quality_severity "${ciph[i]}")" "$proto_text $(neat_list "${normalized_hexcode[i]}" "${ciph[i]}" "${kx[i]}" "${enc[i]}" "${export2[i]}")"
done
else
outln
From cec5726f30da8c315c2402750f1c5bf4bc40c2ce Mon Sep 17 00:00:00 2001
From: Dirk
Date: Fri, 10 Jul 2020 19:52:47 +0200
Subject: [PATCH 127/211] Revised risk for BREACH --> medium
---
testssl.sh | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index c18299c..425f17b 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -16102,7 +16102,7 @@ run_breach() {
ret=1
;;
no_compression)
- pr_svrty_best "no gzip/deflate/compress/br HTTP compression (OK) "
+ pr_svrty_good "no gzip/deflate/compress/br HTTP compression (OK) "
outln "$disclaimer"
fileout "$jsonID" "OK" "not vulnerable, no gzip/deflate/compress/br HTTP compression $disclaimer" "$cve" "$cwe"
ret=0
@@ -16150,10 +16150,10 @@ run_breach() {
fi
done
detected_compression="$(strip_trailing_space "$detected_compression")"
- pr_svrty_high "potentially NOT ok, \"$detected_compression\" HTTP compression detected."
+ pr_svrty_medium "potentially NOT ok, \"$detected_compression\" HTTP compression detected."
outln "$disclaimer"
outln "${spaces}${when_makesense}"
- fileout "$jsonID" "HIGH" "potentially VULNERABLE, $detected_compression HTTP compression detected $disclaimer" "$cve" "$cwe" "$hint"
+ fileout "$jsonID" "MEDIUM" "potentially VULNERABLE, $detected_compression HTTP compression detected $disclaimer" "$cve" "$cwe" "$hint"
fi
debugme outln "${spaces}has_compression: ${has_compression[@]}"
;;
From 903eeec97b3c6e0fcc85a83957c4996dc773df38 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Tue, 14 Jul 2020 22:23:11 +0200
Subject: [PATCH 128/211] Start of implementing of hanno's bad OCSP
intermediate CA detector
see https://github.com/hannob/badocspcert
---
testssl.sh | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/testssl.sh b/testssl.sh
index 425f17b..dbfd4ef 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -8965,6 +8965,30 @@ certificate_info() {
# https://certs.opera.com/03/ev-oids.xml
# see #967
+ # courtesy Hanno Boeck (see https://github.com/hannob/badocspcert)
+ out "$indent"; pr_bold " Bad OCSP intermediate"
+ out " (exp.) "
+ jsonID="cert_bad_ocsp"
+ badocspcerts="${TESTSSL_INSTALL_DIR}/etc/bad_ocsp_certs.txt"
+
+#FIXME: there might be >1 certificate. We parse the file intermediatecerts.pem
+# but just raise the flag saying the chain is bad w/o naming the intermediate
+# cert to blame. We should have split intermediatecerts.pem e.g. into
+# intermediatecert1.pem, intermediatecert2.pem before
+ badocsp=1
+ for pem in "$TEMPDIR/intermediatecerts.pem"; do
+ hash=$($OPENSSL x509 -in "$pem" -outform der 2>/dev/null | $OPENSSL dgst -sha256 -binary | $OPENSSL base64)
+ grep -q "$hash" "$badocspcerts"
+ badocsp=$?
+ [[ $badocsp -eq 0 ]] && break
+ done
+ if [[ $badocsp -eq 0 ]]; then
+ prln_svrty_medium "NOT ok"
+ fileout "${jsonID}${json_postfix}" "MEDIUM" "NOT ok is/are intermediate certificate(s)"
+ else
+ fileout "${jsonID}${json_postfix}" "OK" "intermediate certificate(s) is/are ok"
+ fi
+
out "$indent"; pr_bold " ETS/\"eTLS\""
out ", visibility info "
jsonID="cert_eTLS"
From eb7b0c96444d1197a4d36cde68c4eeac8d95a71c Mon Sep 17 00:00:00 2001
From: Dirk
Date: Tue, 14 Jul 2020 22:26:23 +0200
Subject: [PATCH 129/211] add hash file
---
etc/bad_ocsp_certs.txt | 293 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 293 insertions(+)
create mode 100644 etc/bad_ocsp_certs.txt
diff --git a/etc/bad_ocsp_certs.txt b/etc/bad_ocsp_certs.txt
new file mode 100644
index 0000000..e3b84f5
--- /dev/null
+++ b/etc/bad_ocsp_certs.txt
@@ -0,0 +1,293 @@
+wXYR23sxE2HiDXuCMarfR4vLf/oL5YXAbeIwkiPC74o=
+/bNF0mk3ftnTQwi7eIVjKzDmH46vt+tedfgCTV/U4Yc=
+16BtRir8gNcRg9lKOYstzIJYNefGbaXkVAVXLwSwWl0=
+gptouX8R3uNEhXrBLrQM5QLuUmARIwFv3r8UIAkaQEg=
+VEULJ4BS+pGRFgDLmPMQCg+1gVKNj+q5i2/++KSMmY4=
+c50MOnG2w3fL0cQIrnzBlzLCy++GINY7Fsn9AYXfmnE=
+VQdJ/141xAfVFdmLMnUEvEhP2q4opxOv5OIoKYa+BOg=
+Qavo+alRqJkPvc0+FM9HnUJkAbEV8BcBibZl6UDDYyw=
+iKuWH2T5No9MTRMH9Z1OWcXlcPhSpsUROo/yjgQxUVc=
+zXQZjUwj5HAd6leYkjIbnk9HoIvYN0cQuJmq0UlaSzU=
+vEicbcK94lP1hto0E01mQLi1g6MSCJzhCTPEvAP8XzM=
+89kW0bcyAfBJ7afll/4KXM1XEaaVj7wLem9/pk96/kc=
+h6rZeKX+LulB5AaPmWPqKb2qWIeNJBIkmoLNIvgSbYI=
+REzv7dg/YxXF7Iay8c1jsdvyOHz6K+sPtAAVPyr5QI8=
+6keT4uuBTUMmH4Borv3ng7g358AhrBnI6bCFUfLWyD8=
+DLZoT2AcQW+ZKolAmRSjKgwgmXFodfX3jsDEaxtXCZw=
+fTW/BMhXKCtCLoUeqKYit10uzLq2XVumJZjB2koR1QI=
+TefMrLUJmUJkSVDyzIYTQBJWXGFNUap9MIf6wZaVihQ=
+kO5UjrrKyrQCB6YaN4zhhrlNJK58Vb/IMGXqlgcuKzg=
+EaJ2cYciZURctyWOsoRO5hTRR3e59vc76VMhIvIfrQ0=
+HLRwcoz1bzAgA7sOTrBiQU+hHU+X4/BhFwyWyIBx1xE=
+ysBfTwUIEJkybc8nxNlwqKPqkU5nkq2swQSWEcntQ7o=
+7AICWhoVeywCrEn1Wai2zwchJvg3lJn658Uu0YPakBI=
+VvMhZ/AD2PLLc4qzhsNcoVJlzCmpjuEGbNPhrFVsoVw=
+7r7fhG8dug6Iqba5qw/2Xwl/KEwGpkqTnujFyebzE/Q=
+U1cNBeQNxi+d+R0Vr7AVtWqqaAwgzBaObVfZRsnOJoQ=
+9kDlZDxAwfMp4QBDjijJV2ka+opT5AWjJvev63DCO8E=
+GwRlNTeOB9EKzaok7vziBCC7mllhFOtHXKaWNXdT6SU=
+fTOuYYzWJVM3fSU9LryihdhOmKkk2J+Y1L5P7jH5Kqg=
+wC2KMO1psvhk7Y+xpjo+clUoiSDKKUvcow9jiY+5GVw=
+BOy6j5K/90WMSl58aSYfx+LvUtWvVPvdkrFxQbvgZR8=
+48UkTRX44LA09QCQO32hHFfBZWF1uGYIx/zcVh0IG/Y=
+lA0vISoqOcyEvULQ9txPe6TEd+elqZIslrn17BTkpsg=
+WXK5vUcQF9XzJwW+6RVwNiZXX4snCjnBwxLH+SRsENQ=
+q/OAPNKTniaAPlIoCoH2fEbD4O51/Nux4w+wOjIaz60=
+N9IgpsdSJ5kCEZE0nBg/kXvhvoYmz5JrD9bgqGge4DE=
+QqtNnxgJRU6+wkXY2wb/YaqCibBaJj3+6WYtrJFmYEM=
+Bb+2YF1IUWpXG6+af/dTdhMEcNpe5/9oTCZy6qDAyK0=
+/UwrmT4DVukNT5+9I2He8aSYN4zuzrkt12/grX4sexY=
+k5BxSx2Qn6PXDdx2gbOPB+1OY1bLXHGRXRvc1I/jNfg=
+MafFefJNVWLNsgP6Fanyw/9dwfLmv3wL2V+8sBFMjSE=
+jlzqHRASUhwnpOEScHArx8mhFW8TUHPWyk5C7ugmJJ4=
+Irbr3umwptpcn6ztJ7+dzgmAPCr8EfdrXAvPR7f31WA=
+gP3kKCEq8MoKxTHu5u0t89PCpFV9/OhXBw/JR5IumyQ=
+P+i+OSoIaEuZ9JfmGMfd9aAqQom/nQjllQRZMb+6gU8=
+3Ist7lDdR4qxNcrCac6miFFVepEpq82Y31ITsj2/s80=
+UCx6hwNB175n2ybb+s+WR6/YmoVL+IEvpO9ww1bsE+U=
+vzmkJB9C1SI2iUSz3FPtnqpax3NeJC4GJ8DdW7pxRIQ=
+OuaZ2U6P69rLhtT5DUCQMzNHjmXgZVxDJFEZfjP6B/I=
+oloZVGgZ0EgADvnGV3xLzY0hVbHkNGpFmdbIt5eZ1KE=
+8YRCvt9wtNFSETVscrZZMyvtA//Tu6evqqvm3p1yMAI=
+2IiPSoT3TJdN/7Vzob9bu6zRcTuQUJb46wFQYr85bE0=
+BkNqyNDI4SCltfqMK83LLx+AWF55x3t+D40PYWjZxF4=
+Uk5bOlWNX/AafEYCahS1jHfPne+6aR6sjkoX+sKjo7Y=
+1B0jxRVZ9l5cIlA9enq/XNll7DnGHGmKfZjXl69we0g=
+XIDlafzuk/FaK8BDUQKyagT1qh7JkSwToFiBwarVAtI=
+3gqS5UNbYTII3ENezHFYvyj0IKk+CpHVlllyBT9SNUk=
+IcrbfNgi6hO0luJau4FRx/sA77se5FijtKTzwWvDwW8=
+7T23SNbXju/wuUUrxqAuA5A5xVB1pDkyO4uoX7Ibndo=
+SyTFIcR2AOg4AKP/DC1Y3ALIF3732ml8WoDB1IZ6Zt0=
+XbHSLXBmhPBxnokC+4azRrP8nk0aH5IoOkiLw9GgSEs=
+P3hQJbzPrKRwGhc0zg97MM5BBpQsjZL0G3CwZ+1l01Q=
+FQc8a73HRpmohRjCelfJVuXiPWypYZ5SGkaMeHPeT4o=
+qbVpjFJjvv89YHINwYRMuV0W8G4EJovOO+TWAoKwHvk=
+o38cCp3HIpi2H5M8tUxlQ4Y3sm2+29HmuAgnnz2tMOU=
+Pq1PcvBvEFSIHSco3gM6jhP63mvRZQhAGOuUPBc3jao=
+2FU6KIDpa3qkx0E92QOv09WAUEaV3SahaP1IzOexR0o=
+UH22DSY9PQnSg94uOqQ139h3XlK8M1cC44Mru1fsHL0=
+Uz/pfrRfztJASeQe/p2yVKXdnZDf1TyVEsYgftsh2Cw=
+0o20NeMSEqO9zPh2IPZUS5mpwCMov5g+iC/QYnodEw8=
+X2yqRKRmPEQd2SyLZlX7+Xz24daTTbj1+Nl633Az+qw=
+X79u1PD4etpl+ueqq0rZ4bWlhpOa7fs5pJJr5/ZcZQw=
+hTY6JMsbZubPYkTofSQ9u4MG9gc1fGFMucTCJKDgQ1g=
+fggrvFaXaxWdRpZUCpa2AUhhS6m14psgNfeJvs+/Blc=
+vs/eEkzt00TZJctV7dpmLZqcBoj6mghwzj27baQxPk4=
+T/QE8C4s0AGI8V0cAPS20eOLWjlc+FMU6uuoVbamS3U=
+8i22V6GpKYQavKxSZxpc7op9BpWGr4XOFt4rBd2iIlI=
+ON7T/2gnV5AIr0iH65aYo8+pJ/qO1Z8GugkPuaY+LXc=
+cFYQcjyWE/ZBMYHK33PVEHG9dh/aSRQj4avQAVAbZPM=
+lylXMEAxI07Rdnn9y5dVbWFz1fK/Dm5m1hJoDKbndoU=
+VnmkMeedTrnulnxg2HA8fHj0Q/cduXFX5DBZ3kLYUN8=
+ziMyOQIIdCoaymUTl0xMnbJpHq9FaLUz5KF+1d2pc+Y=
+x0It4hzryS7K5r6dzX5xHuZQ0wrtcR+7Dfayx4S2xPs=
+OUzLvAs1lcoN7UAHL6+YY27QIWma0olFZIeRZbW11Mk=
+xhkwd8YYnR37v4E7h9x8vwSYrPcniHvH7FQyCQbem8g=
+ApN5EY5XdSJsVNcYKjZ6JAtRdw9QEbs1F3z9F9myRFo=
+ThB8mBtCrL5BwBBn4W1E22SBTUGT5XIxfqBLh8ecR18=
+1Ia/o/ANFl7iz2Jw/afQCBfljNot9Polbg8usSLPjwI=
+6+h7tBiFAnCfREBVJZq7IrxRuIyQhBmhNVnfyO9mMNE=
+rxiY1/Bjh1HAddAULU4qDqcx/GIjJPFT/hvztq/ZrxM=
+LgGRdRygy6gcOmM43uGgK41rzE8fgmG4CbzOerrxpD0=
+TCQc/j0/+2DKiNawalUqsc8O99jS4I2hUoK1UZLrvSk=
+Yy/Wl7rK8e0jJRfsm3Yit8JeFEiwzGJrMyhnGeNRzoo=
+OALkJFFveO6sMpqumx9gpBLb4dWwldesncDc3ePB9fs=
+8DdiFAXg81ZQfiOfrdZHhC07UIV8PP+ECFkXT3L2/Rg=
+OTuLFcq8OIb7LkFkldY8i63Y3K+HVSB2yKCpY3wk3kc=
+d+rEdkU8tzIlf/FmpevRZWyx9nO2jijfQXdBM5efoqQ=
+X/rEPg3cW0rytpb2vE236R3zFLuP4NBxOgsaetKmj6w=
+FHxEf+64YgK1AzFPyvADa+qu9DfDm1azWOxEap0gOH8=
+Qs/dpvZguOW0wcQRllpFGTElWeMmL422nS2uF7JrO6M=
+e0ZNw4T9saUlwswnntDHz60kvs9yxGp9cJPRV8IXYH4=
+rgO5rRcQaih4WDCx3NY2eXxMZNgcuNFhWV26+DQz5kw=
+rkGVTarL/T5bn9cHj3tvquYbVZ7Oee+O2FitjAIqejw=
+Fmz4lA9HJR1VUo7Z5Z4melkqToo43T1on43LpknpS3M=
+0Dnu/3EIjMDxagWo/zxhYQ4UHR6FCsfhH3cT7uiMuVE=
+gxB49+Ifpx/iT5HXGOSlcynv5vSHGxJhFdXSc7+tn3Y=
+YmQD4Ho5PnB8iKRwRQSRcEsSK2TRGDI5F91NQfwGPDg=
+V0k5vjI5lVaapElYqzCJ9jmpyG45ezg+9g6ZRGSbQwo=
+8O5ZFO2UxyUtBYtOOYCK7m+o9izwl0+31tKp3xbjqH8=
+2/EmjBPmRa31jRYmxDNr0/qFoaTRAyDDHqDn0KZgiJY=
+zYmOTBarGJLzY6Rh4RAzPHTp3Us+Z+IjZMzAMOu1718=
+5UEx8Tn8I8Kcm9MiLhrnEVYZTK3SgXIt3mEwOXl46GE=
+EcYS0zK0wSJCUqb+L4o5bbr0A9+cy2IFbeOZWIBKuC8=
+nHyngZxD4CplRlj7NmUL2KPyKpuFNe81fiu8i5IakOI=
+v1SpOD9EZi517KIusOR/LCNeXRGKfoluyLZFkWy6aOk=
+AaBwYTqusQLERGiiMVWeO2bRmC7GQ1iRkJqeazZkI9I=
+prt/LZfwpe6H5EaWrtD6IQWjOw73Dc9ocygcbroIE84=
+lu8zwkqLHxbPFw9DIh4X5ir/aQqLAU8kUpv+s49AoNo=
+YOh1YzkH5QH7JqEK+9lzAhxTri9gGHFFhxYOg9UuGaI=
+3YcG9HnxHbxsapDBI1j/oAo3MfC+0rG2UpBIMI3MEuM=
+nk5sCNP756rPK3o/wrrD1swblHU/PJYVIj1qj2txcj4=
+JTTsG9dMPBt2YaDnzCjxvfKoLM05Q+6q3Nj+2VBV6tE=
+z2TrVpvtIKtWfKZcicZOoeeIxmBHoO8exeS9LlbKwnE=
+rUcj6rVaV0U6X1W/W/dvygi1p/I5tCabOqm44Uk1MB0=
+nM3gEf9hnDId/o1kkM2N4Thn0ZOpte5qb1rED2HXEcU=
+gFp7gGAab/tKveY170dwXq4XYg3vnPr2FGK2LXxLiGo=
+cWCg2EGxxcEgoIyS3iMmSD2Q2b/OGYS91v9KtrfSc8M=
+qQ+X1rXHYS4CDLvPB0YgDJZ24YKMWoUL5ryIjDRfpLU=
+nACcovl+osvygXNgDe9velTFZkWZuKtQDuGIWlbk8nA=
+rJWg/X4L9eG+bwKgQvDwmmV6euEnLt7FBatrmmEWeCw=
+ZAF9eLXwwExBlzXWpKbVLsHSARUkOw18dFB+JX/6SkA=
+OGTWwQAfAMSqgdzbN14qC0348ooaqZ+h84t0vOgtWxg=
+Yv3R3U29JpQAZqoDD82kUbK8IUP+zmWoqgP8C9MR8P0=
+vL0E1K7ZYsnSWv4M+vhjjOFDFlKYjsUhcynnVZrDxnE=
+z4mkHf7l9xdA3vYCc13b8d6+DLgW1zmA2aWDxYgc53g=
+OoglMMA+phXl702tvXyGYJEvqT+vUIhxb7Rqjh/6khg=
+HJJmkCoxw5QbUG1E0NTQbsnbdlXmX5VXZZ+rdospCxs=
+fLiI73QNy/wMIL2kTywmGfbQ1FmPuTLQN9ryeAd3c6U=
+WONo7k1hW4iOEcVSsss7Rp8wrEv0jYs3m1EAnAgmQ+w=
+yXgWNowrekYIszRNvmhI2L0SEmDC952siskMrhfI5Xw=
+O/HkFQPH8CPQ1Mr/vo5RJiwscxC8bZbozI0UOmAK7oA=
+PoS6Q0KQhRbndXPAmS8JecoITkaFaB/xlcy6iiKbinY=
+jZz9mPUrHCxvTpztPR2ZWSfvsNVjj73wiDTQ9yyikRg=
+s5YnQBRBzrQv9sf5g+DyqSMNGHdAPJ9AllyHV86/19Y=
+ePE8SR4TAgaDfDqu2lXFby1dYN0NGXkQhD9G1freNek=
+4qtqY+hkbg8jKCDtBH29RICWdFYhFJHJGvonr1qVVbk=
+AFHJiSTyOb1Jq4yPaAL4uc9K1B6zJy8aNMDNbWHcs9Q=
+j0FFvUjMm/ciklkj59LQnMy+mXOlODjKNvlWH3TownE=
+LAlx85e6hzewM1hFVpBllJNqzhdTpaS+Xi8RtCukt1k=
+UVh8hnv2bzXs5VSgjgpBwTuLvZtZ0mLSBKcDCaZyvuY=
+VbDNLMrRjiWXfZBtrJ+ouGQ9eiWOezg38RV6E6wZ0Yc=
+/T5EKAyNy+jPjPVVEeBmnIU3lF2h+nRowOpStobdW2g=
+dNmS05ELz340uLXNKPkerrT0Hz2mOU14uMQ2ctQ/Tw8=
+CrEV3p0Saj1OoQ3fCGPMnYlWdE63tMzat+V9agblhRg=
+e4X20IWbJAozYzdKEYHgEgIQR9ztI1KoQfblW10HfqU=
+QlIC1Lv9qbeZ0Peqkn2UT0LMpCN8L8GYdbkHXes1piE=
+D3UQNcGOHTkunMVXxX6UpV0S+7CG8mpFKeJhNiW/0Tw=
+yErgHs0gLa++7h8OZ5ZG3ozNZT14RnGKO19OEpMkKYo=
+UrY9G9COg73HI9ex/pYs7BgG5/U/dvLHCFjKNSk6HcE=
+4KZw9PEFfpF56dtF4zPON+PuMcNJnxxYSlh72aX1NkA=
+oBmBHkNpykxiqqgKFUlhPmD2xc7Tg6+ded+Pjxk/Hf4=
+Af1hSHk5SzrhSSUvwVaYZ0FZzlVQZp/5EokuGYNaHkw=
+gyJm1rqMv8vyjgYUoB2fTDm45B98h9IHfbtsA4QMqcI=
+5z8fGaRFmmBnpF6E21hdbB348SpznXM/WyiZZUbxh1o=
+jAFyH2+p0h38KDZvUkNOqLRL+IQ/HEM7llv2WTNE6zY=
++Hiz3yE7CBe/8eXvTozXybV8gP/J+KcwnqRqr1QLrhg=
+tA1oOJ/QQcVuKT+j1X19t5LdALYuvf8ZCw4mRAcsk0o=
+Q9tljdTkAg+LXGvXEH4V4jNFmiJs0Nd++PcrKxzCmv4=
+oK8UGM0U9rJBXsYxbH1Yi7JdQwo9bQJvV94g+WXqvdw=
+weRTSNcUy0fbssC5uvm6HyfkIAR82nqLaTVkMATKq5c=
+jmkw14oTnzgnFGpZRu+f46dzmbL9DOuwsu0I7hih11g=
+2FLeXQmAht/ppvPXKNUmGGVYfEid5nV1PScjdKXW6fw=
+6Mpy7LmIXCTqKd4OrJdwQnjSoeWbZmZtMn+wzGvdkS8=
+SHR1jWVj4EM7HtzufMxdnCqtjroSvLBwRFS7Tvjq95k=
+tc/msLKqhhoLNnwMBTlaU4rUk6nfARVEqO/EaH/bLMg=
+uWj7/D7KKFqtw40jZ3JyQf99NzPxJ4+KT1DsyMDvHoA=
+/x3SHxpdC0Us2WnPSqVTg1yr4Ck8bHsAnxRaogLALIs=
+gGoqp37b08dtj9Bm37XMMxDzWbAQLOksD67BaqQ//wo=
+M81TfgCducdYpWhDXAZwb58BE4BU4gud3JPgOXE4qms=
+jZkhf/gtYOTfWb6KESFiXN/8TyLyHhJjod8G0twLVA4=
+xrclJq9F1orhZnHp8cJFMECNk4+PBEfhEG4vKnDTrSE=
+YPBm3Hik4ukpocjtEC7bcH3wMYH4L99Q1TpS2sNVxls=
+dkoNhNVVLNWHLHNGTzfwIXXNpwWIECsTraKgGZ/EA+k=
+Ko2+vTr9uXK8H3fP576FBoiM/tNe38VMuqY446WrPv8=
+W9DA1XmAFWfzOI/mRO95CrMeLbIkbq9MiB5aV9mgpYI=
+xbZ5EGlYFS+D+1iG3cQfB4UZPvZ8aXW+PlCfF/KbeoY=
+kFjVBl+PPppjqv5c6Jp2RHCw3vnc87nsfQWH+riP66A=
+1WAk8MXZI31+CyOFBn2O+I7dro7BmZafXKoszClp2YI=
+rCiRmOxpliiAP4hD3WPHZOhWuCdM957bjtjpmXlpf5U=
+x0eO33MQG6Eu7N3zSMd0f/94nvtAHMjcrfrglClUPlQ=
+4P+T6QVsSO3ca2jpTzFcOiIp6c4krzNjTTTV7wMjMok=
+Qf2VNoVpPOZ9DSPMkcoXkmHWuZSLIdO75fet++U5gt4=
+3oPj/CRfawSJMeHIE06qypb6p7HvHROV86Ys4BSwUYI=
+BmTx7u7RpzVXACAdL0Qx3EOwvOqxKajKv9Tth9BDQe8=
+cbPtjO7MwGOM0gIrQm6SF2YnHeYjZ8fNhS7C8eERHnY=
+zgJQ8qnxj2jV/5RKTGWfZpL3PgNpzswhX18lfjIlmHg=
+t3h0inkrj5HwSwG6/DGjHtfvanEq/4C2YQ2are4get8=
+iGWwLhQDkWdWEyLIwewud8R89763MdL+HLusv3LRdyw=
+6Va4oVaHH3HUNMrHjr0j1Q79GrkHYc5DbnnQOu0TZkw=
+wXOXph2a+dKiKczyYqsdMrSph6E0rlvZ3k/BVfAN0W4=
+TzBNg2b/kJHt121TO+1Vko5zt6qtUuNbhudip38EaU4=
+DzMgaSsXqRbOVPfk2nv+Ui+zGxrCHgiHdrN8B6NO4qg=
+4MJ6zLmueGBbYeeCbAIdkczS92mljEvW2lRgC5njVDg=
+FslKjMwVyYOCW1vT8txo1pTIoyDyMo7NjJylfeUdoOU=
+AfiXESH0ED0wvkI1zX3A7ubGrhL8p3UISOoOLhP8JCg=
+JbrMQKU5K4Kq3qBJA5BaRnEh8oIg5vL34P6YKq/BT6Y=
++5U8T8AEWEbQJJHI7M84e6NDR8F6uw6m1Z9t5NLx6gQ=
++1Tuqbzo6eqXghVPPUFCd/twn0m5R9c5eKwnhUbCzgM=
+yKk01qjoRfemX1yPcf5E9Si4XjJldaDWeTnHTYDNF9g=
+HJQqIqAWoeVVna537FzoZx+YrgukrC3CWUGOjh6flK0=
+z3O1LQQbcwm0OdFiR0FLkMnSbkTjh0ijZQDVgptRh/k=
+v17fvuuFmZxRacvz9NtjtnmtLh4icvw3lfn5kh5tBIc=
+oBM75bFOAjEKLUvqtgEJTxGU7ovW/Snd/nuTR0Z8Luw=
+ygBap14zWUvR3txYTh505RmOux3oiSntTz4un/zjhzs=
+I6dHBNd6A8/T/xnmLFAISCFObGD9Kq733Oeo+e6fkjI=
+O5Zo9Z9V+jg4/Co7gLf5tbE9Gkbx6qbgvP8ExUGYBWw=
+WkBVNcESoKga8NKsyjw/m8Gmd1hs28Yzy09fd44aNVA=
+kVPkQg3cfrTm6GSqA3fa30CC7NNQUhE2OOBdPClrwAY=
+3QOOh+C00sNpaA0954Y4qzn8HX5QYymWkhEBdo241Ng=
+TmPxQkAahPikc9bd7jQaFh+tqG00MMjCxTRTZBPZ25c=
+cW824XTQWVrowV39agxJjpe2plWz8g/lSIyo+exgktY=
+mk45jSqmA/7RCGPANi4TkNl+wS+gJ4/XgqqzzdV9wh0=
+O7YMQ5NGQUpA4twtHW9WYiV40rHygyR2fBSQFaY/80o=
+9dLSumgXp6mqDiE1S78Ob5XF4ofuiM8vJ58P/sTtrBU=
+cBtDKsDN1NnPlbS4hMMr9cypDUTgFhq9E7k01o44BHI=
+xMfENr2I6OaNsAKX34OsyBnhmGOboAUiyOMkWHaJhSM=
+XN2AnPRPX4Zl6sFQVVBMWwa3h6wYKUUFvbq0p35Q13Y=
+RgOPYyYijNtWYZxSJmYT2gTIykmeDQOw7c/8EQ1c/HA=
+7cc0xQFQHceidEj6AsdJMfhXi/KXsXPzS4QegsZpGSY=
+J9b9r4ApeEbf7/guf1i5pIrJ4+6ToRKxu+JD7hqXRHw=
+yBksMve0nH8yocoAFZWn+eNsnnIFjW6qG6t3UqjBZxg=
+vkCBOGmrJ6Bx0SrWqIMFg+vDthjj8jRjWfSxGhyUNO4=
+HoZCeMIIgbZxwMbS4UthFQrR8Tz5LG7BS1UNy8R+FUE=
+VMN6joU/0dY3jTeLk5MH7DIaMcwaWonnGAYzvBPxh2I=
+nomO0D+kaWlpDa1zxylmdQRf+bWgEAo5m+uENamPUYU=
+Sw0TktORVzUyB6ZMyxRoPd6dLO0ftYsW4Di+VwfCeBM=
+eqRdb1sU2rHGhEwZwoBOFLWBHm7eHwKwrvBlp7NZxo8=
+lMZj6epcJ+5PZBJ/m0JYY+mRqeFWwH3xoAgDrjF2QWI=
+Logg3A6vrj1tKFwFfs4URws3dDiwAs7dTHK080OlT0M=
+TnB4Z5RqwFNDxrqP8SHqZqdYA3kTJXqO5JdDUNOaEDQ=
+wlxO28NuP7fD2Te+6fLSnjavsHz6MYgmLg1f3JGeDXc=
+Xn/LnJe9pWmTsWWNEgIydh1mWjZEU0MA+mpb7F4NV5U=
+ETE43XshZyWEAjji1+7ss3ONsTkGSyTLhT/CcKSeYFc=
+vjPRxX693ZJ7V722BL5Fe1Uv5Wjn89y6CTw57Rwwojk=
+g/yJGzUNng1+vm3Spr/j0LD0ZT/KBIYVpd7rvAOaP2Y=
+VyZLgqhk26HBHvP4CruUysNmBmKwwi9XH/mTs/vPdvs=
+dKvl5czrdUkf9yxM8yVAXYrb/jkOGJz0MLpg5ieYh44=
+wv6s1nSHjHsMIyWi7O0KMz23eAqG3+w3WBAO/AEBxmU=
+ndwuDVW0YeDHMigoLfVrK+8iTKI4VoHRe26MB3hSVzw=
+MG6XOeNFj/RUaHe3BLLjkF5YsjXWTjL08CaskbcpXRU=
+/ToPPdRIAJK21FBHPeuSAaCzCKiAeDOjxzj4oH64HtM=
+Cqny59lccYt9HrfM29AWToYFeunWaSK8YPmQP5Sg8O8=
+9XCaLS9otTv29kW7F4rflTRvif2lxjv94IBComSSqrI=
+66NMexCWcWFMNn4d4HUSTDlUzhn4X6z2EJDsMZ9/Gn8=
+Eo3tGorWDCS0JU4x25T8Q5K/k+1UNEcqpDoLmFYQYGg=
+txawif5OU9Gi73ulesheaOxyLPYQUsJaWWJq07FcX0A=
+al9MFnjKZeWfBg1Xzf9mUGUxSGHVOo59FFDKktlsoQI=
+q8hnBsmNa/ZzcvkI7AGt9jGxkdczron4ND6wR7EIFEs=
+QEfJ1pJgwHITvLhgin7F4oOKVrefZ4R4EurAd40NJ/E=
+kl7n1aIq1/vpurVNfI0LmnT341qK9q9kXi6MNRmnCS8=
+8GjeqhjMAtWovjXLgzgyeRApH25i5yFqk0dkoaukqAA=
+sf466/ljp4gOdLCwVWaB6osczOPmmn07EKaKy+huSKE=
+//4HdQP9cvDlM4sKe04hjn0f+C5JPn6FKuUaocdYXRc=
+lcanR90Lx1WhlBgn6JS4CDWSJBt5JUHi6xsw+5sT9X8=
+DTF2xY8yGqNMV8jffBfR9OdseX7BFsnx1pd0jtH859k=
+DW5GeE87aU6cdQZ4ZBe8b4f50vc9GbXoCBYSshE3t2Y=
+l4vPOcPDqs7+EEj6A2AoPcLr+lFQAkxeN4UU0+decpU=
+LYGa85fiidxBcJxKr22jsZBHScN6mVhgdFgDcW19VpA=
+oaBOTPxW/RkX60gfxGYpouRmVnVvoI4iSH9Utk4co+c=
+Zj/elPiDah/r2DvoMQl5MS1l/4wbcWOU5o9B2COWwfg=
+SDlfccwm9kJ0vQbH6xWR+dTsYrZPpsFlMfPLcsJGnYI=
++AhlYjZyW1ZvByHFGBWKZ1bJaQPLcetI3dqO3f6g8mw=
+TngnF2hJQIjtH5uycSUxq10TjGxZtGZQ0oWzWFjmexM=
+QqIfNyhYBPLnNgdctUh0Nozw4hEAiLPxOEEu7IhZCVQ=
+RnFuv2oirqHfH5fmKl73CVEnzkVQtiQuumkHr8XEgs8=
+iH1/Het/BxLIWvq/UMrfib8C6xPlUsv1LXtd8/IdsNo=
+VbgN72B/iOMcWEBn0J1DNE2UEXuvZINlhHsc5bZ2d8k=
+/DqYk44u07024NQfGFF2STIpBrLmszaQiRMlquzRlkQ=
+UjV1BHNxu6iCY+WrXe2PawaVxdKhkqbdEUBsR2ujxy8=
+KlCKX+YXPE6PASZpShpqcdkABFH6MdsDO4cFiQRB7MU=
+/S8zJI85ZFZGh5gCNaXwvLOrVi5H9AT3QuUzQsU3UoA=
+U4pFqvkAPU05iLv8+fhZsyXOX3ddwGASBQWFF/m8FeU=
+50rUSw1W7r45uxhcUqub7+T3WJm2qBQW6RA9XCm/J/s=
+53rALbbqoOmmtXOpmHDG3029uDOd2jvEB4b3DivX9/Y=
+HpU+FRI6leRwRL+vBrGXT7mXa4T0Nx69d/itge/QXAA=
+5Xu/UHn5gpO0FC80iXLmjjUeUrkDc/BfRvCcyzCvW/A=
+vUQgxZKm9/JSromBJOAC8bnP4fJTiGTVazSntN+zH8g=
+CE7KcKm0Dk4VY+NXdrcW5BCpcrsn7VHCSMSNMkL6ja8=
+bsjTVRvQRUsMxLnbh2Nmrgh2TF/PFbAPlBG94w1TNq4=
+qONS2wyOJ7rlg9AVFG6Led7gkdVjj1g6DEQvO/Vd7rM=
+LRskT6zq+tlHVbXpmqv3rJHFmdpzv6Rh7uuvtLlptck=
+6tyA999jBWDMGzU/aOpmAVnOlm4i1ARYh4B4fAR20OQ=
+IuXm21yuQo7alq7QVk4rl3DsoswCUVjjep3e7eMfReU=
From d07d1f102ed233e76e697beba4d4114f3e1b234c Mon Sep 17 00:00:00 2001
From: Dirk
Date: Tue, 14 Jul 2020 23:42:06 +0200
Subject: [PATCH 130/211] Works now
* open: generation of intermediate certificate files. We do that
at several places. But for some reasons I do not understand currently
we remove those files.
* we don't name the offending certificate
---
testssl.sh | 28 +++++++++++++++++++---------
1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index dbfd4ef..6bd0294 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -8314,13 +8314,14 @@ certificate_info() {
local certificate_list_ordering_problem="${12}"
local cert_sig_algo cert_sig_hash_algo cert_key_algo cert_spki_info
local common_primes_file="$TESTSSL_INSTALL_DIR/etc/common-primes.txt"
+ local badocspcerts="${TESTSSL_INSTALL_DIR}/etc/bad_ocsp_certs.txt"
local -i lineno_matched=0
local cert_keyusage cert_ext_keyusage short_keyAlgo
local outok=true
local expire days2expire secs2warn ocsp_uri crl
local startdate enddate issuer_CN issuer_C issuer_O issuer sans san all_san="" cn
local issuer_DC issuerfinding cn_nosni=""
- local cert_fingerprint_sha1 cert_fingerprint_sha2 cert_serial
+ local cert_fingerprint_sha1 cert_fingerprint_sha2 cert_serial cert
local policy_oid
local spaces=""
local -i trust_sni=0 trust_nosni=0 diffseconds=0
@@ -8342,6 +8343,7 @@ certificate_info() {
local response=""
local yearstart yearend clockstart clockend y m d
local gt_825=false gt_825warn=false
+ local badocsp=1
if [[ $number_of_certificates -gt 1 ]]; then
[[ $certificate_number -eq 1 ]] && outln
@@ -8969,15 +8971,22 @@ certificate_info() {
out "$indent"; pr_bold " Bad OCSP intermediate"
out " (exp.) "
jsonID="cert_bad_ocsp"
- badocspcerts="${TESTSSL_INSTALL_DIR}/etc/bad_ocsp_certs.txt"
-#FIXME: there might be >1 certificate. We parse the file intermediatecerts.pem
-# but just raise the flag saying the chain is bad w/o naming the intermediate
-# cert to blame. We should have split intermediatecerts.pem e.g. into
-# intermediatecert1.pem, intermediatecert2.pem before
- badocsp=1
- for pem in "$TEMPDIR/intermediatecerts.pem"; do
- hash=$($OPENSSL x509 -in "$pem" -outform der 2>/dev/null | $OPENSSL dgst -sha256 -binary | $OPENSSL base64)
+# There might be >1 certificate, so we split intermediatecerts.pem e.g. into
+# intermediatecert1.crt, intermediatecert2.cert.
+#FIXME: This is redundant code. We do that elsewhere, e.g. before in extract_certificates()
+# and run_hpkp() at least but didn't keep the result
+#
+#FIXME: We just raise the flag saying the chain is bad w/o naming the intermediate
+# cert to blame.
+
+ awk -v n=-1 "{start=1}
+ /-----BEGIN CERTIFICATE-----/{ if (start) {inc=1; n++} }
+ inc { print > (\"$TEMPDIR/intermediatecert\" n \".crt\") }
+ /---END CERTIFICATE-----/{ inc=0 }" "$TEMPDIR/intermediatecerts.pem"
+
+ for cert in $TEMPDIR/intermediatecert?.crt; do
+ hash=$($OPENSSL x509 -in "$cert" -outform der 2>/dev/null | $OPENSSL dgst -sha256 -binary | $OPENSSL base64)
grep -q "$hash" "$badocspcerts"
badocsp=$?
[[ $badocsp -eq 0 ]] && break
@@ -8986,6 +8995,7 @@ certificate_info() {
prln_svrty_medium "NOT ok"
fileout "${jsonID}${json_postfix}" "MEDIUM" "NOT ok is/are intermediate certificate(s)"
else
+ prln_svrty_good "Ok"
fileout "${jsonID}${json_postfix}" "OK" "intermediate certificate(s) is/are ok"
fi
From 851cd564e625c595412c34fdf3c7c7489962aa6f Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Wed, 15 Jul 2020 11:52:19 -0400
Subject: [PATCH 131/211] Check for bad OCSP intermediate certificates
This commit checks whether any intermediate certificates provided by the server include an extended key usage extension that asserts the OCSP Signing key purpose.
This commit replaces #1680, which checks for such certificates by comparing the server's intermediate certificates against a fixed list of known bad certificates.
---
etc/bad_ocsp_certs.txt | 293 -----------------------------------------
testssl.sh | 7 +-
2 files changed, 2 insertions(+), 298 deletions(-)
delete mode 100644 etc/bad_ocsp_certs.txt
diff --git a/etc/bad_ocsp_certs.txt b/etc/bad_ocsp_certs.txt
deleted file mode 100644
index e3b84f5..0000000
--- a/etc/bad_ocsp_certs.txt
+++ /dev/null
@@ -1,293 +0,0 @@
-wXYR23sxE2HiDXuCMarfR4vLf/oL5YXAbeIwkiPC74o=
-/bNF0mk3ftnTQwi7eIVjKzDmH46vt+tedfgCTV/U4Yc=
-16BtRir8gNcRg9lKOYstzIJYNefGbaXkVAVXLwSwWl0=
-gptouX8R3uNEhXrBLrQM5QLuUmARIwFv3r8UIAkaQEg=
-VEULJ4BS+pGRFgDLmPMQCg+1gVKNj+q5i2/++KSMmY4=
-c50MOnG2w3fL0cQIrnzBlzLCy++GINY7Fsn9AYXfmnE=
-VQdJ/141xAfVFdmLMnUEvEhP2q4opxOv5OIoKYa+BOg=
-Qavo+alRqJkPvc0+FM9HnUJkAbEV8BcBibZl6UDDYyw=
-iKuWH2T5No9MTRMH9Z1OWcXlcPhSpsUROo/yjgQxUVc=
-zXQZjUwj5HAd6leYkjIbnk9HoIvYN0cQuJmq0UlaSzU=
-vEicbcK94lP1hto0E01mQLi1g6MSCJzhCTPEvAP8XzM=
-89kW0bcyAfBJ7afll/4KXM1XEaaVj7wLem9/pk96/kc=
-h6rZeKX+LulB5AaPmWPqKb2qWIeNJBIkmoLNIvgSbYI=
-REzv7dg/YxXF7Iay8c1jsdvyOHz6K+sPtAAVPyr5QI8=
-6keT4uuBTUMmH4Borv3ng7g358AhrBnI6bCFUfLWyD8=
-DLZoT2AcQW+ZKolAmRSjKgwgmXFodfX3jsDEaxtXCZw=
-fTW/BMhXKCtCLoUeqKYit10uzLq2XVumJZjB2koR1QI=
-TefMrLUJmUJkSVDyzIYTQBJWXGFNUap9MIf6wZaVihQ=
-kO5UjrrKyrQCB6YaN4zhhrlNJK58Vb/IMGXqlgcuKzg=
-EaJ2cYciZURctyWOsoRO5hTRR3e59vc76VMhIvIfrQ0=
-HLRwcoz1bzAgA7sOTrBiQU+hHU+X4/BhFwyWyIBx1xE=
-ysBfTwUIEJkybc8nxNlwqKPqkU5nkq2swQSWEcntQ7o=
-7AICWhoVeywCrEn1Wai2zwchJvg3lJn658Uu0YPakBI=
-VvMhZ/AD2PLLc4qzhsNcoVJlzCmpjuEGbNPhrFVsoVw=
-7r7fhG8dug6Iqba5qw/2Xwl/KEwGpkqTnujFyebzE/Q=
-U1cNBeQNxi+d+R0Vr7AVtWqqaAwgzBaObVfZRsnOJoQ=
-9kDlZDxAwfMp4QBDjijJV2ka+opT5AWjJvev63DCO8E=
-GwRlNTeOB9EKzaok7vziBCC7mllhFOtHXKaWNXdT6SU=
-fTOuYYzWJVM3fSU9LryihdhOmKkk2J+Y1L5P7jH5Kqg=
-wC2KMO1psvhk7Y+xpjo+clUoiSDKKUvcow9jiY+5GVw=
-BOy6j5K/90WMSl58aSYfx+LvUtWvVPvdkrFxQbvgZR8=
-48UkTRX44LA09QCQO32hHFfBZWF1uGYIx/zcVh0IG/Y=
-lA0vISoqOcyEvULQ9txPe6TEd+elqZIslrn17BTkpsg=
-WXK5vUcQF9XzJwW+6RVwNiZXX4snCjnBwxLH+SRsENQ=
-q/OAPNKTniaAPlIoCoH2fEbD4O51/Nux4w+wOjIaz60=
-N9IgpsdSJ5kCEZE0nBg/kXvhvoYmz5JrD9bgqGge4DE=
-QqtNnxgJRU6+wkXY2wb/YaqCibBaJj3+6WYtrJFmYEM=
-Bb+2YF1IUWpXG6+af/dTdhMEcNpe5/9oTCZy6qDAyK0=
-/UwrmT4DVukNT5+9I2He8aSYN4zuzrkt12/grX4sexY=
-k5BxSx2Qn6PXDdx2gbOPB+1OY1bLXHGRXRvc1I/jNfg=
-MafFefJNVWLNsgP6Fanyw/9dwfLmv3wL2V+8sBFMjSE=
-jlzqHRASUhwnpOEScHArx8mhFW8TUHPWyk5C7ugmJJ4=
-Irbr3umwptpcn6ztJ7+dzgmAPCr8EfdrXAvPR7f31WA=
-gP3kKCEq8MoKxTHu5u0t89PCpFV9/OhXBw/JR5IumyQ=
-P+i+OSoIaEuZ9JfmGMfd9aAqQom/nQjllQRZMb+6gU8=
-3Ist7lDdR4qxNcrCac6miFFVepEpq82Y31ITsj2/s80=
-UCx6hwNB175n2ybb+s+WR6/YmoVL+IEvpO9ww1bsE+U=
-vzmkJB9C1SI2iUSz3FPtnqpax3NeJC4GJ8DdW7pxRIQ=
-OuaZ2U6P69rLhtT5DUCQMzNHjmXgZVxDJFEZfjP6B/I=
-oloZVGgZ0EgADvnGV3xLzY0hVbHkNGpFmdbIt5eZ1KE=
-8YRCvt9wtNFSETVscrZZMyvtA//Tu6evqqvm3p1yMAI=
-2IiPSoT3TJdN/7Vzob9bu6zRcTuQUJb46wFQYr85bE0=
-BkNqyNDI4SCltfqMK83LLx+AWF55x3t+D40PYWjZxF4=
-Uk5bOlWNX/AafEYCahS1jHfPne+6aR6sjkoX+sKjo7Y=
-1B0jxRVZ9l5cIlA9enq/XNll7DnGHGmKfZjXl69we0g=
-XIDlafzuk/FaK8BDUQKyagT1qh7JkSwToFiBwarVAtI=
-3gqS5UNbYTII3ENezHFYvyj0IKk+CpHVlllyBT9SNUk=
-IcrbfNgi6hO0luJau4FRx/sA77se5FijtKTzwWvDwW8=
-7T23SNbXju/wuUUrxqAuA5A5xVB1pDkyO4uoX7Ibndo=
-SyTFIcR2AOg4AKP/DC1Y3ALIF3732ml8WoDB1IZ6Zt0=
-XbHSLXBmhPBxnokC+4azRrP8nk0aH5IoOkiLw9GgSEs=
-P3hQJbzPrKRwGhc0zg97MM5BBpQsjZL0G3CwZ+1l01Q=
-FQc8a73HRpmohRjCelfJVuXiPWypYZ5SGkaMeHPeT4o=
-qbVpjFJjvv89YHINwYRMuV0W8G4EJovOO+TWAoKwHvk=
-o38cCp3HIpi2H5M8tUxlQ4Y3sm2+29HmuAgnnz2tMOU=
-Pq1PcvBvEFSIHSco3gM6jhP63mvRZQhAGOuUPBc3jao=
-2FU6KIDpa3qkx0E92QOv09WAUEaV3SahaP1IzOexR0o=
-UH22DSY9PQnSg94uOqQ139h3XlK8M1cC44Mru1fsHL0=
-Uz/pfrRfztJASeQe/p2yVKXdnZDf1TyVEsYgftsh2Cw=
-0o20NeMSEqO9zPh2IPZUS5mpwCMov5g+iC/QYnodEw8=
-X2yqRKRmPEQd2SyLZlX7+Xz24daTTbj1+Nl633Az+qw=
-X79u1PD4etpl+ueqq0rZ4bWlhpOa7fs5pJJr5/ZcZQw=
-hTY6JMsbZubPYkTofSQ9u4MG9gc1fGFMucTCJKDgQ1g=
-fggrvFaXaxWdRpZUCpa2AUhhS6m14psgNfeJvs+/Blc=
-vs/eEkzt00TZJctV7dpmLZqcBoj6mghwzj27baQxPk4=
-T/QE8C4s0AGI8V0cAPS20eOLWjlc+FMU6uuoVbamS3U=
-8i22V6GpKYQavKxSZxpc7op9BpWGr4XOFt4rBd2iIlI=
-ON7T/2gnV5AIr0iH65aYo8+pJ/qO1Z8GugkPuaY+LXc=
-cFYQcjyWE/ZBMYHK33PVEHG9dh/aSRQj4avQAVAbZPM=
-lylXMEAxI07Rdnn9y5dVbWFz1fK/Dm5m1hJoDKbndoU=
-VnmkMeedTrnulnxg2HA8fHj0Q/cduXFX5DBZ3kLYUN8=
-ziMyOQIIdCoaymUTl0xMnbJpHq9FaLUz5KF+1d2pc+Y=
-x0It4hzryS7K5r6dzX5xHuZQ0wrtcR+7Dfayx4S2xPs=
-OUzLvAs1lcoN7UAHL6+YY27QIWma0olFZIeRZbW11Mk=
-xhkwd8YYnR37v4E7h9x8vwSYrPcniHvH7FQyCQbem8g=
-ApN5EY5XdSJsVNcYKjZ6JAtRdw9QEbs1F3z9F9myRFo=
-ThB8mBtCrL5BwBBn4W1E22SBTUGT5XIxfqBLh8ecR18=
-1Ia/o/ANFl7iz2Jw/afQCBfljNot9Polbg8usSLPjwI=
-6+h7tBiFAnCfREBVJZq7IrxRuIyQhBmhNVnfyO9mMNE=
-rxiY1/Bjh1HAddAULU4qDqcx/GIjJPFT/hvztq/ZrxM=
-LgGRdRygy6gcOmM43uGgK41rzE8fgmG4CbzOerrxpD0=
-TCQc/j0/+2DKiNawalUqsc8O99jS4I2hUoK1UZLrvSk=
-Yy/Wl7rK8e0jJRfsm3Yit8JeFEiwzGJrMyhnGeNRzoo=
-OALkJFFveO6sMpqumx9gpBLb4dWwldesncDc3ePB9fs=
-8DdiFAXg81ZQfiOfrdZHhC07UIV8PP+ECFkXT3L2/Rg=
-OTuLFcq8OIb7LkFkldY8i63Y3K+HVSB2yKCpY3wk3kc=
-d+rEdkU8tzIlf/FmpevRZWyx9nO2jijfQXdBM5efoqQ=
-X/rEPg3cW0rytpb2vE236R3zFLuP4NBxOgsaetKmj6w=
-FHxEf+64YgK1AzFPyvADa+qu9DfDm1azWOxEap0gOH8=
-Qs/dpvZguOW0wcQRllpFGTElWeMmL422nS2uF7JrO6M=
-e0ZNw4T9saUlwswnntDHz60kvs9yxGp9cJPRV8IXYH4=
-rgO5rRcQaih4WDCx3NY2eXxMZNgcuNFhWV26+DQz5kw=
-rkGVTarL/T5bn9cHj3tvquYbVZ7Oee+O2FitjAIqejw=
-Fmz4lA9HJR1VUo7Z5Z4melkqToo43T1on43LpknpS3M=
-0Dnu/3EIjMDxagWo/zxhYQ4UHR6FCsfhH3cT7uiMuVE=
-gxB49+Ifpx/iT5HXGOSlcynv5vSHGxJhFdXSc7+tn3Y=
-YmQD4Ho5PnB8iKRwRQSRcEsSK2TRGDI5F91NQfwGPDg=
-V0k5vjI5lVaapElYqzCJ9jmpyG45ezg+9g6ZRGSbQwo=
-8O5ZFO2UxyUtBYtOOYCK7m+o9izwl0+31tKp3xbjqH8=
-2/EmjBPmRa31jRYmxDNr0/qFoaTRAyDDHqDn0KZgiJY=
-zYmOTBarGJLzY6Rh4RAzPHTp3Us+Z+IjZMzAMOu1718=
-5UEx8Tn8I8Kcm9MiLhrnEVYZTK3SgXIt3mEwOXl46GE=
-EcYS0zK0wSJCUqb+L4o5bbr0A9+cy2IFbeOZWIBKuC8=
-nHyngZxD4CplRlj7NmUL2KPyKpuFNe81fiu8i5IakOI=
-v1SpOD9EZi517KIusOR/LCNeXRGKfoluyLZFkWy6aOk=
-AaBwYTqusQLERGiiMVWeO2bRmC7GQ1iRkJqeazZkI9I=
-prt/LZfwpe6H5EaWrtD6IQWjOw73Dc9ocygcbroIE84=
-lu8zwkqLHxbPFw9DIh4X5ir/aQqLAU8kUpv+s49AoNo=
-YOh1YzkH5QH7JqEK+9lzAhxTri9gGHFFhxYOg9UuGaI=
-3YcG9HnxHbxsapDBI1j/oAo3MfC+0rG2UpBIMI3MEuM=
-nk5sCNP756rPK3o/wrrD1swblHU/PJYVIj1qj2txcj4=
-JTTsG9dMPBt2YaDnzCjxvfKoLM05Q+6q3Nj+2VBV6tE=
-z2TrVpvtIKtWfKZcicZOoeeIxmBHoO8exeS9LlbKwnE=
-rUcj6rVaV0U6X1W/W/dvygi1p/I5tCabOqm44Uk1MB0=
-nM3gEf9hnDId/o1kkM2N4Thn0ZOpte5qb1rED2HXEcU=
-gFp7gGAab/tKveY170dwXq4XYg3vnPr2FGK2LXxLiGo=
-cWCg2EGxxcEgoIyS3iMmSD2Q2b/OGYS91v9KtrfSc8M=
-qQ+X1rXHYS4CDLvPB0YgDJZ24YKMWoUL5ryIjDRfpLU=
-nACcovl+osvygXNgDe9velTFZkWZuKtQDuGIWlbk8nA=
-rJWg/X4L9eG+bwKgQvDwmmV6euEnLt7FBatrmmEWeCw=
-ZAF9eLXwwExBlzXWpKbVLsHSARUkOw18dFB+JX/6SkA=
-OGTWwQAfAMSqgdzbN14qC0348ooaqZ+h84t0vOgtWxg=
-Yv3R3U29JpQAZqoDD82kUbK8IUP+zmWoqgP8C9MR8P0=
-vL0E1K7ZYsnSWv4M+vhjjOFDFlKYjsUhcynnVZrDxnE=
-z4mkHf7l9xdA3vYCc13b8d6+DLgW1zmA2aWDxYgc53g=
-OoglMMA+phXl702tvXyGYJEvqT+vUIhxb7Rqjh/6khg=
-HJJmkCoxw5QbUG1E0NTQbsnbdlXmX5VXZZ+rdospCxs=
-fLiI73QNy/wMIL2kTywmGfbQ1FmPuTLQN9ryeAd3c6U=
-WONo7k1hW4iOEcVSsss7Rp8wrEv0jYs3m1EAnAgmQ+w=
-yXgWNowrekYIszRNvmhI2L0SEmDC952siskMrhfI5Xw=
-O/HkFQPH8CPQ1Mr/vo5RJiwscxC8bZbozI0UOmAK7oA=
-PoS6Q0KQhRbndXPAmS8JecoITkaFaB/xlcy6iiKbinY=
-jZz9mPUrHCxvTpztPR2ZWSfvsNVjj73wiDTQ9yyikRg=
-s5YnQBRBzrQv9sf5g+DyqSMNGHdAPJ9AllyHV86/19Y=
-ePE8SR4TAgaDfDqu2lXFby1dYN0NGXkQhD9G1freNek=
-4qtqY+hkbg8jKCDtBH29RICWdFYhFJHJGvonr1qVVbk=
-AFHJiSTyOb1Jq4yPaAL4uc9K1B6zJy8aNMDNbWHcs9Q=
-j0FFvUjMm/ciklkj59LQnMy+mXOlODjKNvlWH3TownE=
-LAlx85e6hzewM1hFVpBllJNqzhdTpaS+Xi8RtCukt1k=
-UVh8hnv2bzXs5VSgjgpBwTuLvZtZ0mLSBKcDCaZyvuY=
-VbDNLMrRjiWXfZBtrJ+ouGQ9eiWOezg38RV6E6wZ0Yc=
-/T5EKAyNy+jPjPVVEeBmnIU3lF2h+nRowOpStobdW2g=
-dNmS05ELz340uLXNKPkerrT0Hz2mOU14uMQ2ctQ/Tw8=
-CrEV3p0Saj1OoQ3fCGPMnYlWdE63tMzat+V9agblhRg=
-e4X20IWbJAozYzdKEYHgEgIQR9ztI1KoQfblW10HfqU=
-QlIC1Lv9qbeZ0Peqkn2UT0LMpCN8L8GYdbkHXes1piE=
-D3UQNcGOHTkunMVXxX6UpV0S+7CG8mpFKeJhNiW/0Tw=
-yErgHs0gLa++7h8OZ5ZG3ozNZT14RnGKO19OEpMkKYo=
-UrY9G9COg73HI9ex/pYs7BgG5/U/dvLHCFjKNSk6HcE=
-4KZw9PEFfpF56dtF4zPON+PuMcNJnxxYSlh72aX1NkA=
-oBmBHkNpykxiqqgKFUlhPmD2xc7Tg6+ded+Pjxk/Hf4=
-Af1hSHk5SzrhSSUvwVaYZ0FZzlVQZp/5EokuGYNaHkw=
-gyJm1rqMv8vyjgYUoB2fTDm45B98h9IHfbtsA4QMqcI=
-5z8fGaRFmmBnpF6E21hdbB348SpznXM/WyiZZUbxh1o=
-jAFyH2+p0h38KDZvUkNOqLRL+IQ/HEM7llv2WTNE6zY=
-+Hiz3yE7CBe/8eXvTozXybV8gP/J+KcwnqRqr1QLrhg=
-tA1oOJ/QQcVuKT+j1X19t5LdALYuvf8ZCw4mRAcsk0o=
-Q9tljdTkAg+LXGvXEH4V4jNFmiJs0Nd++PcrKxzCmv4=
-oK8UGM0U9rJBXsYxbH1Yi7JdQwo9bQJvV94g+WXqvdw=
-weRTSNcUy0fbssC5uvm6HyfkIAR82nqLaTVkMATKq5c=
-jmkw14oTnzgnFGpZRu+f46dzmbL9DOuwsu0I7hih11g=
-2FLeXQmAht/ppvPXKNUmGGVYfEid5nV1PScjdKXW6fw=
-6Mpy7LmIXCTqKd4OrJdwQnjSoeWbZmZtMn+wzGvdkS8=
-SHR1jWVj4EM7HtzufMxdnCqtjroSvLBwRFS7Tvjq95k=
-tc/msLKqhhoLNnwMBTlaU4rUk6nfARVEqO/EaH/bLMg=
-uWj7/D7KKFqtw40jZ3JyQf99NzPxJ4+KT1DsyMDvHoA=
-/x3SHxpdC0Us2WnPSqVTg1yr4Ck8bHsAnxRaogLALIs=
-gGoqp37b08dtj9Bm37XMMxDzWbAQLOksD67BaqQ//wo=
-M81TfgCducdYpWhDXAZwb58BE4BU4gud3JPgOXE4qms=
-jZkhf/gtYOTfWb6KESFiXN/8TyLyHhJjod8G0twLVA4=
-xrclJq9F1orhZnHp8cJFMECNk4+PBEfhEG4vKnDTrSE=
-YPBm3Hik4ukpocjtEC7bcH3wMYH4L99Q1TpS2sNVxls=
-dkoNhNVVLNWHLHNGTzfwIXXNpwWIECsTraKgGZ/EA+k=
-Ko2+vTr9uXK8H3fP576FBoiM/tNe38VMuqY446WrPv8=
-W9DA1XmAFWfzOI/mRO95CrMeLbIkbq9MiB5aV9mgpYI=
-xbZ5EGlYFS+D+1iG3cQfB4UZPvZ8aXW+PlCfF/KbeoY=
-kFjVBl+PPppjqv5c6Jp2RHCw3vnc87nsfQWH+riP66A=
-1WAk8MXZI31+CyOFBn2O+I7dro7BmZafXKoszClp2YI=
-rCiRmOxpliiAP4hD3WPHZOhWuCdM957bjtjpmXlpf5U=
-x0eO33MQG6Eu7N3zSMd0f/94nvtAHMjcrfrglClUPlQ=
-4P+T6QVsSO3ca2jpTzFcOiIp6c4krzNjTTTV7wMjMok=
-Qf2VNoVpPOZ9DSPMkcoXkmHWuZSLIdO75fet++U5gt4=
-3oPj/CRfawSJMeHIE06qypb6p7HvHROV86Ys4BSwUYI=
-BmTx7u7RpzVXACAdL0Qx3EOwvOqxKajKv9Tth9BDQe8=
-cbPtjO7MwGOM0gIrQm6SF2YnHeYjZ8fNhS7C8eERHnY=
-zgJQ8qnxj2jV/5RKTGWfZpL3PgNpzswhX18lfjIlmHg=
-t3h0inkrj5HwSwG6/DGjHtfvanEq/4C2YQ2are4get8=
-iGWwLhQDkWdWEyLIwewud8R89763MdL+HLusv3LRdyw=
-6Va4oVaHH3HUNMrHjr0j1Q79GrkHYc5DbnnQOu0TZkw=
-wXOXph2a+dKiKczyYqsdMrSph6E0rlvZ3k/BVfAN0W4=
-TzBNg2b/kJHt121TO+1Vko5zt6qtUuNbhudip38EaU4=
-DzMgaSsXqRbOVPfk2nv+Ui+zGxrCHgiHdrN8B6NO4qg=
-4MJ6zLmueGBbYeeCbAIdkczS92mljEvW2lRgC5njVDg=
-FslKjMwVyYOCW1vT8txo1pTIoyDyMo7NjJylfeUdoOU=
-AfiXESH0ED0wvkI1zX3A7ubGrhL8p3UISOoOLhP8JCg=
-JbrMQKU5K4Kq3qBJA5BaRnEh8oIg5vL34P6YKq/BT6Y=
-+5U8T8AEWEbQJJHI7M84e6NDR8F6uw6m1Z9t5NLx6gQ=
-+1Tuqbzo6eqXghVPPUFCd/twn0m5R9c5eKwnhUbCzgM=
-yKk01qjoRfemX1yPcf5E9Si4XjJldaDWeTnHTYDNF9g=
-HJQqIqAWoeVVna537FzoZx+YrgukrC3CWUGOjh6flK0=
-z3O1LQQbcwm0OdFiR0FLkMnSbkTjh0ijZQDVgptRh/k=
-v17fvuuFmZxRacvz9NtjtnmtLh4icvw3lfn5kh5tBIc=
-oBM75bFOAjEKLUvqtgEJTxGU7ovW/Snd/nuTR0Z8Luw=
-ygBap14zWUvR3txYTh505RmOux3oiSntTz4un/zjhzs=
-I6dHBNd6A8/T/xnmLFAISCFObGD9Kq733Oeo+e6fkjI=
-O5Zo9Z9V+jg4/Co7gLf5tbE9Gkbx6qbgvP8ExUGYBWw=
-WkBVNcESoKga8NKsyjw/m8Gmd1hs28Yzy09fd44aNVA=
-kVPkQg3cfrTm6GSqA3fa30CC7NNQUhE2OOBdPClrwAY=
-3QOOh+C00sNpaA0954Y4qzn8HX5QYymWkhEBdo241Ng=
-TmPxQkAahPikc9bd7jQaFh+tqG00MMjCxTRTZBPZ25c=
-cW824XTQWVrowV39agxJjpe2plWz8g/lSIyo+exgktY=
-mk45jSqmA/7RCGPANi4TkNl+wS+gJ4/XgqqzzdV9wh0=
-O7YMQ5NGQUpA4twtHW9WYiV40rHygyR2fBSQFaY/80o=
-9dLSumgXp6mqDiE1S78Ob5XF4ofuiM8vJ58P/sTtrBU=
-cBtDKsDN1NnPlbS4hMMr9cypDUTgFhq9E7k01o44BHI=
-xMfENr2I6OaNsAKX34OsyBnhmGOboAUiyOMkWHaJhSM=
-XN2AnPRPX4Zl6sFQVVBMWwa3h6wYKUUFvbq0p35Q13Y=
-RgOPYyYijNtWYZxSJmYT2gTIykmeDQOw7c/8EQ1c/HA=
-7cc0xQFQHceidEj6AsdJMfhXi/KXsXPzS4QegsZpGSY=
-J9b9r4ApeEbf7/guf1i5pIrJ4+6ToRKxu+JD7hqXRHw=
-yBksMve0nH8yocoAFZWn+eNsnnIFjW6qG6t3UqjBZxg=
-vkCBOGmrJ6Bx0SrWqIMFg+vDthjj8jRjWfSxGhyUNO4=
-HoZCeMIIgbZxwMbS4UthFQrR8Tz5LG7BS1UNy8R+FUE=
-VMN6joU/0dY3jTeLk5MH7DIaMcwaWonnGAYzvBPxh2I=
-nomO0D+kaWlpDa1zxylmdQRf+bWgEAo5m+uENamPUYU=
-Sw0TktORVzUyB6ZMyxRoPd6dLO0ftYsW4Di+VwfCeBM=
-eqRdb1sU2rHGhEwZwoBOFLWBHm7eHwKwrvBlp7NZxo8=
-lMZj6epcJ+5PZBJ/m0JYY+mRqeFWwH3xoAgDrjF2QWI=
-Logg3A6vrj1tKFwFfs4URws3dDiwAs7dTHK080OlT0M=
-TnB4Z5RqwFNDxrqP8SHqZqdYA3kTJXqO5JdDUNOaEDQ=
-wlxO28NuP7fD2Te+6fLSnjavsHz6MYgmLg1f3JGeDXc=
-Xn/LnJe9pWmTsWWNEgIydh1mWjZEU0MA+mpb7F4NV5U=
-ETE43XshZyWEAjji1+7ss3ONsTkGSyTLhT/CcKSeYFc=
-vjPRxX693ZJ7V722BL5Fe1Uv5Wjn89y6CTw57Rwwojk=
-g/yJGzUNng1+vm3Spr/j0LD0ZT/KBIYVpd7rvAOaP2Y=
-VyZLgqhk26HBHvP4CruUysNmBmKwwi9XH/mTs/vPdvs=
-dKvl5czrdUkf9yxM8yVAXYrb/jkOGJz0MLpg5ieYh44=
-wv6s1nSHjHsMIyWi7O0KMz23eAqG3+w3WBAO/AEBxmU=
-ndwuDVW0YeDHMigoLfVrK+8iTKI4VoHRe26MB3hSVzw=
-MG6XOeNFj/RUaHe3BLLjkF5YsjXWTjL08CaskbcpXRU=
-/ToPPdRIAJK21FBHPeuSAaCzCKiAeDOjxzj4oH64HtM=
-Cqny59lccYt9HrfM29AWToYFeunWaSK8YPmQP5Sg8O8=
-9XCaLS9otTv29kW7F4rflTRvif2lxjv94IBComSSqrI=
-66NMexCWcWFMNn4d4HUSTDlUzhn4X6z2EJDsMZ9/Gn8=
-Eo3tGorWDCS0JU4x25T8Q5K/k+1UNEcqpDoLmFYQYGg=
-txawif5OU9Gi73ulesheaOxyLPYQUsJaWWJq07FcX0A=
-al9MFnjKZeWfBg1Xzf9mUGUxSGHVOo59FFDKktlsoQI=
-q8hnBsmNa/ZzcvkI7AGt9jGxkdczron4ND6wR7EIFEs=
-QEfJ1pJgwHITvLhgin7F4oOKVrefZ4R4EurAd40NJ/E=
-kl7n1aIq1/vpurVNfI0LmnT341qK9q9kXi6MNRmnCS8=
-8GjeqhjMAtWovjXLgzgyeRApH25i5yFqk0dkoaukqAA=
-sf466/ljp4gOdLCwVWaB6osczOPmmn07EKaKy+huSKE=
-//4HdQP9cvDlM4sKe04hjn0f+C5JPn6FKuUaocdYXRc=
-lcanR90Lx1WhlBgn6JS4CDWSJBt5JUHi6xsw+5sT9X8=
-DTF2xY8yGqNMV8jffBfR9OdseX7BFsnx1pd0jtH859k=
-DW5GeE87aU6cdQZ4ZBe8b4f50vc9GbXoCBYSshE3t2Y=
-l4vPOcPDqs7+EEj6A2AoPcLr+lFQAkxeN4UU0+decpU=
-LYGa85fiidxBcJxKr22jsZBHScN6mVhgdFgDcW19VpA=
-oaBOTPxW/RkX60gfxGYpouRmVnVvoI4iSH9Utk4co+c=
-Zj/elPiDah/r2DvoMQl5MS1l/4wbcWOU5o9B2COWwfg=
-SDlfccwm9kJ0vQbH6xWR+dTsYrZPpsFlMfPLcsJGnYI=
-+AhlYjZyW1ZvByHFGBWKZ1bJaQPLcetI3dqO3f6g8mw=
-TngnF2hJQIjtH5uycSUxq10TjGxZtGZQ0oWzWFjmexM=
-QqIfNyhYBPLnNgdctUh0Nozw4hEAiLPxOEEu7IhZCVQ=
-RnFuv2oirqHfH5fmKl73CVEnzkVQtiQuumkHr8XEgs8=
-iH1/Het/BxLIWvq/UMrfib8C6xPlUsv1LXtd8/IdsNo=
-VbgN72B/iOMcWEBn0J1DNE2UEXuvZINlhHsc5bZ2d8k=
-/DqYk44u07024NQfGFF2STIpBrLmszaQiRMlquzRlkQ=
-UjV1BHNxu6iCY+WrXe2PawaVxdKhkqbdEUBsR2ujxy8=
-KlCKX+YXPE6PASZpShpqcdkABFH6MdsDO4cFiQRB7MU=
-/S8zJI85ZFZGh5gCNaXwvLOrVi5H9AT3QuUzQsU3UoA=
-U4pFqvkAPU05iLv8+fhZsyXOX3ddwGASBQWFF/m8FeU=
-50rUSw1W7r45uxhcUqub7+T3WJm2qBQW6RA9XCm/J/s=
-53rALbbqoOmmtXOpmHDG3029uDOd2jvEB4b3DivX9/Y=
-HpU+FRI6leRwRL+vBrGXT7mXa4T0Nx69d/itge/QXAA=
-5Xu/UHn5gpO0FC80iXLmjjUeUrkDc/BfRvCcyzCvW/A=
-vUQgxZKm9/JSromBJOAC8bnP4fJTiGTVazSntN+zH8g=
-CE7KcKm0Dk4VY+NXdrcW5BCpcrsn7VHCSMSNMkL6ja8=
-bsjTVRvQRUsMxLnbh2Nmrgh2TF/PFbAPlBG94w1TNq4=
-qONS2wyOJ7rlg9AVFG6Led7gkdVjj1g6DEQvO/Vd7rM=
-LRskT6zq+tlHVbXpmqv3rJHFmdpzv6Rh7uuvtLlptck=
-6tyA999jBWDMGzU/aOpmAVnOlm4i1ARYh4B4fAR20OQ=
-IuXm21yuQo7alq7QVk4rl3DsoswCUVjjep3e7eMfReU=
diff --git a/testssl.sh b/testssl.sh
index 6bd0294..f78de7b 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -8314,7 +8314,6 @@ certificate_info() {
local certificate_list_ordering_problem="${12}"
local cert_sig_algo cert_sig_hash_algo cert_key_algo cert_spki_info
local common_primes_file="$TESTSSL_INSTALL_DIR/etc/common-primes.txt"
- local badocspcerts="${TESTSSL_INSTALL_DIR}/etc/bad_ocsp_certs.txt"
local -i lineno_matched=0
local cert_keyusage cert_ext_keyusage short_keyAlgo
local outok=true
@@ -8986,10 +8985,8 @@ certificate_info() {
/---END CERTIFICATE-----/{ inc=0 }" "$TEMPDIR/intermediatecerts.pem"
for cert in $TEMPDIR/intermediatecert?.crt; do
- hash=$($OPENSSL x509 -in "$cert" -outform der 2>/dev/null | $OPENSSL dgst -sha256 -binary | $OPENSSL base64)
- grep -q "$hash" "$badocspcerts"
- badocsp=$?
- [[ $badocsp -eq 0 ]] && break
+ cert_ext_keyusage="$($OPENSSL x509 -in "$cert" -text -noout 2>/dev/null | awk '/X509v3 Extended Key Usage:/ { getline; print $0 }')"
+ [[ "$cert_ext_keyusage" =~ OCSP\ Signing ]] && badocsp=0 && break
done
if [[ $badocsp -eq 0 ]]; then
prln_svrty_medium "NOT ok"
From 17ee0245b5f4eb34ef13759773ce741e3a00a9ce Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Wed, 15 Jul 2020 11:53:49 -0400
Subject: [PATCH 132/211] Speed up intermediate certificate extraction
This commit speeds up extraction of intermediate certificates by using Bash commands rather than awk.
---
testssl.sh | 38 ++++++++++++++++++++------------------
1 file changed, 20 insertions(+), 18 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index f78de7b..2ac1f95 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -8303,15 +8303,16 @@ certificate_info() {
local -i certificate_number=$1
local -i number_of_certificates=$2
local cert_txt="$3"
- local cipher=$4
- local cert_keysize=$5
- local cert_type="$6"
- local ocsp_response_binary="$7"
- local ocsp_response=$8
- local ocsp_response_status=$9
- local sni_used="${10}"
- local ct="${11}"
- local certificate_list_ordering_problem="${12}"
+ local intermediate_certs="$4"
+ local cipher=$5
+ local cert_keysize=$6
+ local cert_type="$7"
+ local ocsp_response_binary="$8"
+ local ocsp_response=$9
+ local ocsp_response_status=${10}
+ local sni_used="${11}"
+ local ct="${12}"
+ local certificate_list_ordering_problem="${13}"
local cert_sig_algo cert_sig_hash_algo cert_key_algo cert_spki_info
local common_primes_file="$TESTSSL_INSTALL_DIR/etc/common-primes.txt"
local -i lineno_matched=0
@@ -8320,7 +8321,7 @@ certificate_info() {
local expire days2expire secs2warn ocsp_uri crl
local startdate enddate issuer_CN issuer_C issuer_O issuer sans san all_san="" cn
local issuer_DC issuerfinding cn_nosni=""
- local cert_fingerprint_sha1 cert_fingerprint_sha2 cert_serial cert
+ local cert_fingerprint_sha1 cert_fingerprint_sha2 cert_serial intermediates cert
local policy_oid
local spaces=""
local -i trust_sni=0 trust_nosni=0 diffseconds=0
@@ -8979,13 +8980,14 @@ certificate_info() {
#FIXME: We just raise the flag saying the chain is bad w/o naming the intermediate
# cert to blame.
- awk -v n=-1 "{start=1}
- /-----BEGIN CERTIFICATE-----/{ if (start) {inc=1; n++} }
- inc { print > (\"$TEMPDIR/intermediatecert\" n \".crt\") }
- /---END CERTIFICATE-----/{ inc=0 }" "$TEMPDIR/intermediatecerts.pem"
-
- for cert in $TEMPDIR/intermediatecert?.crt; do
- cert_ext_keyusage="$($OPENSSL x509 -in "$cert" -text -noout 2>/dev/null | awk '/X509v3 Extended Key Usage:/ { getline; print $0 }')"
+ intermediates="$intermediate_certs"
+ while true; do
+ [[ "$intermediates" =~ \-\-\-\-\-\BEGIN\ CERTIFICATE\-\-\-\-\- ]] || break
+ intermediates="${intermediates#*-----BEGIN CERTIFICATE-----}"
+ cert="${intermediates%%-----END CERTIFICATE-----*}"
+ intermediates="${intermediates#${cert}-----END CERTIFICATE-----}"
+ cert="-----BEGIN CERTIFICATE-----${cert}-----END CERTIFICATE-----"
+ cert_ext_keyusage="$($OPENSSL x509 -text -noout 2>/dev/null <<< "$cert" | awk '/X509v3 Extended Key Usage:/ { getline; print $0 }')"
[[ "$cert_ext_keyusage" =~ OCSP\ Signing ]] && badocsp=0 && break
done
if [[ $badocsp -eq 0 ]]; then
@@ -9712,7 +9714,7 @@ run_server_defaults() {
echo "${previous_hostcert[i]}" > $HOSTCERT
echo "${previous_intermediates[i]}" > $TEMPDIR/intermediatecerts.pem
echo "${previous_hostcert_issuer[i]}" > $TEMPDIR/hostcert_issuer.pem
- certificate_info "$i" "$certs_found" "${previous_hostcert_txt[i]}" \
+ certificate_info "$i" "$certs_found" "${previous_hostcert_txt[i]}" "${previous_intermediates[i]}" \
"${tested_cipher[i]}" "${keysize[i]}" "${previous_hostcert_type[i]}" \
"${ocsp_response_binary[i]}" "${ocsp_response[i]}" \
"${ocsp_response_status[i]}" "${sni_used[i]}" "${ct[i]}" \
From bd856e2adaf31f7063173052368b3123a1688290 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Thu, 16 Jul 2020 07:57:27 -0400
Subject: [PATCH 133/211] Save intermediate certificates for more use
As there as suggestions to check intermediate certificates for things such as expiration date, this commit saves the text versions of each of the intermediate certificates so that they are available to extract additional information.
---
testssl.sh | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 2ac1f95..beb479d 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -8303,7 +8303,7 @@ certificate_info() {
local -i certificate_number=$1
local -i number_of_certificates=$2
local cert_txt="$3"
- local intermediate_certs="$4"
+ local intermediates="$4"
local cipher=$5
local cert_keysize=$6
local cert_type="$7"
@@ -8321,13 +8321,14 @@ certificate_info() {
local expire days2expire secs2warn ocsp_uri crl
local startdate enddate issuer_CN issuer_C issuer_O issuer sans san all_san="" cn
local issuer_DC issuerfinding cn_nosni=""
- local cert_fingerprint_sha1 cert_fingerprint_sha2 cert_serial intermediates cert
+ local cert_fingerprint_sha1 cert_fingerprint_sha2 cert_serial cert
+ local -a intermediate_certs=()
local policy_oid
local spaces=""
local -i trust_sni=0 trust_nosni=0 diffseconds=0
local has_dns_sans has_dns_sans_nosni
local trust_sni_finding
- local -i certificates_provided
+ local -i i certificates_provided=0
local cnfinding trustfinding trustfinding_nosni
local cnok="OK"
local expfinding expok="OK"
@@ -8980,14 +8981,20 @@ certificate_info() {
#FIXME: We just raise the flag saying the chain is bad w/o naming the intermediate
# cert to blame.
- intermediates="$intermediate_certs"
+ # Store all of the intermediate certificates in an array so that they can
+ # be used later (e.g., to check their expiration dates).
while true; do
[[ "$intermediates" =~ \-\-\-\-\-\BEGIN\ CERTIFICATE\-\-\-\-\- ]] || break
intermediates="${intermediates#*-----BEGIN CERTIFICATE-----}"
cert="${intermediates%%-----END CERTIFICATE-----*}"
intermediates="${intermediates#${cert}-----END CERTIFICATE-----}"
cert="-----BEGIN CERTIFICATE-----${cert}-----END CERTIFICATE-----"
- cert_ext_keyusage="$($OPENSSL x509 -text -noout 2>/dev/null <<< "$cert" | awk '/X509v3 Extended Key Usage:/ { getline; print $0 }')"
+ intermediate_certs[certificates_provided]="$($OPENSSL x509 -text -noout 2>/dev/null <<< "$cert")"
+ certificates_provided+=1
+ done
+ certificates_provided+=1
+ for (( i=0; i < certificates_provided-1; i++ )); do
+ cert_ext_keyusage="$(awk '/X509v3 Extended Key Usage:/ { getline; print $0 }' <<< "${intermediate_certs[i]}")"
[[ "$cert_ext_keyusage" =~ OCSP\ Signing ]] && badocsp=0 && break
done
if [[ $badocsp -eq 0 ]]; then
@@ -9121,7 +9128,6 @@ certificate_info() {
fileout "cert_validityPeriod${json_postfix}" "INFO" "No finding"
fi
- certificates_provided=1+$(grep -c "\-\-\-\-\-BEGIN CERTIFICATE\-\-\-\-\-" $TEMPDIR/intermediatecerts.pem)
out "$indent"; pr_bold " # of certificates provided"; out " $certificates_provided"
fileout "certs_countServer${json_postfix}" "INFO" "${certificates_provided}"
if "$certificate_list_ordering_problem"; then
From 0d9ca76f37bbca1f258498e2ebeba63343407432 Mon Sep 17 00:00:00 2001
From: Magnus Larsen
Date: Sat, 18 Jul 2020 21:14:38 +0200
Subject: [PATCH 134/211] Added complete json/csv output for rating
---
testssl.sh | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/testssl.sh b/testssl.sh
index d5b3c3b..7341d08 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -20820,6 +20820,14 @@ run_rating() {
pr_bold " Cipher Strength"; out " (weighted) "; outln "0 (0)"
pr_bold " Final Score "; outln "0"
pr_bold " Overall Grade "; prln_svrty_critical "$GRADE_CAP"
+
+ fileout "protocol_support_score" "INFO" "0"
+ fileout "protocol_support_score_weighted" "INFO" "0"
+ fileout "key_exchange_score" "INFO" "0"
+ fileout "key_exchange_score_weighted" "INFO" "0"
+ fileout "cipher_strength_score" "INFO" "0"
+ fileout "cipher_strength_score_weighted" "INFO" "0"
+ fileout "final_score" "INFO" "0"
fileout "grade" "CRITICAL" "$GRADE_CAP"
else
## Category 1
@@ -20855,6 +20863,8 @@ run_rating() {
let c1_wscore=$c1_score*30/100 # Gets the weighted score for category (30%)
pr_bold " Protocol Support "; out "(weighted) "; outln "$c1_score ($c1_wscore)"
+ fileout "protocol_support_score" "INFO" "$c1_score"
+ fileout "protocol_support_score_weighted" "INFO" "$c1_wscore"
## Category 2
if [[ $KEY_EXCH_SCORE -le 40 ]]; then
@@ -20867,6 +20877,8 @@ run_rating() {
let c2_wscore=$c2_score*30/100
pr_bold " Key Exchange "; out " (weighted) "; outln "$c2_score ($c2_wscore)"
+ fileout "key_exchange_score" "INFO" "$c2_score"
+ fileout "key_exchange_score_weighted" "INFO" "$c2_wscore"
## Category 3
@@ -20899,11 +20911,14 @@ run_rating() {
let c3_wscore=$c3_score*40/100 # Gets the weighted score for category (40%)
pr_bold " Cipher Strength "; out " (weighted) "; outln "$c3_score ($c3_wscore)"
+ fileout "cipher_strength_score" "INFO" "$c3_score"
+ fileout "cipher_strength_score_weighted" "INFO" "$c3_wscore"
## Calculate final score and grade
let final_score=$c1_wscore+$c2_wscore+$c3_wscore
pr_bold " Final Score "; outln $final_score
+ fileout "final_score" "INFO" "$final_score"
# Calculate the pre-cap grade
if [[ $final_score -ge 80 ]]; then
From 86c730b74e53d1148748eb69b62fbba75350a9a5 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Mon, 20 Jul 2020 11:34:44 +0200
Subject: [PATCH 135/211] Polish completion of json/csv output
To be more consistent with the screen output:
* grade --> overall grade
* add rating doc url
---
testssl.sh | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index aee635a..a3c7d04 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -20877,6 +20877,7 @@ run_rating() {
pr_bold " Specification documentation "; pr_url "https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide"
outln
fileout "rating_spec" "INFO" "SSL Labs's 'SSL Server Rating Guide' (version 2009q from 2020-01-30)"
+ fileout "rating_doc" "INFO" "https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide"
# No point in calculating a score, if a cap of "F", "T", or "M" has been set
if [[ $GRADE_CAP == F || $GRADE_CAP == T || $GRADE_CAP == M ]]; then
@@ -20893,7 +20894,7 @@ run_rating() {
fileout "cipher_strength_score" "INFO" "0"
fileout "cipher_strength_score_weighted" "INFO" "0"
fileout "final_score" "INFO" "0"
- fileout "grade" "CRITICAL" "$GRADE_CAP"
+ fileout "overall_grade" "CRITICAL" "$GRADE_CAP"
else
## Category 1
# get best score, by searching for the best protocol, until a hit occurs
@@ -21017,22 +21018,22 @@ run_rating() {
pr_bold " Overall Grade "
case "$final_grade" in
A*) prln_svrty_best $final_grade
- fileout "grade" "OK" "$final_grade"
+ fileout "overall_grade" "OK" "$final_grade"
;;
B) prln_svrty_medium $final_grade
- fileout "grade" "MEDIUM" "$final_grade"
+ fileout "overall_grade" "MEDIUM" "$final_grade"
;;
C) prln_svrty_medium $final_grade
fileout "grade" "MEDIUM" "$final_grade"
;;
D) prln_svrty_high $final_grade
- fileout "grade" "HIGH" "$final_grade"
+ fileout "overall_grade" "HIGH" "$final_grade"
;;
E) prln_svrty_high $final_grade
- fileout "grade" "HIGH" "$final_grade"
+ fileout "overall_grade" "HIGH" "$final_grade"
;;
F) prln_svrty_critical $final_grade
- fileout "grade" "CRITICAL" "$final_grade"
+ fileout "overall_grade" "CRITICAL" "$final_grade"
;;
esac
fi
From a51a0a73a76571bfd0a072f180437d99ed78caab Mon Sep 17 00:00:00 2001
From: Dirk
Date: Mon, 20 Jul 2020 11:43:52 +0200
Subject: [PATCH 136/211] Squash "No engine or GOST support via engine..."
This is a legacy warning and seems only needed in a very few cases
whereas in other few cases we don't issue such warnings. So to be
consistent it's right to remove this message as it confuses users
unnecessarily,
It'll appear in debug mode though.
See https://github.com/drwetter/testssl.sh/issues/1119#issuecomment-656271849
---
testssl.sh | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index aee635a..cd32a8f 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -19208,8 +19208,7 @@ initialize_engine(){
export OPENSSL_CONF=''
return 1
elif $OPENSSL engine gost -v 2>&1 | grep -Eq 'invalid command|no such engine'; then
- outln
- pr_warning "No engine or GOST support via engine with your $OPENSSL"; outln
+ [[ $DEBUG -ge 1 ]] && outln && pr_warning "No engine or GOST support via engine with your $OPENSSL"; outln
fileout_insert_warning "engine_problem" "WARN" "No engine or GOST support via engine with your $OPENSSL"
export OPENSSL_CONF=''
return 1
@@ -19218,8 +19217,7 @@ initialize_engine(){
# to suppress the warning (confuses users), see #1119
# https://github.com/openssl/openssl/commit/b524b808a1d1ba204dbdcbb42de4e3bddb3472ac
if ! grep -q 'using the .include directive' /etc/ssl/openssl.cnf; then
- outln
- pr_warning "No engine or GOST support via engine with your $OPENSSL"; outln
+ [[ $DEBUG -ge 1 ]] && outln && pr_warning "No engine or GOST support via engine with your $OPENSSL"; outln
fi
fileout_insert_warning "engine_problem" "WARN" "No engine or GOST support via engine with your $OPENSSL"
# Avoid clashes of OpenSSL 1.1.1 config file with our openssl 1.0.2. This is for Debian 10
From 161567f9d29d2bb8872e5e201268b141e6dc4e02 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Mon, 20 Jul 2020 20:13:41 +0200
Subject: [PATCH 137/211] add quotes
---
testssl.sh | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index cd32a8f..0d933cb 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -19208,7 +19208,7 @@ initialize_engine(){
export OPENSSL_CONF=''
return 1
elif $OPENSSL engine gost -v 2>&1 | grep -Eq 'invalid command|no such engine'; then
- [[ $DEBUG -ge 1 ]] && outln && pr_warning "No engine or GOST support via engine with your $OPENSSL"; outln
+ [[ "$DEBUG" -ge 1 ]] && outln && pr_warning "No engine or GOST support via engine with your $OPENSSL"; outln
fileout_insert_warning "engine_problem" "WARN" "No engine or GOST support via engine with your $OPENSSL"
export OPENSSL_CONF=''
return 1
@@ -19217,7 +19217,7 @@ initialize_engine(){
# to suppress the warning (confuses users), see #1119
# https://github.com/openssl/openssl/commit/b524b808a1d1ba204dbdcbb42de4e3bddb3472ac
if ! grep -q 'using the .include directive' /etc/ssl/openssl.cnf; then
- [[ $DEBUG -ge 1 ]] && outln && pr_warning "No engine or GOST support via engine with your $OPENSSL"; outln
+ [[ "$DEBUG" -ge 1 ]] && outln && pr_warning "No engine or GOST support via engine with your $OPENSSL"; outln
fi
fileout_insert_warning "engine_problem" "WARN" "No engine or GOST support via engine with your $OPENSSL"
# Avoid clashes of OpenSSL 1.1.1 config file with our openssl 1.0.2. This is for Debian 10
From 5b44e43ec4ce1a22bc0bf1e36f430410fcbe2c97 Mon Sep 17 00:00:00 2001
From: a1346054 <36859588+a1346054@users.noreply.github.com>
Date: Sun, 2 Aug 2020 21:47:40 +0000
Subject: [PATCH 138/211] Fix grammar
---
doc/testssl.1.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/testssl.1.html b/doc/testssl.1.html
index af08013..57a89ae 100644
--- a/doc/testssl.1.html
+++ b/doc/testssl.1.html
@@ -303,7 +303,7 @@ Also for multiple server certificates are being checked for as well as for the c
--c, --client-simulation
This simulates a handshake with a number of standard clients so that you can figure out which client cannot or can connect to your site. For the latter case the protocol, cipher and curve is displayed, also if there's Forward Secrecy. testssl.sh uses a handselected set of clients which are retrieved by the SSLlabs API. The output is aligned in columns when combined with the --wide
option. If you want the full nine yards of clients displayed use the environment variable ALL_CLIENTS.
--g, --grease
checks several server implementation bugs like tolerance to size limitations and GREASE, see https://www.ietf.org/archive/id/draft-ietf-tls-grease-01.txt . This checks doesn't run per default.
+-g, --grease
checks several server implementation bugs like tolerance to size limitations and GREASE, see https://www.ietf.org/archive/id/draft-ietf-tls-grease-01.txt . This check doesn't run per default.
VULNERABILITIES
From e8d2992add9e0af07701c442b415415d3da179d0 Mon Sep 17 00:00:00 2001
From: a1346054 <36859588+a1346054@users.noreply.github.com>
Date: Sun, 2 Aug 2020 21:48:15 +0000
Subject: [PATCH 139/211] Fix grammar
---
doc/testssl.1.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index 6755235..c246c7f 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -215,7 +215,7 @@ Also for multiple server certificates are being checked for as well as for the c
`--c, --client-simulation` This simulates a handshake with a number of standard clients so that you can figure out which client cannot or can connect to your site. For the latter case the protocol, cipher and curve is displayed, also if there's Forward Secrecy. testssl.sh uses a handselected set of clients which are retrieved by the SSLlabs API. The output is aligned in columns when combined with the `--wide` option. If you want the full nine yards of clients displayed use the environment variable ALL_CLIENTS.
-`-g, --grease` checks several server implementation bugs like tolerance to size limitations and GREASE, see https://www.ietf.org/archive/id/draft-ietf-tls-grease-01.txt . This checks doesn't run per default.
+`-g, --grease` checks several server implementation bugs like tolerance to size limitations and GREASE, see https://www.ietf.org/archive/id/draft-ietf-tls-grease-01.txt . This check doesn't run per default.
From e6c5507b20361de23ccfc901cb672149f659abcf Mon Sep 17 00:00:00 2001
From: a1346054 <36859588+a1346054@users.noreply.github.com>
Date: Sun, 2 Aug 2020 21:54:27 +0000
Subject: [PATCH 140/211] Fix grammar
---
doc/testssl.1 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/testssl.1 b/doc/testssl.1
index 834d339..25a4471 100644
--- a/doc/testssl.1
+++ b/doc/testssl.1
@@ -334,7 +334,7 @@ Security headers (X\-Frame\-Options, X\-XSS\-Protection, Expect\-CT,\.\.\. , CSP
\fB\-\-c, \-\-client\-simulation\fR This simulates a handshake with a number of standard clients so that you can figure out which client cannot or can connect to your site\. For the latter case the protocol, cipher and curve is displayed, also if there\'s Forward Secrecy\. testssl\.sh uses a handselected set of clients which are retrieved by the SSLlabs API\. The output is aligned in columns when combined with the \fB\-\-wide\fR option\. If you want the full nine yards of clients displayed use the environment variable ALL_CLIENTS\.
.
.P
-\fB\-g, \-\-grease\fR checks several server implementation bugs like tolerance to size limitations and GREASE, see https://www\.ietf\.org/archive/id/draft\-ietf\-tls\-grease\-01\.txt \. This checks doesn\'t run per default\.
+\fB\-g, \-\-grease\fR checks several server implementation bugs like tolerance to size limitations and GREASE, see https://www\.ietf\.org/archive/id/draft\-ietf\-tls\-grease\-01\.txt \. This check doesn\'t run per default\.
.
.SS "VULNERABILITIES"
\fB\-U, \-\-vulnerable, \-\-vulnerabilities\fR Just tests all (of the following) vulnerabilities\. The environment variable \fBVULN_THRESHLD\fR determines after which value a separate headline for each vulnerability is being displayed\. Default is \fB1\fR which means if you check for two vulnerabilities, only the general headline for vulnerabilities section is displayed \-\- in addition to the vulnerability and the result\. Otherwise each vulnerability or vulnerability section gets its own headline in addition to the output of the name of the vulnerabilty and test result\. A vulnerability section is comprised of more than one check, e\.g\. the renegotiation vulnerability check has two checks, so has Logjam\.
From 57c49132604a59276d83821b05acb372358d30f4 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Mon, 3 Aug 2020 10:43:15 -0400
Subject: [PATCH 141/211] Update GREASE reference
The GEASE Internet Draft is now RFC 8701. This commit updates the references.
---
doc/testssl.1 | 2 +-
doc/testssl.1.html | 2 +-
doc/testssl.1.md | 2 +-
testssl.sh | 12 ++++++------
4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/doc/testssl.1 b/doc/testssl.1
index 25a4471..24a5408 100644
--- a/doc/testssl.1
+++ b/doc/testssl.1
@@ -334,7 +334,7 @@ Security headers (X\-Frame\-Options, X\-XSS\-Protection, Expect\-CT,\.\.\. , CSP
\fB\-\-c, \-\-client\-simulation\fR This simulates a handshake with a number of standard clients so that you can figure out which client cannot or can connect to your site\. For the latter case the protocol, cipher and curve is displayed, also if there\'s Forward Secrecy\. testssl\.sh uses a handselected set of clients which are retrieved by the SSLlabs API\. The output is aligned in columns when combined with the \fB\-\-wide\fR option\. If you want the full nine yards of clients displayed use the environment variable ALL_CLIENTS\.
.
.P
-\fB\-g, \-\-grease\fR checks several server implementation bugs like tolerance to size limitations and GREASE, see https://www\.ietf\.org/archive/id/draft\-ietf\-tls\-grease\-01\.txt \. This check doesn\'t run per default\.
+\fB\-g, \-\-grease\fR checks several server implementation bugs like tolerance to size limitations and GREASE, see RFC 8701\. This check doesn\'t run per default\.
.
.SS "VULNERABILITIES"
\fB\-U, \-\-vulnerable, \-\-vulnerabilities\fR Just tests all (of the following) vulnerabilities\. The environment variable \fBVULN_THRESHLD\fR determines after which value a separate headline for each vulnerability is being displayed\. Default is \fB1\fR which means if you check for two vulnerabilities, only the general headline for vulnerabilities section is displayed \-\- in addition to the vulnerability and the result\. Otherwise each vulnerability or vulnerability section gets its own headline in addition to the output of the name of the vulnerabilty and test result\. A vulnerability section is comprised of more than one check, e\.g\. the renegotiation vulnerability check has two checks, so has Logjam\.
diff --git a/doc/testssl.1.html b/doc/testssl.1.html
index 57a89ae..9278e3a 100644
--- a/doc/testssl.1.html
+++ b/doc/testssl.1.html
@@ -303,7 +303,7 @@ Also for multiple server certificates are being checked for as well as for the c
--c, --client-simulation
This simulates a handshake with a number of standard clients so that you can figure out which client cannot or can connect to your site. For the latter case the protocol, cipher and curve is displayed, also if there's Forward Secrecy. testssl.sh uses a handselected set of clients which are retrieved by the SSLlabs API. The output is aligned in columns when combined with the --wide
option. If you want the full nine yards of clients displayed use the environment variable ALL_CLIENTS.
--g, --grease
checks several server implementation bugs like tolerance to size limitations and GREASE, see https://www.ietf.org/archive/id/draft-ietf-tls-grease-01.txt . This check doesn't run per default.
+-g, --grease
checks several server implementation bugs like tolerance to size limitations and GREASE, see RFC 8701. This check doesn't run per default.
VULNERABILITIES
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index c246c7f..73544d2 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -215,7 +215,7 @@ Also for multiple server certificates are being checked for as well as for the c
`--c, --client-simulation` This simulates a handshake with a number of standard clients so that you can figure out which client cannot or can connect to your site. For the latter case the protocol, cipher and curve is displayed, also if there's Forward Secrecy. testssl.sh uses a handselected set of clients which are retrieved by the SSLlabs API. The output is aligned in columns when combined with the `--wide` option. If you want the full nine yards of clients displayed use the environment variable ALL_CLIENTS.
-`-g, --grease` checks several server implementation bugs like tolerance to size limitations and GREASE, see https://www.ietf.org/archive/id/draft-ietf-tls-grease-01.txt . This check doesn't run per default.
+`-g, --grease` checks several server implementation bugs like tolerance to size limitations and GREASE, see RFC 8701. This check doesn't run per default.
diff --git a/testssl.sh b/testssl.sh
index 0f22e45..cc9a584 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -17718,7 +17718,7 @@ run_tls_truncation() {
}
# Test for various server implementation errors that aren't tested for elsewhere.
-# Inspired by https://datatracker.ietf.org/doc/draft-ietf-tls-grease.
+# Inspired by RFC 8701.
run_grease() {
local -i success
local bug_found=false
@@ -17729,7 +17729,7 @@ run_grease() {
local ciph list temp curve_found
local -i i j rnd alpn_list_len extn_len debug_level=""
local -i ret=0
- # Note: The following values were taken from https://datatracker.ietf.org/doc/draft-ietf-tls-grease.
+ # Note: The following values were taken from RFC 8701.
# These arrays may need to be updated if the values change in the final version of this document.
local -a -r grease_cipher_suites=( "0a,0a" "1a,1a" "2a,2a" "3a,3a" "4a,4a" "5a,5a" "6a,6a" "7a,7a" "8a,8a" "9a,9a" "aa,aa" "ba,ba" "ca,ca" "da,da" "ea,ea" "fa,fa" )
local -a -r grease_supported_groups=( "0a,0a" "1a,1a" "2a,2a" "3a,3a" "4a,4a" "5a,5a" "6a,6a" "7a,7a" "8a,8a" "9a,9a" "aa,aa" "ba,ba" "ca,ca" "da,da" "ea,ea" "fa,fa" )
@@ -17823,7 +17823,7 @@ run_grease() {
DEBUG="$debug_level"
# Check that server ignores unrecognized extensions
- # see https://datatracker.ietf.org/doc/draft-ietf-tls-grease
+ # see RFC 8701
if "$normal_hello_ok" && [[ "$proto" != "00" ]]; then
# Try multiple different randomly-generated GREASE extensions,
# but make final test use zero-length extension value, just to
@@ -17934,7 +17934,7 @@ run_grease() {
fi
# Check that server ignores unrecognized cipher suite values
- # see https://datatracker.ietf.org/doc/draft-ietf-tls-grease
+ # see RFC 8701
if "$normal_hello_ok"; then
list=""
for ciph in "${grease_cipher_suites[@]}"; do
@@ -17952,7 +17952,7 @@ run_grease() {
# Check that servers that support ECDHE cipher suites ignore
# unrecognized named group values.
- # see https://datatracker.ietf.org/doc/draft-ietf-tls-grease
+ # see RFC 8701
if [[ "$proto" != "00" ]]; then
# Send a ClientHello that lists all of the ECDHE cipher suites
tls_sockets "$proto" "$ecdhe_ciphers, 00,ff" "ephemeralkey"
@@ -17999,7 +17999,7 @@ run_grease() {
# Check that servers that support the ALPN extension ignore
# unrecognized ALPN values.
- # see https://datatracker.ietf.org/doc/draft-ietf-tls-grease
+ # see RFC 8701
if "$normal_hello_ok" && [[ -z $STARTTLS ]] && [[ "$proto" != "00" ]]; then
for alpn_proto in $ALPN_PROTOs; do
alpn+=",$(printf "%02x" ${#alpn_proto}),$(string_to_asciihex "$alpn_proto")"
From 5b17bbcf878a1587248e0ee1b484d971a792aea7 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Mon, 3 Aug 2020 11:14:10 -0400
Subject: [PATCH 142/211] Add RFC 8701 to list of RFCs
This commit adds RFC 8701 to the list of RFCs in the documentation.
---
doc/testssl.1 | 3 +++
doc/testssl.1.html | 1 +
doc/testssl.1.md | 1 +
3 files changed, 5 insertions(+)
diff --git a/doc/testssl.1 b/doc/testssl.1
index 24a5408..3d1bd53 100644
--- a/doc/testssl.1
+++ b/doc/testssl.1
@@ -824,6 +824,9 @@ RFC 8143: Using Transport Layer Security (TLS) with Network News Transfer Protoc
RFC 8446: The Transport Layer Security (TLS) Protocol Version 1\.3
.
.IP "\(bu" 4
+RFC 8701: Applying Generate Random Extensions And Sustain Extensibility (GREASE) to TLS Extensibility
+.
+.IP "\(bu" 4
W3C CSP: Content Security Policy Level 1\-3
.
.IP "\(bu" 4
diff --git a/doc/testssl.1.html b/doc/testssl.1.html
index 9278e3a..c5e9de3 100644
--- a/doc/testssl.1.html
+++ b/doc/testssl.1.html
@@ -593,6 +593,7 @@ This is to prevent giving out a misleading or wrong grade.
RFC 7919: Negotiated Finite Field Diffie-Hellman Ephemeral Parameters for Transport Layer Security
RFC 8143: Using Transport Layer Security (TLS) with Network News Transfer Protocol (NNTP)
RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3
+RFC 8701: Applying Generate Random Extensions And Sustain Extensibility (GREASE) to TLS Extensibility
W3C CSP: Content Security Policy Level 1-3
TLSWG Draft: The Transport Layer Security (TLS) Protocol Version 1.3
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index 73544d2..30e07aa 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -491,6 +491,7 @@ Please note that for plain TLS-encrypted ports you must not specify the protocol
* RFC 7919: Negotiated Finite Field Diffie-Hellman Ephemeral Parameters for Transport Layer Security
* RFC 8143: Using Transport Layer Security (TLS) with Network News Transfer Protocol (NNTP)
* RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3
+* RFC 8701: Applying Generate Random Extensions And Sustain Extensibility (GREASE) to TLS Extensibility
* W3C CSP: Content Security Policy Level 1-3
* TLSWG Draft: The Transport Layer Security (TLS) Protocol Version 1.3
From e8a930088c74d68676ba3d4435291bcf9664a794 Mon Sep 17 00:00:00 2001
From: Dirk
Date: Mon, 3 Aug 2020 23:11:00 +0200
Subject: [PATCH 143/211] Better debugging of STARTTLS commands
Improved:
* readability of my old code
* readability of debugging statements
* honor $SNEAKY for SMTP greeting
* hook (arg2 to starttls_smtp_dialog() ), if we plan to add / replace SMTP greeting at some point
---
testssl.sh | 103 +++++++++++++++++++++++++++++++----------------------
1 file changed, 60 insertions(+), 43 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 0f22e45..019006b 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -10409,10 +10409,10 @@ starttls_io() {
# Line-based send with newline characters appended (arg2 empty)
-# Stream-based send: arg2:
+# Stream-based send (not in use currently): arg2: .
starttls_just_send(){
if [[ -z "$2" ]] ; then
- debugme echo -e "C: $1 plus lf"
+ debugme echo "C: $1\r\n"
echo -ne "$1\r\n" >&5
else
debugme echo -e "C: $1"
@@ -10436,37 +10436,37 @@ starttls_just_read(){
}
starttls_full_read(){
+ local cont_pattern="$1"
+ local end_pattern="$2"
+ local regex="$3"
local starttls_read_data=()
local one_line=""
local ret=0
- local cont_pattern="$1"
- local end_pattern="$2"
local ret_found=0
+ local debugpad=" > found: "
debugme echo "=== reading banner ... ==="
if [[ $# -ge 3 ]]; then
- debugme echo "=== we'll have to search for \"$3\" pattern ==="
+ debugme echo "=== we'll have to search for \"$regex\" pattern ==="
ret_found=3
fi
local oldIFS="$IFS"
IFS=''
while read -r -t $STARTTLS_SLEEP one_line; ret=$?; (exit $ret); do
- debugme echo "S: ${one_line}"
+ debugme tmln_out "S: ${one_line}"
+ if [[ $DEBUG -ge 5 ]]; then
+ echo "end_pattern/cont_pattern: ${end_pattern} / ${cont_pattern}"
+ fi
if [[ $# -ge 3 ]]; then
- if [[ ${one_line} =~ $3 ]]; then
+ if [[ ${one_line} =~ $regex ]]; then
ret_found=0
- debugme echo "^^^^^^^ that's what we were looking for ==="
+ debugme tmln_out "${debugpad} ${one_line} "
fi
fi
starttls_read_data+=("${one_line}")
- if [[ $DEBUG -ge 4 ]]; then
- echo "one_line: ${one_line}"
- echo "end_pattern: ${end_pattern}"
- echo "cont_pattern: ${cont_pattern}"
- fi
if [[ ${one_line} =~ ${end_pattern} ]]; then
- debugme echo "=== full read finished ==="
+ debugme tmln_out "${debugpad} ${one_line} "
IFS="${oldIFS}"
return ${ret_found}
fi
@@ -10488,13 +10488,15 @@ starttls_full_read(){
}
starttls_ftp_dialog() {
- debugme echo "=== starting ftp STARTTLS dialog ==="
+ local debugpad=" > "
local reAUTHTLS='^ AUTH TLS'
- starttls_full_read '^220-' '^220 ' && debugme echo "received server greeting" &&
- starttls_just_send 'FEAT' && debugme echo "sent FEAT" &&
- starttls_full_read '^(211-| )' '^211 ' "${reAUTHTLS}" && debugme echo "received server features and checked STARTTLS availability" &&
- starttls_just_send 'AUTH TLS' && debugme echo "initiated STARTTLS" &&
- starttls_full_read '^234-' '^234 ' && debugme echo "received ack for STARTTLS"
+
+ debugme echo "=== starting ftp STARTTLS dialog ==="
+ starttls_full_read '^220-' '^220 ' && debugme echo "${debugpad}received server greeting" &&
+ starttls_just_send 'FEAT' && debugme echo "${debugpad}sent FEAT" &&
+ starttls_full_read '^(211-| )' '^211 ' "${reAUTHTLS}" && debugme echo "${debugpad}received server features and checked STARTTLS availability" &&
+ starttls_just_send 'AUTH TLS' && debugme echo "${debugpad}initiated STARTTLS" &&
+ starttls_full_read '^234-' '^234 ' && debugme echo "${debugpad}received ack for STARTTLS"
local ret=$?
debugme echo "=== finished ftp STARTTLS dialog with ${ret} ==="
return $ret
@@ -10503,44 +10505,55 @@ starttls_ftp_dialog() {
# argv1: empty: SMTP, "lmtp" : LMTP
#
starttls_smtp_dialog() {
- local greet_str="EHLO"
+ local greet_str="EHLO testssl.sh"
local proto="smtp"
+ local re250STARTTLS='^250[ -]STARTTLS'
+ local debugpad=" > "
if [[ "$1" == lmtp ]]; then
proto="lmtp"
greet_str="LHLO"
fi
+ if [[ -n "$2" ]]; then
+ # Here we can "add" commands in the future. Please note \r\n will automatically appended
+ greet_str="$2"
+ elif "$SNEAKY"; then
+ greet_str="EHLO google.com"
+ fi
debugme echo "=== starting $proto STARTTLS dialog ==="
- local re250STARTTLS='^250[ -]STARTTLS'
- starttls_full_read '^220-' '^220 ' && debugme echo "received server greeting" &&
- starttls_just_send "$greet_str testssl.sh" && debugme echo "sent $greet_str" &&
- starttls_full_read '^250-' '^250 ' "${re250STARTTLS}" && debugme echo "received server capabilities and checked STARTTLS availability" &&
- starttls_just_send 'STARTTLS' && debugme echo "initiated STARTTLS" &&
- starttls_full_read '^220-' '^220 ' && debugme echo "received ack for STARTTLS"
+ starttls_full_read '^220-' '^220 ' && debugme echo "${debugpad}received server greeting" &&
+ starttls_just_send "$greet_str" && debugme echo "${debugpad}sent $greet_str" &&
+ starttls_full_read '^250-' '^250 ' "${re250STARTTLS}" && debugme echo "${debugpad}received server capabilities and checked STARTTLS availability" &&
+ starttls_just_send 'STARTTLS' && debugme echo "${debugpad}initiated STARTTLS" &&
+ starttls_full_read '^220-' '^220 ' && debugme echo "${debugpad}received ack for STARTTLS"
local ret=$?
debugme echo "=== finished $proto STARTTLS dialog with ${ret} ==="
return $ret
}
starttls_pop3_dialog() {
+ local debugpad=" > "
+
debugme echo "=== starting pop3 STARTTLS dialog ==="
- starttls_full_read '^\+OK' '^\+OK' && debugme echo "received server greeting" &&
- starttls_just_send 'STLS' && debugme echo "initiated STARTTLS" &&
- starttls_full_read '^\+OK' '^\+OK' && debugme echo "received ack for STARTTLS"
+ starttls_full_read '^\+OK' '^\+OK' && debugme echo "${debugpad}received server greeting" &&
+ starttls_just_send 'STLS' && debugme echo "${debugpad}initiated STARTTLS" &&
+ starttls_full_read '^\+OK' '^\+OK' && debugme echo "${debugpad}received ack for STARTTLS"
local ret=$?
debugme echo "=== finished pop3 STARTTLS dialog with ${ret} ==="
return $ret
}
starttls_imap_dialog() {
- debugme echo "=== starting imap STARTTLS dialog ==="
local reSTARTTLS='^\* CAPABILITY(( .*)? IMAP4rev1( .*)? STARTTLS(.*)?|( .*)? STARTTLS( .*)? IMAP4rev1(.*)?)$'
- starttls_full_read '^\* ' '^\* OK ' && debugme echo "received server greeting" &&
- starttls_just_send 'a001 CAPABILITY' && debugme echo "sent CAPABILITY" &&
- starttls_full_read '^\* ' '^a001 OK ' "${reSTARTTLS}" && debugme echo "received server capabilities and checked STARTTLS availability" &&
- starttls_just_send 'a002 STARTTLS' && debugme echo "initiated STARTTLS" &&
- starttls_full_read '^\* ' '^a002 OK ' && debugme echo "received ack for STARTTLS"
+ local debugpad=" > "
+
+ debugme echo "=== starting imap STARTTLS dialog ==="
+ starttls_full_read '^\* ' '^\* OK ' && debugme echo "${debugpad}received server greeting" &&
+ starttls_just_send 'a001 CAPABILITY' && debugme echo "${debugpad}sent CAPABILITY" &&
+ starttls_full_read '^\* ' '^a001 OK ' "${reSTARTTLS}" && debugme echo "${debugpad}received server capabilities and checked STARTTLS availability" &&
+ starttls_just_send 'a002 STARTTLS' && debugme echo "${debugpad}initiated STARTTLS" &&
+ starttls_full_read '^\* ' '^a002 OK ' && debugme echo "${debugpad}received ack for STARTTLS"
local ret=$?
debugme echo "=== finished imap STARTTLS dialog with ${ret} ==="
return $ret
@@ -10562,10 +10575,12 @@ starttls_xmpp_dialog() {
}
starttls_nntp_dialog() {
+ local debugpad=" > "
+
debugme echo "=== starting nntp STARTTLS dialog ==="
- starttls_full_read '$^' '^20[01] ' && debugme echo "received server greeting" &&
- starttls_just_send 'STARTTLS' && debugme echo "initiated STARTTLS" &&
- starttls_full_read '$^' '^382 ' && debugme echo "received ack for STARTTLS"
+ starttls_full_read '$^' '^20[01] ' && debugme echo "${debugpad}received server greeting" &&
+ starttls_just_send 'STARTTLS' && debugme echo "${debugpad}initiated STARTTLS" &&
+ starttls_full_read '$^' '^382 ' && debugme echo "${debugpad}received ack for STARTTLS"
local ret=$?
debugme echo "=== finished nntp STARTTLS dialog with ${ret} ==="
return $ret
@@ -10574,15 +10589,15 @@ starttls_nntp_dialog() {
starttls_postgres_dialog() {
debugme echo "=== starting postgres STARTTLS dialog ==="
local init_tls=", x00, x00 ,x00 ,x08 ,x04 ,xD2 ,x16 ,x2F"
- socksend "${init_tls}" 0 && debugme echo "initiated STARTTLS" &&
- starttls_io "" S 1 && debugme echo "received ack (="S") for STARTTLS"
+ socksend "${init_tls}" 0 && debugme echo "${debugpad}initiated STARTTLS" &&
+ starttls_io "" S 1 && debugme echo "${debugpad}received ack (="S") for STARTTLS"
local ret=$?
debugme echo "=== finished postgres STARTTLS dialog with ${ret} ==="
return $ret
}
starttls_mysql_dialog() {
- debugme echo "=== starting mysql STARTTLS dialog ==="
+ local debugpad=" > "
local login_request="
, x20, x00, x00, x01, # payload_length, sequence_id
x85, xae, xff, x00, # capability flags, CLIENT_SSL always set
@@ -10591,8 +10606,10 @@ starttls_mysql_dialog() {
x00, x00, x00, x00, x00, x00, x00, x00, # string[23] reserved (all [0])
x00, x00, x00, x00, x00, x00, x00, x00,
x00, x00, x00, x00, x00, x00, x00"
+
+ debugme echo "=== starting mysql STARTTLS dialog ==="
socksend "${login_request}" 0
- starttls_just_read 1 && debugme echo "read succeeded"
+ starttls_just_read 1 && debugme echo "${debugpad}read succeeded"
# 1 is the timeout value which only MySQL needs. Note, there seems no response whether STARTTLS
# succeeded. We could try harder, see https://github.com/openssl/openssl/blob/master/apps/s_client.c
# but atm this seems sufficient as later we will fail if there's no STARTTLS.
From 9d626472268a84b8519cb4ff9bb8e120c84b3446 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Tue, 4 Aug 2020 07:35:05 -0400
Subject: [PATCH 144/211] Align ALPN GREASE test with RFC 8701
The ALPN GREASE test was written based on draft-ietf-tls-grease-01, which reserved all ALPN identifiers beginning with the prefix "ignore/". This commit changes the test to align with RFC 8701, which instead reserves {0x0A,0x0A}, {0x1A,0x1A}, ..., {0xFA,0xFA}.
---
testssl.sh | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index cc9a584..ca6d540 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -18018,7 +18018,7 @@ run_grease() {
selected_alpn_protocol="$(grep "ALPN protocol:" "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" | sed 's/ALPN protocol: //')"
# If using a "normal" ALPN extension worked, then add an unrecognized
# ALPN value to the beginning of the extension and try again.
- alpn_proto="ignore/$selected_alpn_protocol"
+ alpn_proto="ZZ" # "ZZ" = "{0x5A,0x5A}"
alpn=",$(printf "%02x" ${#alpn_proto}),$(string_to_asciihex "$alpn_proto")$alpn"
alpn_list_len=${#alpn}/3
alpn_list_len_hex=$(printf "%04x" $alpn_list_len)
@@ -18029,7 +18029,7 @@ run_grease() {
success=$?
if [[ $success -ne 0 ]] && [[ $success -ne 2 ]]; then
prln_svrty_medium " Server fails if ClientHello contains an application_layer_protocol_negotiation extension with an unrecognized ALPN value."
- fileout "$jsonID" "MEDIUM" "erver fails if ClientHello contains an application_layer_protocol_negotiation extension with an unrecognized ALPN value."
+ fileout "$jsonID" "MEDIUM" "Server fails if ClientHello contains an application_layer_protocol_negotiation extension with an unrecognized ALPN value."
bug_found=true
else
grease_selected_alpn_protocol="$(grep "ALPN protocol:" "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" | sed 's/ALPN protocol: //')"
@@ -18037,9 +18037,9 @@ run_grease() {
prln_svrty_medium " Server did not ignore unrecognized ALPN value in the application_layer_protocol_negotiation extension."
fileout "$jsonID" "MEDIUM" "Server did not ignore unrecognized ALPN value in the application_layer_protocol_negotiation extension."
bug_found=true
- elif [[ "$grease_selected_alpn_protocol" =~ ignore/ ]]; then
- prln_svrty_medium " Server selected \"ignore/\" ALPN value in the application_layer_protocol_negotiation extension."
- fileout "$jsonID" "MEDIUM" "Server selected \"ignore/\" ALPN value in the application_layer_protocol_negotiation extension."
+ elif [[ "$grease_selected_alpn_protocol" == $alpn_proto ]]; then
+ prln_svrty_medium " Server selected GREASE ALPN value ($alpn_proto) in the application_layer_protocol_negotiation extension."
+ fileout "$jsonID" "MEDIUM" "Server selected GREASE ALPN value ($alpn_proto) in the application_layer_protocol_negotiation extension."
bug_found=true
fi
fi
From 7f99ffa55d42f0f736e574dc017b9167dc0aad06 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Tue, 4 Aug 2020 07:42:10 -0400
Subject: [PATCH 145/211] Update ETSI ETS test
The commit updates the test for the "Visibility Information" certificate extension used in the ETSI Enterprise Transport Security protocol.
The main change is to support OpenSSL 3.0.0, which prints more information about subject alternative names that are encoded as otherName. For otherName types for the OpenSSL has no information, it prints "otherName: ::" rather than just "otherName: ". So, testssl.sh needs to account for the possibility that the OID for the visibility information certificate extension will be printed.
This commit also updates the reference for this extension and changes the name of the function from etsi_etls_visibility_info() to etls_ets_visibility_info() since the name of the protocol was changed from Enterprise TLS (eTLS) to Enterprise Transport Security (ETS).
This commit does not change the output to the terminal or to JSON/CSV, even though those outputs use the previous name of eTLS rather than ETS.
---
testssl.sh | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index cc9a584..2f6724e 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -8008,8 +8008,8 @@ compare_server_name_to_cert() {
# This function determines whether the certificate (arg3) contains "visibility
# information" (see Section 4.3.3 of
-# https://www.etsi.org/deliver/etsi_ts/103500_103599/10352303/01.01.01_60/ts_10352303v010101p.pdf .
-etsi_etls_visibility_info() {
+# https://www.etsi.org/deliver/etsi_ts/103500_103599/10352303/01.02.01_60/ts_10352303v010201p.pdf.
+etsi_ets_visibility_info() {
local jsonID="$1"
local spaces="$2"
local cert="$3"
@@ -8020,11 +8020,12 @@ etsi_etls_visibility_info() {
# If "visibility information" is present, it will appear in the subjectAltName
# extension (0603551D11) as an otherName with OID 0.4.0.3523.3.1 (060604009B430301).
- # OpenSSL displays all names of type otherName as "othername:".
+ # OpenSSL 1.1.1 and earlier displays all names of type otherName as "othername:".
# As certificates will rarely include a name encoded as an otherName, check the
# text version of the certificate for "othername:" before calling
# external functions to obtain the DER encoded certficate.
- if [[ "$cert_txt" =~ X509v3\ Subject\ Alternative\ Name:.*othername:\ ]]; then
+ if [[ "$cert_txt" =~ X509v3\ Subject\ Alternative\ Name:.*othername:\ ]] || \
+ [[ "$cert_txt" =~ X509v3\ Subject\ Alternative\ Name:.*othername:\ 0.4.0.3523.3.1 ]]; then
dercert="$($OPENSSL x509 -in "$cert" -outform DER 2>>$ERRFILE | hexdump -v -e '16/1 "%02X"')"
if [[ "$dercert" =~ 0603551D110101FF04[0-9A-F]*060604009B430301 ]] || \
[[ "$dercert" =~ 0603551D1104[0-9A-F]*060604009B430301 ]]; then
@@ -9008,7 +9009,7 @@ certificate_info() {
out "$indent"; pr_bold " ETS/\"eTLS\""
out ", visibility info "
jsonID="cert_eTLS"
- etsi_etls_visibility_info "${jsonID}${json_postfix}" "$spaces" "$HOSTCERT" "$cert_txt"
+ etsi_ets_visibility_info "${jsonID}${json_postfix}" "$spaces" "$HOSTCERT" "$cert_txt"
# *Currently* this is even listed as a vulnerability (CWE-310, CVE-2019-919), see
# https://nvd.nist.gov/vuln/detail/CVE-2019-9191, https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9191
# For now we leave this here. We may want to change that later or add infos to other sections (FS & vulnerability)
From fd5928af475d32b0c541264a52f8a929f886d231 Mon Sep 17 00:00:00 2001
From: David Cooper
Date: Thu, 6 Aug 2020 07:50:01 -0400
Subject: [PATCH 146/211] Use fewer external function calls
This commit modifies a few functions to use fewer external function calls. In most cases this involves replacing external function calls with Bash internal functions, but in one case it involves replacing multiple external function calls with one call to awk.
This commit makes a few changes to the way that some functions work.
is_ipv4addr() and is_ipv6addr() will now strictly only accept a string that is an IPv4 (or IPv6) address and nothing else.
A couple of changes were also made to match_ipv4_httpheader(). First, lines that match $excluded_header (formerly $whitelisted_header) are not processed in the while loop. This prevents the excluded header from being output in the case that $HEADERFILE includes a non-excluded header with an IPv4 address and an excluded header with a string that looks like an IPv4 address.
The list of excluded headers was also modified to exclude any line that begins "Server: " rather than just lines that begin "Server: PRTG". According to https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server, the "Server" header describes the software used by the server, so it seems reasonable to expect that this header line will never contain an IPv4 address. Also, looking at some old test results I found cases in which Oracle software version numbers in the Server header were mistakenly matched as IPv4 addresses.
---
testssl.sh | 81 ++++++++++++++++++++++++++++++------------------------
1 file changed, 45 insertions(+), 36 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 4fb0bdd..3af9081 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -124,7 +124,7 @@ trap "child_error" USR1
#
declare -r VERSION="3.1dev"
declare -r SWCONTACT="dirk aet testssl dot sh"
-grep -E -q "dev|rc|beta" <<< "$VERSION" && \
+[[ "$VERSION" =~ dev|rc|beta ]] && \
SWURL="https://testssl.sh/dev/" ||
SWURL="https://testssl.sh/"
if git log &>/dev/null; then
@@ -843,24 +843,35 @@ is_ipv4addr() {
local ipv4address="$octet\\.$octet\\.$octet\\.$octet"
[[ -z "$1" ]] && return 1
- # more than numbers, important for hosts like AAA.BBB.CCC.DDD.in-addr.arpa.DOMAIN.TLS
- [[ -n $(tr -d '0-9\.' <<< "$1") ]] && return 1
- grep -Eq "$ipv4address" <<< "$1" && \
+ # Check that $1 contains an IPv4 address and nothing else
+ [[ "$1" =~ $ipv4address ]] && [[ "$1" == $BASH_REMATCH ]] && \
return 0 || \
return 1
}
-# a bit easier
+# See RFC 4291, Section 2.2
is_ipv6addr() {
+ local ipv6seg="[0-9A-Fa-f]{1,4}"
+ local octet="(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])"
+ local ipv4address="$octet\\.$octet\\.$octet\\.$octet"
+ local ipv6address
+
+ ipv6address="($ipv6seg:){7}(:|$ipv6seg)"
+ ipv6address+="|($ipv6seg:){6}(:|:$ipv6seg|$ipv4address)"
+ ipv6address+="|($ipv6seg:){5}(:|(:$ipv6seg){1,2}|:$ipv4address)"
+ ipv6address+="|($ipv6seg:){4}(:|(:$ipv6seg){1,3}|:($ipv6seg:){0,1}$ipv4address)"
+ ipv6address+="|($ipv6seg:){3}(:|(:$ipv6seg){1,4}|:($ipv6seg:){0,2}$ipv4address)"
+ ipv6address+="|($ipv6seg:){2}(:|(:$ipv6seg){1,5}|:($ipv6seg:){0,3}$ipv4address)"
+ ipv6address+="|($ipv6seg:){1}(:|(:$ipv6seg){1,6}|:($ipv6seg:){0,4}$ipv4address)"
+ ipv6address+="|:((:$ipv6seg){1,7}|:($ipv6seg:){0,5}$ipv4address)"
+
[[ -z "$1" ]] && return 1
- # less than 2x ":"
- [[ $(count_lines "$(tr ':' '\n' <<< "$1")") -le 1 ]] && \
+
+ # Check that $1 contains an IPv4 address and nothing else
+ [[ "$1" =~ $ipv6address ]] && [[ "$1" == $BASH_REMATCH ]] && \
+ return 0 || \
return 1
- # check which chars allowed:
- [[ -n "$(tr -d '0-9:a-fA-F ' <<< "$1" | sed -e '/^$/d')" ]] && \
- return 1
- return 0
}
###### END universal helper function definitions ######
@@ -2379,12 +2390,11 @@ run_http_header() {
match_ipv4_httpheader() {
local octet="(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])"
local ipv4address="$octet\\.$octet\\.$octet\\.$octet"
- local whitelisted_header="pagespeed|page-speed|^Content-Security-Policy|^MicrosoftSharePointTeamServices|^X-OWA-Version|^Location|^Server: PRTG"
+ local excluded_header="pagespeed|page-speed|^Content-Security-Policy|^MicrosoftSharePointTeamServices|^X-OWA-Version|^Location|^Server: "
local your_ip_msg="(check if it's your IP address or e.g. a cluster IP)"
- local result
+ local headers result
local first=true
local spaces=" "
- local count
local jsonID="ipv4_in_header"
local cwe="CWE-212"
local cve=""
@@ -2393,27 +2403,24 @@ match_ipv4_httpheader() {
run_http_header "$1" || return 1
fi
- # Whitelist some headers as they are mistakenly identified as ipv4 address. Issues #158, #323.
+ # Exclude some headers as they are mistakenly identified as ipv4 address. Issues #158, #323.
# Also facebook used to have a CSP rule for 127.0.0.1
- if grep -Evai "$whitelisted_header" $HEADERFILE | grep -Eiq "$ipv4address"; then
+ headers="$(grep -Evai "$excluded_header" $HEADERFILE)"
+ if [[ "$headers" =~ $ipv4address ]]; then
pr_bold " IPv4 address in header "
- count=0
while read line; do
- result="$(grep -E "$ipv4address" <<< "$line")"
- result=$(strip_lf "$result")
- if [[ -n "$result" ]]; then
- if ! $first; then
- out "$spaces"
- your_ip_msg=""
- else
- first=false
- fi
- pr_svrty_medium "$result"
- outln "\n$spaces$your_ip_msg"
- fileout "$jsonID" "MEDIUM" "$result $your_ip_msg" "$cve" "$cwe"
+ [[ "$line" =~ $ipv4address ]] || continue
+ result=$(strip_lf "$line")
+ if ! $first; then
+ out "$spaces"
+ your_ip_msg=""
+ else
+ first=false
fi
- count=$count+1
- done < $HEADERFILE
+ pr_svrty_medium "$result"
+ outln "\n$spaces$your_ip_msg"
+ fileout "$jsonID" "MEDIUM" "$result $your_ip_msg" "$cve" "$cwe"
+ done <<< "$headers"
fi
}
@@ -8437,7 +8444,7 @@ certificate_info() {
fileout "${jsonID}${json_postfix}" "OK" "DSA with SHA256"
;;
rsassaPss)
- cert_sig_hash_algo="$(grep -A 1 "Signature Algorithm" <<< "$cert_txt" | head -2 | tail -1 | sed 's/^.*Hash Algorithm: //')"
+ cert_sig_hash_algo="$(awk '/Signature Algorithm/ { getline; print $0; exit }' <<< "$cert_txt" | sed 's/^.*Hash Algorithm: //')"
case $cert_sig_hash_algo in
sha1)
prln_svrty_medium "RSASSA-PSS with SHA1"
@@ -11221,7 +11228,7 @@ hmac() {
else
output="$(asciihex_to_binary "$text" | $OPENSSL dgst "$hash_fn" -mac HMAC -macopt hexkey:"$key" 2>/dev/null)"
ret=$?
- tm_out "$(awk '/=/ { print $2 }' <<< "$output")"
+ tm_out "${output#*= }"
fi
return $ret
}
@@ -11246,7 +11253,7 @@ hmac-transcript() {
$OPENSSL dgst "$hash_fn" -binary 2>/dev/null | \
$OPENSSL dgst "$hash_fn" -mac HMAC -macopt hexkey:"$key" 2>/dev/null)"
ret=$?
- tm_out "$(toupper "$(awk '/=/ { print $2 }' <<< "$output")")"
+ tm_out "$(toupper "${output#*= }")"
fi
return $ret
}
@@ -11336,7 +11343,8 @@ derive-secret() {
*) return 7
esac
- hash_messages="$(asciihex_to_binary "$messages" | $OPENSSL dgst "$hash_fn" 2>/dev/null | awk '/=/ { print $2 }')"
+ hash_messages="$(asciihex_to_binary "$messages" | $OPENSSL dgst "$hash_fn" 2>/dev/null)"
+ hash_messages="${hash_messages#*= }"
hkdf-expand-label "$hash_fn" "$secret" "$label" "$hash_messages" "$hash_len"
return $?
}
@@ -11380,7 +11388,8 @@ create-initial-transcript() {
else
return 1
fi
- hash_clienthello1="$(asciihex_to_binary "$clienthello1" | $OPENSSL dgst "$hash_fn" 2>/dev/null | awk '/=/ { print $2 }')"
+ hash_clienthello1="$(asciihex_to_binary "$clienthello1" | $OPENSSL dgst "$hash_fn" 2>/dev/null)"
+ hash_clienthello1="${hash_clienthello1#*= }"
msg_transcript="FE0000$(printf "%02x" $((${#hash_clienthello1}/2)))$hash_clienthello1$hrr$clienthello2$serverhello"
else
msg_transcript="$clienthello2$serverhello"
From ac6b64ce3648a8e3370763fa63a18ff03f94a6b6 Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Tue, 11 Aug 2020 12:01:28 +0200
Subject: [PATCH 147/211] Trying to address no STARTTLS offerings (2)
This PR will replace #1566. It addresses that if the server side doesn't show STARTTLS
testssl.sh should exit and label it accordingly (see #1536).
For this to achieve starttls_just_send() was were changed so that a return value from of 3
signals the STARTTLS pattern wasn't found is passed back to the parent fd_socket() whcih
will then act accordingly.
Also:
* starttls_full_read() + starttls_just_send() were improved for readability and debugging.
* The caller of starttls_full_read() + starttls_just_send() had redundant indentations which were moved to the callee
* minor bugs were squashed (e.g. ``fd_socket()``'s return values =!0 always were referring to STARTTLS also when no STARTTLS was requested)
This was tested (negative + test and positive) for FTP and SMTP which worked as expected. For POP, IMAP and NNTP it should work
accordingly but I had trouble finding a server whcih DID NOT support STARTTLS.
All other protocols basically should also cause testssl.sh to bail out but haven't been tested either. However
here starttls_io() won't return 3. It returns 1 in a case of problems. It uses NR_STARTTLS_FAIL. If it's encountered 2+
times that STARTTLS fails it early exists using fatal(). So we maybe want to consider changing starttls_io() in the future
to also use return 3 in the case STARTTLS is not offered.
---
testssl.sh | 157 +++++++++++++++++++++++++++++++----------------------
1 file changed, 93 insertions(+), 64 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 3af9081..243eb19 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -197,6 +197,7 @@ IGN_OCSP_PROXY=${IGN_OCSP_PROXY:-false} # Also when --proxy is supplied it is ig
HEADER_MAXSLEEP=${HEADER_MAXSLEEP:-5} # we wait this long before killing the process to retrieve a service banner / http header
MAX_SOCKET_FAIL=${MAX_SOCKET_FAIL:-2} # If this many failures for TCP socket connects are reached we terminate
MAX_OSSL_FAIL=${MAX_OSSL_FAIL:-2} # If this many failures for s_client connects are reached we terminate
+MAX_STARTTLS_FAIL=${MAX_STARTTLS_FAIL:-2} # max number of STARTTLS handshake failures in plaintext phase
MAX_HEADER_FAIL=${MAX_HEADER_FAIL:-2} # If this many failures for HTTP GET are encountered we don't try again to get the header
MAX_WAITSOCK=${MAX_WAITSOCK:-10} # waiting at max 10 seconds for socket reply. There shouldn't be any reason to change this.
CCS_MAX_WAITSOCK=${CCS_MAX_WAITSOCK:-5} # for the two CCS payload (each). There shouldn't be any reason to change this.
@@ -252,6 +253,7 @@ TIMEOUT_CMD=""
HAD_SLEPT=0
NR_SOCKET_FAIL=0 # Counter for socket failures
NR_OSSL_FAIL=0 # .. for OpenSSL connects
+NR_STARTTLS_FAIL=0 # .. for STARTTLS failures
NR_HEADER_FAIL=0 # .. for HTTP_GET
PROTOS_OFFERED="" # This keeps which protocol is being offered. See has_server_protocol().
TLS12_CIPHER_OFFERED="" # This contains the hexcode of a cipher known to be supported by the server with TLS 1.2
@@ -10417,16 +10419,19 @@ starttls_io() {
# Line-based send with newline characters appended (arg2 empty)
-# Stream-based send (not in use currently): arg2: .
+# arg2: debug_string -- what we had in the caller previously
starttls_just_send(){
- if [[ -z "$2" ]] ; then
- debugme echo "C: $1\r\n"
- echo -ne "$1\r\n" >&5
+ local -i ret=0
+
+ debugme echo "C: $1\r\n"
+ echo -ne "$1\r\n" >&5
+ ret=$?
+ if [[ $ret -eq 0 ]]; then
+ debugme echo " > succeeded: $2"
else
- debugme echo -e "C: $1"
- echo -ne "$1" >&5
+ debugme echo " > failed: $2 ($ret)"
fi
- return $?
+ return $ret
}
# arg1: (optional): wait time
@@ -10446,66 +10451,74 @@ starttls_just_read(){
starttls_full_read(){
local cont_pattern="$1"
local end_pattern="$2"
- local regex="$3"
+ local starttls_regex="$3" # optional: pattern we search for in the server's response
+ local debug_str="$4" # optional
local starttls_read_data=()
local one_line=""
local ret=0
local ret_found=0
local debugpad=" > found: "
+ local oldIFS="$IFS"
debugme echo "=== reading banner ... ==="
- if [[ $# -ge 3 ]]; then
- debugme echo "=== we'll have to search for \"$regex\" pattern ==="
+ if [[ -n "$starttls_regex" ]]; then
+ debugme echo "=== we'll have to search for \"$starttls_regex\" pattern ==="
+ # pre-set an error if we won't find the ~regex
ret_found=3
fi
- local oldIFS="$IFS"
IFS=''
+ # Now read handshake line by line and act on the args supplied.
+ # Exit the subshell if timeout has been hit (-t $STARTTLS_SLEEP)
while read -r -t $STARTTLS_SLEEP one_line; ret=$?; (exit $ret); do
debugme tmln_out "S: ${one_line}"
if [[ $DEBUG -ge 5 ]]; then
echo "end_pattern/cont_pattern: ${end_pattern} / ${cont_pattern}"
fi
- if [[ $# -ge 3 ]]; then
- if [[ ${one_line} =~ $regex ]]; then
- ret_found=0
+ if [[ -n "$starttls_regex" ]]; then
+ if [[ ${one_line} =~ $starttls_regex ]]; then
debugme tmln_out "${debugpad} ${one_line} "
+ # We don't exit here as the buffer is not empty. So we continue reading but save the status:
+ ret_found=0
fi
fi
starttls_read_data+=("${one_line}")
if [[ ${one_line} =~ ${end_pattern} ]]; then
debugme tmln_out "${debugpad} ${one_line} "
IFS="${oldIFS}"
- return ${ret_found}
+ break
fi
if [[ ! ${one_line} =~ ${cont_pattern} ]]; then
debugme echo "=== full read syntax error, expected regex pattern ${cont_pattern} (cont) or ${end_pattern} (end) ==="
IFS="${oldIFS}"
- return 2
+ ret_found=2
+ break
fi
done <&5
- if [[ $DEBUG -ge 2 ]]; then
+ if [[ $ret_found -eq 0 ]]; then
+ # Print the debug statement we previously had in the caller function
+ [[ -n "$debug_str" ]] && debugme echo " >> $debug_str"
+ else
if [[ $ret -ge 128 ]]; then
- echo "=== timeout reading ==="
- else
- echo "=== full read error (no timeout) ==="
+ debugme echo "=== timeout reading ==="
+ $ret_found=$ret
fi
fi
IFS="${oldIFS}"
- return $ret
+ return $ret_found
}
starttls_ftp_dialog() {
- local debugpad=" > "
- local reAUTHTLS='^ AUTH TLS'
+ local -i ret=0
+ local reSTARTTLS='^ AUTH TLS'
debugme echo "=== starting ftp STARTTLS dialog ==="
- starttls_full_read '^220-' '^220 ' && debugme echo "${debugpad}received server greeting" &&
- starttls_just_send 'FEAT' && debugme echo "${debugpad}sent FEAT" &&
- starttls_full_read '^(211-| )' '^211 ' "${reAUTHTLS}" && debugme echo "${debugpad}received server features and checked STARTTLS availability" &&
- starttls_just_send 'AUTH TLS' && debugme echo "${debugpad}initiated STARTTLS" &&
- starttls_full_read '^234-' '^234 ' && debugme echo "${debugpad}received ack for STARTTLS"
- local ret=$?
+ starttls_full_read '^220-' '^220 ' '' "received server greeting" &&
+ starttls_just_send 'FEAT' "sent FEAT" &&
+ starttls_full_read '^(211-| )' '^211 ' "${reSTARTTLS}" "received server features and checked STARTTLS availability" &&
+ starttls_just_send 'AUTH TLS' "initiated STARTTLS" &&
+ starttls_full_read '^234-' '^234 ' '' "received ack for STARTTLS"
+ ret=$?
debugme echo "=== finished ftp STARTTLS dialog with ${ret} ==="
return $ret
}
@@ -10515,59 +10528,61 @@ starttls_ftp_dialog() {
starttls_smtp_dialog() {
local greet_str="EHLO testssl.sh"
local proto="smtp"
- local re250STARTTLS='^250[ -]STARTTLS'
- local debugpad=" > "
+ local reSTARTTLS='^250[ -]STARTTLS'
+ local -i ret=0
if [[ "$1" == lmtp ]]; then
proto="lmtp"
greet_str="LHLO"
fi
if [[ -n "$2" ]]; then
- # Here we can "add" commands in the future. Please note \r\n will automatically appended
+ # Here we can "add" commands in the future. Please note \r\n will automatically be appended
greet_str="$2"
elif "$SNEAKY"; then
greet_str="EHLO google.com"
fi
debugme echo "=== starting $proto STARTTLS dialog ==="
- starttls_full_read '^220-' '^220 ' && debugme echo "${debugpad}received server greeting" &&
- starttls_just_send "$greet_str" && debugme echo "${debugpad}sent $greet_str" &&
- starttls_full_read '^250-' '^250 ' "${re250STARTTLS}" && debugme echo "${debugpad}received server capabilities and checked STARTTLS availability" &&
- starttls_just_send 'STARTTLS' && debugme echo "${debugpad}initiated STARTTLS" &&
- starttls_full_read '^220-' '^220 ' && debugme echo "${debugpad}received ack for STARTTLS"
- local ret=$?
+ starttls_full_read '^220-' '^220 ' '' "received server greeting" &&
+ starttls_just_send "$greet_str" "sent $greet_str" &&
+ starttls_full_read '^250-' '^250 ' "${reSTARTTLS}" "received server capabilities and checked STARTTLS availability" &&
+ starttls_just_send 'STARTTLS' "initiated STARTTLS" &&
+ starttls_full_read '^220-' '^220 ' '' "received ack for STARTTLS"
+ ret=$?
debugme echo "=== finished $proto STARTTLS dialog with ${ret} ==="
return $ret
}
starttls_pop3_dialog() {
- local debugpad=" > "
+ local -i ret=0
debugme echo "=== starting pop3 STARTTLS dialog ==="
- starttls_full_read '^\+OK' '^\+OK' && debugme echo "${debugpad}received server greeting" &&
- starttls_just_send 'STLS' && debugme echo "${debugpad}initiated STARTTLS" &&
- starttls_full_read '^\+OK' '^\+OK' && debugme echo "${debugpad}received ack for STARTTLS"
- local ret=$?
+ starttls_full_read '^\+OK' '^\+OK' '' "received server greeting" &&
+ starttls_just_send 'STLS' "initiated STARTTLS" &&
+ starttls_full_read '^\+OK' '^\+OK' '' "received ack for STARTTLS"
+ ret=$?
debugme echo "=== finished pop3 STARTTLS dialog with ${ret} ==="
return $ret
}
starttls_imap_dialog() {
+ local -i ret=0
local reSTARTTLS='^\* CAPABILITY(( .*)? IMAP4rev1( .*)? STARTTLS(.*)?|( .*)? STARTTLS( .*)? IMAP4rev1(.*)?)$'
- local debugpad=" > "
debugme echo "=== starting imap STARTTLS dialog ==="
- starttls_full_read '^\* ' '^\* OK ' && debugme echo "${debugpad}received server greeting" &&
- starttls_just_send 'a001 CAPABILITY' && debugme echo "${debugpad}sent CAPABILITY" &&
- starttls_full_read '^\* ' '^a001 OK ' "${reSTARTTLS}" && debugme echo "${debugpad}received server capabilities and checked STARTTLS availability" &&
- starttls_just_send 'a002 STARTTLS' && debugme echo "${debugpad}initiated STARTTLS" &&
- starttls_full_read '^\* ' '^a002 OK ' && debugme echo "${debugpad}received ack for STARTTLS"
- local ret=$?
+ starttls_full_read '^\* ' '^\* OK ' '' "received server greeting" &&
+ starttls_just_send 'a001 CAPABILITY' "sent CAPABILITY" &&
+ starttls_full_read '^\* ' '^a001 OK ' "${reSTARTTLS}" "received server capabilities and checked STARTTLS availability" &&
+ starttls_just_send 'a002 STARTTLS' "initiated STARTTLS" &&
+ starttls_full_read '^\* ' '^a002 OK ' '' "received ack for STARTTLS"
+ ret=$?
debugme echo "=== finished imap STARTTLS dialog with ${ret} ==="
return $ret
}
starttls_xmpp_dialog() {
+ local -i ret=0
+
debugme echo "=== starting xmpp STARTTLS dialog ==="
[[ -z $XMPP_HOST ]] && XMPP_HOST="$NODE"
@@ -10577,36 +10592,40 @@ starttls_xmpp_dialog() {
starttls_io "" 'starttls(.*)features' 1 &&
starttls_io " " '" 'JUSTSEND' 2
- local ret=$?
+ ret=$?
debugme echo "=== finished xmpp STARTTLS dialog with ${ret} ==="
return $ret
}
starttls_nntp_dialog() {
- local debugpad=" > "
+ local -i ret=0
debugme echo "=== starting nntp STARTTLS dialog ==="
- starttls_full_read '$^' '^20[01] ' && debugme echo "${debugpad}received server greeting" &&
- starttls_just_send 'STARTTLS' && debugme echo "${debugpad}initiated STARTTLS" &&
- starttls_full_read '$^' '^382 ' && debugme echo "${debugpad}received ack for STARTTLS"
- local ret=$?
+ starttls_full_read '$^' '^20[01] ' '' "received server greeting" &&
+ starttls_just_send 'STARTTLS' "initiated STARTTLS" &&
+ starttls_full_read '$^' '^382 ' '' "received ack for STARTTLS"
+ ret=$?
debugme echo "=== finished nntp STARTTLS dialog with ${ret} ==="
return $ret
}
starttls_postgres_dialog() {
+ local -i ret=0
+ local debugpad=" > "
+ local starttls_init=", x00, x00 ,x00 ,x08 ,x04 ,xD2 ,x16 ,x2F"
+
debugme echo "=== starting postgres STARTTLS dialog ==="
- local init_tls=", x00, x00 ,x00 ,x08 ,x04 ,xD2 ,x16 ,x2F"
- socksend "${init_tls}" 0 && debugme echo "${debugpad}initiated STARTTLS" &&
+ socksend "${starttls_init}" 0 && debugme echo "${debugpad}initiated STARTTLS" &&
starttls_io "" S 1 && debugme echo "${debugpad}received ack (="S") for STARTTLS"
- local ret=$?
+ ret=$?
debugme echo "=== finished postgres STARTTLS dialog with ${ret} ==="
return $ret
}
starttls_mysql_dialog() {
local debugpad=" > "
- local login_request="
+ local -i ret=0
+ local starttls_init="
, x20, x00, x00, x01, # payload_length, sequence_id
x85, xae, xff, x00, # capability flags, CLIENT_SSL always set
x00, x00, x00, x01, # max-packet size
@@ -10616,8 +10635,8 @@ starttls_mysql_dialog() {
x00, x00, x00, x00, x00, x00, x00"
debugme echo "=== starting mysql STARTTLS dialog ==="
- socksend "${login_request}" 0
- starttls_just_read 1 && debugme echo "${debugpad}read succeeded"
+ socksend "${starttls_init}" 0 && debugme echo "${debugpad}initiated STARTTLS" &&
+ starttls_just_read 1 "read succeeded"
# 1 is the timeout value which only MySQL needs. Note, there seems no response whether STARTTLS
# succeeded. We could try harder, see https://github.com/openssl/openssl/blob/master/apps/s_client.c
# but atm this seems sufficient as later we will fail if there's no STARTTLS.
@@ -10625,7 +10644,7 @@ starttls_mysql_dialog() {
# also there's a banner in the reply "mysql_native_password"
# TODO: We could detect if the server supports STARTTLS via the "Server Capabilities"
# bit field, but we'd need to parse the binary stream, with greater precision than regex.
- local ret=$?
+ ret=$?
debugme echo "=== finished mysql STARTTLS dialog with ${ret} ==="
return $ret
}
@@ -10733,9 +10752,19 @@ fd_socket() {
*) # we need to throw an error here -- otherwise testssl.sh treats the STARTTLS protocol as plain SSL/TLS which leads to FP
fatal "FIXME: STARTTLS protocol $STARTTLS_PROTOCOL is not yet supported" $ERR_NOSUPPORT
esac
+ ret=$?
+ case $ret in
+ 0) return 0 ;;
+ 3) fatal "No STARTTLS found in handshake" $ERR_CONNECT ;;
+ *) ((NR_STARTTLS_FAIL++))
+ # This are mostly timeouts here (code >=128). We give the client a chance to try again later. For cases
+ # where we have no STARTTLS in the server banner however - ret code=3 - we don't neet to try again
+ connectivity_problem $NR_STARTTLS_FAIL $MAX_STARTTLS_FAIL "STARTTLS handshake failed (code: $ret)" "repeated STARTTLS problems, giving up ($ret)"
+ return 6 ;;
+ esac
fi
+ # Plain socket ok, yes or no?
[[ $? -eq 0 ]] && return 0
- prln_warning " STARTTLS handshake failed"
return 1
}
From c4841c83eb9b954e02d896c9802bc72bb6c9520a Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Tue, 11 Aug 2020 15:30:53 +0200
Subject: [PATCH 148/211] Don't penalize rating for CAs which aren't in the
Java store
This fixes #1648.
Java store doesn't seem to be as complete. No downgrading of trust rating
to T but we still need to raise a red flag for some Java clients
---
testssl.sh | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/testssl.sh b/testssl.sh
index 3af9081..490aa54 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -7221,10 +7221,9 @@ determine_trust() {
# we did to stdout the warning above already, so we could stay here with OK:
fileout "${jsonID}${json_postfix}" "OK" "passed. $addtl_warning"
else
- # at least one failed
pr_svrty_critical "NOT ok"
if ! "$some_ok"; then
- # all failed (we assume with the same issue), we're displaying the reason
+ # ALL failed (we assume with the same issue), we're displaying the reason
out " "
code="$(verify_retcode_helper "${verify_retcode[1]}")"
if [[ "$code" =~ "pls report" ]]; then
@@ -7235,15 +7234,13 @@ determine_trust() {
fileout "${jsonID}${json_postfix}" "CRITICAL" "failed $code. $addtl_warning"
set_grade_cap "T" "Issues with the chain of trust $code"
else
- # is one ok and the others not ==> display the culprit store
+ # alt least one ok and other(s) not ==> display the culprit store(s)
if "$some_ok"; then
pr_svrty_critical ":"
- for ((i=1;i<=num_ca_bundles;i++)); do
+ for (( i=1; i<=num_ca_bundles; i++ )); do
if ${trust[i]}; then
ok_was="${certificate_file[i]} $ok_was"
else
- #code="$(verify_retcode_helper ${verify_retcode[i]})"
- #notok_was="${certificate_file[i]} $notok_was"
pr_svrty_high " ${certificate_file[i]} "
code="$(verify_retcode_helper "${verify_retcode[i]}")"
if [[ "$code" =~ "pls report" ]]; then
@@ -7252,11 +7249,13 @@ determine_trust() {
out "$code"
fi
notok_was="${certificate_file[i]} $code $notok_was"
- set_grade_cap "T" "Issues with chain of trust $code"
+ if ! [[ ${certificate_file[i]} =~ Java ]]; then
+ # Exemption for Java AND rating, as this store doesn't seem to be as complete.
+ # We won't penelize this but we still need to raise a red flag. See #1648
+ set_grade_cap "T" "Issues with chain of trust $code"
+ fi
fi
done
- #pr_svrty_high "$notok_was "
- #outln "$code"
outln
# lf + green ones
[[ "$DEBUG" -eq 0 ]] && tm_out "$spaces"
@@ -7269,7 +7268,6 @@ determine_trust() {
outln
return 0
}
-
# not handled: Root CA supplied ("contains anchor" in SSLlabs terminology)
tls_time() {
From 46536132111cd39f2dbd21a45a6113600535d3fc Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Tue, 11 Aug 2020 15:36:43 +0200
Subject: [PATCH 149/211] Add mitigate_javastore4rating
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7ada38e..b57102f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@
* Don't use external pwd anymore
* STARTTLS: XMPP server support
* Rating (SSL Labs, not complete)
+* Don't penalize missing trust in rating when CA not in Java store
* Added support for certificates with EdDSA signatures and pubilc keys
### Features implemented / improvements in 3.0
From 1915a7b624ccace78455057c6817cff8c52f048c Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Tue, 11 Aug 2020 15:41:20 +0200
Subject: [PATCH 150/211] STARTTLS
---
CHANGELOG.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7ada38e..918a568 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,8 @@
* Security fix: DNS input
* Don't use external pwd anymore
* STARTTLS: XMPP server support
+* Code improvements to STARTTLS
+* Detect better when no STARTTLS is offered
* Rating (SSL Labs, not complete)
* Added support for certificates with EdDSA signatures and pubilc keys
From 953e1bd0ff89dda8b3d2a296a06673a8eb91cd2a Mon Sep 17 00:00:00 2001
From: Dirk Wetter
Date: Thu, 13 Aug 2020 18:11:24 +0200
Subject: [PATCH 151/211] Phrase --version & friends as standalone
This PR fixes #1671.
Primarily there's now an additional case statement in the main while loop
which just calls fatal() when it detects --help -b --banner -v or --version.
The documentation was also updated to reflect that.
(Some grammar and other errors which I stumbled over were corrected too)
---
doc/testssl.1 | 6 +++---
doc/testssl.1.html | 14 ++++++--------
doc/testssl.1.md | 6 +++---
testssl.sh | 24 ++++++++++++------------
4 files changed, 24 insertions(+), 26 deletions(-)
diff --git a/doc/testssl.1 b/doc/testssl.1
index 3d1bd53..2f4fea5 100644
--- a/doc/testssl.1
+++ b/doc/testssl.1
@@ -75,8 +75,8 @@ Options are either short or long options\. Any long or short option requiring a
.P
\fB\fR or \fB\-\-file \fR always needs to be the last parameter\.
.
-.SS "BANNER OPTIONS"
-\fB\-\-help\fR (or no arg) display command line help
+.SS "BANNER OPTIONS (standalone)"
+\fB\-\-help\fR (or no arg) displays command line help
.
.P
\fB\-b, \-\-banner\fR displays testssl\.sh banner, including license, usage conditions, version of testssl\.sh, detected openssl version, its path to it, # of ciphers of openssl, its build date and the architecture\.
@@ -85,7 +85,7 @@ Options are either short or long options\. Any long or short option requiring a
\fB\-v, \-\-version\fR same as before
.
.P
-\fB\-V [pattern] , \-\-local [pattern]\fR pretty print all local ciphers supported by openssl version\. If a pattern is supplied it performs a match (ignore case) on any of the strings supplied in the wide output, see below\. The pattern will be searched in the any of the columns: hexcode, cipher suite name (OpenSSL or IANA), key exchange, encryption, bits\. It does a word pattern match for non\-numbers, for number just a normal match applies\. Numbers here are defined as [0\-9,A\-F]\. This means (attention: catch) that the pattern CBC is matched as non\-word, but AES as word\.
+\fB\-V [pattern], \-\-local [pattern]\fR pretty print all local ciphers supported by openssl version\. If a pattern is supplied it performs a match (ignore case) on any of the strings supplied in the wide output, see below\. The pattern will be searched in the any of the columns: hexcode, cipher suite name (OpenSSL or IANA), key exchange, encryption, bits\. It does a word pattern match for non\-numbers, for number just a normal match applies\. Numbers here are defined as [0\-9,A\-F]\. This means (attention: catch) that the pattern CBC is matched as non\-word, but AES as word\. This option also accepts -\fB-openssl=\fR\.
.
.SS "INPUT PARAMETERS"
\fBURI\fR can be a hostname, an IPv4 or IPv6 address (restriction see below) or an URL\. IPv6 addresses need to be in square brackets\. For any given parameter port 443 is assumed unless specified by appending a colon and a port number\. The only preceding protocol specifier allowed is \fBhttps\fR\. You need to be aware that checks for an IP address might not hit the vhost you want\. DNS resolution (A/AAAA record) is being performed unless you have an \fB/etc/hosts\fR entry for the hostname\.
diff --git a/doc/testssl.1.html b/doc/testssl.1.html
index c5e9de3..e3d78d7 100644
--- a/doc/testssl.1.html
+++ b/doc/testssl.1.html
@@ -143,15 +143,15 @@ linked OpenSSL binaries for major operating systems are supplied in ./bin/
<URI>
or --file <FILE>
always needs to be the last parameter.
-BANNER OPTIONS
+BANNER OPTIONS (standalone)
---help
(or no arg) display command line help
+--help
(or no arg) displays command line help
-b, --banner
displays testssl.sh banner, including license, usage conditions, version of testssl.sh, detected openssl version, its path to it, # of ciphers of openssl, its build date and the architecture.
-v, --version
same as before
--V [pattern] , --local [pattern]
pretty print all local ciphers supported by openssl version. If a pattern is supplied it performs a match (ignore case) on any of the strings supplied in the wide output, see below. The pattern will be searched in the any of the columns: hexcode, cipher suite name (OpenSSL or IANA), key exchange, encryption, bits. It does a word pattern match for non-numbers, for number just a normal match applies. Numbers here are defined as [0-9,A-F]. This means (attention: catch) that the pattern CBC is matched as non-word, but AES as word.
+-V [pattern], --local [pattern]
pretty print all local ciphers supported by openssl version. If a pattern is supplied it performs a match (ignore case) on any of the strings supplied in the wide output, see below. The pattern will be searched in the any of the columns: hexcode, cipher suite name (OpenSSL or IANA), key exchange, encryption, bits. It does a word pattern match for non-numbers, for number just a normal match applies. Numbers here are defined as [0-9,A-F]. This means (attention: catch) that the pattern CBC is matched as non-word, but AES as word. This option also accepts --openssl=<path_to_openssl>
.
INPUT PARAMETERS
@@ -189,7 +189,7 @@ The same can be achieved by setting the environment variable WARNINGSSPECIAL 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.
+-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.
--xmpphost <jabber_domain>
is an additional option for STARTTLS enabled XMPP: It expects the jabber domain as a parameter. This is only needed if the domain is different from the URI supplied.
@@ -199,7 +199,7 @@ The same can be achieved by setting the environment variable WARNINGS--proxy <host>:<port>
does ANY check via the specified proxy. --proxy=auto
inherits the proxy setting from the environment. The hostname supplied will be resolved to the first A record. In addition if you want lookups via proxy you can specify DNS_VIA_PROXY=true
. OCSP revocation checking (-S --phone-out
) is not supported by OpenSSL via proxy. As supplying a proxy is an indicator for port 80 and 443 outgoing being blocked in your network an OCSP revocation check won't be performed. However if IGN_OCSP_PROXY=true
has been supplied it will be tried directly. Authentication to the proxy is not supported. Proxying via IPv6 addresses is not possible, no HTTPS or SOCKS proxy is supported.
--6
does (also) IPv6 checks. Please note that testssl.sh doesn't perform checks on an IPv6 address automatically, because of two reasons: testssl.sh does no connectivity checks for IPv6 and it cannot determine reliably whether the OpenSSL binary you're using has IPv6 s_client support. -6
assumes both is the case. If both conditions are met and you in general prefer to test for IPv6 branches as well you can add HAS_IPv6
to your shell environment. Besides the OpenSSL binary supplied IPv6 is known to work with vanilla OpenSSL >= 1.1.0 and older versions >=1.0.2 in RHEL/CentOS/FC and Gentoo.
+-6
does (also) IPv6 checks. Please note that testssl.sh doesn't perform checks on an IPv6 address automatically, because of two reasons: testssl.sh does no connectivity checks for IPv6 and it cannot determine reliably whether the OpenSSL binary you're using has IPv6 s_client support. -6
assumes both is the case. If both conditions are met and you in general prefer to test for IPv6 branches as well you can add HAS_IPv6
to your shell environment. Besides the OpenSSL binary supplied IPv6 is known to work with vanilla OpenSSL ≥ 1.1.0 and older versions ≥1.0.2 in RHEL/CentOS/FC and Gentoo.
--ssl-native
Instead of using a mixture of bash sockets and a few openssl s_client connects, testssl.sh uses the latter (almost) only. This is faster at the moment but provides less accurate results, especially for the client simulation and for cipher support. For all checks you will see a warning if testssl.sh cannot tell if a particular check cannot be performed. For some checks however you might end up getting false negatives without a warning. This option is only recommended if you prefer speed over accuracy or you know that your target has sufficient overlap with the protocols and cipher provided by your openssl binary.
@@ -667,9 +667,7 @@ from. That helps us to get bugfixes, other feedback and more contributions.
- - May 2020
- - testssl(1)
-
+ August 2020 testssl(1)
diff --git a/doc/testssl.1.md b/doc/testssl.1.md
index 30e07aa..42f8c7e 100644
--- a/doc/testssl.1.md
+++ b/doc/testssl.1.md
@@ -66,15 +66,15 @@ Options are either short or long options. Any long or short option requiring a v
`` or `--file ` always needs to be the last parameter.
-### BANNER OPTIONS
+### BANNER OPTIONS (standalone)
-`--help` (or no arg) display command line help
+`--help` (or no arg) displays command line help
`-b, --banner` displays testssl.sh banner, including license, usage conditions, version of testssl.sh, detected openssl version, its path to it, # of ciphers of openssl, its build date and the architecture.
`-v, --version` same as before
-`-V [pattern] , --local [pattern]` pretty print all local ciphers supported by openssl version. If a pattern is supplied it performs a match (ignore case) on any of the strings supplied in the wide output, see below. The pattern will be searched in the any of the columns: hexcode, cipher suite name (OpenSSL or IANA), key exchange, encryption, bits. It does a word pattern match for non-numbers, for number just a normal match applies. Numbers here are defined as [0-9,A-F]. This means (attention: catch) that the pattern CBC is matched as non-word, but AES as word.
+`-V [pattern], --local [pattern]` pretty print all local ciphers supported by openssl version. If a pattern is supplied it performs a match (ignore case) on any of the strings supplied in the wide output, see below. The pattern will be searched in the any of the columns: hexcode, cipher suite name (OpenSSL or IANA), key exchange, encryption, bits. It does a word pattern match for non-numbers, for number just a normal match applies. Numbers here are defined as [0-9,A-F]. This means (attention: catch) that the pattern CBC is matched as non-word, but AES as word. This option also accepts `--openssl=`.
### INPUT PARAMETERS
diff --git a/testssl.sh b/testssl.sh
index c365cd9..ed93ca8 100755
--- a/testssl.sh
+++ b/testssl.sh
@@ -18808,26 +18808,23 @@ help() {
"$PROG_NAME [options] " or "$PROG_NAME "
-
-"$PROG_NAME ", where is:
+"$PROG_NAME