diff --git a/.github/workflows/docker-3.2.yml b/.github/workflows/docker-3.2.yml index 2c6128b..0335c0f 100644 --- a/.github/workflows/docker-3.2.yml +++ b/.github/workflows/docker-3.2.yml @@ -23,7 +23,7 @@ jobs: - name: Setup QEMU id: qemu - uses: docker/setup-qemu-action@v3.2.0 + uses: docker/setup-qemu-action@v3.3.0 - name: Setup Buildx id: buildx @@ -48,7 +48,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v6.7.0 + uses: docker/build-push-action@v6.12.0 with: push: ${{ github.event_name != 'pull_request' }} context: . diff --git a/.github/workflows/test.yml b/.github/workflows/unit_tests.yml similarity index 100% rename from .github/workflows/test.yml rename to .github/workflows/unit_tests.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 3aed6cd..4084521 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * Improved compatibility with Open/LibreSSL versions not supporting TLS 1.0-1.1 anymore * Renamed PFS/perfect forward secrecy --> FS/forward secrecy * Cipher list straightening +* Support RFC 9150 cipher suites * Improved mass testing * Better align colors of ciphers with standard cipherlists * Save a few cycles for ROBOT @@ -23,13 +24,16 @@ * Test for STARTTLS injection vulnerabilities (SMTP, POP3, IMAP) * STARTTLS: XMPP server support, plus new set of OpenSSL-bad binaries * Several code improvements to STARTTLS, also better detection when no STARTTLS is offered +* Renegotiation checks more reliable against different servers * STARTTLS on active directory service support * Security fixes: DNS and other input from servers * Don't penalize missing trust in rating when CA not in Java store * Added support for certificates with EdDSA signatures and public keys * Extract CA list shows supported certification authorities sent by the server +* Wildcard certificates: detection and warning * TLS 1.2 and TLS 1.3 sig algs added * Check for ffdhe groups +* Check for three KEMs in draft-kwiatkowski-tls-ecdhe-mlkem/draft-tls-westerbaan-xyber768d00 * Show server supported signature algorithms * --add-ca can also now be a directory with \*.pem files * Warning of 398 day limit for certificates issued after 2020/9/1 @@ -41,12 +45,14 @@ * DNS via proxy improvements * Client simulation runs in wide mode which is even better readable * Added --reqheader to support custom headers in HTTP requests +* Search for more HTTP security headers on the server * Test for support for RFC 8879 certificate compression * Deprecating --fast and --ssl-native (warning but still av) * Compatible to GNU grep 3.8 * Don't use external pwd command anymore * Doesn't hang anymore when there's no local resolver -* Added --mtls feature to support client authentication +* Added --mtls feature to support client authentication +* If a TLS 1.3 host is tested and e.g. /usr/bin/openssl supports it, it'll automagically will switch to it ### Features implemented / improvements in 3.0 @@ -136,7 +142,7 @@ * Trust chain check against certificate stores from Apple (OS), Linux (OS), Microsoft (OS), Mozilla (Firefox Browser), works for openssl >=1.0.1 * IPv6 (status: 80% working, details see - https://github.com/drwetter/testssl.sh/issues/11 + https://github.com/testssl/testssl.sh/issues/11 * works now on servers requiring a x509 certificate for authentication * extensive CN <--> hostname check * SSL Session ID check @@ -182,7 +188,7 @@ * quite some LibreSSL fixes, still not recommended to use though (see https://testssl.sh/) * lots of fixes, code improvements, even more robust -Full log @ https://github.com/drwetter/testssl.sh/commits/2.6/testssl.sh +Full log @ https://github.com/testssl/testssl.sh/commits/2.6/testssl.sh ### New in 2.4 * "only one cmd line option at a time" is completely gone @@ -197,7 +203,7 @@ Full log @ https://github.com/drwetter/testssl.sh/commits/2.6/testssl.sh * lots of cosmetic and maintainability code cleanups * bugfixing -Full changelog: https://github.com/drwetter/testssl.sh/commits/2.4/testssl.sh +Full changelog: https://github.com/testssl/testssl.sh/commits/2.4/testssl.sh ### 2.2. new features: * Works fully under FreeBSD (openssl >=1.0) @@ -213,7 +219,7 @@ Full changelog: https://github.com/drwetter/testssl.sh/commits/2.4/testssl.sh * RFC <---> OpenSSL name space mapping of ciphers everywhere * includes a lot of fixes -Full changelog @ https://github.com/drwetter/testssl.sh/commits/2.2/testssl.sh +Full changelog @ https://github.com/testssl/testssl.sh/commits/2.2/testssl.sh ### 2.0 major release, new features: * SNI diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5953205..1029fbe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,21 +1,25 @@ -### Contributions / participation +### Contributing / participating -is always welcome, here @ github or via e-mail. +Contributing / participating is always welcome! -Note please the following +Please note the following: -* Please read at least the [coding convention](https://github.com/drwetter/testssl.sh/Coding_Convention.md). -* One PR per feature or bug fix or improvement. Please do not mix issues. -* Document your PR, both in the PR and/or commit message and in the code. +* Please read the [coding convention](https://github.com/testssl/testssl.sh/blob/3.2/Coding_Convention.md). +* If you have something new and/or bigger which you like to contribute, better open an issue first before you get frustrated. +* Please one pull request per feature or bug fix or improvement. Please do not mix issues. +* Documentation pays off in the long run. So please your document your code and the pull request and/or commit message. * Please test your changes thoroughly as reliability is important for this project. You may want to check different servers with different settings. -* Travis runs automatically when anything is committed/PR'd. You should check any complains from Travis. Beforehand you can check with `prove -v`. -* If it's a new feature please consider writing a unit test for it. You can use e.g. `t/20_baseline_ipv4_http.t` as a template. The general documentation for [Test::More](https://perldoc.perl.org/Test/More.html) is a good start. -* If it's a new feature it would need to be documented in the appropriate section in `help()` and in `~/doc/testssl.1.md` +* GitHub actions are running automatically when anything is committed. You should see any complains. Beforehand you can check with `prove -v` from the "root dir" of this project. +* If it's a new feature, please consider writing a unit test for it. You can use e.g. `t/10_baseline_ipv4_http.t` or `t/61_diff_testsslsh.t` as a template. The general documentation for [Test::More](https://perldoc.perl.org/Test/More.html) is a good start. +* If it's a new feature, it would need to be documented in the appropriate section in `help()` and in `~/doc/testssl.1.md` -For questions just open an issue or feel free to send me an e-mail. +If you're interested in contributing and wonder how you can help, you can search for different tags in the issues (somewhat increasing degree of difficulty): +* [documentation](https://github.com/testssl/testssl.sh/issues?q=is:issue%20state:open%20label:documentation) +* [good first issue](https://github.com/testssl/testssl.sh/issues?q=is:issue%20state:open%20label:%22good%20first%20issue%22) +* [help wanted](https://github.com/testssl/testssl.sh/issues?q=is:issue%20state:open%20label:%22help%20wanted%22) +* [for grabs](https://github.com/testssl/testssl.sh/issues?q=is:issue%20state:open%20label:%22good%20first%20issue%22) + +For questions just open an issue. Thanks for reading this! -#### Patches via e-mail -Of course it is fine when you want to send in patches to use e-mail. For the address please grep for SWCONTACT in testssl.sh . -Let me know how you like them to be attributed. diff --git a/Dockerfile b/Dockerfile index fc58f57..6c5db47 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ RUN source /etc/os-release \ && zypper "${ZYPPER_OPTIONS[@]}" --gpg-auto-import-keys refresh \ && rpm -e util-linux --nodeps \ && zypper "${ZYPPER_OPTIONS[@]}" --non-interactive install --download-in-advance --no-recommends \ - bash procps grep gawk sed coreutils busybox-util-linux busybox-vi ldns libidn2-0 socat openssl curl \ + bash procps grep gawk sed coreutils busybox ldns libidn2-0 socat openssl curl \ && zypper up -y \ && zypper "${ZYPPER_OPTIONS[@]}" clean --all ## Cleanup (reclaim approx 13 MiB): @@ -35,6 +35,7 @@ ARG INSTALL_ROOT COPY --link --from=builder ${INSTALL_ROOT} / # Link busybox to tar, see #2403. Create user + (home with SGID set): RUN ln -s /usr/bin/busybox /usr/bin/tar \ + && ln -s /usr/bin/busybox /usr/bin/hexdump \ && echo 'testssl:x:1000:1000::/home/testssl:/bin/bash' >> /etc/passwd \ && echo 'testssl:x:1000:' >> /etc/group \ && echo 'testssl:!::0:::::' >> /etc/shadow \ diff --git a/Dockerfile.git b/Dockerfile.git index e822163..8e69382 100644 --- a/Dockerfile.git +++ b/Dockerfile.git @@ -5,8 +5,8 @@ FROM alpine:3.20 WORKDIR /home/testssl ARG BUILD_VERSION -ARG ARCHIVE_URL=https://github.com/drwetter/testssl.sh/archive/ -ARG URL=https://github.com/drwetter/testssl.sh.git +ARG ARCHIVE_URL=https://github.com/testssl/testssl.sh/archive/ +ARG URL=https://github.com/testssl/testssl.sh.git RUN test -n "${BUILD_VERSION}" \ && apk update \ diff --git a/Readme.md b/Readme.md index 3fb943e..6736329 100644 --- a/Readme.md +++ b/Readme.md @@ -1,11 +1,11 @@ ## Intro - -[![Build Status](https://github.com/drwetter/testssl.sh/actions/workflows/test.yml/badge.svg)](https://github.com/drwetter/testssl.sh/actions/workflows/test.yml) -[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/drwetter/testssl.sh?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![License](https://img.shields.io/github/license/drwetter/testssl.sh)](https://github.com/drwetter/testssl.sh/LICENSE) -[![Docker](https://img.shields.io/docker/pulls/drwetter/testssl.sh)](https://github.com/drwetter/testssl.sh/blob/3.2/Dockerfile.md) +[![CI tests](https://github.com/testssl/testssl.sh/actions/workflows/unit_tests.yml/badge.svg)](https://github.com/testssl/testssl.sh/actions/workflows/unit_tests.yml) +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/testssl/testssl.sh?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![License](https://img.shields.io/github/license/testssl/testssl.sh)](https://github.com/testssl/testssl.sh/LICENSE) +[![Docker](https://img.shields.io/docker/pulls/testssl/testssl.sh)](https://github.com/testssl/testssl.sh/blob/3.2/Dockerfile.md) + `testssl.sh` is a free command line tool which checks a server's service on any port for the support of TLS/SSL ciphers, protocols as well as some @@ -45,16 +45,16 @@ due to bash-socket-based checks. As a result you can also use e.g. LibreSSL or O (silent) check for binaries is done when you start testssl.sh . System V needs probably to have GNU grep installed. MacOS X and Windows (using MSYS2, Cygwin or WSL) work too. -Update notification here or @ [mastodon](https://infosec.exchange/@testssl) (old: [twitter](https://twitter.com/drwetter)) +Update notification here or @ [mastodon](https://infosec.exchange/@testssl or [bluesky](https://bsky.app/profile/testssl.bsky.social). Please note the [twitter](https://twitter.com/drwetter) account is not being used anymore. ### Installation You can download testssl.sh branch 3.2 just by cloning this git repository: - git clone --depth 1 https://github.com/drwetter/testssl.sh.git + git clone --depth 1 https://github.com/testssl/testssl.sh.git -3.2 is now the latest branch which evolved from 3.1dev. It's in the release candidate phase. -For the former stable version help yourself by downloading the [ZIP](https://codeload.github.com/drwetter/testssl.sh/zip/v3.0.8) or [tar.gz](https://codeload.github.com/drwetter/testssl.sh/tar.gz/v3.0.8) archive. Just ``cd`` to the directory created (=INSTALLDIR) and run it off there. +3.2 is now the latest branch which evolved from 3.1dev. It's in the release candidate phase and considered as stable. +For the former stable version named oldstable please help yourself by downloading the [ZIP](https://codeload.github.com/testssl/testssl.sh/zip/v3.0.9) or [tar.gz](https://codeload.github.com/testssl/testssl.sh/tar.gz/v3.0.9) archive. Just ``cd`` to the directory created (=INSTALLDIR) and run it off there. #### Docker @@ -69,19 +69,19 @@ Or if you have cloned this repo you also can just ``cd`` to the INSTALLDIR and r docker build . -t imagefoo && docker run --rm -t imagefoo example.com ``` -For more please consult [Dockerfile.md](https://github.com/drwetter/testssl.sh/blob/3.2/Dockerfile.md). +For more please consult [Dockerfile.md](https://github.com/testssl/testssl.sh/blob/3.2/Dockerfile.md). ### No Warranty -Usage of the program is without any warranty. Use it at yor own risk. +Usage of the program is without any warranty. Use it at your own risk. Testssl.sh is intended to be used as a standalone CLI tool. While we tried to apply best practise security measures, we can't guarantee that the program is without any vulnerabilities. Running as a service may pose security risks and you're recommended to apply additional security measures. ### Status -We're currently in the release candidate phase for version 3.2. Bigger features will be developed in a separate branch before merged into a 3.3dev to avoid hiccups or inconsistencies. +We're currently in the release candidate phase for version 3.2. You should use it despite the label "RC". Bigger features will be developed in a separate branch before merged into a 3.3dev to avoid hiccups or inconsistencies. -Version 3.0.X receives bugfixes, labeled as 3.0.1, 3.0.2 and so on. This will happen until 3.2 is released. +Version 3.0.X receives bugfixes, labeled as 3.0.1, 3.0.2 and so on. This will happen until 3.2 is finally released. Support for 2.9.5 has been dropped. Supported is >= 3.0.x only. @@ -93,16 +93,19 @@ Support for 2.9.5 has been dropped. Supported is >= 3.0.x only. ### Contributing -Contributions are welcome! See [CONTRIBUTING.md](https://github.com/drwetter/testssl.sh/blob/3.2/CONTRIBUTING.md) for details. Please also have a look at the [Coding Convention](https://github.com/drwetter/testssl.sh/blob/3.2/Coding_Convention.md). +Contributions are welcome! See [CONTRIBUTING.md](https://github.com/testssl/testssl.sh/blob/3.2/CONTRIBUTING.md) for details. Please also have a look at the [Coding Convention](https://github.com/testssl/testssl.sh/blob/3.2/Coding_Convention.md). A lot of contributors already helped to push the project where it currently is, see [CREDITS.md](https://github.com/testssl/testssl.sh/blob/3.2/CREDITS.md). We still you use your help now. A start would be look for issues which are labeled as [good first issue](https://github.com/testssl/testssl.sh/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22), [for grabs](https://github.com/testssl/testssl.sh/issues?q=is%3Aissue+is%3Aopen+label%3A%22for+grabs%22) or [help wanted](https://github.com/testssl/testssl.sh/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22). The latter is more advanced. + +In general there's some maintenance burden, like maintaining handshakes and CA stores, writing unit tests, improving github actions. If you believe you can contribute, speak up. + ### Bug reports Bug reports are important. It makes this project more robust. Please file bugs in the issue tracker @ GitHub. Do not forget to provide detailed information, see template for issue, and further details @ -https://github.com/drwetter/testssl.sh/wiki/Bug-reporting. Nobody can read your thoughts -- yet. And only agencies your screen ;-) +https://github.com/testssl/testssl.sh/wiki/Bug-reporting. Nobody can read your thoughts -- yet. And only agencies your screen ;-) -You can also debug yourself, see [here](https://github.com/drwetter/testssl.sh/wiki/Findings-and-HowTo-Fix-them). +You can also debug yourself, see [here](https://github.com/testssl/testssl.sh/wiki/Findings-and-HowTo-Fix-them). ---- @@ -129,7 +132,7 @@ Please address questions not specifically to the code of testssl.sh to the respe #### Brew package -* see [#233](https://github.com/drwetter/testssl.sh/issues/233) and +* see [#233](https://github.com/testssl/testssl.sh/issues/233) and [https://github.com/Homebrew/homebrew](https://github.com/Homebrew/homebrew) #### Daemon for batch execution of testssl.sh command files diff --git a/bin/Readme.md b/bin/Readme.md index 83d7094..2998804 100644 --- a/bin/Readme.md +++ b/bin/Readme.md @@ -10,7 +10,7 @@ for some new / advanced cipher suites and/or features which are not in the official branch like (old version of the) CHACHA20+POLY1305 and CAMELLIA 256 bit ciphers. The (stripped) binaries this directory are all compiled from my openssl snapshot -(https://github.com/drwetter/openssl-1.0.2.bad) which adds a few bits to Peter +(https://github.com/testssl/openssl-1.0.2.bad) which adds a few bits to Peter Mosman's openssl fork (https://github.com/PeterMosmans/openssl). Thx a bunch, Peter! The few bits are IPv6 support (except IPV6 proxy) and some STARTTLS backports. @@ -71,11 +71,11 @@ Compilation instructions If you want to compile OpenSSL yourself, here are the instructions: 1.) - git git clone https://github.com/drwetter/openssl-1.0.2-bad + git git clone https://github.com/testssl/openssl-1.0.2-bad cd openssl -2.) configure the damned thing. Options I used (see https://github.com/drwetter/testssl.sh/blob/master/utils/make-openssl.sh) +2.) configure the damned thing. Options I used (see https://github.com/testssl/testssl.sh/blob/master/utils/make-openssl.sh) **for 64Bit including Kerberos ciphers:** diff --git a/doc/testssl.1 b/doc/testssl.1 index c192cb3..810d54a 100644 --- a/doc/testssl.1 +++ b/doc/testssl.1 @@ -141,7 +141,7 @@ Any single check switch supplied as an argument prevents testssl\.sh from doing .P \fB\-f, \-\-fs, \-\-nsa, \-\-forward\-secrecy\fR 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 -\fB\-p, \-\-protocols\fR 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\. +\fB\-p, \-\-protocols\fR 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\. Note the supplied openssl\-bad version doesn't support TLS 1\.3 \. As the check for TLS 1\.3 will be done in sockets this normally does not pose a problem\. However if a TLS\-1\.3\-only host is encountered and to have a complete test coverage (e.g. header checks) \fB/usr/bin/openssl\fR (or the content of \fBOPENSSL2\fR) is checked for existence and support of TLS 1\.3 and if those tests succeeded it will be switched to this binary\. A message will notify you\. .P \fB\-P, \-\-server\-preference, \-\-preference\fR displays the servers preferences: cipher order, with used openssl client: negotiated protocol and cipher\. If there's a cipher order enforced by the server it displays it for each protocol (openssl+sockets)\. If there's not, it displays instead which ciphers from the server were picked with each protocol\. .P @@ -418,13 +418,17 @@ MAX_SOCKET_FAIL: A number which tells testssl\.sh how often a TCP socket connect MAX_OSSL_FAIL: A number which tells testssl\.sh how often an OpenSSL s_client connect may fail before the program gives up and terminates\. The default is 2\. You can increase it to a higher value if you frequently see a message like \fIFatal error: repeated TCP connect problems, giving up\fR\. .IP "\[ci]" 4 MAX_HEADER_FAIL: A number which tells testssl\.sh how often a HTTP GET request over OpenSSL may return an empty file before the program gives up and terminates\. The default is 3\. Also here you can increase the threshold when you spot messages like \fIFatal error: repeated HTTP header connect problems, doesn't make sense to continue\fR\. +.IP "\[ci]" 4 +OPENSSL2 can be used to supply an alternative openssl version\. This only makes sense if you want to amend the supplied version in \fBbin/\fR which lacks TLS 1\.3 support with a version which does not and is not in \fB/usr/bin/openssl\fR. +.IP "\[ci]" 4 +OSSL_SHORTCUT can be set to true when you run interactively and don't want to switch automatically to \fB/usr/bin/openssl\fR (\fBOPENSSL2\fR) if you encounter a TLS 1\.3-only host\. .IP "" 0 .SS "RATING" This program has a near\-complete implementation of SSL Labs's 'SSL Server Rating Guide \fIhttps://github\.com/ssllabs/research/wiki/SSL\-Server\-Rating\-Guide\fR'\. .P 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\. 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\. +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\. Use TLS, see also RFC 8314\. The security of STARTTLS is always client determined, i'\.e\. checking the certificate which for SMTP port 25 is often enough not the case\. Also with DANE or MTA\-STS no one can test on the server side whether a client makes use if it\. .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 * 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 .P @@ -603,4 +607,4 @@ All native Windows platforms emulating Linux are known to be slow\. .SH "BUGS" Probably\. Current known ones and interface for filing new ones: https://testssl\.sh/bugs/ \. .SH "SEE ALSO" -\fBciphers\fR(1), \fBopenssl\fR(1), \fBs_client\fR(1), \fBx509\fR(1), \fBverify\fR(1), \fBocsp\fR(1), \fBcrl\fR(1), \fBbash\fR(1) and the websites https://testssl\.sh/ and https://github\.com/drwetter/testssl\.sh/ \. +\fBciphers\fR(1), \fBopenssl\fR(1), \fBs_client\fR(1), \fBx509\fR(1), \fBverify\fR(1), \fBocsp\fR(1), \fBcrl\fR(1), \fBbash\fR(1) and the websites https://testssl\.sh/ and https://github\.com/testssl/testssl\.sh/ \. diff --git a/doc/testssl.1.html b/doc/testssl.1.html index 17a8ddf..0336c4b 100644 --- a/doc/testssl.1.html +++ b/doc/testssl.1.html @@ -262,7 +262,7 @@ in /etc/hosts. The use of the switch is only useful if you either

-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.

+

-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. Note the supplied openssl-bad version doesn't support TLS 1.3 . As the check for TLS 1.3 will be done in sockets this normally does not pose a problem. However if a TLS-1.3-only host is encountered and to have a complete test coverage (e.g. header checks) `/usr/bin/openssl` (or the content of `OPENSSL2`) is checked for existence and support of TLS 1.3 and if those tests succeeded it will be switched to this binary. A message will notify you.

-P, --server-preference, --preference displays the servers preferences: cipher order, with used openssl client: negotiated protocol and cipher. If there's a cipher order enforced by the server it displays it for each protocol (openssl+sockets). If there's not, it displays instead which ciphers from the server were picked with each protocol.

@@ -501,6 +501,8 @@ Rating automatically gets disabled, to not give a wrong or misleading grade, whe
  • MAX_SOCKET_FAIL: A number which tells testssl.sh how often a TCP socket connection may fail before the program gives up and terminates. The default is 2. You can increase it to a higher value if you frequently see a message like Fatal error: repeated openssl s_client connect problem, doesn't make sense to continue.
  • MAX_OSSL_FAIL: A number which tells testssl.sh how often an OpenSSL s_client connect may fail before the program gives up and terminates. The default is 2. You can increase it to a higher value if you frequently see a message like Fatal error: repeated TCP connect problems, giving up.
  • MAX_HEADER_FAIL: A number which tells testssl.sh how often a HTTP GET request over OpenSSL may return an empty file before the program gives up and terminates. The default is 3. Also here you can increase the threshold when you spot messages like Fatal error: repeated HTTP header connect problems, doesn't make sense to continue.
  • +
  • OPENSSL2 can be used to supply an alternative openssl version. This only makes sense if you want to amend the supplied version in bin/ which lacks TLS 1.3 support with a version which does not and is not in /usr/bin/openssl.
  • +
  • OSSL_SHORTCUT should be set to false when you run interactively and don't want to switch automatically to /usr/bin/openssl (OPENSSL2) if you encounter a TLS 1.3-only host.
  • RATING

    @@ -509,7 +511,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. 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.

    +would lead to a false sense of security. Use TLS, see also RFC 8314. The security of STARTTLS is always client determined, i.e. checking the certificate which for SMTP port 25 is often enough not the case. Also with DANE or MTA-STS no one can test on the server side whether a client makes use if it.

    As of writing, these checks are missing: * GOLDENDOODLE - should be graded F if vulnerable @@ -679,7 +681,7 @@ from. That helps us to get bugfixes, other feedback and more contributions.

    SEE ALSO

    -

    ciphers(1), openssl(1), s_client(1), x509(1), verify(1), ocsp(1), crl(1), bash(1) and the websites https://testssl.sh/ and https://github.com/drwetter/testssl.sh/ .

    +

    ciphers(1), openssl(1), s_client(1), x509(1), verify(1), ocsp(1), crl(1), bash(1) and the websites https://testssl.sh/ and https://github.com/testssl/testssl.sh/ .

    1. diff --git a/doc/testssl.1.md b/doc/testssl.1.md index 65c1df9..edbc304 100644 --- a/doc/testssl.1.md +++ b/doc/testssl.1.md @@ -175,7 +175,7 @@ Any single check switch supplied as an argument prevents testssl.sh from doing a `-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. +`-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. Note the supplied openssl-bad version doesn't support TLS 1.3 . As the check for TLS 1.3 will be done in sockets this normally does not pose a problem. However if a TLS-1.3-only host is encountered and to have a complete test coverage (e.g. header checks) `/usr/bin/openssl` (or the content of `OPENSSL2`) is checked for existence and support of TLS 1.3 and if those tests succeeded it will be switched to this binary. A message will notify you. `-P, --server-preference, --preference` displays the servers preferences: cipher order, with used openssl client: negotiated protocol and cipher. If there's a cipher order enforced by the server it displays it for each protocol (openssl+sockets). If there's not, it displays instead which ciphers from the server were picked with each protocol. @@ -403,6 +403,9 @@ Except the environment variables mentioned above which can replace command line * MAX_SOCKET_FAIL: A number which tells testssl.sh how often a TCP socket connection may fail before the program gives up and terminates. The default is 2. You can increase it to a higher value if you frequently see a message like *Fatal error: repeated openssl s_client connect problem, doesn't make sense to continue*. * MAX_OSSL_FAIL: A number which tells testssl.sh how often an OpenSSL s_client connect may fail before the program gives up and terminates. The default is 2. You can increase it to a higher value if you frequently see a message like *Fatal error: repeated TCP connect problems, giving up*. * MAX_HEADER_FAIL: A number which tells testssl.sh how often a HTTP GET request over OpenSSL may return an empty file before the program gives up and terminates. The default is 3. Also here you can increase the threshold when you spot messages like *Fatal error: repeated HTTP header connect problems, doesn't make sense to continue*. +* OPENSSL2 can be used to supply an alternative openssl version. This only makes sense if you want to amend the supplied version in `bin/` which lacks TLS 1.3 support with a version which doesn not and is not in `/usr/bin/openssl`. +* OSSL_SHORTCUT should be set to false when you run interactively and don't want to switch automatically to `/usr/bin/openssl` (`OPENSSL2`) if you encounter a TLS 1.3-only host. + ### RATING @@ -410,8 +413,7 @@ 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. 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. +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. Use TLS, see also RFC 8314. The security of STARTTLS is always client determined, i.e. checking the certificate which for SMTP port 25 is often enough not the case. Also with DANE or MTA-STS no one can test on the server side whether a client makes use if it. As of writing, these checks are missing: @@ -585,4 +587,4 @@ Probably. Current known ones and interface for filing new ones: https://testssl. ## SEE ALSO -`ciphers`(1), `openssl`(1), `s_client`(1), `x509`(1), `verify`(1), `ocsp`(1), `crl`(1), `bash`(1) and the websites https://testssl.sh/ and https://github.com/drwetter/testssl.sh/ . +`ciphers`(1), `openssl`(1), `s_client`(1), `x509`(1), `verify`(1), `ocsp`(1), `crl`(1), `bash`(1) and the websites https://testssl.sh/ and https://github.com/testssl/testssl.sh/ . diff --git a/etc/cipher-mapping.txt b/etc/cipher-mapping.txt index e0b542f..1125f87 100644 --- a/etc/cipher-mapping.txt +++ b/etc/cipher-mapping.txt @@ -342,6 +342,8 @@ 0x02,0x00,0x80 - EXP-RC4-MD5 SSL_CK_RC4_128_EXPORT40_WITH_MD5 SSLv2 Kx=RSA(512) Au=RSA Enc=RC4(40) Mac=MD5 export 0x00,0x28 - EXP-KRB5-RC4-SHA TLS_KRB5_EXPORT_WITH_RC4_40_SHA SSLv3 Kx=KRB5 Au=KRB5 Enc=RC4(40) Mac=SHA1 export 0x00,0x2B - EXP-KRB5-RC4-MD5 TLS_KRB5_EXPORT_WITH_RC4_40_MD5 SSLv3 Kx=KRB5 Au=KRB5 Enc=RC4(40) Mac=MD5 export + 0xC0,0xB4 - TLS_SHA256_SHA256 TLS_SHA256_SHA256 TLSv1.3 Kx=any Au=any Enc=None Mac=SHA256 + 0xC0,0xB5 - TLS_SHA384_SHA384 TLS_SHA384_SHA384 TLSv1.3 Kx=any Au=any Enc=None Mac=SHA384 0xC0,0x10 - ECDHE-RSA-NULL-SHA TLS_ECDHE_RSA_WITH_NULL_SHA SSLv3 Kx=ECDH Au=RSA Enc=None Mac=SHA1 0xC0,0x06 - ECDHE-ECDSA-NULL-SHA TLS_ECDHE_ECDSA_WITH_NULL_SHA SSLv3 Kx=ECDH Au=ECDSA Enc=None Mac=SHA1 0xC0,0x15 - AECDH-NULL-SHA TLS_ECDH_anon_WITH_NULL_SHA SSLv3 Kx=ECDH Au=None Enc=None Mac=SHA1 diff --git a/etc/curves-mapping.txt b/etc/curves-mapping.txt index 444f92d..2120f0a 100644 --- a/etc/curves-mapping.txt +++ b/etc/curves-mapping.txt @@ -45,3 +45,7 @@ 0x01,0x02 - ffdhe4096 ffdhe4096 0x01,0x03 - ffdhe6144 ffdhe6144 0x01,0x04 - ffdhe8192 ffdhe8192 + 0x11,0xeb - SecP256r1MLKEM768 SecP256r1MLKEM768 + 0x11,0xec - X25519MLKEM768 X25519MLKEM768 + 0x11,0xed - SecP384r1MLKEM1024 SecP384r1MLKEM1024 + 0x63,0x99 - X25519Kyber768Draft00 X25519Kyber768Draft00 diff --git a/etc/tls_data.txt b/etc/tls_data.txt index 5fc5b7c..6b16b06 100644 --- a/etc/tls_data.txt +++ b/etc/tls_data.txt @@ -1,11 +1,11 @@ # data we need for socket based handshakes # see #807 and #806 (especially -# https://github.com/drwetter/testssl.sh/issues/806#issuecomment-318686374) +# https://github.com/testssl/testssl.sh/issues/806#issuecomment-318686374) -# All 5 ciphers defined for TLS 1.3 +# 7 ciphers defined for TLS 1.3 in RFCs 8446 and 9150 readonly TLS13_CIPHER=" -13,01, 13,02, 13,03, 13,04, 13,05" +13,01, 13,02, 13,03, 13,04, 13,05, c0,b4, c0,b5" # 123 standard cipher + 4x GOST for TLS 1.2 and SPDY/NPN HTTP2/ALPN declare TLS12_CIPHER=" @@ -339,5 +339,8 @@ readonly -a TLS13_PUBLIC_KEY_SHARES=( "01,02,02,00,8f,b3,b5,3f,0b,de,23,e1,5c,4a,77,ed,b2,4d,1c,4b,76,91,12,c4,fe,5b,15,23,13,a4,f3,b6,5b,23,8d,88,d5,77,0e,e4,1d,60,0b,58,1b,af,67,ee,31,fb,b6,ce,f5,1b,36,10,c1,f2,f0,83,e6,b9,23,13,1e,b2,9f,ae,e0,9e,42,64,4c,bd,1e,87,18,bd,a6,9b,ae,59,20,e8,9f,52,78,e6,f7,35,56,b6,3a,e6,82,8e,87,b5,c8,23,07,e1,f5,6e,95,8d,c6,83,83,88,b8,41,d8,63,58,33,fe,39,20,d4,9c,37,0e,68,5b,e9,1f,48,0e,85,d6,36,70,a2,06,a8,dc,5c,62,75,4d,bd,bd,3a,6f,03,b0,25,33,11,20,67,0f,76,23,d9,ab,5b,e9,c4,bc,ff,a8,1f,49,c0,e1,42,c7,3c,cb,25,7a,d3,c8,39,e2,f7,b1,22,ca,14,b2,3a,2e,7a,a0,80,a9,e0,dc,96,53,ca,d7,48,be,6d,bc,68,a9,38,b0,be,b0,1b,8c,85,9e,51,42,69,24,f0,28,c8,7c,f1,bc,e3,0f,1f,9c,f3,8b,3a,96,3b,52,ed,36,b1,88,10,9f,c8,02,89,2b,5a,eb,d5,fc,af,03,46,fa,cf,8a,ba,80,ae,8f,89,f7,fd,0f,77,f3,4e,24,35,32,35,e9,c4,82,97,25,51,ab,2b,01,dd,ca,53,5f,7c,3b,25,89,d2,54,69,30,48,6b,4a,03,25,dd,be,c6,ea,33,c2,86,7f,e9,d0,9b,31,fd,70,37,54,c2,8c,dc,96,6d,5a,2e,b6,c2,6d,85,ee,f2,32,b8,95,b0,66,40,44,1e,a2,bf,25,ed,1f,41,9d,37,5b,56,e0,1d,95,1d,ec,d8,f6,24,68,d4,06,17,16,7e,8c,31,7e,40,c2,88,29,d1,f9,8e,eb,4d,4e,5a,9d,65,c8,a2,43,83,4c,04,8b,93,eb,40,23,5f,80,8f,2f,29,ff,c3,13,47,ad,b0,c1,5a,28,08,dc,1e,83,e7,ed,26,4e,30,2c,6e,5a,0e,f1,db,68,ab,89,bb,61,63,6d,55,97,b2,94,16,cd,6f,d5,60,92,e8,71,ef,a3,b2,ae,0c,40,26,d5,35,1d,c8,ed,12,94,86,8c,1c,97,bd,cc,1d,53,0f,4c,99,21,fc,34,5a,79,8c,ca,ea,ae,99,bc,8b,a9,52,fe,f9,63,75,6f,7d,51,79,e6,ca,92,6c,b8,7e,7b,20,a9,c0,2a,15,1d,bb,c0,c2,b1,52,42,7f,dd,1c,8d,e5,a7,7f,26,f5,29,cb,4b,91,5b,80,c2,3a,94,e8,c5,2f,6d,7a,0d" "01,03,03,00,13,37,f3,03,0c,1f,cf,3d,2f,9c,e1,aa,a2,d5,90,ab,4a,e0,e6,b3,87,d2,a2,16,1e,26,7b,21,17,7d,82,39,ce,d4,50,94,17,b4,d0,5a,37,6e,ba,82,2b,fa,0f,7c,b6,e2,1d,01,7d,40,ca,a9,c3,fb,0d,4e,ef,ce,8a,b8,f8,61,54,14,02,6c,50,f9,dd,86,a8,2c,a8,5b,06,ff,60,4d,19,a9,ff,77,77,ba,6d,96,72,b4,d2,46,71,e2,2b,45,d8,5e,1f,84,64,07,ef,56,f9,64,1b,11,ff,ad,05,19,f9,2b,5d,af,50,91,24,c1,ca,ff,c8,78,92,32,13,fc,90,f3,12,24,62,c6,97,7f,5d,73,90,70,72,43,e2,bc,90,3f,3b,a4,85,3e,53,2e,43,a2,4f,c6,c6,38,88,0b,07,52,3d,98,b7,e3,4d,24,86,02,86,36,b8,2c,fa,49,28,e2,b9,a8,8c,75,16,32,8b,c8,e4,90,47,ba,d8,da,a6,ae,2e,af,4c,1e,ae,a1,99,70,c9,cf,1d,a8,e1,5c,fc,1f,61,25,f8,e5,5c,d2,27,8c,32,a6,28,51,42,91,91,08,e5,8f,48,d0,33,ad,7f,45,1a,5f,ee,30,f7,29,2c,23,88,b0,5c,6e,76,2d,56,7c,bc,63,73,a0,d6,13,71,58,82,91,79,4c,9b,aa,22,05,61,48,b5,51,af,d0,0e,9c,7d,94,a7,f5,6a,b9,cb,57,97,55,ca,d1,cc,b8,f5,3e,f7,bc,93,05,1a,af,c4,57,54,4c,a3,83,80,53,90,ac,16,5b,ec,6d,5f,82,83,e5,ca,fa,12,c2,8d,2b,a6,36,a8,b2,38,50,fc,f0,a5,fb,52,2d,eb,68,95,4d,f7,94,6d,75,f7,41,1f,46,db,86,71,d0,37,16,91,34,df,2f,89,78,4c,88,27,7d,2a,46,39,f0,8b,ec,75,e1,f3,5c,3f,98,b4,03,f3,c4,ea,70,af,67,0d,ee,97,d0,31,cd,3e,c1,c9,6e,4c,97,a0,64,19,44,9f,ad,16,4c,be,10,b6,e4,cc,9c,9d,2d,4f,79,02,a4,ea,09,2c,1d,2e,fd,c2,12,1a,de,ba,c9,a1,98,77,41,1c,14,56,ca,d9,19,02,46,87,7c,8d,a1,c4,3f,90,99,ca,2e,99,18,40,7e,ae,93,91,c3,4a,5f,68,f8,62,f9,34,83,ae,2e,64,c6,cf,a7,6d,80,eb,28,8b,ac,90,3b,1a,a2,a2,13,26,f3,91,40,bb,3a,44,2b,d2,0c,58,74,fc,9d,60,a9,d2,a6,34,c4,21,65,f6,00,c2,73,e1,e4,29,9d,c8,a9,88,33,38,c7,dd,83,23,d8,4b,66,d5,7c,78,7f,c3,62,23,34,12,1a,ee,a1,62,84,fe,62,3a,09,6b,72,69,58,d8,1b,fd,b0,89,e9,e1,da,fa,35,db,83,5f,93,a5,62,ad,c7,f7,e2,a7,6d,db,00,9e,7e,ea,9f,53,ef,d4,bd,32,e7,9e,2a,d1,90,a4,37,1b,b2,cd,cc,21,28,4a,96,3f,35,54,78,88,90,3b,e5,22,94,e4,2a,9f,d2,ef,7f,75,3d,b2,83,34,fe,66,45,4c,c2,ca,06,f3,fd,46,29,6b,40,32,66,a2,64,30,16,ee,04,cb,3d,28,bd,bf,a7,f1,84,9d,23,bf,61,e1,59,c7,36,b5,60,b5,39,39,eb,fd,ff,06,9e,52,99,69,97,d4,8b,bb,8f,84,90,fd,e2,0d,fd,7b,85,49,cc,81,3c,1d,c1,37,1e,5f,34,cd,52,4f,61,9a,85,c5,29,1d,b4,42,8c,c4,8d,94,43,cb,6a,e2,af,90,a6,ec,09,89,07,ae,62,9d,66,bd,fe,87,4d,76,0c,ce,e4,70,87,74,89,02,00,6c,54,4b,86,45,b5,f2,d6,fe,6e,f1,74,ae,c5,1f,67,f0,19,44,44,32,5d,d1,8a,a4,71,17,b0,9c,a4,5d,90,d4,29,b6,24" "01,04,04,00,67,47,f0,4b,9c,5b,75,a3,4d,9b,1f,b2,b4,32,56,a4,dd,23,69,70,4c,c3,ee,f2,0f,82,51,bc,54,8c,0d,a3,21,bf,94,88,82,7c,69,e8,55,d3,1d,8d,80,be,71,4d,4c,48,f8,ce,1e,f8,72,ac,a5,4c,74,aa,8f,a7,e0,51,99,ad,51,35,14,e7,98,02,1b,9d,07,e5,d1,07,d0,15,d2,9b,33,81,62,b7,7e,52,d5,b1,37,ea,55,f7,80,74,4c,25,cb,61,e9,75,c0,c9,7b,4e,19,4d,d1,69,46,ca,01,c9,14,06,a8,17,e0,f4,e5,c4,5d,e9,f6,2a,d5,02,b8,8b,6e,4a,26,ec,8c,a4,c0,bd,17,a6,48,5c,46,4f,bf,6f,c9,f1,4a,27,fa,4c,d1,93,e7,22,8c,2b,32,55,0c,2b,c6,ea,73,19,7d,e8,b7,fc,64,0d,f0,f9,bf,0d,3a,8b,3c,a9,30,a1,03,1b,e3,1b,d6,94,a8,39,4b,23,ce,ea,7b,2a,3a,af,4f,6c,15,cd,13,ca,67,84,05,9c,a7,d0,f6,7f,97,0b,e0,b3,bb,fd,ca,10,f6,35,57,5f,9b,e7,c2,5f,5c,16,f8,31,0c,23,34,7b,0b,f0,d1,b0,e4,e6,6a,45,db,32,be,fa,fc,92,df,01,3d,ca,bc,c8,d2,c9,57,8e,6b,eb,7b,f4,8c,23,b4,cf,16,73,a3,20,50,e7,f6,98,7a,19,f8,be,e4,72,3f,45,e7,e9,df,69,10,dd,72,24,94,d4,ce,c9,70,13,49,9d,af,bd,61,7a,a8,ee,82,9f,ce,2e,0f,4f,cf,c0,26,9b,98,a6,9e,a7,06,ed,b6,d7,f0,db,c6,c4,f0,db,55,94,87,92,af,11,dc,07,47,eb,e4,b5,3b,c8,5a,24,31,f2,d7,06,c5,a5,19,80,75,88,5e,45,f1,0f,e0,94,ea,9f,1b,65,4d,1a,ec,18,db,b0,c8,05,ca,25,46,6a,85,8a,49,d1,e7,06,9d,84,1f,ca,7e,48,02,34,b2,0d,4c,5e,61,d5,5d,b5,51,8c,19,18,2c,87,9e,69,b2,81,c1,4c,62,09,25,1f,e9,8d,0b,23,81,d3,36,a1,c5,41,f8,db,c6,8c,cf,1c,55,54,41,d0,5b,92,a8,3f,a5,ae,dd,69,98,c4,f3,8f,7b,26,70,43,f6,62,e5,89,4f,e4,cb,c7,de,63,13,f7,a9,6b,51,e4,41,dc,fe,9e,50,32,32,32,04,bd,d2,d7,8b,4d,29,9a,78,91,28,6e,56,30,5e,89,ba,1e,62,c5,8a,27,05,bc,ad,1e,2c,d1,cf,d4,bc,c0,69,a7,2d,3f,07,3c,77,f9,69,ca,16,1f,a7,14,4e,c8,0b,fa,e7,3a,9e,38,a6,c0,aa,b6,1e,66,30,a8,18,51,8f,76,27,fa,5c,c2,07,e8,e6,f0,98,6e,bb,b0,d7,53,d3,db,d4,2e,d6,1f,83,49,23,a3,1f,c4,0c,12,8c,67,ed,1c,01,a6,40,a8,ad,68,9a,6e,af,ee,ad,5f,d0,78,5f,15,5d,09,8e,e6,80,a4,f0,f3,c8,55,27,f1,44,6f,58,07,16,ed,87,1f,8e,26,d6,3c,a0,17,2e,79,d0,72,12,dc,81,d5,ae,a0,ad,86,31,8e,6d,45,d7,d1,3a,94,e7,e5,7b,3d,b7,5f,50,3c,af,e8,ea,2b,f0,e2,3c,eb,14,b6,16,31,0c,70,3b,92,e8,a2,f9,84,d1,aa,ba,73,80,89,ec,54,3c,23,a9,d5,87,87,b9,27,9a,87,bb,c5,06,96,9a,37,2b,d8,d9,af,32,e8,fd,8d,b0,49,c1,cb,81,bc,0d,0b,fe,dc,40,fb,b1,50,41,ed,71,3b,87,cc,95,6d,df,80,85,92,c6,66,cb,4c,75,16,46,f1,b1,08,ed,be,91,21,c5,b0,e8,83,58,96,24,16,28,15,e2,fe,94,e4,42,99,84,77,43,7b,1f,ac,a7,55,ff,33,09,6a,6e,b4,66,21,d6,c0,6f,88,35,94,6f,ab,1d,c6,74,7b,4c,30,a9,e0,70,36,7f,94,aa,c0,c7,98,71,ec,10,c9,96,86,32,08,83,37,16,60,cf,19,f0,19,11,4c,f4,65,87,d8,5f,16,ad,c6,80,89,1d,37,d6,26,91,bf,ef,de,47,62,c5,05,b8,b9,c1,a8,6c,19,ec,80,af,ec,dd,d8,ee,d3,c4,b5,13,77,88,20,fe,68,64,b3,bd,f1,90,67,c4,d7,29,e5,b9,4e,7c,29,34,a8,14,4f,09,60,9b,5f,87,c5,23,d2,49,da,e6,da,2a,cf,c4,c6,3d,c8,9a,5f,37,ca,fb,08,d0,28,1e,88,f0,30,37,74,b0,c3,8f,3f,2c,b3,bc,39,3a,96,27,d6,c0,c7,91,bb,d1,fc,f0,28,be,82,3b,ac,2b,28,72,9d,31,2d,42,5d,d8,36,d8,a8,c9,ca,58,b9,f9,4a,14,b8,38,52,c9,ea,aa,8d,05,52,d5,4b,22,87,8f,09,d3,0d,c9,16,f1,d3,26,61,e5,5c,bd,84,64,88,7d,32,8d,ea,6d,8a,00,dc,54,a5,75,50,a4,3b,99,33,b1,e2,ef,8d,e5,f6,78,d8,dd,71,1a,64,02,6f,ac,37,a5,2a,fc,5d,c8,af,f9,87,3b,77,f3,1c,2c,cc,db,a6" - "105" "106" "107" "108" "109" "10a" "10b" "10c" "10d" "10e" "10f" ) + [4587]="11,eb,04,e1,04,4e,42,eb,6e,46,64,d1,91,3e,88,28,08,ee,82,61,a2,2b,db,42,50,96,ff,0c,ae,4b,c7,1f,5b,b1,50,99,5f,37,77,b3,70,53,3f,96,2f,23,6a,83,07,eb,b2,91,ce,c0,ea,0e,aa,33,42,80,ce,cf,3b,ce,02,58,46,4f,58,ba,e1,68,65,e7,ba,7b,79,2b,05,03,89,dd,48,91,d4,d2,be,bc,ba,0e,9d,86,1f,fe,42,a6,91,f4,43,5a,33,34,59,f6,6e,26,c3,11,1b,08,0d,7f,a1,5b,fd,75,2f,61,f6,5e,f9,91,24,94,d9,97,d8,f5,43,f9,6a,c8,20,da,84,b9,35,7a,04,45,1c,d2,10,4b,e2,2b,05,28,30,be,85,1a,75,4a,d8,25,91,6c,6a,47,12,95,7d,f6,aa,8d,57,55,b1,24,c1,7c,13,9d,bf,f0,06,9a,56,5c,fc,d5,2c,af,39,0d,12,59,17,91,02,3f,39,c8,28,a3,24,2b,8d,fb,57,c1,02,94,23,94,0c,a4,9a,31,8d,08,87,d6,01,15,d1,dc,b6,12,93,03,3a,57,3f,1b,bb,94,30,3a,71,20,72,54,b1,50,12,13,03,0e,61,da,85,7e,f3,12,fe,08,a5,ef,9c,3c,6d,30,af,03,c6,62,02,41,55,46,ba,8c,59,a6,48,2e,4a,92,a4,d5,ae,61,97,16,1b,f0,4a,58,48,45,d7,9c,1b,63,b6,b8,b8,46,0f,c8,7b,be,f0,91,57,8f,20,7e,93,1a,97,10,bc,a3,6f,23,92,ce,c5,59,8b,b1,94,a6,95,85,08,41,62,8e,8b,2c,b4,f7,af,9c,e6,17,70,58,24,90,bb,0e,09,a1,a1,1f,b2,03,98,7a,61,a7,a3,5a,89,37,b5,eb,97,18,9a,17,22,43,53,bf,88,ab,6b,0f,a0,57,b5,74,71,f6,41,28,0b,84,85,31,b2,2f,c7,08,0e,b8,40,12,8f,87,c4,38,99,b0,80,43,13,ba,eb,54,ab,b6,6e,b7,43,9c,64,69,7b,3f,66,5f,35,5b,03,c1,bb,78,54,47,8b,9e,c8,70,68,42,75,c9,e1,47,2d,39,38,a0,9c,66,f3,bc,b4,75,b1,98,b8,77,85,bf,01,70,6e,81,49,c5,8b,59,5b,6a,b3,f9,cc,0c,4f,1b,2c,2c,d3,50,ef,b1,89,1d,54,2c,5d,22,2a,a0,fa,53,60,02,05,e0,b0,13,fe,e9,85,cc,57,5a,88,97,38,63,45,56,d3,2b,69,c4,00,1e,e3,92,22,2f,e4,55,8e,86,13,c8,a4,16,98,d3,3d,51,53,77,ea,d8,37,ca,41,0e,16,94,68,66,b5,c9,ca,06,28,de,78,02,94,d0,8e,67,5c,9b,57,ac,74,a4,73,66,10,d4,4c,74,14,68,01,db,1a,a9,b8,aa,56,91,71,3c,f6,75,23,bb,99,e5,5c,89,47,a3,7c,9f,d6,a4,82,a1,39,a9,35,42,49,94,29,0c,a5,22,e6,03,5d,fd,59,28,63,8c,05,b3,1a,84,8a,99,86,1a,02,10,c1,ec,c5,4f,58,0a,50,67,c0,c3,a5,7d,22,01,b5,57,c6,68,63,37,cb,74,e8,44,18,17,1f,ce,54,59,2a,4c,5f,e1,bb,96,85,77,81,d6,d9,88,54,02,69,51,1c,41,e4,03,3f,6c,62,94,e2,68,2e,9c,03,cb,b3,5b,73,a3,9c,36,ab,c4,29,0c,b5,c1,e6,b6,5a,bd,f4,89,3b,93,97,0c,33,59,a5,71,71,fc,2c,7a,d9,46,b3,11,1c,10,fe,55,9e,01,82,42,60,ec,3d,e5,83,c7,84,eb,8e,10,f9,8d,eb,7b,b3,82,0a,88,2f,50,53,20,1c,7b,de,27,39,1a,68,86,be,db,80,b6,4c,29,11,68,4f,3d,f0,76,eb,b5,4e,e1,65,7c,a4,82,2b,30,23,15,1d,65,7b,a8,06,24,3f,77,65,ab,80,84,d1,7b,a4,10,1b,08,c3,f6,a7,9d,c5,bb,e9,c5,02,2d,47,c0,22,47,6b,32,8b,2f,a4,5c,02,6d,7c,38,72,23,6d,a7,09,ba,7f,45,b1,04,76,cd,0e,12,0b,61,75,81,1a,94,68,88,c9,c5,1c,d5,7a,42,a4,c4,f3,dc,51,ed,6a,78,e6,45,a6,1f,31,74,de,9c,9c,61,32,51,67,e3,a5,bb,19,88,77,77,76,52,59,27,49,82,8c,c2,59,00,df,80,67,8c,82,ad,13,f0,13,17,21,43,3c,40,76,71,96,72,40,57,38,d9,e0,80,56,d7,bc,40,fb,9a,a4,8a,a1,a6,bb,99,94,31,96,38,b8,57,8b,68,08,27,d7,9e,18,1b,1b,3f,a1,9a,92,5b,6b,b8,73,72,8e,d7,3d,86,c7,24,73,98,ba,6e,07,17,0e,11,36,44,69,b8,7d,aa,b7,de,e6,71,5f,13,1a,55,c9,bb,e9,06,bd,4e,d7,04,df,e5,29,9f,c6,59,cf,77,4c,11,b1,41,ef,5c,68,2d,22,9d,8f,13,80,2c,cc,a9,35,8b,b3,1e,73,2c,0f,61,13,0f,2b,8f,a2,69,b4,bf,22,2e,23,4c,b5,24,66,39,a9,a3,19,12,56,44,3a,f4,15,e2,f4,cb,b7,36,08,bf,79,c1,fa,90,71,e8,84,4c,ec,95,73,e7,41,62,7f,f2,57,95,ca,13,3c,f3,ba,36,03,cd,e1,37,6f,31,b0,9f,17,8b,b8,a6,85,44,e3,26,71,8b,b1,05,b1,91,73,96,7b,bb,04,35,19,a5,44,a0,d8,17,c8,73,5b,58,d5,e9,b1,dc,9a,71,3d,16,84,a4,10,37,67,cc,0c,d4,77,94,e4,f2,5e,f1,e9,36,b0,61,93,68,59,bb,e0,24,c0,4c,e8,58,1e,83,2d,a9,88,7a,15,52,16,6b,94,18,2e,2b,2d,60,93,78,b1,32,98,4f,a7,5c,4d,2a,7e,4d,b5,27,04,79,20,d5,83,bf,37,1a,68,11,0a,b5,1b,45,31,3a,31,b9,4f,a7,ba,e5,49,20,2d,d1,19,ab,38,3c,7d,f1,cd,bf,db,1e,13,8c,70,0c,ab,bd,23,24,53,3b,39,bb,01,b2,56,e2,3c,96,94,22,92,f6,89,86,31,fb,ad,59,ea,07,64,e3,d7,68,35,6f,33,41,b7,c9,38,2e,08,b7,3a,01,10,9a,96,9d,e0,d1,92,24,e5,d6,26,af,45" + [4588]="11,ec,04,c0,15,45,8a,33,c6,16,72,fb,44,02,c9,c1,42,63,5d,2e,d0,30,a8,9b,a8,84,19,33,bf,23,10,ec,05,67,68,d9,12,0e,88,07,0a,39,85,85,6c,52,6e,24,70,69,38,aa,a1,a7,10,41,b5,4f,5a,99,2f,38,dc,07,0e,ab,a8,a2,44,40,49,7c,47,5d,3a,bd,7c,ea,af,63,11,47,5f,d2,8c,ef,81,b1,4d,e1,57,40,e6,32,0c,49,5d,43,63,62,7e,a8,49,71,7a,85,ea,00,9f,42,54,85,71,97,16,0e,43,35,4b,d1,26,2c,73,c8,cc,f2,43,63,c3,66,17,b4,7c,a7,d2,66,98,b4,60,e8,0b,a7,94,49,75,03,e3,4f,bf,69,ba,e7,67,68,89,c2,8a,4b,24,a2,42,f4,74,92,e3,44,85,bc,9e,da,e3,40,e9,e4,bd,4c,02,20,88,dc,67,2d,25,ba,4f,0a,4b,7c,dc,1f,96,d3,6a,01,86,5b,ad,75,b2,23,c5,c7,39,10,35,34,59,6e,23,fc,c9,cd,c0,17,e0,16,79,4b,04,82,70,d9,1f,62,a4,36,67,d3,00,a9,db,a4,25,09,21,38,f0,0b,d1,17,6a,3d,d5,22,51,1a,a6,0b,97,23,c7,67,32,0b,7c,a0,b3,a7,0d,06,49,01,52,69,9c,4f,f5,37,dd,0c,a7,bc,d0,c2,72,d5,6f,9c,26,aa,c3,ca,0d,84,6b,27,40,f8,1b,e3,55,bb,e4,f0,9a,15,52,2f,a3,da,06,45,c2,10,6e,a3,2a,07,87,61,89,1c,39,b1,52,26,2a,80,a5,a6,4b,2c,b3,3c,40,d7,42,0d,8b,67,90,d6,c6,49,09,a7,6e,d3,f2,c2,ac,b5,46,75,2c,8c,0d,03,0a,d8,f2,b7,19,a7,a4,84,f4,90,48,34,29,aa,00,28,e8,01,bf,2b,02,94,57,e2,62,36,59,61,d2,c0,0e,1c,69,04,57,b0,ba,c3,2c,a4,aa,e7,46,03,45,c9,a1,b6,58,13,ba,3f,ea,80,b3,ef,dc,5c,7f,28,8b,c6,92,18,db,81,0b,43,e1,07,65,b4,be,96,33,58,f0,31,c0,8c,29,9c,4c,d9,a8,95,91,58,e1,e7,61,b5,b5,23,0e,fa,39,62,63,38,3e,d4,3c,df,c1,09,81,ea,4f,0b,a2,7c,e3,08,1f,e6,e1,0f,5e,e0,5f,f1,02,c3,99,fa,6a,6f,45,96,87,31,18,f6,d8,48,13,15,6b,ed,7a,02,1e,da,a5,ec,da,67,07,67,ab,c2,ab,94,a5,07,01,17,54,8e,9c,35,12,55,60,53,02,8b,48,46,06,79,9f,da,6c,f3,51,86,a6,34,16,af,ba,45,ac,77,68,10,0b,c1,ce,f0,0a,c5,20,98,37,42,22,f8,e8,2e,9b,80,52,23,e4,90,f3,01,6e,f9,40,a7,19,c1,9d,59,97,9d,2e,57,06,d2,2a,75,28,c5,5b,aa,0c,a8,94,62,7b,ff,80,c4,6c,01,67,7f,c5,98,61,06,a3,bf,2c,19,32,77,86,7c,1c,42,36,0c,8c,7b,6b,62,01,d7,5a,2c,62,6f,a5,18,1b,19,c3,47,f7,e9,c9,ff,a9,c1,89,31,1d,46,79,2c,35,51,63,4a,f7,66,91,4a,b8,93,f9,40,b9,28,71,29,85,9a,0d,c5,16,c7,7b,ae,b9,4a,cc,50,d3,39,37,54,5f,31,fc,1b,fc,5a,76,23,e5,49,6b,c0,bd,11,1b,a2,b0,ca,36,55,07,54,40,0a,08,c8,49,ca,09,ea,29,73,02,80,d5,30,4c,e6,00,ae,0a,a4,2f,b8,57,4c,2d,75,58,05,8b,b6,c5,55,be,22,e6,48,63,75,c5,aa,f9,8d,e9,4c,8a,51,84,b7,96,b0,2e,14,58,18,99,48,29,de,36,7d,be,e5,8e,01,7c,9d,0f,71,2f,f8,84,7d,6e,d2,88,d0,67,b2,5b,e3,bb,63,bc,53,fa,80,88,29,26,c5,22,54,42,d8,21,82,5d,6a,4a,b1,b7,a2,8f,48,68,c2,c7,2f,79,fa,8d,25,f4,85,7b,47,a5,46,a5,af,3e,88,37,06,f5,41,40,71,02,89,f9,3e,1d,46,43,3e,34,5e,7e,39,4b,f2,25,c8,30,33,59,45,8a,c2,95,4b,94,37,53,b3,f0,03,73,21,d5,36,51,fc,6f,e9,1c,69,dd,a6,47,2b,39,5e,fc,35,c4,a8,84,7e,34,32,b3,76,f5,23,1b,67,07,e7,c8,b3,99,82,36,ec,9b,c7,a3,2c,80,de,09,46,c9,c9,22,cd,19,b9,a7,e0,c8,cb,a3,20,f7,f4,3a,7c,48,44,86,db,96,a4,b0,9d,bd,63,84,54,d9,c6,09,16,03,1e,45,89,65,da,57,2d,b3,33,0a,7b,1a,98,5a,cc,e5,08,ba,8c,35,7e,fe,4a,36,fa,f4,58,c3,fb,c8,e1,66,14,9e,91,b6,02,88,6f,fe,a9,6e,41,cb,63,6d,92,cc,65,c4,a9,9e,69,38,75,ec,6f,0f,89,c7,65,aa,2a,a1,8b,90,ad,e5,83,4b,b2,3e,68,60,84,be,a0,98,32,e6,47,53,41,c4,35,49,ca,10,16,c5,52,53,47,2b,ac,4f,44,1b,6a,04,7a,ab,95,7b,ae,20,b6,cc,be,21,9d,66,0a,c9,b0,a4,0b,2c,36,48,f2,6c,70,1d,56,11,b5,54,0a,7a,75,41,f1,fc,94,97,fc,5f,1c,53,c2,80,d5,64,6e,f9,c4,32,a1,69,fb,f6,b4,d7,63,a9,86,b8,7a,70,30,2f,45,22,47,19,1a,0e,54,b6,c4,58,81,b8,36,c1,2f,b5,67,6e,07,05,7b,68,37,aa,a8,73,46,c7,1b,1c,d8,34,44,83,83,b8,d7,07,76,5a,e9,32,38,30,9f,17,78,b0,c0,11,73,43,f2,c9,10,b1,cc,59,e9,59,f8,44,60,a0,1b,9c,98,f2,43,2e,5b,5a,b1,6a,07,e7,9a,73,79,56,cf,73,05,9a,a6,6a,79,a5,49,1f,c0,97,22,fe,89,e2,e4,66,6d,9a,18,ac,5e,d1,41,ba,dc,99,b4,01,0d,b0,43,11,3e,be,a0,50,d6,39,8a,4f,58,7d,cc,30,ba,c0,e6,41,51,ab,4e" + [4589]="11,ed,06,81,04,28,4e,85,ac,80,07,2c,4d,65,e1,21,0b,bb,ef,c5,1b,a6,0e,34,8b,9f,4b,c7,2a,3a,7b,dd,46,85,32,47,c4,00,dd,17,4b,7b,e6,18,fd,b5,77,bd,0e,90,8d,fe,4c,75,e0,b1,ca,68,d1,6b,cd,ce,7c,06,91,c2,f5,97,9d,3c,3c,46,e4,07,64,96,3a,8b,fd,dc,92,cb,f1,b8,56,7d,76,1f,bd,db,c7,af,3b,de,b9,74,75,13,3c,10,6f,ee,12,c4,68,60,39,4b,6b,cd,4d,5b,6f,55,03,5a,bc,70,40,78,15,9e,74,81,9a,68,b2,4c,4c,40,ce,02,32,5a,d7,89,10,48,e4,63,f9,f2,bc,e8,d6,0c,80,db,24,2f,27,2a,9d,29,22,55,a2,b7,c1,bb,92,a4,b9,a5,32,42,cf,41,e1,09,55,0b,68,21,c1,07,50,6c,0a,8b,cc,18,db,bb,7a,9f,91,4c,de,72,53,c4,5a,7e,17,10,c8,ed,34,16,11,9b,2b,a0,10,84,1b,48,60,bf,17,42,3f,84,56,0b,d1,19,55,3c,56,ea,83,26,f4,e8,a6,82,6a,7d,c0,49,c3,5b,b6,36,89,d0,8f,1f,b5,3b,d1,52,34,cd,c3,3f,8a,f8,04,b7,68,84,df,e8,75,f8,9b,23,65,c7,2f,05,aa,cd,ea,48,28,6e,54,57,44,99,76,c1,68,6a,c8,3b,6c,18,1c,50,54,c5,ba,96,71,ac,d8,0a,00,8d,41,0e,f3,41,c2,9f,8b,21,4a,ec,af,d7,64,5a,29,37,54,5a,a2,11,f7,ba,60,04,b6,b7,77,0c,bf,6f,30,ac,dd,00,3f,de,53,23,f3,a9,9e,de,c1,6e,ad,4a,00,9f,da,6d,a4,73,4d,57,83,a3,2d,5a,32,d2,76,3b,85,b2,5a,b8,89,5e,93,79,8b,aa,24,8e,a3,5c,16,d6,21,0f,15,08,c9,19,0c,6f,6d,fa,b9,00,4d,69,43,43,29,34,3c,99,77,2a,29,ef,d7,1c,fb,02,a2,4c,41,90,07,d5,78,03,0c,74,e4,03,7f,bc,d2,61,f4,da,aa,b2,89,5f,23,0a,9f,73,a4,ac,a3,e2,bf,1c,23,4c,c4,95,42,8e,44,18,4a,92,0f,f5,13,89,07,12,a7,8d,11,4b,43,07,7a,62,eb,cf,25,49,ce,73,11,c1,b0,f3,c2,4d,24,1e,94,69,30,19,c1,ba,57,66,72,d9,52,b5,1a,35,4e,af,f6,9c,85,26,80,73,92,22,1c,54,90,3d,67,01,11,01,2f,4c,7c,57,06,c8,6f,bb,87,14,88,d1,2f,4b,a9,92,4b,57,ce,59,c3,76,db,b6,71,6e,27,9c,d8,60,52,07,77,0c,10,c9,6e,32,74,bc,d6,75,c7,77,80,81,5f,6a,a9,f0,c2,42,8c,79,83,db,75,15,68,1c,1d,78,59,96,7b,82,98,0f,74,49,ef,c0,b4,82,d7,c0,cd,a3,27,4d,ac,18,cd,bb,38,43,ac,04,70,73,6c,f3,d1,80,d1,88,28,c2,83,0e,54,89,61,01,8b,81,b0,27,45,46,1c,b8,11,81,23,45,b9,12,4c,a4,06,85,00,3e,75,0c,0c,1a,d6,99,d0,79,cf,2d,a0,00,94,09,34,e5,d9,1c,80,08,ca,71,3c,03,df,12,02,c8,77,92,9f,4b,7d,cf,3c,75,08,c2,16,39,73,b8,d1,ab,6a,bb,05,32,35,2a,70,b4,d7,03,4c,74,76,3e,eb,ac,f7,c5,70,4f,18,62,3a,55,86,0b,6c,13,82,45,c0,33,b5,2c,57,36,5a,1b,a7,7b,32,b3,4b,89,78,c2,d9,04,ca,66,f5,2b,32,26,c1,c0,76,a5,87,93,2f,0d,b9,6f,1a,c2,a4,48,32,c9,b4,98,98,b4,c2,4a,cf,74,ae,b6,fb,9f,ff,5c,c2,c7,66,47,35,89,9d,32,02,79,34,aa,c7,f7,44,a3,cb,f8,7a,dc,b6,66,21,51,93,d4,e4,c0,3f,f7,0f,e9,56,57,84,b9,81,3b,d3,8d,ea,73,40,45,22,34,e2,cc,c5,8b,b3,b3,b6,4b,cf,71,14,61,a5,31,36,5f,c6,64,de,19,0a,67,7c,0c,df,90,16,b0,78,0b,b3,88,54,80,ea,5e,6b,eb,44,c5,bb,4d,ea,11,1c,52,b6,39,8d,72,1b,ac,02,cf,bc,36,6b,9d,a9,5b,db,87,3d,72,66,20,20,5c,6f,43,86,1f,aa,3c,95,90,0c,60,e2,86,c4,57,57,21,b6,47,33,40,a2,4d,c5,70,50,8d,11,0a,ce,77,2b,f3,70,39,64,42,81,49,18,c1,ae,79,0d,43,55,01,99,bb,55,7a,5a,19,20,a7,a6,6c,75,6a,39,cc,87,4b,73,61,a4,9c,13,c3,d1,25,a3,51,39,b9,8b,a0,82,2c,2f,67,db,b9,de,65,34,eb,8a,3d,56,6a,7e,23,32,91,d4,86,70,30,11,03,e9,54,3b,87,bc,47,7d,eb,17,b1,b5,84,c0,10,59,50,f5,24,08,e6,59,0b,28,b9,c8,7c,3a,ad,e1,b8,28,cc,28,52,a6,b2,1f,1b,17,30,28,10,aa,b9,06,13,55,86,41,35,7b,98,20,10,94,65,2e,7a,42,09,d2,f4,62,b2,b5,39,6c,c8,88,99,f4,0f,bf,69,03,5a,63,79,05,b4,19,4b,72,43,ba,26,14,44,6a,70,dc,82,2f,32,47,68,28,91,87,30,87,70,4b,93,1c,75,9a,28,fb,a8,ac,cf,95,2e,5e,89,4f,1b,0b,31,72,77,0a,6b,f0,0b,41,a1,45,fb,65,5a,09,6c,54,7a,c7,00,ef,e9,97,6f,2c,a1,82,47,50,7e,3a,1b,41,56,99,15,97,a0,71,50,c1,77,9b,bc,d8,bb,9c,3a,43,90,c1,ea,4e,10,88,41,61,31,33,60,01,30,44,f1,37,e0,ca,88,fa,14,45,d5,d5,8e,20,a5,6e,53,62,77,93,13,8b,ea,cb,63,f7,05,25,cd,2c,a0,81,33,a3,6e,d0,7e,07,c1,98,fc,19,87,47,5a,a5,6e,cb,7b,47,f1,ae,ac,f4,bc,e4,30,a1,0e,36,4c,0e,04,76,5b,08,a9,10,d7,c7,ac,67,0b,0b,88,a5,09,03,54,ef,e7,18,ab,47,69,18,74,af,06,11,43,4b,a1,73,bd,66,7b,e7,15,8c,16,d6,43,cb,6a,2c,a0,32,c2,e0,46,95,81,f0,cb,49,b4,1e,4b,5a,0a,6f,c8,4e,d7,3b,47,93,08,8e,c2,78,3b,95,d6,02,b4,5c,8d,ac,b9,a6,ac,16,50,1a,8b,63,34,20,4d,bc,2b,23,9f,cb,a1,de,8c,15,95,98,cf,50,e7,30,f4,1b,3f,2f,a8,1d,cf,c5,5c,19,84,35,9e,1b,21,ef,95,4d,58,49,6a,5a,50,1b,c6,20,47,b6,78,3e,1e,59,3d,df,91,63,75,4b,c6,dd,58,b4,1e,12,2a,58,16,8d,44,68,8f,40,db,1d,c7,34,02,aa,3a,43,c4,f1,44,a7,47,c7,37,82,0b,05,31,c7,a8,a6,71,74,58,89,1e,f9,b9,78,67,c5,ef,b2,b8,fb,14,22,f2,ac,8e,c3,73,a2,f8,c2,5a,42,e3,33,8f,fc,9d,33,6a,ac,d2,67,43,8e,a2,44,5b,30,0d,74,f2,8a,d1,82,84,c5,11,a7,80,ca,b3,ab,5c,11,97,b9,92,68,82,46,3b,34,53,15,62,bb,b2,86,14,1b,68,90,a0,0a,c5,a4,e7,34,38,95,4d,66,61,3e,6c,6a,91,d8,44,a6,9a,85,b9,9f,d3,82,65,c1,8a,4d,11,75,3c,86,0b,b5,1b,25,ab,e0,7f,9c,7c,cd,ff,1b,29,8e,dc,15,63,25,ba,be,40,84,ae,11,b9,fa,09,17,36,f0,21,47,11,9d,fc,3c,8b,6e,08,22,eb,c5,a7,25,c3,86,9d,c1,a3,a0,4c,00,d5,66,3f,d5,d0,be,8b,59,09,d8,3c,1b,a8,a0,b0,8a,c1,16,5c,94,1d,50,42,b9,b0,95,3e,22,26,b2,45,89,b1,b9,b6,bd,b3,33,75,e9,69,6b,d6,11,28,cd,61,47,cc,c8,28,60,99,42,a1,c7,b7,f9,2a,61,f7,fb,12,91,99,71,94,1b,8c,69,c5,67,25,b6,50,12,e1,6d,ed,f9,3b,bb,f0,57,e9,e5,13,8d,d8,46,9f,4e,dc,8c,06,fd,b1,67,f4,66,fe,e8,06,79,97,ee,fd,07,aa,26,90,86,f2,1a,c4,9d,c5,f5,33,6a,ca,59" +[25497]="63,99,04,c0,15,45,8a,33,c6,16,72,fb,44,02,c9,c1,42,63,5d,2e,d0,30,a8,9b,a8,84,19,33,bf,23,10,ec,05,67,68,d9,12,0e,88,07,0a,39,85,85,6c,52,6e,24,70,69,38,aa,a1,a7,10,41,b5,4f,5a,99,2f,38,dc,07,0e,ab,a8,a2,44,40,49,7c,47,5d,3a,bd,7c,ea,af,63,11,47,5f,d2,8c,ef,81,b1,4d,e1,57,40,e6,32,0c,49,5d,43,63,62,7e,a8,49,71,7a,85,ea,00,9f,42,54,85,71,97,16,0e,43,35,4b,d1,26,2c,73,c8,cc,f2,43,63,c3,66,17,b4,7c,a7,d2,66,98,b4,60,e8,0b,a7,94,49,75,03,e3,4f,bf,69,ba,e7,67,68,89,c2,8a,4b,24,a2,42,f4,74,92,e3,44,85,bc,9e,da,e3,40,e9,e4,bd,4c,02,20,88,dc,67,2d,25,ba,4f,0a,4b,7c,dc,1f,96,d3,6a,01,86,5b,ad,75,b2,23,c5,c7,39,10,35,34,59,6e,23,fc,c9,cd,c0,17,e0,16,79,4b,04,82,70,d9,1f,62,a4,36,67,d3,00,a9,db,a4,25,09,21,38,f0,0b,d1,17,6a,3d,d5,22,51,1a,a6,0b,97,23,c7,67,32,0b,7c,a0,b3,a7,0d,06,49,01,52,69,9c,4f,f5,37,dd,0c,a7,bc,d0,c2,72,d5,6f,9c,26,aa,c3,ca,0d,84,6b,27,40,f8,1b,e3,55,bb,e4,f0,9a,15,52,2f,a3,da,06,45,c2,10,6e,a3,2a,07,87,61,89,1c,39,b1,52,26,2a,80,a5,a6,4b,2c,b3,3c,40,d7,42,0d,8b,67,90,d6,c6,49,09,a7,6e,d3,f2,c2,ac,b5,46,75,2c,8c,0d,03,0a,d8,f2,b7,19,a7,a4,84,f4,90,48,34,29,aa,00,28,e8,01,bf,2b,02,94,57,e2,62,36,59,61,d2,c0,0e,1c,69,04,57,b0,ba,c3,2c,a4,aa,e7,46,03,45,c9,a1,b6,58,13,ba,3f,ea,80,b3,ef,dc,5c,7f,28,8b,c6,92,18,db,81,0b,43,e1,07,65,b4,be,96,33,58,f0,31,c0,8c,29,9c,4c,d9,a8,95,91,58,e1,e7,61,b5,b5,23,0e,fa,39,62,63,38,3e,d4,3c,df,c1,09,81,ea,4f,0b,a2,7c,e3,08,1f,e6,e1,0f,5e,e0,5f,f1,02,c3,99,fa,6a,6f,45,96,87,31,18,f6,d8,48,13,15,6b,ed,7a,02,1e,da,a5,ec,da,67,07,67,ab,c2,ab,94,a5,07,01,17,54,8e,9c,35,12,55,60,53,02,8b,48,46,06,79,9f,da,6c,f3,51,86,a6,34,16,af,ba,45,ac,77,68,10,0b,c1,ce,f0,0a,c5,20,98,37,42,22,f8,e8,2e,9b,80,52,23,e4,90,f3,01,6e,f9,40,a7,19,c1,9d,59,97,9d,2e,57,06,d2,2a,75,28,c5,5b,aa,0c,a8,94,62,7b,ff,80,c4,6c,01,67,7f,c5,98,61,06,a3,bf,2c,19,32,77,86,7c,1c,42,36,0c,8c,7b,6b,62,01,d7,5a,2c,62,6f,a5,18,1b,19,c3,47,f7,e9,c9,ff,a9,c1,89,31,1d,46,79,2c,35,51,63,4a,f7,66,91,4a,b8,93,f9,40,b9,28,71,29,85,9a,0d,c5,16,c7,7b,ae,b9,4a,cc,50,d3,39,37,54,5f,31,fc,1b,fc,5a,76,23,e5,49,6b,c0,bd,11,1b,a2,b0,ca,36,55,07,54,40,0a,08,c8,49,ca,09,ea,29,73,02,80,d5,30,4c,e6,00,ae,0a,a4,2f,b8,57,4c,2d,75,58,05,8b,b6,c5,55,be,22,e6,48,63,75,c5,aa,f9,8d,e9,4c,8a,51,84,b7,96,b0,2e,14,58,18,99,48,29,de,36,7d,be,e5,8e,01,7c,9d,0f,71,2f,f8,84,7d,6e,d2,88,d0,67,b2,5b,e3,bb,63,bc,53,fa,80,88,29,26,c5,22,54,42,d8,21,82,5d,6a,4a,b1,b7,a2,8f,48,68,c2,c7,2f,79,fa,8d,25,f4,85,7b,47,a5,46,a5,af,3e,88,37,06,f5,41,40,71,02,89,f9,3e,1d,46,43,3e,34,5e,7e,39,4b,f2,25,c8,30,33,59,45,8a,c2,95,4b,94,37,53,b3,f0,03,73,21,d5,36,51,fc,6f,e9,1c,69,dd,a6,47,2b,39,5e,fc,35,c4,a8,84,7e,34,32,b3,76,f5,23,1b,67,07,e7,c8,b3,99,82,36,ec,9b,c7,a3,2c,80,de,09,46,c9,c9,22,cd,19,b9,a7,e0,c8,cb,a3,20,f7,f4,3a,7c,48,44,86,db,96,a4,b0,9d,bd,63,84,54,d9,c6,09,16,03,1e,45,89,65,da,57,2d,b3,33,0a,7b,1a,98,5a,cc,e5,08,ba,8c,35,7e,fe,4a,36,fa,f4,58,c3,fb,c8,e1,66,14,9e,91,b6,02,88,6f,fe,a9,6e,41,cb,63,6d,92,cc,65,c4,a9,9e,69,38,75,ec,6f,0f,89,c7,65,aa,2a,a1,8b,90,ad,e5,83,4b,b2,3e,68,60,84,be,a0,98,32,e6,47,53,41,c4,35,49,ca,10,16,c5,52,53,47,2b,ac,4f,44,1b,6a,04,7a,ab,95,7b,ae,20,b6,cc,be,21,9d,66,0a,c9,b0,a4,0b,2c,36,48,f2,6c,70,1d,56,11,b5,54,0a,7a,75,41,f1,fc,94,97,fc,5f,1c,53,c2,80,d5,64,6e,f9,c4,32,a1,69,fb,f6,b4,d7,63,a9,86,b8,7a,70,30,2f,45,22,47,19,1a,0e,54,b6,c4,58,81,b8,36,c1,2f,b5,67,6e,07,05,7b,68,37,aa,a8,73,46,c7,1b,1c,d8,34,44,83,83,b8,d7,07,76,5a,e9,32,38,30,9f,17,78,b0,c0,11,73,43,f2,c9,10,b1,cc,59,e9,59,f8,44,60,a0,1b,9c,98,f2,43,2e,5b,5a,b1,6a,07,e7,9a,73,79,56,cf,73,05,9a,a6,6a,79,a5,49,1f,c0,97,22,fe,89,e2,e4,66,6d,9a,18,ac,5e,d1,41,ba,dc,99,b4,01,0d,b0,43,11,3e,be,a0,50,d6,39,8a,4f,58,7d,cc,30,ba,c0,e6,41,51,ab,4e" ) diff --git a/openssl-iana.mapping.html b/openssl-iana.mapping.html index 8b6363d..9e90ce2 100644 --- a/openssl-iana.mapping.html +++ b/openssl-iana.mapping.html @@ -425,6 +425,10 @@ xB9 TLS_RSA_PSK_WITH_NULL_SHA384 [0xc0ae] ECDHE-ECDSA-AES128-CCM8 ECDH AESCCM 128 TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 [0xc0af] ECDHE-ECDSA-AES256-CCM8 ECDH AESCCM 256 TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 + + [0xc0b4] TLS_SHA256_SHA256 ECDH Null 0 TLS_SHA256_SHA256 + [0xc0b5] TLS_SHA384_SHA384 ECDH Null 0 TLS_SHA384_SHA384 + [0xcc13] ECDHE-RSA-CHACHA20-POLY1305-OLD ECDH ChaCha20-Poly1305 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256_OLD [0xcc14] ECDHE-ECDSA-CHACHA20-POLY1305-OLD ECDH ChaCha20-Poly1305 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256_OLD diff --git a/t/00_testssl_help.t b/t/00_testssl_help.t index bedcb8c..b979fa8 100755 --- a/t/00_testssl_help.t +++ b/t/00_testssl_help.t @@ -24,10 +24,10 @@ printf "\n%s\n", "Testing whether just calling \"./testssl.sh\" produces no erro my $info = stat($prg); my $retMode = $info->mode; -is($retMode & 0400, 0400, "Checking \"./testssl.sh\" for read permission"); +is($retMode & 0400, 0400, "Checking \"./testssl.sh\" for read permission"); $tests++; -is($retMode & 0100, 0100, "Checking \"./testssl.sh\" for execute permission"); +is($retMode & 0100, 0100, "Checking \"./testssl.sh\" for execute permission"); $tests++; $fileout = `timeout 10 bash $prg 2>&1`; @@ -55,7 +55,7 @@ $out=`grep -E "$debug_regexp" $prg`; unlike($out, qr/$debug_regexp/, "Debug RegEx"); $tests++; -printf "\n"; +printf "\n\n"; done_testing($tests); diff --git a/t/05_ca_hashes_up_to_date.t b/t/05_ca_hashes_up_to_date.t index 434b7a0..7124e5f 100755 --- a/t/05_ca_hashes_up_to_date.t +++ b/t/05_ca_hashes_up_to_date.t @@ -6,7 +6,7 @@ use Test::More; printf "\n%s\n", "Testing whether CA certificates are newer their SPKI hashes \"~/etc/ca_hashes.txt\" ..."; my $newer_bundles=`find etc/*.pem -newer etc/ca_hashes.txt`; -is($newer_bundles,"","If there's an output with a *.pem file run \"~/utils/create_ca_hashes.sh\""); +is($newer_bundles,"","Checking if there's an output with a *.pem file run \"~/utils/create_ca_hashes.sh\""); printf "\n"; done_testing; diff --git a/t/10_baseline_ipv4_http.t b/t/10_baseline_ipv4_http.t index c98e6f2..90ededa 100755 --- a/t/10_baseline_ipv4_http.t +++ b/t/10_baseline_ipv4_http.t @@ -15,48 +15,51 @@ use JSON; my $tests = 0; my $prg="./testssl.sh"; -my $check2run="-p -s -P --fs -S -h -U -q --ip=one --color 0"; +my $tmp_json="tmp.json"; +my $check2run="-p -s -P --fs -S -h -U -q --ip=one --color 0 --jsonfile $tmp_json"; my $uri="google.com"; my $socket_out=""; my $openssl_out=""; -# Blacklists we use to trigger an error: -my $socket_regex_bl='(e|E)rror|\.\/testssl\.sh: line |(f|F)atal|(c|C)ommand not found'; -my $openssl_regex_bl='(e|E)rror|(f|F)atal|\.\/testssl\.sh: line |Oops|s_client connect problem|(c|C)ommand not found'; -my $json_regex_bl='(id".*:\s"scanProblem"|severity".*:\s"FATAL"|"Scan interrupted")'; - my $socket_json=""; my $openssl_json=""; -$check2run="--jsonfile tmp.json $check2run"; +#FIXME: Blacklists we use to trigger an error, but likely we can skip that and instead we should?/could use +# @args="$prg $check2run $uri >/dev/null"; +# system("@args") == 0 +# or die ("FAILED: \"@args\" "); +my $socket_errors='(e|E)rror|\.\/testssl\.sh: line |(f|F)atal|(c|C)ommand not found'; +my $openssl_errors='(e|E)rror|(f|F)atal|\.\/testssl\.sh: line |Oops|s_client connect problem|(c|C)ommand not found'; +my $json_errors='(id".*:\s"scanProblem"|severity".*:\s"FATAL"|"Scan interrupted")'; + die "Unable to open $prg" unless -f $prg; # Provide proper start conditions -unlink "tmp.json"; +unlink $tmp_json; # Title printf "\n%s\n", "Baseline unit test IPv4 against \"$uri\""; #1 $socket_out = `$prg $check2run $uri 2>&1`; -$socket_json = json('tmp.json'); -unlink "tmp.json"; -unlike($socket_out, qr/$socket_regex_bl/, "via sockets, terminal output"); +$socket_json = json($tmp_json); +unlike($socket_out, qr/$socket_errors≈/, "via sockets, checking terminal output"); $tests++; -unlike($socket_json, qr/$json_regex_bl/, "via sockets JSON output"); +unlike($socket_json, qr/$json_errors/, "via sockets checking JSON output"); $tests++; +unlink $tmp_json; + + #2 $openssl_out = `$prg --ssl-native $check2run $uri 2>&1`; -$openssl_json = json('tmp.json'); -unlink "tmp.json"; -# With Google only we sometimes encounter an error as they return a 0 char with openssl, so we white list this pattern here: -# It should be fixed in the code though so we comment this out -# $openssl_out =~ s/testssl.*warning: command substitution: ignored null byte in input\n//g; -unlike($openssl_out, qr/$openssl_regex_bl/, "via OpenSSL"); +$openssl_json = json($tmp_json); +unlike($openssl_out, qr/$openssl_errors/, "via (builtin) OpenSSL, checking terminal output"); $tests++; -unlike($openssl_json, qr/$json_regex_bl/, "via OpenSSL JSON output"); +unlike($openssl_json, qr/$json_errors/, "via OpenSSL (builtin) checking JSON output"); $tests++; +unlink $tmp_json; + done_testing($tests); printf "\n"; @@ -69,5 +72,5 @@ sub json($) { } -# vim:ts=5:sw=5:expandtab +# vim:ts=5:sw=5:expandtab diff --git a/t/11_baseline_ipv6_http.t.DISABLED b/t/11_baseline_ipv6_http.t.DISABLED index affa18a..028cbea 100755 --- a/t/11_baseline_ipv6_http.t.DISABLED +++ b/t/11_baseline_ipv6_http.t.DISABLED @@ -1,6 +1,6 @@ #!/usr/bin/env perl -# disabled as IPv6 is not supported by Travis, see https://github.com/drwetter/testssl.sh/issues/1177 +# disabled as IPv6 wasn't supported by Travis CI and isn't by GH action, see https://github.com/testssl/testssl.sh/issues/1177 # Just a functional test, whether there are any problems on the client side # Probably we could also inspect the JSON for any problems for diff --git a/t/12_diff_opensslversions.t b/t/12_diff_opensslversions.t new file mode 100755 index 0000000..c91e10c --- /dev/null +++ b/t/12_diff_opensslversions.t @@ -0,0 +1,85 @@ +#!/usr/bin/env perl + +# Baseline diff test against testssl.sh (csv output) +# +# This runs a basic test with the supplied openssl vs /usr/bin/openssl + +use strict; +use Test::More; +use Data::Dumper; +use Text::Diff; + +my $tests = 0; +my $prg="./testssl.sh"; +my $check2run="--protocols --std --server-preference --fs --header --renegotiation --crime --breach --poodle --tls-fallback --sweet32 --beast --lucky13 --freak --logjam --drown --rc4 --phone-out --client-simulation -q --ip=one --color 0 --csvfile"; +my $csvfile="tmp.csv"; +my $csvfile2="tmp2.csv"; +my $cat_csvfile=""; +my $cat_csvfile2=""; +my $uri="google.com"; +my $diff=""; +my $distro_openssl="/usr/bin/openssl"; +my @args=""; + +die "Unable to open $prg" unless -f $prg; +die "Unable to open $distro_openssl" unless -f $distro_openssl; + +# Provide proper start conditions +unlink $csvfile; +unlink $csvfile2; + +#1 run +printf "\n%s\n", "Diff test IPv4 with supplied openssl against \"$uri\""; +@args="$prg $check2run $csvfile $uri >/dev/null"; +system("@args") == 0 + or die ("FAILED: \"@args\""); + +# 2 +printf "\n%s\n", "Diff test IPv4 with $distro_openssl against \"$uri\""; +@args="$prg $check2run $csvfile2 --openssl=$distro_openssl $uri >/dev/null"; +system("@args") == 0 + or die ("FAILED: \"@args\" "); + +$cat_csvfile = `cat $csvfile`; +$cat_csvfile2 = `cat $csvfile2`; + +# Filter for changes that are allowed to occur +$cat_csvfile =~ s/HTTP_clock_skew.*\n//g; +$cat_csvfile2 =~ s/HTTP_clock_skew.*\n//g; + +# HTTP time +$cat_csvfile =~ s/HTTP_headerTime.*\n//g; +$cat_csvfile2 =~ s/HTTP_headerTime.*\n//g; + +#engine_problem +$cat_csvfile =~ s/"engine_problem.*\n//g; +$cat_csvfile2 =~ s/"engine_problem.*\n//g; + +# PR #2628. TL:DR; make the kx between tls_sockets() and openssl the same for this CI run +$cat_csvfile =~ s/ECDH 256/ECDH 253/g; +$cat_csvfile =~ s/ECDH\/MLKEM/ECDH 253 /g; + +# Nonce in CSP +$cat_csvfile =~ s/.nonce-.* //g; +$cat_csvfile2 =~ s/.nonce-.* //g; + ++# Fix IP addresses. needed when we don't hit the same IP address. We just remove them +$cat_csvfile =~ s/","google.com\/.*","443/","google.com","443/; +$cat_csvfile2 =~ s/","google.com\/.*","443/","google.com","443/; + +$diff = diff \$cat_csvfile, \$cat_csvfile2; + +# Compare the differences -- and print them if there were any +ok( $cat_csvfile eq $cat_csvfile2, "Check whether CSV outputs match" ) or + diag ("\n%s\n", "$diff"); + +unlink "tmp.csv"; +unlink "tmp2.csv"; + +$tests++; +done_testing($tests); +printf "\n"; + + +# vim:ts=5:sw=5:expandtab + diff --git a/t/32_isHTML_valid.t b/t/32_isHTML_valid.t index 84db98d..afb5d64 100755 --- a/t/32_isHTML_valid.t +++ b/t/32_isHTML_valid.t @@ -46,15 +46,16 @@ $edited_html =~ s/>/>/g; $edited_html =~ s/"/"/g; $edited_html =~ s/'/'/g; -cmp_ok($edited_html, "eq", $out, "HTML file matches terminal output"); -$tests++; - $diff = diff \$edited_html, \$out; -printf "\n%s\n", "$diff"; + +cmp_ok($edited_html, "eq", $out, "Checking if HTML file matches terminal output") or + diag ("\n%s\n", "$diff"); + +$tests++; #2 -printf "\n%s\n", " .. running again $prg against \"$uri\", now with --debug 4 to create HTML output (may take another ~2 minutes)"; +printf "%s\n", " .. running again $prg against \"$uri\", now with --debug 4 to create HTML output (may take another ~2 minutes)"; # Redirect stderr to /dev/null in order to avoid some unexplained "date: invalid date" error messages $out = `TERM_WIDTH=120 $prg $check2run --debug 4 $uri 2> /dev/null`; $debughtml = `cat $htmlfile`; @@ -79,15 +80,14 @@ $debughtml =~ s/.*built: .*\n//g; $debughtml =~ s/.*Using bash .*\n//g; # is whole line: s/.* .*\n//g; -cmp_ok($debughtml, "eq", $html, "HTML file created with --debug 4 matches HTML file created without --debug"); +$diff = diff \$debughtml, \$html; + +cmp_ok($debughtml, "eq", $html, "Checking if HTML file created with --debug 4 matches HTML file created without --debug") or + diag ("\n%s\n", "$diff"); $tests++; -$diff = diff \$debughtml, \$html; -printf "\n%s\n", "$diff"; - - -printf "\n"; +printf "\n\n"; done_testing($tests); diff --git a/t/51_badssl.com.t b/t/51_badssl.com.t index 40b6e91..db734e4 100755 --- a/t/51_badssl.com.t +++ b/t/51_badssl.com.t @@ -17,7 +17,7 @@ pass("Running testssl.sh against badssl.com to create a baseline (may take 2~3 m my $okout = `./testssl.sh -S -e --freak --logjam --drown --rc4 --sweet32 --breach --winshock --crime --jsonfile tmp.json --color 0 badssl.com`; my $okjson = json('tmp.json'); unlink 'tmp.json'; -cmp_ok(@$okjson,'>',10,"We have more then 10 findings"); $tests++; +cmp_ok(@$okjson,'>',10,"We should have more then 10 findings"); $tests++; # Expiration pass("Running testssl against expired.badssl.com"); $tests++; @@ -35,7 +35,7 @@ foreach my $f ( @$json ) { last; } } -is($found,1,"We had a finding for this in the JSON output"); $tests++; +is($found,1,"We should have a finding for this in the JSON output"); $tests++; # Self signed and not-expired pass("Running testssl against self-signed.badssl.com"); $tests++; @@ -52,7 +52,7 @@ foreach my $f ( @$json ) { last; } } -is($found,1,"We had a finding for this in the JSON output"); $tests++; +is($found,1,"We should a finding for this in the JSON output"); $tests++; like($out, qr/Chain of trust.*?NOT ok.*\(self signed\)/,"Chain of trust should fail because of self signed"); $tests++; $found = 0; @@ -64,7 +64,7 @@ foreach my $f ( @$json ) { last; } } -is($found,1,"We had a finding for this in the JSON output"); $tests++; +is($found,1,"We should have a finding for this in the JSON output"); $tests++; like($okout, qr/Chain of trust[^\n]*?Ok/,"Chain of trust should be ok"); $tests++; $found = 0; @@ -77,7 +77,7 @@ foreach my $f ( @$okjson ) { last; } } -is($found,1,"We had a finding for this in the JSON output"); $tests++; +is($found,1,"We should have a finding for this in the JSON output"); $tests++; # Wrong host #pass("Running testssl against wrong.host.badssl.com"); $tests++; @@ -111,7 +111,7 @@ foreach my $f ( @$json ) { last; } } -is($found,1,"We had a finding for this in the JSON output"); $tests++; +is($found,1,"We should have a finding for this in the JSON output"); $tests++; # TODO: RSA 8192 diff --git a/t/61_diff_testsslsh.t b/t/61_diff_testsslsh.t index f4070b1..8532e8f 100755 --- a/t/61_diff_testsslsh.t +++ b/t/61_diff_testsslsh.t @@ -3,11 +3,10 @@ # Baseline diff test against testssl.sh (csv output) # # We don't use a full run yet and only the certificate section. -# There we would need to blacklist at least: +# There we would need to blacklist more, like: # cert_serialNumber, cert_fingerprintSHA1, cert_fingerprintSHA256, cert # cert_expirationStatus, cert_notBefore, cert_notAfter, cert_caIssuers, intermediate_cert # -# help is appreciated here use strict; use Test::More; @@ -16,55 +15,54 @@ use Text::Diff; my $tests = 0; my $prg="./testssl.sh"; -my $master_socket_csv="./t/baseline_data/default_testssl.csvfile"; -my $socket_csv="tmp.csv"; -my $check2run="-p -s -P --fs -h -U -c -q --ip=one --color 0 --csvfile $socket_csv"; -#my $check2run="-p --color 0 --csvfile $socket_csv"; +my $baseline_csv="./t/baseline_data/default_testssl.csvfile"; +my $cat_csv="tmp.csv"; +my $check2run="-p -s -P --fs -h -U -c -q --ip=one --color 0 --csvfile $cat_csv"; my $uri="testssl.sh"; my $diff=""; +my @args=""; die "Unable to open $prg" unless -f $prg; -die "Unable to open $master_socket_csv" unless -f $master_socket_csv; - +die "Unable to open $baseline_csv" unless -f $baseline_csv; # Provide proper start conditions -unlink "tmp.csv"; +unlink $cat_csv; -# Title -printf "\n%s\n", "Diff unit test IPv4 against \"$uri\""; #1 run -`$prg $check2run $uri 2>&1`; +printf "\n%s\n", "Diff unit test (IPv4) against \"$uri\""; +@args="$prg $check2run $uri >/dev/null"; +system("@args") == 0 + or die ("FAILED: \"@args\" "); -$diff = diff $socket_csv, $master_socket_csv; - -$socket_csv=`cat tmp.csv`; -$master_socket_csv=`cat $master_socket_csv`; +$cat_csv=`cat $cat_csv`; +$baseline_csv=`cat $baseline_csv`; # Filter for changes that are allowed to occur -$socket_csv=~ s/HTTP_clock_skew.*\n//g; -$master_socket_csv=~ s/HTTP_clock_skew.*\n//g; - -# DROWN -$socket_csv=~ s/censys.io.*\n//g; -$master_socket_csv=~ s/censys.io.*\n//g; +$cat_csv =~ s/HTTP_clock_skew.*\n//g; +$baseline_csv =~ s/HTTP_clock_skew.*\n//g; # HTTP time -$socket_csv=~ s/HTTP_headerTime.*\n//g; -$master_socket_csv=~ s/HTTP_headerTime.*\n//g; +$cat_csv =~ s/HTTP_headerTime.*\n//g; +$baseline_csv =~ s/HTTP_headerTime.*\n//g; -# Compare the differences to the master file -- and print differences if there were detected. +# DROWN +$cat_csv =~ s/censys.io.*\n//g; +$baseline_csv =~ s/censys.io.*\n//g; + +$diff = diff \$cat_csv, \$baseline_csv; + +# Compare the differences to the baseline file -- and print differences if there were detected. # -cmp_ok($socket_csv, "eq", $master_socket_csv, "Check whether CSV output matches master file from $uri") or +ok($cat_csv eq $baseline_csv, "Check whether CSV output matches baseline file from $uri") or diag ("\n%s\n", "$diff"); -$tests++; - unlink "tmp.csv"; +$tests++; done_testing($tests); printf "\n"; -# vim:ts=5:sw=5:expandtab +# vim:ts=5:sw=5:expandtab diff --git a/t/Readme.md b/t/Readme.md index 272372b..bfdeac0 100644 --- a/t/Readme.md +++ b/t/Readme.md @@ -5,6 +5,6 @@ * 30-39: Does reporting work? * 50-69: Are the results what I expect (server side)? -Please help to write Travis/CI tests! Documentation can be found [here](https://perldoc.perl.org/Test/More.html). -You can consult the existing code here. Feel free to use `10_baseline_ipv4_http.t` or `23_client_simulation.t` as a -template. +Please help to write CI tests! Documentation can be found [here](https://perldoc.perl.org/Test/More.html). +You can consult the existing code here. Feel free to use `10_baseline_ipv4_http.t` or `12_diff_opensslversions.t` as a +template. The latter is newer and code is cleaner. diff --git a/t/baseline_data/default_testssl.csvfile b/t/baseline_data/default_testssl.csvfile index 28118ba..bb91a05 100644 --- a/t/baseline_data/default_testssl.csvfile +++ b/t/baseline_data/default_testssl.csvfile @@ -70,7 +70,7 @@ "FS_TLS13_sig_algs","testssl.sh/81.169.166.184","443","INFO","RSA-PSS-RSAE+SHA256 RSA-PSS-RSAE+SHA384 RSA-PSS-RSAE+SHA512","","" "HTTP_status_code","testssl.sh/81.169.166.184","443","INFO","200 OK ('/')","","" "HTTP_clock_skew","testssl.sh/81.169.166.184","443","INFO","0 seconds from localtime","","" -"HTTP_headerTime","testssl.sh/81.169.166.184","443","INFO","1654006271","","" +"HTTP_headerTime","testssl.sh/81.169.166.184","443","INFO","1737570310","","" "HSTS_time","testssl.sh/81.169.166.184","443","OK","362 days (=31337000 seconds) > 15552000 seconds","","" "HSTS_subdomains","testssl.sh/81.169.166.184","443","INFO","only for this domain","","" "HSTS_preload","testssl.sh/81.169.166.184","443","INFO","domain is NOT marked for preloading","","" @@ -81,6 +81,8 @@ "X-Frame-Options","testssl.sh/81.169.166.184","443","OK","DENY","","" "X-Content-Type-Options","testssl.sh/81.169.166.184","443","OK","nosniff","","" "Content-Security-Policy","testssl.sh/81.169.166.184","443","OK","script-src 'unsafe-inline'; style-src 'unsafe-inline' 'self'; object-src 'self'; base-uri 'none'; form-action 'none'; img-src 'self' ; default-src 'self'; frame-ancestors 'self'; upgrade-insecure-requests;","","" +"Cross-Origin-Opener-Policy","testssl.sh/81.169.166.184","443","INFO","same-origin-allow-popups","","" +"Cross-Origin-Resource-Policy","testssl.sh/81.169.166.184","443","INFO","same-site","","" "banner_reverseproxy","testssl.sh/81.169.166.184","443","INFO","--","","CWE-200" "heartbleed","testssl.sh/81.169.166.184","443","OK","not vulnerable, no heartbeat extension","CVE-2014-0160","CWE-119" "CCS","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2014-0224","CWE-310" @@ -95,7 +97,7 @@ "SWEET32","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2016-2183 CVE-2016-6329","CWE-327" "FREAK","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2015-0204","CWE-310" "DROWN","testssl.sh/81.169.166.184","443","OK","not vulnerable on this host and port","CVE-2016-0800 CVE-2016-0703","CWE-310" -"DROWN_hint","testssl.sh/81.169.166.184","443","INFO","Make sure you don't use this certificate elsewhere with SSLv2 enabled services, see https://search.censys.io/search?resource=hosts&virtual_hosts=INCLUDE&q=31B44391529821C6A77F3C78B02D716A07F99B8FDB342BF5A78F263C25375968","CVE-2016-0800 CVE-2016-0703","CWE-310" +"DROWN_hint","testssl.sh/81.169.166.184","443","INFO","Make sure you don't use this certificate elsewhere with SSLv2 enabled services, see https://search.censys.io/search?resource=hosts&virtual_hosts=INCLUDE&q=5B4BC205947AED96ECB1879F2668F7F69D696C143BA8D1C69DBB4DC873C92AE9","CVE-2016-0800 CVE-2016-0703","CWE-310" "LOGJAM","testssl.sh/81.169.166.184","443","OK","not vulnerable, no DH EXPORT ciphers,","CVE-2015-4000","CWE-310" "LOGJAM-common_primes","testssl.sh/81.169.166.184","443","OK","--","CVE-2015-4000","CWE-310" "BEAST_CBC_TLS1","testssl.sh/81.169.166.184","443","MEDIUM","ECDHE-RSA-AES256-SHA ECDHE-RSA-AES128-SHA DHE-RSA-CAMELLIA256-SHA DHE-RSA-CAMELLIA128-SHA DHE-RSA-AES256-SHA DHE-RSA-AES128-SHA AES256-SHA","CVE-2011-3389","CWE-20" diff --git a/testssl.sh b/testssl.sh index efe0fdc..67fa39d 100755 --- a/testssl.sh +++ b/testssl.sh @@ -7,9 +7,9 @@ # vulnerabilities or features. It may or may be not distributed by your distribution. # The upstream versions are available (please leave the links intact): # -# Development version https://github.com/drwetter/testssl.sh +# Development version https://github.com/testssl/testssl.sh # Stable version https://testssl.sh -# File bugs at GitHub https://github.com/drwetter/testssl.sh/issues +# File bugs at GitHub https://github.com/testssl/testssl.sh/issues # # Project lead and initiator: Dirk Wetter, copyleft: 2007-today, contributions so far see CREDITS.md # Main contributions from David Cooper @@ -122,7 +122,7 @@ trap "child_error" USR1 ########### Internal definitions # -declare -r VERSION="3.2rc3" +declare -r VERSION="3.2rc4" declare -r SWCONTACT="dirk aet testssl dot sh" [[ "$VERSION" =~ dev|rc|beta ]] && \ SWURL="https://testssl.sh/dev/" || @@ -243,10 +243,12 @@ SYSTEM2="" # currently only being used for WSL = ba PRINTF="" # which external printf to use. Empty presets the internal one, see #1130 CIPHERS_BY_STRENGTH_FILE="" TLS_DATA_FILE="" # mandatory file for socket-based handshakes -OPENSSL="" # If you run this from GitHub it's ~/bin/openssl.$(uname).$(uname -m) otherwise /usr/bin/openssl -OPENSSL2="" # When running from GitHub, this will be openssl version >=1.1.1 (auto determined) -OPENSSL2_HAS_TLS_1_3=false # If we run with supplied binary AND /usr/bin/openssl supports TLS 1.3 this is set to true +OPENSSL="" # ~/bin/openssl.$(uname).$(uname -m) if you run this from GitHub. Linux otherwise probably /usr/bin/openssl +OPENSSL2=${OPENSSL2:-/usr/bin/openssl} # This will be openssl version >=1.1.1 (auto determined) as opposed to openssl-bad (OPENSSL) +OPENSSL2_HAS_TLS_1_3=false # If we run with supplied binary AND $OPENSSL2 supports TLS 1.3 this will be set to true +OSSL_SHORTCUT=${OSSL_SHORTCUT:-true} # If you don't want automagically switch from $OPENSSL to $OPENSSL2 for TLS 1.3-only hosts, set this to false OPENSSL_LOCATION="" +OPENSSL_NOTIMEOUT="" # Needed for renegotiation tests IKNOW_FNAME=false FIRST_FINDING=true # is this the first finding we are outputting to file? JSONHEADER=true # include JSON headers and footers in HTML file, if one is being created @@ -275,7 +277,6 @@ KNOWN_OSSL_PROB=false # We need OpenSSL a few times. This vari DETECTED_TLS_VERSION="" # .. as hex string, e.g. 0300 or 0303 APP_TRAF_KEY_INFO="" # Information about the application traffic keys for a TLS 1.3 connection. TLS13_ONLY=false # Does the server support TLS 1.3 ONLY? -OSSL_SHORTCUT=${OSSL_SHORTCUT:-false} # Hack: if during the scan turns out the OpenSSL binary supports TLS 1.3 would be a better choice, this enables it. TLS_EXTENSIONS="" TLS13_CERT_COMPRESS_METHODS="" CERTIFICATE_TRANSPARENCY_SOURCE="" @@ -399,7 +400,7 @@ RSA_CERT_FINGERPRINT_SHA2="" STARTTLS_PROTOCOL="" OPTIMAL_PROTO="" # Need this for IIS6 (sigh) + OpenSSL 1.0.2, otherwise some handshakes will fail see # https://github.com/PeterMosmans/openssl/issues/19#issuecomment-100897892 -STARTTLS_OPTIMAL_PROTO="" # Same for STARTTLS, see https://github.com/drwetter/testssl.sh/issues/188 +STARTTLS_OPTIMAL_PROTO="" # Same for STARTTLS, see https://github.com/testssl/testssl.sh/issues/188 OPTIMAL_SOCKETS_PROTO="" # Same for tls_sockets(). -- not yet used ALL_FAILED_SOCKETS=true # Set to true if all attempts to connect to server using tls_sockets/sslv2_sockets failed TLS_TIME="" # To keep the value of TLS server timestamp @@ -415,6 +416,7 @@ END_TIME=0 # .. ended SCAN_TIME=0 # diff of both: total scan time LAST_TIME=0 # only used for performance measurements (MEASURE_TIME=true) SERVER_COUNTER=0 # Counter for multiple servers +OPEN_MSG="" # Null the poor man's implementation of a message stack TLS_LOW_BYTE="" # For "secret" development stuff, see -q below HEX_CIPHER="" # -- " -- @@ -453,7 +455,7 @@ declare TLS_CIPHER_AUTH=() declare TLS_CIPHER_ENC=() declare TLS_CIPHER_EXPORT=() declare TLS_CIPHER_OSSL_SUPPORTED=() -declare TLS13_OSSL_CIPHERS="TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256" +declare TLS13_OSSL_CIPHERS="TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_SHA256_SHA256:TLS_SHA384_SHA384" ########### Some predefinitions: date, sed (we always use tests for binaries and NOT try to determine @@ -581,8 +583,6 @@ tmln_out() { printf -- "%b" "$1\n"; } out() { printf -- "%b" "$1"; html_out "$(html_reserved "$1")"; } outln() { printf -- "%b" "$1\n"; html_out "$(html_reserved "$1")\n"; } -#TODO: Still no shell injection safe but if just run it from the cmd line: that's fine - # Color print functions, see also https://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html tm_liteblue() { [[ "$COLOR" -ge 2 ]] && { "$COLORBLIND" && tm_out "\033[0;32m$1" || tm_out "\033[0;34m$1"; } || tm_out "$1"; tm_off; } # not yet used pr_liteblue() { tm_liteblue "$1"; [[ "$COLOR" -ge 2 ]] && { "$COLORBLIND" && html_out "$(html_reserved "$1")" || html_out "$(html_reserved "$1")"; } || html_out "$(html_reserved "$1")"; } @@ -616,7 +616,7 @@ tmln_cyan() { tm_cyan "$1"; tmln_out; } pr_cyan() { tm_cyan "$1"; [[ "$COLOR" -ge 2 ]] && html_out "$(html_reserved "$1")" || html_out "$(html_reserved "$1")"; } prln_cyan() { pr_cyan "$1"; outln; } -tm_litegrey() { [[ "$COLOR" -ne 0 ]] && tm_out "\033[0;37m$1" || tm_out "$1"; tm_off; } # ... https://github.com/drwetter/testssl.sh/pull/600#issuecomment-276129876 +tm_litegrey() { [[ "$COLOR" -ne 0 ]] && tm_out "\033[0;37m$1" || tm_out "$1"; tm_off; } # ... https://github.com/testssl/testssl.sh/pull/600#issuecomment-276129876 tmln_litegrey() { tm_litegrey "$1"; tmln_out; } # not really usable on a black background, see .. prln_litegrey() { pr_litegrey "$1"; outln; } pr_litegrey() { tm_litegrey "$1"; [[ "$COLOR" -ne 0 ]] && html_out "$(html_reserved "$1")" || html_out "$(html_reserved "$1")"; } @@ -971,9 +971,14 @@ join_by() { actually_supported_osslciphers() { local ciphers="$1" local tls13_ciphers="$TLS13_OSSL_CIPHERS" + local cipher tls13_supported_ciphers="" local options="$3 " [[ "$2" != ALL ]] && tls13_ciphers="$2" + for cipher in ${tls13_ciphers//:/ }; do + [[ "$TLS13_OSSL_CIPHERS" =~ $cipher ]] && tls13_supported_ciphers+=":$cipher" + done + tls13_ciphers="${tls13_supported_ciphers:1}" "$HAS_SECLEVEL" && [[ -n "$ciphers" ]] && ciphers="@SECLEVEL=0:$1" # With OpenSSL 1.0.2 the only way to exclude SSLv2 ciphers is to use the -tls1 option. # However, with newer versions of OpenSSL, the -tls1 option excludes TLSv1.2 ciphers. @@ -1000,7 +1005,10 @@ strip_inconsistent_ciphers() { local -i proto=0x$1 local cipherlist="$2" - [[ $proto -lt 4 ]] && cipherlist="${cipherlist//, 13,0[0-9a-fA-F]/}" + if [[ $proto -lt 4 ]]; then + cipherlist="${cipherlist//, 13,0[0-9a-fA-F]/}" + cipherlist="${cipherlist//, [cC]0,[bB][45]/}" + fi if [[ $proto -lt 3 ]]; then cipherlist="${cipherlist//, 00,3[b-fB-F]/}" cipherlist="${cipherlist//, 00,40/}" @@ -1028,7 +1036,7 @@ get_cipher() { # However there seem to be cases where the preferred $(< "$1") logic has a problem. # Especially with bash 3.2 (Mac OS X) and when on the server side binary chars # are returned, see https://stackoverflow.com/questions/7427262/how-to-read-a-file-into-a-variable-in-shell#22607352 - # and https://github.com/drwetter/testssl.sh/issues/1292 + # and https://github.com/testssl/testssl.sh/issues/1292 # Performance measurements showed no to barely measurable penalty (1s displayed in 9 tries). if [[ "$server_hello" =~ Cipher\ *:\ ([A-Z0-9]+-[A-Za-z0-9\-]+|TLS_[A-Za-z0-9_]+|SSL_[A-Za-z0-9_]+) ]]; then @@ -1362,13 +1370,17 @@ fileout_insert_warning() { [[ "$CMDLINE=" =~ -iL ]] && return 0 # Note we still have the message on screen + in HTML which is not as optimal as it could be - if "$do_pretty_json" && "$JSONHEADER"; then + # See #2599. The "clientProblem" wrapper should only be added if fileout_insert_warning() + # is called before fileout_banner(). The only instance in which this function is called + # after fileout_banner() is in the case of a TLS 1.3 only server when $OPENSSL does not + # support TLS 1.3. + if "$do_pretty_json" && "$JSONHEADER" && ! "$TLS13_ONLY"; then echo -e " \"clientProblem${CLIENT_PROB_NO}\" : [" >>"$JSONFILE" CLIENT_PROB_NO=$((CLIENT_PROB_NO + 1)) FIRST_FINDING=true # make sure we don't have a comma here fi fileout "$1" "$2" "$3" - if "$do_pretty_json"; then + if "$do_pretty_json" && ! "$TLS13_ONLY"; then if "$JSONHEADER"; then echo -e "\n ]," >>"$JSONFILE" else @@ -2034,7 +2046,7 @@ check_revocation_ocsp() { local stapled_response="$2" local jsonID="$3" local tmpfile="" - local -i success + local -i success=1 local response="" local host_header="" @@ -2051,9 +2063,20 @@ check_revocation_ocsp() { tmpfile=$TEMPDIR/${NODE}-${NODEIP}.${uri##*\/} || exit $ERR_FCREATE if [[ -n "$stapled_response" ]]; then hex2binary "$stapled_response" > "$TEMPDIR/stapled_ocsp_response.dd" - $OPENSSL ocsp -no_nonce -respin "$TEMPDIR/stapled_ocsp_response.dd" \ - -issuer $TEMPDIR/hostcert_issuer.pem -verify_other $TEMPDIR/intermediatecerts.pem \ - -CAfile <(cat $ADDTL_CA_FILES "$GOOD_CA_BUNDLE") -cert $HOSTCERT -text &> "$tmpfile" + if [[ "$stapled_response" =~ 06052[bB]0[eE]03021[aA] ]]; then + # Response appears to use SHA-1 in CertID + $OPENSSL ocsp -no_nonce -respin "$TEMPDIR/stapled_ocsp_response.dd" \ + -issuer $TEMPDIR/hostcert_issuer.pem -verify_other $TEMPDIR/intermediatecerts.pem \ + -CAfile <(cat $ADDTL_CA_FILES "$GOOD_CA_BUNDLE") -cert $HOSTCERT -text &> "$tmpfile" + success=$? + fi + if [[ $success -ne 0 ]] && [[ "$stapled_response" =~ 0609608648016503040201 ]]; then + # Response appears to use SHA-256 in CertID + $OPENSSL ocsp -sha256 -no_nonce -respin "$TEMPDIR/stapled_ocsp_response.dd" \ + -issuer $TEMPDIR/hostcert_issuer.pem -verify_other $TEMPDIR/intermediatecerts.pem \ + -CAfile <(cat $ADDTL_CA_FILES "$GOOD_CA_BUNDLE") -cert $HOSTCERT -text &> "$tmpfile" + success=$? + fi else host_header=${uri##http://} host_header=${host_header%%/*} @@ -2068,8 +2091,9 @@ check_revocation_ocsp() { $OPENSSL ocsp -no_nonce ${host_header} -url "$uri" \ -issuer $TEMPDIR/hostcert_issuer.pem -verify_other $TEMPDIR/intermediatecerts.pem \ -CAfile <(cat $ADDTL_CA_FILES "$GOOD_CA_BUNDLE") -cert $HOSTCERT -text &> "$tmpfile" + success=$? fi - if [[ $? -eq 0 ]] && grep -Fq "Response verify OK" "$tmpfile"; then + if [[ $success -eq 0 ]] && grep -Fq "Response verify OK" "$tmpfile"; then response="$(grep -F "$HOSTCERT: " "$tmpfile")" response="${response#$HOSTCERT: }" response="${response%\.}" @@ -2219,6 +2243,7 @@ string_to_asciihex() { s_client_options() { local options=" $1" local ciphers="notpresent" tls13_ciphers="notpresent" + local cipher tls13_supported_ciphers="" # Extract the TLSv1.3 ciphers and the non-TLSv1.3 ciphers if [[ " $options " =~ \ -cipher\ ]]; then @@ -2235,6 +2260,10 @@ s_client_options() { tls13_ciphers="${tls13_ciphers##\'}" tls13_ciphers="${tls13_ciphers%%\'}" [[ "$tls13_ciphers" == ALL ]] && tls13_ciphers="$TLS13_OSSL_CIPHERS" + for cipher in ${tls13_ciphers//:/ }; do + [[ "$TLS13_OSSL_CIPHERS" =~ $cipher ]] && tls13_supported_ciphers+=":$cipher" + done + tls13_ciphers="${tls13_supported_ciphers:1}" fi # Don't include the -servername option for an SSLv2 or SSLv3 ClientHello. @@ -2287,6 +2316,13 @@ s_client_options() { if "$HAS_SECLEVEL"; then if [[ "$ciphers" == notpresent ]]; then [[ ! " $options " =~ \ -tls1_3\ ]] && ciphers="@SECLEVEL=0:ALL:COMPLEMENTOFALL" + if "$HAS_CIPHERSUITES" && [[ "$tls13_ciphers" == notpresent ]] && \ + [[ ! " $options " =~ \ -ssl[2|3]\ ]] && \ + [[ ! " $options " =~ \ -tls1\ ]] && \ + [[ ! " $options " =~ \ -tls1_[1|2]\ ]] && \ + [[ ! " $options " =~ \ -no_tls1_3\ ]]; then + tls13_ciphers="$TLS13_OSSL_CIPHERS" + fi elif [[ -n "$ciphers" ]]; then ciphers="@SECLEVEL=0:$ciphers" fi @@ -3097,11 +3133,13 @@ emphasize_stuff_in_headers(){ -e "s/X-Powered-By/${yellow}X-Powered-By${off}/g" \ -e "s/X-UA-Compatible/${yellow}X-UA-Compatible${off}/g" \ -e "s/Link/${yellow}Link${off}/g" \ + -e "s/X-DNS-Prefetch-Control/${yellow}X-DNS-Prefetch-Control${off}/g" \ -e "s/X-Rack-Cache/${yellow}X-Rack-Cache${off}/g" \ -e "s/X-Runtime/${yellow}X-Runtime${off}/g" \ -e "s/X-Pingback/${yellow}X-Pingback${off}/g" \ -e "s/X-Permitted-Cross-Domain-Policies/${yellow}X-Permitted-Cross-Domain-Policies${off}/g" \ -e "s/X-AspNet-Version/${yellow}X-AspNet-Version${off}/g" \ + -e "s/X-AspNetMvc-Version/${yellow}X-AspNetMvc-Version${off}/g" \ -e "s/x-note/${yellow}x-note${off}/g" \ -e "s/x-global-transaction-id/${yellow}x-global-transaction-id${off}/g" \ -e "s/X-Global-Transaction-ID/${yellow}X-Global-Transaction-ID${off}/g" \ @@ -3111,7 +3149,7 @@ emphasize_stuff_in_headers(){ if "$do_html"; then if [[ $COLOR -ge 2 ]]; then html_out "$(tm_out "$1" | sed -e 's/\&/\&/g' \ - -e 's//\>/g' -e 's/"/\"/g' -e "s/'/\'/g" \ + -e 's//\>/g' -e 's/\"/\"/g' -e "s/\'/\'/g" \ -e "s/\([0-9]\)/${html_brown}\1${html_off}/g" \ -e "s/Unix/${html_yellow}Unix${html_off}/g" \ -e "s/Debian/${html_yellow}Debian${html_off}/g" \ @@ -3147,18 +3185,19 @@ emphasize_stuff_in_headers(){ -e "s/Link/${html_yellow}Link${html_off}/g" \ -e "s/X-Runtime/${html_yellow}X-Runtime${html_off}/g" \ -e "s/X-Rack-Cache/${html_yellow}X-Rack-Cache${html_off}/g" \ + -e "s/X-DNS-Prefetch-Control/${html_yellow}X-DNS-Prefetch-Control${html_off}/g" \ -e "s/X-Pingback/${html_yellow}X-Pingback${html_off}/g" \ -e "s/X-Permitted-Cross-Domain-Policies/${html_yellow}X-Permitted-Cross-Domain-Policies${html_off}/g" \ - -e "s/X-AspNet-Version/${html_yellow}X-AspNet-Version${html_off}/g")" \ + -e "s/X-AspNet-Version/${html_yellow}X-AspNet-Version${html_off}/g" \ + -e "s/X-AspNetMvc-Version/${html_yellow}X-AspNetMvc-Version${html_off}/g" \ -e "s/x-note/${html_yellow}x-note${html_off}/g" \ -e "s/X-Global-Transaction-ID/${html_yellow}X-Global-Transaction-ID${html_off}/g" \ -e "s/x-global-transaction-id/${html_yellow}x-global-transaction-id${html_off}/g" \ -e "s/Alt-Svc/${html_yellow}Alt-Svc${html_off}/g" \ - -e "s/system-wsgw-management-loopback/${html_yellow}system-wsgw-management-loopback${html_off}/g" -#FIXME: this is double code. The pattern to emphasize would fit better into -# one function. -# Also we need another function like run_other_header as otherwise "Link" "Alt-Svc" will never be found. -# And: I matches case sensitive only which might not detect all banners. (sed ignorecase is not possible w/ BSD sed) + -e "s/system-wsgw-management-loopback/${html_yellow}system-wsgw-management-loopback${html_off}/g" \ + )" +#FIXME: this is double code. The pattern to emphasize headers should be better in one single function +# And: It matches case sensitive headers only which won't detect all banners. (sed ignorecase is not a/v for OpenBSD sed) else html_out "$(html_reserved "$1")" fi @@ -3290,7 +3329,7 @@ sub_f5_bigip_check() { [[ -z "$cookievalue" ]] && break cookievalue=${cookievalue/;/} debugme echo $cookiename : $cookievalue - if grep -Eq '[0-9]{9,10}\.[0-9]{3,5}\.0000' <<< "$cookievalue"; then + if grep -Eq '[0-9]{8,10}\.[0-9]{3,5}\.0000' <<< "$cookievalue"; then ip="$(f5_ip_oldstyle "$cookievalue")" port="$(f5_port_decode $cookievalue)" out "${spaces}F5 cookie (default IPv4 pool member): "; pr_italic "$cookiename "; prln_svrty_medium "${ip}:${port}" @@ -3405,16 +3444,22 @@ run_security_headers() { pr_bold " Security headers " # X-XSS-Protection is useless and at worst harmful, see https://news.ycombinator.com/item?id=20472947 + # Expect-CT is deprecated, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect-CT for header_and_svrty in "X-Frame-Options OK" \ "X-Content-Type-Options OK" \ "Content-Security-Policy OK" \ - "X-Content-Security-Policy OK" \ - "X-WebKit-CSP OK" \ + "X-Content-Security-Policy INFO" \ + "X-WebKit-CSP INFO" \ "Content-Security-Policy-Report-Only OK" \ - "Expect-CT OK" \ + "Expect-CT INFO" \ "Permissions-Policy OK" \ + "Cross-Origin-Opener-Policy INFO" \ + "Cross-Origin-Resource-Policy INFO" \ + "Cross-Origin-Embedder-Policy INFO" \ "X-XSS-Protection INFO" \ "Access-Control-Allow-Origin INFO" \ + "Access-Control-Allow-Credentials INFO" \ + "Permissions-Policy INFO" \ "Upgrade INFO" \ "X-Served-By INFO" \ "Referrer-Policy INFO" \ @@ -3995,7 +4040,7 @@ run_cipher_match(){ ! "${ciphers_found2[i]}" && ciphers_to_test+=", ${hexcode2[i]}" done [[ -z "$ciphers_to_test" ]] && break - [[ "$proto" == 04 ]] && [[ ! "$ciphers_to_test" =~ ,\ 13,[0-9a-f][0-9a-f] ]] && break + [[ "$proto" == 04 ]] && [[ ! "$ciphers_to_test" =~ ,\ 13,[0-9a-f][0-9a-f] ]] && [[ ! "$ciphers_to_test" =~ ,\ [cC]0,[bB][45] ]] && break ciphers_to_test="$(strip_inconsistent_ciphers "$proto" "$ciphers_to_test")" [[ -z "$ciphers_to_test" ]] && break if "$SHOW_SIGALGO"; then @@ -4270,7 +4315,7 @@ run_allciphers() { ! "${ciphers_found2[i]}" && ciphers_to_test+=", ${hexcode2[i]}" done [[ -z "$ciphers_to_test" ]] && break - [[ "$proto" == 04 ]] && [[ ! "$ciphers_to_test" =~ ,\ 13,[0-9a-f][0-9a-f] ]] && break + [[ "$proto" == 04 ]] && [[ ! "$ciphers_to_test" =~ ,\ 13,[0-9a-f][0-9a-f] ]] && [[ ! "$ciphers_to_test" =~ ,\ [cC]0,[bB][45] ]] && break ciphers_to_test="$(strip_inconsistent_ciphers "$proto" "$ciphers_to_test")" [[ -z "$ciphers_to_test" ]] && break if "$SHOW_SIGALGO"; then @@ -4386,9 +4431,9 @@ ciphers_by_strength() { if { "$using_sockets" || "${TLS_CIPHER_OSSL_SUPPORTED[i]}"; }; then if [[ ${#hexc} -eq 9 ]] && [[ "$proto" != -ssl2 ]]; then if [[ "$proto" == -tls1_3 ]]; then - [[ "${hexc:2:2}" == 13 ]] && nr_ciphers+=1 + [[ "${TLS_CIPHER_SSLVERS[i]}" == TLSv1.3 ]] && nr_ciphers+=1 elif [[ "$proto" == -tls1_2 ]]; then - [[ "${hexc:2:2}" != 13 ]] && nr_ciphers+=1 + [[ "${TLS_CIPHER_SSLVERS[i]}" != TLSv1.3 ]] && nr_ciphers+=1 elif [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ SHA256 ]] && [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ SHA384 ]] && \ [[ "${TLS_CIPHER_RFC_NAME[i]}" != *_CCM ]] && [[ "${TLS_CIPHER_RFC_NAME[i]}" != *_CCM_8 ]]; then nr_ciphers+=1 @@ -4896,9 +4941,9 @@ client_simulation_sockets() { data+=", ${clienthello:i:2}" done # same as above. If a CIPHER_SUITES string was provided, then check that it is in the ServerHello - # this appeared 1st in yassl + MySQL (https://github.com/drwetter/testssl.sh/pull/784) but adds + # this appeared 1st in yassl + MySQL (https://github.com/testssl/testssl.sh/pull/784) but adds # robustness to the implementation - # see also https://github.com/drwetter/testssl.sh/pull/797 + # see also https://github.com/testssl/testssl.sh/pull/797 if [[ "${1:0:4}" == 1603 ]]; then # Extract list of cipher suites from SSLv3 or later ClientHello sid_len=4*$(hex2dec "${data:174:2}") @@ -5256,7 +5301,9 @@ run_client_simulation() { fi if [[ -n "$what_dh" ]]; then [[ -n "$curve" ]] && curve="($curve)" - if [[ "$what_dh" == ECDH ]]; then + if [[ "$what_dh" =~ MLKEM ]] || [[ "$what_dh" =~ Kyber ]]; then + pr_kem_quality "$bits" "$(printf -- "%-12s" "$what_dh")" + elif [[ "$what_dh" == ECDH ]]; then pr_ecdh_quality "$bits" "$(printf -- "%-12s" "$bits bit $what_dh") $curve" else pr_dh_quality "$bits" "$(printf -- "%-12s" "$bits bit $what_dh") $curve" @@ -5493,7 +5540,8 @@ run_protocols() { fileout "$jsonID" "OK" "not offered" add_proto_offered ssl2 no ;; - 4) out "likely "; pr_svrty_best "not offered (OK), " + 4) # STARTTLS problem + out "likely "; pr_svrty_best "not offered (OK), " fileout "$jsonID" "OK" "likely not offered" add_proto_offered ssl2 no pr_warning "received 4xx/5xx after STARTTLS handshake"; outln "$debug_recomm" @@ -5671,7 +5719,7 @@ run_protocols() { pr_warning "TLS downgraded to STARTTLS plaintext"; outln fileout "$jsonID" "WARN" "TLS downgraded to STARTTLS plaintext" ;; - 4) out "likely not offered, " + 4) out "likely not offered, " # STARTTLS problem fileout "$jsonID" "INFO" "likely not offered" add_proto_offered tls1 no pr_warning "received 4xx/5xx after STARTTLS handshake"; outln "$debug_recomm" @@ -5756,8 +5804,8 @@ run_protocols() { pr_warning "TLS downgraded to STARTTLS plaintext"; outln fileout "$jsonID" "WARN" "TLS downgraded to STARTTLS plaintext" ;; - 4) out "likely not offered, " - fileout "$jsonID" "INFO" "not offered" + 4) out "likely not offered, " # STARTTLS problem + fileout "$jsonID" "INFO" "likely not offered" add_proto_offered tls1_1 no pr_warning "received 4xx/5xx after STARTTLS handshake"; outln "$debug_recomm" fileout "$jsonID" "WARN" "received 4xx/5xx after STARTTLS handshake${debug_recomm}" @@ -6028,8 +6076,8 @@ run_protocols() { pr_warning "TLS downgraded to STARTTLS plaintext"; outln fileout "$jsonID" "WARN" "TLS downgraded to STARTTLS plaintext" ;; - 4) out "likely not offered, " - fileout "$jsonID" "INFO" "not offered" + 4) out "likely not offered, " # STARTTLS problem + fileout "$jsonID" "INFO" "likely not offered" add_proto_offered tls1_3 no pr_warning "received 4xx/5xx after STARTTLS handshake"; outln "$debug_recomm" fileout "$jsonID" "WARN" "received 4xx/5xx after STARTTLS handshake${debug_recomm}" @@ -6072,10 +6120,15 @@ listciphers() { local -i ret local debugname="" local ciphers="$1" - local tls13_ciphers="$TLS13_OSSL_CIPHERS" + local tls13_ciphers="$TLS13_OSSL_CIPHERS" cipher tls13_supported_ciphers="" local options="$3 " [[ "$2" != ALL ]] && tls13_ciphers="$2" + for cipher in ${tls13_ciphers//:/ }; do + [[ "$TLS13_OSSL_CIPHERS" =~ $cipher ]] && tls13_supported_ciphers+=":$cipher" + done + tls13_ciphers="${tls13_supported_ciphers:1}" + "$HAS_SECLEVEL" && [[ -n "$ciphers" ]] && ciphers="@SECLEVEL=0:$1" ! "$HAS_TLS1" && options="${options//-tls1 /}" if "$HAS_CIPHERSUITES"; then @@ -6144,7 +6197,7 @@ sub_cipherlists() { for proto in 04 03 02 01 00; do # If $cipherlist doesn't contain any TLSv1.3 ciphers, then there is # no reason to try a TLSv1.3 ClientHello. - [[ "$proto" == 04 ]] && [[ ! "$6" =~ 13,0 ]] && continue + [[ "$proto" == 04 ]] && [[ ! "$6" =~ 13,0 ]] && [[ ! "$6" =~ [cC]0,[bB][45] ]] && continue [[ $(has_server_protocol "$proto") -eq 1 ]] && continue cipherlist="$(strip_inconsistent_ciphers "$proto" ", $6")" cipherlist="${cipherlist:2}" @@ -6283,13 +6336,14 @@ run_cipherlists() { local hexc hexcode strength local -i i local -i ret=0 - local ossl_null_ciphers null_ciphers sslv2_null_ciphers + local ossl_null_ciphers ossl_null_ciphersuites null_ciphers sslv2_null_ciphers 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_ciphers local ossl_obsoleted_ciphers obsoleted_ciphers - local strong_ciphers + local ossl_good_ciphers good_ciphers + local ossl_strong_ciphers ossl_strong_ciphersuites strong_ciphers local cwe="CWE-327" local cwe2="CWE-310" local cve="" @@ -6303,7 +6357,8 @@ run_cipherlists() { # conversion 2 byte ciphers via: echo "$@" | sed -e 's/[[:xdigit:]]\{2\},/0x&/g' -e 's/, /\n/g' | while read ci; do grep -wi $ci etc/cipher-mapping.txt; done ossl_null_ciphers='NULL:eNULL' - null_ciphers="c0,10, c0,06, c0,15, c0,0b, c0,01, c0,3b, c0,3a, c0,39, 00,b9, 00,b8, 00,b5, 00,b4, 00,2e, 00,2d, 00,b1, 00,b0, 00,2c, 00,3b, 00,02, 00,01, 00,82, 00,83, ff,87, 00,ff" + ossl_null_ciphersuites="TLS_SHA256_SHA256:TLS_SHA384_SHA384" + null_ciphers="c0,10, c0,06, c0,15, c0,0b, c0,01, c0,3b, c0,3a, c0,39, 00,b9, 00,b8, 00,b5, 00,b4, 00,2e, 00,2d, 00,b1, 00,b0, 00,2c, 00,3b, 00,02, 00,01, 00,82, 00,83, c0,b4, c0,b5, ff,87, 00,ff" sslv2_null_ciphers="FF,80,10, 00,00,00" ossl_anon_ciphers='aNULL:ADH' @@ -6339,6 +6394,7 @@ run_cipherlists() { good_ciphers="00,9C, 00,9D, 00,A0, 00,A1, 00,A4, 00,A5, 00,A8, 00,A9, 00,AC, 00,AD, C0,2D, C0,2E, C0,31, C0,32, C0,50, C0,51, C0,54, C0,55, C0,58, C0,59, C0,5E, C0,5F, C0,62, C0,63, C0,6A, C0,6B, C0,6E, C0,6F, C0,7A, C0,7B, C0,7E, C0,7F, C0,82, C0,83, C0,88, C0,89, C0,8C, C0,8D, C0,8E, C0,8F, C0,92, C0,93, C0,9C, C0,9D, C0,A0, C0,A1, C0,A4, C0,A5, C0,A8, C0,A9, CC,AB, CC,AE, 00,FF" ossl_strong_ciphers='AESGCM:CHACHA20:CamelliaGCM:AESCCM:ARIAGCM:!kPSK:!kRSAPSK:!kRSA:!kDH:!kECDH:!aNULL' + ossl_strong_ciphersuites="TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256" # grep AEAD etc/cipher-mapping.txt | grep -E 'TLS_ECDHE|TLS_DHE|TLS_PSK_DHE|TLSv1.3' strong_ciphers="00,9E, 00,9F, 00,A2, 00,A3, 00,AA, 00,AB, 13,01, 13,02, 13,03, 13,04, 13,05, 16,B7, 16,B8, 16,B9, 16,BA, C0,2B, C0,2C, C0,2F, C0,30, C0,52, C0,53, C0,56, C0,57, C0,5C, C0,5D, C0,60, C0,61, C0,6C, C0,6D, C0,7C, C0,7D, C0,80, C0,81, C0,86, C0,87, C0,8A, C0,8B, C0,90, C0,91, C0,9E, C0,9F, C0,A2, C0,A3, C0,A6, C0,A7, C0,AA, C0,AB, C0,AC, C0,AD, C0,AE, C0,AF, CC,13, CC,14, CC,15, CC,A8, CC,A9, CC,AA, CC,AC, CC,AD, 00,FF" @@ -6353,7 +6409,7 @@ run_cipherlists() { # argv[9]: CVE # argv[10]: CWE - sub_cipherlists "$ossl_null_ciphers" "" " NULL ciphers (no encryption) " 1 "NULL" "$null_ciphers" "$sslv2_null_ciphers" "$using_sockets" "$cve" "$cwe" + sub_cipherlists "$ossl_null_ciphers" "$ossl_null_ciphersuites" " NULL ciphers (no encryption) " 1 "NULL" "$null_ciphers" "$sslv2_null_ciphers" "$using_sockets" "$cve" "$cwe" ret=$? sub_cipherlists "$ossl_anon_ciphers" "" " Anonymous NULL Ciphers (no authentication) " 1 "aNULL" "$anon_ciphers" "$sslv2_anon_ciphers" "$using_sockets" "$cve" "$cwe" ret=$((ret + $?)) @@ -6367,7 +6423,7 @@ run_cipherlists() { ret=$((ret + $?)) sub_cipherlists "$ossl_good_ciphers" "" " Strong encryption (AEAD ciphers) with no FS " 6 "STRONG_NOFS" "$good_ciphers" "" "$using_sockets" "" "" ret=$((ret + $?)) - sub_cipherlists "$ossl_strong_ciphers" 'ALL' " Forward Secrecy strong encryption (AEAD ciphers)" 7 "STRONG_FS" "$strong_ciphers" "" "$using_sockets" "" "" + sub_cipherlists "$ossl_strong_ciphers" "$ossl_strong_ciphersuites" " Forward Secrecy strong encryption (AEAD ciphers)" 7 "STRONG_FS" "$strong_ciphers" "" "$using_sockets" "" "" ret=$((ret + $?)) outln @@ -6436,7 +6492,7 @@ pr_ecdh_quality() { elif [[ "$bits" -le 163 ]]; then pr_svrty_medium "$string" elif [[ "$bits" -le 193 ]]; then # hmm, according to https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography it should ok - pr_svrty_low "$string" # but openssl removed it https://github.com/drwetter/testssl.sh/issues/299#issuecomment-220905416 + pr_svrty_low "$string" # but openssl removed it https://github.com/testssl/testssl.sh/issues/299#issuecomment-220905416 elif [[ "$bits" -le 224 ]]; then out "$string" elif [[ "$bits" -gt 224 ]]; then @@ -6485,6 +6541,30 @@ pr_ecdh_curve_quality() { pr_ecdh_quality "$bits" "$curve" } +pr_kem_quality() { + local bits="$1" + local string="$2" + + # At the moment all KEMs offer at least 128 bits of security strength + # (comparable to 256-bit elliptic curve key). So, all KEMs should be + # considered good. + pr_svrty_good "$string" +} + + +pr_kem_param_set_quality() { + kem="$1" + local -i bits=0 + + case "$kem" in + "SecP256r1MLKEM768") bits=192 ;; + "X25519MLKEM768") bits=192 ;; + "SecP384r1MLKEM1024") bits=256 ;; + "X25519Kyber768Draft00") bits=128 ;; + esac + pr_kem_quality "$bits" "$kem" +} + # 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 @@ -6508,7 +6588,7 @@ get_cipher_quality() { # We have an OpenSSL name and can't convert it to the RFC name which is rarely # the case, see "prepare_arrays()" and "./etc/cipher-mapping.txt" case "$cipher" in - *NULL*|EXP*|ADH*|AECDH*|*anon*) + *NULL*|EXP*|ADH*|AECDH*|*anon*|TLS_SHA*) return 1 ;; *RC4*|*RC2*|*MD5|*M1) @@ -6550,7 +6630,7 @@ get_cipher_quality() { # Now we look at the RFC cipher names. The sequence matters - as above. case "$cipher" in - *NULL*|*EXP*|*_DES40_*|*anon*) + *NULL*|*EXP*|*_DES40_*|*anon*|TLS_SHA*) return 1 ;; *RC4*|*RC2*|*MD5|*MD5_1) @@ -6637,6 +6717,10 @@ read_dhtype_from_file() { kx="Kx=${temp%%,*}" [[ "$kx" == "Kx=X25519" ]] && kx="Kx=ECDH" [[ "$kx" == "Kx=X448" ]] && kx="Kx=ECDH" + [[ "$kx" == "Kx=SecP256r1MLKEM768" ]] && kx="Kx=ECDH/MLKEM" + [[ "$kx" == "Kx=X25519MLKEM768" ]] && kx="Kx=ECDH/MLKEM" + [[ "$kx" == "Kx=SecP384r1MLKEM1024" ]] && kx="Kx=ECDH/MLKEM" + [[ "$kx" == "Kx=X25519Kyber768Draft00" ]] && kx="Kx=ECDH/Kyber" tm_out "$kx" return 0 } @@ -6875,7 +6959,7 @@ run_server_preference() { "c0,2c, c0,30, 00,9f, cc,a9, cc,a8, cc,aa, c0,2b, c0,2f, 00,9a, 00,96, 00,9e, c0,24, c0,28, 00,6b, c0,23, c0,27, 00,67, c0,0a, c0,14, 00,39, c0,09, c0,13, 00,33, 00,9d, 00,9c, 13,02, - 13,03, 13,01, 13,04, 13,05, 00,3d, 00,3c, 00,35, 00,2f, 00,ff" \ + 13,03, 13,01, 13,04, 13,05, c0,b4, c0,b5, 00,3d, 00,3c, 00,35, 00,2f, 00,ff" \ "ephemeralkey" sclient_success=$? if [[ $sclient_success -eq 0 ]]; then @@ -6917,12 +7001,12 @@ run_server_preference() { # Some servers don't have a TLS 1.3 cipher order, see #1163 if [[ "$default_proto" == TLSv1.3 ]]; then - tls_sockets "04" "13,05, 13,04, 13,03, 13,02, 13,01, 00,ff" + tls_sockets "04" "c0,b5, c0,b4, 13,05, 13,04, 13,03, 13,02, 13,01, 00,ff" [[ $? -ne 0 ]] && ret=1 && prln_fixme "something weird happened around line $((LINENO - 1))" cp "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" $TMPFILE tls13_cipher1=$(get_cipher $TMPFILE) debugme tm_out "TLS 1.3: --> $tls13_cipher1\n" - tls_sockets "04" "13,01, 13,02, 13,03, 13,04, 13,05, 00,ff" + tls_sockets "04" "13,01, 13,02, 13,03, 13,04, 13,05, c0,b4, c0,b5, 00,ff" [[ $? -ne 0 ]] && ret=1 && prln_fixme "something weird happened around line $((LINENO - 1))" cp "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" $TMPFILE tls13_cipher2=$(get_cipher $TMPFILE) @@ -7309,9 +7393,9 @@ cipher_pref_check() { index[nr_nonossl_ciphers]=$i # Only test ciphers that are relevant to the protocol. if [[ $proto == tls1_3 ]]; then - [[ "${hexc:2:2}" == 13 ]] && nr_nonossl_ciphers+=1 + [[ "${TLS_CIPHER_SSLVERS[i]}" == TLSv1.3 ]] && nr_nonossl_ciphers+=1 elif [[ $proto == tls1_2 ]]; then - [[ "${hexc:2:2}" != 13 ]] && nr_nonossl_ciphers+=1 + [[ "${TLS_CIPHER_SSLVERS[i]}" != TLSv1.3 ]] && nr_nonossl_ciphers+=1 elif [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ SHA256 ]] && \ [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ SHA384 ]] && \ [[ "${TLS_CIPHER_RFC_NAME[i]}" != *_CCM ]] && \ @@ -7383,9 +7467,9 @@ cipher_pref_check() { hexcode[nr_ciphers]="${hexc:2:2},${hexc:7:2}" rfc_ciph[nr_ciphers]="${TLS_CIPHER_RFC_NAME[i]}" if [[ $proto == tls1_3 ]]; then - [[ "${hexc:2:2}" == 13 ]] && nr_ciphers+=1 + [[ "${TLS_CIPHER_SSLVERS[i]}" == TLSv1.3 ]] && nr_ciphers+=1 elif [[ $proto == tls1_2 ]]; then - [[ "${hexc:2:2}" != 13 ]] && nr_ciphers+=1 + [[ "${TLS_CIPHER_SSLVERS[i]}" != TLSv1.3 ]] && nr_ciphers+=1 elif [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ SHA256 ]] && \ [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ SHA384 ]] && \ [[ "${TLS_CIPHER_RFC_NAME[i]}" != *_CCM ]] && \ @@ -7402,9 +7486,9 @@ cipher_pref_check() { hexcode[nr_ciphers]="${hexc:2:2},${hexc:7:2}" rfc_ciph[nr_ciphers]="${TLS_CIPHER_RFC_NAME[i]}" if [[ $proto == tls1_3 ]]; then - [[ "${hexc:2:2}" == 13 ]] && nr_ciphers+=1 + [[ "${TLS_CIPHER_SSLVERS[i]}" == TLSv1.3 ]] && nr_ciphers+=1 elif [[ $proto == tls1_2 ]]; then - [[ "${hexc:2:2}" != 13 ]] && nr_ciphers+=1 + [[ "${TLS_CIPHER_SSLVERS[i]}" != TLSv1.3 ]] && nr_ciphers+=1 elif [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ SHA256 ]] && \ [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ SHA384 ]] && \ [[ "${TLS_CIPHER_RFC_NAME[i]}" != *_CCM ]] && \ @@ -7630,7 +7714,7 @@ determine_trust() { [[ -n $json_postfix ]] && spaces=" " case $OSSL_VER_MAJOR.$OSSL_VER_MINOR in - 1.0.2|1.1.0|1.1.1|2.[1-9].*|3.*) # 2.x is LibreSSL. 2.1.1 was tested to work, below is not sure + 1.0.2|1.1.0|1.1.1|2.[1-9].*|3.*|4.*) # 2.x is LibreSSL. 2.1.1 was tested to work, below is not sure : ;; *) addtl_warning="Your $OPENSSL <= 1.0.2 might be too unreliable to determine trust" @@ -8347,12 +8431,14 @@ wildcard_match() # 8, if the server name provided is a wildcard match against the CN # 9, if the server name provided matches a name in the SAN AND is a wildcard match against the CN # 10, if the server name provided is a wildcard match against the CN AND a name in the SAN +# +# Add 128 to the return value if the CN or a DNS name in the SAN is a wildcard. compare_server_name_to_cert() { local cert="$1" local servername cns cn dns_sans ip_sans san dercert tag local srv_id="" xmppaddr="" - local -i i len len1 cn_match=0 + local -i i len len1 cn_match=0 wildcard_cert=0 local -i subret=0 # no error condition, passing results HAS_DNS_SANS=false @@ -8497,10 +8583,16 @@ compare_server_name_to_cert() { fi # Check whether any of the DNS names in the certificate are wildcard names - # that match the servername + # and if they match the servername if [[ $subret -eq 0 ]]; then while read san; do [[ -n "$san" ]] || continue + is_wildcard "$san" + if [[ $? -eq 0 ]]; then + wildcard_cert=128 + else + continue + fi wildcard_match "$servername" "$san" [[ $? -eq 0 ]] && subret=2 && break done <<< "$dns_sans" @@ -8516,13 +8608,20 @@ compare_server_name_to_cert() { # Check whether the CN matches the servername [[ $(toupper "$cn") == "$servername" ]] && cn_match=4 && break - # Check whether the CN is a wildcard name that matches the servername + # Check whether the CN is a wildcard name and if it matches the servername # NOTE: Don't stop loop on a wildcard match in case there is another CN # that is an exact match. + is_wildcard "$cn" + if [[ $? -eq 0 ]]; then + wildcard_cert=128 + else + continue + fi wildcard_match "$servername" "$cn" [[ $? -eq 0 ]] && cn_match=8 done <<< "$cns" subret+=$cn_match + subret+=$wildcard_cert return $subret } @@ -8780,7 +8879,7 @@ certificate_transparency() { if [[ $number_of_certificates -gt 1 ]] && ! "$SSL_NATIVE"; then if [[ "$tls_version" == 0304 ]]; then - ciphers=", 13,01, 13,02, 13,03, 13,04, 13,05" + ciphers=", 13,01, 13,02, 13,03, 13,04, 13,05, c0,b4, c0,b5" if [[ "$cipher" == tls1_3_RSA ]]; then extra_extns=", 00,0d,00,10,00,0e,08,04,08,05,08,06,04,01,05,01,06,01,02,01" elif [[ "$cipher" == tls1_3_ECDSA ]]; then @@ -9417,7 +9516,7 @@ certificate_info() { # supported by the client. has_dns_sans=$HAS_DNS_SANS - case $trust_sni in + case $((trust_sni%128)) in 0) trustfinding="certificate does not match supplied URI" set_grade_cap "M" "Domain name mismatch" ;; @@ -9444,10 +9543,10 @@ certificate_info() { ;; esac - if [[ $trust_sni -eq 0 ]]; then + if [[ $((trust_sni%128)) -eq 0 ]]; then pr_svrty_high "$trustfinding" trust_sni_finding="HIGH" - elif [[ $trust_sni -eq 4 ]] || [[ $trust_sni -eq 8 ]]; then + elif [[ $((trust_sni%128)) -eq 4 ]] || [[ $((trust_sni%128)) -eq 8 ]]; then if [[ $SERVICE == HTTP ]] || "$ASSUME_HTTP"; then # https://bugs.chromium.org/p/chromium/issues/detail?id=308330 # https://bugzilla.mozilla.org/show_bug.cgi?id=1245280 @@ -9474,17 +9573,17 @@ certificate_info() { # See issue #733. if [[ -z "$sni_used" ]]; then trustfinding_nosni="" - elif [[ $trust_sni -eq $trust_nosni && "$has_dns_sans" == "$has_dns_sans_nosni" ]] || \ - [[ $trust_sni -eq 0 && $trust_nosni -eq 0 ]]; then + elif [[ $((trust_sni%128)) -eq $((trust_nosni%128)) && "$has_dns_sans" == "$has_dns_sans_nosni" ]] || \ + [[ $((trust_sni%128)) -eq 0 && $((trust_nosni%128)) -eq 0 ]]; then trustfinding_nosni=" (same w/o SNI)" - elif [[ $trust_nosni -eq 0 ]]; then - if [[ $trust_sni -eq 4 ]] || [[ $trust_sni -eq 8 ]]; then + elif [[ $((trust_nosni%128)) -eq 0 ]]; then + if [[ $((trust_sni%128)) -eq 4 ]] || [[ $((trust_sni%128)) -eq 8 ]]; then trustfinding_nosni=" (w/o SNI: certificate does not match supplied URI)" else trustfinding_nosni=" (SNI mandatory)" fi - elif [[ $trust_nosni -eq 4 ]] || [[ $trust_nosni -eq 8 ]] || [[ $trust_sni -eq 4 ]] || [[ $trust_sni -eq 8 ]]; then - case $trust_nosni in + elif [[ $((trust_nosni%128)) -eq 4 ]] || [[ $((trust_nosni%128)) -eq 8 ]] || [[ $((trust_sni%128)) -eq 4 ]] || [[ $((trust_sni%128)) -eq 8 ]]; then + case $((trust_nosni%128)) in 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 @@ -9504,12 +9603,12 @@ certificate_info() { 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 + elif [[ $((trust_sni%128)) -ne 0 ]]; then trustfinding_nosni=" (works w/o SNI)" else trustfinding_nosni=" (however, works w/o SNI)" fi - if [[ -n "$sni_used" ]] || [[ $trust_nosni -eq 0 ]] || [[ $trust_nosni -ne 4 && $trust_nosni -ne 8 ]]; then + if [[ -n "$sni_used" ]] || [[ $((trust_nosni%128)) -eq 0 ]] || [[ $((trust_nosni%128)) -ne 4 && $((trust_nosni%128)) -ne 8 ]]; then outln "$trustfinding_nosni" elif [[ $SERVICE == HTTP ]] || "$ASSUME_HTTP"; then prln_svrty_high "$trustfinding_nosni" @@ -9519,7 +9618,7 @@ certificate_info() { fileout "cert_trust${json_postfix}" "$trust_sni_finding" "${trustfinding}${trustfinding_nosni}" - if [[ "$trust_sni" =~ ^(2|6|8|9|10)$ ]] || [[ "$trust_nosni" =~ ^(2|6|8|9|10)$ ]]; then + if [[ $((trust_sni&128)) -eq 128 ]] || [[ $((trust_nosni&128)) -eq 128 ]]; then out "${spaces}" pr_svrty_low "wildcard certificate" ; outln " could be problematic, see other hosts at" outln "${spaces}https://search.censys.io/search?resource=hosts&virtual_hosts=INCLUDE&q=$cert_fingerprint_sha2" @@ -10127,7 +10226,7 @@ run_server_defaults() { # $NODE being tested or if it has the same subject # (CN and SAN) as other certificates for this host. compare_server_name_to_cert "$HOSTCERT" - [[ $? -ne 0 ]] && success[n]=0 || success[n]=1 + [[ $(($?%128)) -ne 0 ]] && success[n]=0 || success[n]=1 if [[ ${success[n]} -ne 0 ]]; then cn_nosni="$(toupper "$(get_cn_from_cert $HOSTCERT)")" @@ -10460,13 +10559,13 @@ run_fs() { local fs_cipher_list="DHE-DSS-AES128-GCM-SHA256:DHE-DSS-AES128-SHA256:DHE-DSS-AES128-SHA:DHE-DSS-AES256-GCM-SHA384:DHE-DSS-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-DSS-CAMELLIA128-SHA256:DHE-DSS-CAMELLIA128-SHA:DHE-DSS-CAMELLIA256-SHA256:DHE-DSS-CAMELLIA256-SHA:DHE-DSS-SEED-SHA:DHE-RSA-AES128-CCM8:DHE-RSA-AES128-CCM:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-CCM8:DHE-RSA-AES256-CCM:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-CAMELLIA128-SHA256:DHE-RSA-CAMELLIA128-SHA:DHE-RSA-CAMELLIA256-SHA256:DHE-RSA-CAMELLIA256-SHA:DHE-RSA-CHACHA20-POLY1305-OLD:DHE-RSA-CHACHA20-POLY1305:DHE-RSA-SEED-SHA:ECDHE-ECDSA-AES128-CCM8:ECDHE-ECDSA-AES128-CCM:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-CCM8:ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-CAMELLIA128-SHA256:ECDHE-ECDSA-CAMELLIA256-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305-OLD:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-CAMELLIA128-SHA256:ECDHE-RSA-CAMELLIA256-SHA384:ECDHE-RSA-CHACHA20-POLY1305-OLD:ECDHE-RSA-CHACHA20-POLY1305" local fs_hex_cipher_list="" ciphers_to_test tls13_ciphers_to_test local ecdhe_cipher_list="" tls13_cipher_list="" ecdhe_cipher_list_hex="" ffdhe_cipher_list_hex="" - local curves_hex=("00,01" "00,02" "00,03" "00,04" "00,05" "00,06" "00,07" "00,08" "00,09" "00,0a" "00,0b" "00,0c" "00,0d" "00,0e" "00,0f" "00,10" "00,11" "00,12" "00,13" "00,14" "00,15" "00,16" "00,17" "00,18" "00,19" "00,1a" "00,1b" "00,1c" "00,1d" "00,1e" "00,1f" "00,20" "00,21") - local -a curves_ossl=("sect163k1" "sect163r1" "sect163r2" "sect193r1" "sect193r2" "sect233k1" "sect233r1" "sect239k1" "sect283k1" "sect283r1" "sect409k1" "sect409r1" "sect571k1" "sect571r1" "secp160k1" "secp160r1" "secp160r2" "secp192k1" "prime192v1" "secp224k1" "secp224r1" "secp256k1" "prime256v1" "secp384r1" "secp521r1" "brainpoolP256r1" "brainpoolP384r1" "brainpoolP512r1" "X25519" "X448" "brainpoolP256r1tls13" "brainpoolP384r1tls13" "brainpoolP512r1tls13") - local -a curves_ossl_output=("K-163" "sect163r1" "B-163" "sect193r1" "sect193r2" "K-233" "B-233" "sect239k1" "K-283" "B-283" "K-409" "B-409" "K-571" "B-571" "secp160k1" "secp160r1" "secp160r2" "secp192k1" "P-192" "secp224k1" "P-224" "secp256k1" "P-256" "P-384" "P-521" "brainpoolP256r1" "brainpoolP384r1" "brainpoolP512r1" "X25519" "X448" "brainpoolP256r1tls13" "brainpoolP384r1tls13" "brainpoolP512r1tls13") - local -ai curves_bits=(163 162 163 193 193 232 233 238 281 282 407 409 570 570 161 161 161 192 192 225 224 256 256 384 521 256 384 512 253 448 256 384 512) + local curves_hex=("00,01" "00,02" "00,03" "00,04" "00,05" "00,06" "00,07" "00,08" "00,09" "00,0a" "00,0b" "00,0c" "00,0d" "00,0e" "00,0f" "00,10" "00,11" "00,12" "00,13" "00,14" "00,15" "00,16" "00,17" "00,18" "00,19" "00,1a" "00,1b" "00,1c" "00,1d" "00,1e" "00,1f" "00,20" "00,21" "11,eb" "11,ec" "11,ed" "63,99") + local -a curves_ossl=("sect163k1" "sect163r1" "sect163r2" "sect193r1" "sect193r2" "sect233k1" "sect233r1" "sect239k1" "sect283k1" "sect283r1" "sect409k1" "sect409r1" "sect571k1" "sect571r1" "secp160k1" "secp160r1" "secp160r2" "secp192k1" "prime192v1" "secp224k1" "secp224r1" "secp256k1" "prime256v1" "secp384r1" "secp521r1" "brainpoolP256r1" "brainpoolP384r1" "brainpoolP512r1" "X25519" "X448" "brainpoolP256r1tls13" "brainpoolP384r1tls13" "brainpoolP512r1tls13" "SecP256r1MLKEM768" "X25519MLKEM768" "SecP384r1MLKEM1024" "X25519Kyber768Draft00") + local -a curves_ossl_output=("K-163" "sect163r1" "B-163" "sect193r1" "sect193r2" "K-233" "B-233" "sect239k1" "K-283" "B-283" "K-409" "B-409" "K-571" "B-571" "secp160k1" "secp160r1" "secp160r2" "secp192k1" "P-192" "secp224k1" "P-224" "secp256k1" "P-256" "P-384" "P-521" "brainpoolP256r1" "brainpoolP384r1" "brainpoolP512r1" "X25519" "X448" "brainpoolP256r1tls13" "brainpoolP384r1tls13" "brainpoolP512r1tls13" "SecP256r1MLKEM768" "X25519MLKEM768" "SecP384r1MLKEM1024" "X25519Kyber768Draft00") + local -ai curves_bits=(163 162 163 193 193 232 233 238 281 282 407 409 570 570 161 161 161 192 192 225 224 256 256 384 521 256 384 512 253 448 256 384 512 192 192 256 128) # Many curves have been deprecated, and RFC 8446, Appendix B.3.1.4, states # that these curves MUST NOT be offered in a TLS 1.3 ClientHello. - local -a curves_deprecated=("true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "false" "false" "false" "true" "true" "true" "false" "false" "false" "false" "false") + local -a curves_deprecated=("true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "true" "false" "false" "false" "true" "true" "true" "false" "false" "false" "false" "false" "false" "false" "false" "false") local -a ffdhe_groups_hex=("01,00" "01,01" "01,02" "01,03" "01,04") local -a ffdhe_groups_output=("ffdhe2048" "ffdhe3072" "ffdhe4096" "ffdhe6144" "ffdhe8192") local -a supported_curve @@ -10477,7 +10576,7 @@ run_fs() { local rsa_cipher="" ecdsa_cipher="" dss_cipher="" local sigalgs_to_test tls12_supported_sigalg_list="" tls13_supported_sigalg_list="" local -i nr_supported_ciphers=0 nr_curves=0 nr_ossl_curves=0 i j low high - local fs_ciphers curves_offered="" curves_to_test temp + local fs_ciphers curves_offered="" kems_offered="" curves_to_test temp local curves_option="" curves_list1="" curves_list2="" local len1 len2 curve_found sigalg_found local key_bitstring quality_str @@ -10537,13 +10636,10 @@ run_fs() { sigalg[nr_supported_ciphers]="" ossl_supported[nr_supported_ciphers]=true nr_supported_ciphers+=1 - done < <(actually_supported_osslciphers "$fs_cipher_list" "ALL" "-V") + done < <(actually_supported_osslciphers "$fs_cipher_list" "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256" "-V") fi - if [[ $(has_server_protocol "tls1_3") -eq 0 ]]; then - # All TLSv1.3 cipher suites offer robust FS. - sclient_success=0 - elif "$using_sockets"; then + if "$using_sockets"; then tls_sockets "04" "${fs_hex_cipher_list:2}, 00,ff" sclient_success=$? [[ $sclient_success -eq 2 ]] && sclient_success=0 @@ -10555,7 +10651,7 @@ run_fs() { fi else debugme echo $nr_supported_ciphers - debugme echo $(actually_supported_osslciphers $fs_cipher_list "ALL") + debugme echo $(actually_supported_osslciphers $fs_cipher_list "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256") if [[ "$nr_supported_ciphers" -le "$CLIENT_MIN_FS" ]]; then outln prln_local_problem "You only have $nr_supported_ciphers FS ciphers on the client side " @@ -10576,7 +10672,7 @@ run_fs() { curves_list2="${curves_list2// /:}" fi curves_list1="${curves_list1// /:}" - $OPENSSL s_client $(s_client_options "-cipher $fs_cipher_list -ciphersuites ALL $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI") >$TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE $ERRFILE >$TMPFILE + + # TLS 1.3 s_client doesn't support -nextprotoneg when connecting with TLS 1.3. So we need to make sure it won't be used + # TLS13_ONLY is tested here again, just to be sure, see npn_pre + if "$HAS_TLS13" && ! $TLS13_ONLY ]] ; then + proto="-no_tls1_3" + fi + $OPENSSL s_client $(s_client_options "$proto -connect $NODEIP:$PORT $BUGS $SNI -nextprotoneg "$NPN_PROTOs"") $ERRFILE >$TMPFILE [[ $? -ne 0 ]] && ret=1 tmpstr="$(grep -a '^Protocols' $TMPFILE | sed 's/Protocols.*: //')" if [[ -z "$tmpstr" ]] || [[ "$tmpstr" == " " ]]; then @@ -12558,7 +12679,7 @@ derive-handshake-traffic-keys() { local cipher="$1" handshake_secret="$2" transcript="$3" local sender="$4" local hash_fn - local -i hash_len key_len + local -i hash_len key_len iv_len local handshake_traffic_secret label key iv finished="0000" if [[ "$cipher" == *SHA256 ]]; then @@ -12570,13 +12691,14 @@ derive-handshake-traffic-keys() { else return 1 fi - if [[ "$cipher" == *AES_128* ]]; then - key_len=16 - elif [[ "$cipher" == *AES_256* ]] || [[ "$cipher" == *CHACHA20_POLY1305* ]]; then - key_len=32 - else - return 1 - fi + iv_len=12 + case "$cipher" in + *AES_128*) key_len=16 ;; + *AES_256*|*CHACHA20_POLY1305*) key_len=32 ;; + TLS_SHA256_SHA256) key_len=32; iv_len=32 ;; + TLS_SHA384_SHA384) key_len=48; iv_len=48 ;; + *) return 1 ;; + esac if [[ "${TLS_SERVER_HELLO:8:2}" == 7F ]] && [[ 0x${TLS_SERVER_HELLO:10:2} -lt 0x14 ]]; then if [[ "$sender" == server ]]; then @@ -12600,7 +12722,7 @@ derive-handshake-traffic-keys() { key="$(derive-traffic-key "$hash_fn" "$handshake_traffic_secret" "6b6579" "$key_len")" [[ $? -ne 0 ]] && return 1 # "6976" = "iv" - iv="$(derive-traffic-key "$hash_fn" "$handshake_traffic_secret" "6976" "12")" + iv="$(derive-traffic-key "$hash_fn" "$handshake_traffic_secret" "6976" "$iv_len")" [[ $? -ne 0 ]] && return 1 if [[ $DEBUG -ge 1 ]] || [[ "$sender" == client ]]; then # "66696e6973686564" = "finished" @@ -12651,7 +12773,7 @@ derive-application-traffic-keys() { local cipher="$1" master_secret="$2" transcript="$3" local sender="$4" local hash_fn - local -i key_len + local -i key_len iv_len local application_traffic_secret_0 label key iv if [[ "$cipher" == *SHA256 ]]; then @@ -12661,13 +12783,14 @@ derive-application-traffic-keys() { else return 1 fi - if [[ "$cipher" == *AES_128* ]]; then - key_len=16 - elif [[ "$cipher" == *AES_256* ]] || [[ "$cipher" == *CHACHA20_POLY1305* ]]; then - key_len=32 - else - return 1 - fi + iv_len=12 + case "$cipher" in + *AES_128*) key_len=16 ;; + *AES_256*|*CHACHA20_POLY1305*) key_len=32 ;; + TLS_SHA256_SHA256) key_len=32; iv_len=32 ;; + TLS_SHA384_SHA384) key_len=48; iv_len=48 ;; + *) return 1 ;; + esac if [[ "${TLS_SERVER_HELLO:8:2}" == 7F ]] && [[ 0x${TLS_SERVER_HELLO:10:2} -lt 0x14 ]]; then if [[ "$sender" == server ]]; then @@ -12691,7 +12814,7 @@ derive-application-traffic-keys() { key="$(derive-traffic-key "$hash_fn" "$application_traffic_secret_0" "6b6579" "$key_len")" [[ $? -ne 0 ]] && return 1 # "6976" = "iv" - iv="$(derive-traffic-key "$hash_fn" "$application_traffic_secret_0" "6976" "12")" + iv="$(derive-traffic-key "$hash_fn" "$application_traffic_secret_0" "6976" "$iv_len")" [[ $? -ne 0 ]] && return 1 tm_out "$key $iv" } @@ -13600,6 +13723,53 @@ gcm-encrypt() { return $? } +# arg1: integrity-only TLS cipher +# arg2: key +# arg3: nonce +# arg4: ciphertext +# arg5: aad +# arg6: expected tag +# arg7: true if authentication tag should be checked. false otherwise. +integrity_only_decrypt() +{ + local cipher="$1" key="$2" nonce="$3" ciphertext="$4" aad="$5" expected_tag="$(toupper "$6")" + local compute_tag="$7" + local hash_fn + local computed_tag + + if "$compute_tag"; then + case "$cipher" in + TLS_SHA256_SHA256) hash_fn="-sha256" ;; + TLS_SHA384_SHA384) hash_fn="-sha384" ;; + *) return 7 ;; + esac + computed_tag="$(toupper "$(hmac "$hash_fn" "$key" "$nonce$aad$ciphertext")")" + if [[ "$computed_tag" != $expected_tag ]]; then + return 7 + fi + fi + tm_out "$ciphertext" + return 0 +} + +# arg1: integrity-only TLS cipher +# arg2: key +# arg3: nonce +# arg4: plaintext +# arg5: additional authenticated data +integrity_only_encrypt() { + local cipher="$1" key="$2" nonce="$3" plaintext="$4" aad="$5" + local hash_fn + + case "$cipher" in + TLS_SHA256_SHA256) hash_fn="-sha256" ;; + TLS_SHA384_SHA384) hash_fn="-sha384" ;; + *) return 7 ;; + esac + tm_out "$plaintext$(hmac "$hash_fn" "$key" "$nonce$aad$plaintext")" + return 0 +} + # arg1: TLS cipher # arg2: key # arg3: nonce (must be 96 bits in length) @@ -13619,6 +13789,10 @@ sym-decrypt() { tag_len=16 ;; *CCM*|*GCM*|*CHACHA20_POLY1305*) tag_len=32 ;; + TLS_SHA256_SHA256) + tag_len=64 ;; + TLS_SHA384_SHA384) + tag_len=96 ;; *) return 7 ;; esac @@ -13639,6 +13813,8 @@ sym-decrypt() { plaintext="$(chacha20_aead_decrypt "$key" "$nonce" "${ciphertext:0:ciphertext_len}" "$additional_data" "${ciphertext:ciphertext_len:tag_len}" "$compute_tag")" elif [[ "$cipher" =~ CCM ]]; then plaintext=$(ccm-decrypt "$cipher" "$key" "$nonce" "${ciphertext:0:ciphertext_len}" "$additional_data" "${ciphertext:ciphertext_len:tag_len}" "$compute_tag") + elif [[ "$cipher" == TLS_SHA256_SHA256 ]] || [[ "$cipher" == TLS_SHA384_SHA384 ]]; then + plaintext="$(integrity_only_decrypt "$cipher" "$key" "$nonce" "${ciphertext:0:ciphertext_len}" "$additional_data" "${ciphertext:ciphertext_len:tag_len}" "$compute_tag")" else # GCM plaintext=$(gcm-decrypt "$cipher" "$key" "$nonce" "${ciphertext:0:ciphertext_len}" "$additional_data" "${ciphertext:ciphertext_len:tag_len}" "$compute_tag") fi @@ -13664,6 +13840,8 @@ sym-encrypt() { ciphertext=$(gcm-encrypt "$cipher" "$key" "$nonce" "$plaintext" "$additional_data") elif [[ "$cipher" =~ CHACHA20_POLY1305 ]]; then ciphertext="$(chacha20_aead_encrypt "$key" "$nonce" "$plaintext" "$additional_data")" + elif [[ "$cipher" == TLS_SHA256_SHA256 ]] || [[ "$cipher" == TLS_SHA384_SHA384 ]]; then + ciphertext=$(integrity_only_encrypt "$cipher" "$key" "$nonce" "$plaintext" "$additional_data") else return 7 fi @@ -14405,6 +14583,10 @@ parse_tls_serverhello() { "0102") echo -n "ffdhe4096" >> $TMPFILE ;; "0103") echo -n "ffdhe6144" >> $TMPFILE ;; "0104") echo -n "ffdhe8192" >> $TMPFILE ;; + "11EB") echo -n "SecP256r1MLKEM768" >> $TMPFILE ;; + "11EC") echo -n "X25519MLKEM768" >> $TMPFILE ;; + "11ED") echo -n "SecP384r1MLKEM1024" >> $TMPFILE ;; + "6399") echo -n "X25519Kyber768Draft00" >> $TMPFILE ;; *) echo -n "unknown (${tls_serverhello_ascii:offset:4})" >> $TMPFILE ;; esac offset=$((offset+4)) @@ -14500,6 +14682,10 @@ parse_tls_serverhello() { 258) dh_bits=4096 ; named_curve_str="ffdhe4096" ;; 259) dh_bits=6144 ; named_curve_str="ffdhe6144" ;; 260) dh_bits=8192 ; named_curve_str="ffdhe8192" ;; + 4587) dh_bits=192 ; named_curve_str="SecP256r1MLKEM768" ;; + 4588) dh_bits=192 ; named_curve_str="X25519MLKEM768" ;; + 4589) dh_bits=256 ; named_curve_str="SecP384r1MLKEM1024" ;; + 25497) dh_bits=128 ; named_curve_str="X25519Kyber768Draft00" ;; *) named_curve_str="" ; named_curve_oid="" ;; esac offset=$((extns_offset+20+i)) @@ -14687,9 +14873,9 @@ parse_tls_serverhello() { fi echo "Cipher : $rfc_cipher_suite" >> $TMPFILE if [[ $dh_bits -ne 0 ]]; then - if [[ "$named_curve_str" =~ "ffdhe" ]]; then + if [[ "$named_curve_str" =~ ffdhe ]]; then echo "Server Temp Key: DH, $named_curve_str, $dh_bits bits" >> $TMPFILE - elif [[ "$named_curve_str" == "X25519" ]] || [[ "$named_curve_str" == "X448" ]]; then + elif [[ "$named_curve_str" == X25519 ]] || [[ "$named_curve_str" == X448 ]] || [[ "$named_curve_str" =~ KEM ]] || [[ "$named_curve_str" =~ Kyber ]]; then echo "Server Temp Key: $named_curve_str, $dh_bits bits" >> $TMPFILE else echo "Server Temp Key: ECDH, $named_curve_str, $dh_bits bits" >> $TMPFILE @@ -14732,9 +14918,9 @@ parse_tls_serverhello() { echo "" fi if [[ $dh_bits -ne 0 ]]; then - if [[ "$named_curve_str" =~ "ffdhe" ]]; then + if [[ "$named_curve_str" =~ ffdhe ]]; then echo " dh_bits: DH, $named_curve_str, $dh_bits bits" - elif [[ "$named_curve_str" == "X25519" ]] || [[ "$named_curve_str" == "X448" ]]; then + elif [[ "$named_curve_str" == X25519 ]] || [[ "$named_curve_str" == X448 ]] || [[ "$named_curve_str" =~ KEM ]] || [[ "$named_curve_str" =~ Kyber ]]; then echo " dh_bits: $named_curve_str, $dh_bits bits" else echo " dh_bits: ECDH, $named_curve_str, $dh_bits bits" @@ -14770,7 +14956,7 @@ parse_tls_serverhello() { fi # If a CIPHER_SUITES string was provided, then check that $tls_cipher_suite is in the string. - # this appeared in yassl + MySQL (https://github.com/drwetter/testssl.sh/pull/784) but adds robustness + # this appeared in yassl + MySQL (https://github.com/testssl/testssl.sh/pull/784) but adds robustness # to the implementation if [[ -n "$cipherlist" ]]; then tls_cipher_suite="$(tolower "$tls_cipher_suite")" @@ -15523,7 +15709,15 @@ prepare_tls_clienthello() { 00, 01, 00, 02, 00, 03, 00, 0f, 00, 10, 00, 11, 01, 00, 01, 01" elif [[ 0x$tls_low_byte -gt 0x03 ]]; then # Supported Groups Extension - if [[ ! "$process_full" =~ all ]] || { "$HAS_X25519" && "$HAS_X448"; }; then + if [[ ! "$process_full" =~ all ]]; then + extension_supported_groups=" + 00,0a, # Type: Supported Groups, see RFC 8446 + 00,1e, 00,1c, # lengths + 00,1d, 00,17, 00,1e, 00,18, 00,19, 00,1f, 00,20, 00,21, + 01,00, 01,01, 11,eb, 11,ec, 11,ed, 63,99" + # Only include ML-KEM and Kyber hybrids as options if the response does + # not need to be decrypted. + elif [[ ! "$process_full" =~ all ]] || { "$HAS_X25519" && "$HAS_X448"; }; then extension_supported_groups=" 00,0a, # Type: Supported Groups, see RFC 8446 00,16, 00,14, # lengths @@ -15545,7 +15739,7 @@ prepare_tls_clienthello() { 00,1d, 00,17, 00,18, 00,19, 00,1f, 00,20, 00,21, 01,00, 01,01, 00,1e" # OpenSSL prior to 1.1.0 does not support either X25519 or X448, - # so list them as the least referred options if the response + # so list them as the least preferred options if the response # needs to be decrypted, and do not list them at all if the # response MUST be decrypted. elif [[ "$process_full" == all+ ]]; then @@ -15635,7 +15829,7 @@ prepare_tls_clienthello() { # There does not seem to be any reason to include this extension. However, it appears that # OpenSSL, Firefox, and Chrome include it in TLS 1.3 ClientHello messages, and there is at # least one server that will fail the connection if it is absent - # (see https://github.com/drwetter/testssl.sh/issues/990). + # (see https://github.com/testssl/testssl.sh/issues/990). if [[ "0x$tls_low_byte" -ge 0x04 ]] && [[ ! "$extra_extensions_list" =~ \ 002d\ ]]; then [[ -n "$all_extensions" ]] && all_extensions+="," all_extensions+="$extn_psk_mode" @@ -16234,7 +16428,12 @@ tls_sockets() { else finished_msg="14000030$(hmac-transcript "-sha384" "$finished_key" "$msg_transcript")" fi - [[ "$cipher" =~ CCM_8 ]] && tag_len=8 || tag_len=16 + case "$cipher" in + TLS_SHA256_SHA256) tag_len=32 ;; + TLS_SHA384_SHA384) tag_len=48 ;; + *CCM_8*) tag_len=8 ;; + *) tag_len=16 ;; + esac aad="170303$(printf "%04X" "$(( ${#finished_msg}/2 + tag_len + 1 ))")" if "$include_headers"; then # The header information was added to additional data in TLSv1.3 draft 25. @@ -16311,7 +16510,12 @@ send_app_data() { read -r tls_version cipher server_key server_iv server_seq client_key client_iv client_seq <<< "$APP_TRAF_KEY_INFO" [[ "${tls_version:0:2}" == 7F ]] && [[ 0x${tls_version:2:2} -lt 25 ]] && include_headers=false - [[ "$cipher" =~ CCM_8 ]] && tag_len=8 || tag_len=16 + case "$cipher" in + TLS_SHA256_SHA256) tag_len=32 ;; + TLS_SHA384_SHA384) tag_len=48 ;; + *CCM_8*) tag_len=8 ;; + *) tag_len=16 ;; + esac aad="170303$(printf "%04X" "$(( ${#plaintext}/2 + tag_len + 1 ))")" if "$include_headers"; then @@ -16979,7 +17183,7 @@ run_ticketbleed() { # run_renego() { local legacycmd="" proto="$OPTIMAL_PROTO" - local sec_renego sec_client_renego + local sec_renego local -i ret=0 local cve="" local cwe="CWE-310" @@ -17071,110 +17275,113 @@ run_renego() { elif [[ "$CLIENT_AUTH" == required ]] && [[ -z "$MTLS" ]]; then prln_warning "not having provided client certificate and private key file, the client x509-based authentication prevents this from being tested" fileout "$jsonID" "WARN" "not having provided client certificate and private key file, the client x509-based authentication prevents this from being tested" - sec_client_renego=1 else # We will need $ERRFILE for mitigation detection if [[ $ERRFILE =~ dev.null ]]; then ERRFILE=$TEMPDIR/errorfile.txt || exit $ERR_FCREATE - # cleanup previous run if any (multiple IP) - rm -f $ERRFILE restore_errfile=1 else restore_errfile=0 fi - # We need up to two tries here, as some LiteSpeed servers don't answer on "R" and block. Thus first try in the background - # msg enables us to look deeper into it while debugging - echo R | $OPENSSL s_client $(s_client_options "$proto $BUGS $legacycmd $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI") >$TMPFILE 2>>$ERRFILE & - wait_kill $! $HEADER_MAXSLEEP - if [[ $? -eq 3 ]]; then - pr_svrty_good "likely not vulnerable (OK)"; outln ", timed out" # it hung - fileout "$jsonID" "OK" "likely not vulnerable (timed out)" "$cve" "$cwe" - sec_client_renego=1 - else - # second try in the foreground as we are sure now it won't hang - echo R | $OPENSSL s_client $(s_client_options "$proto $legacycmd $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI") >$TMPFILE 2>>$ERRFILE - sec_client_renego=$? - # 0 means client is renegotiating & doesn't return an error --> vuln! - # 1 means client tried to renegotiating but the server side errored then. You still see RENEGOTIATING in the output - if tail -5 $TMPFILE| grep -qa '^closed'; then - # Exemption from above: server closed the connection but return value was zero - # See https://github.com/drwetter/testssl.sh/issues/1725 and referenced issue @haproxy - sec_client_renego=1 + [[ "$SERVICE" != HTTP ]] && ssl_reneg_attempts=1 + # We try again if server is HTTP. This could be either a node.js server or something else. + # Mitigations (default values) for: + # - node.js allows 3x R and then blocks. So then 4x should be tested. + # - F5 BIG-IP ADS allows 5x R and then blocks. So then 6x should be tested. + # - Stormshield allows 9x and then blocks. So then 10x should be tested. + # This way we save a couple seconds as we weeded out the ones which are more robust + # Amount of times tested before breaking is set in SSL_RENEG_ATTEMPTS. + + # Clear the log to not get the content of previous run before the execution of the new one. + # (Used in the loop tests before s_client invocation) + echo -n > $TMPFILE + echo -n > $ERRFILE + # RENEGOTIATING wait loop watchdog file + touch $TEMPDIR/allowed_to_loop + # If we dont wait for the session to be established on slow server, we will try to re-negotiate + # too early losing all the attempts before the session establishment as OpenSSL will not buffer them + # (only the first will be till the establishement of the session). + (j=0; while [[ $(grep -ac '^SSL-Session:' $TMPFILE) -ne 1 ]] && [[ $j -lt 30 ]]; do sleep $ssl_reneg_wait; ((j++)); done; \ + # Connection could be closed by the server with 0 return value. We do one more iteration to not close + # s_client STDIN too early as the close could come at any time and race with the tear down of s_client. + # See https://github.com/drwetter/testssl.sh/issues/2590 + # In this case the added iteration is harmless as it will just spin in backgroup + for ((i=0; i <= ssl_reneg_attempts; i++ )); do sleep $ssl_reneg_wait; echo R 2>/dev/null; k=0; \ + # 0 means client is renegotiating & doesn't return an error --> vuln! + # 1 means client tried to renegotiating but the server side errored then. You still see RENEGOTIATING in the output + # Exemption from above: server closed the connection but return value was zero + # See https://github.com/drwetter/testssl.sh/issues/1725 and referenced issue @haproxy + while [[ $(grep -ac '^RENEGOTIATING' $ERRFILE) -ne $((i+1)) ]] && [[ -f $TEMPDIR/allowed_to_loop ]] \ + && [[ $(tail -1 $ERRFILE | grep -acE '^(RENEGOTIATING|depth|verify|notAfter)') -eq 1 ]] \ + && [[ $k -lt 120 ]]; \ + do sleep $ssl_reneg_wait; ((k++)); if (tail -5 $TMPFILE| grep -qa '^closed'); then break; fi; done; \ + done) | \ + $OPENSSL_NOTIMEOUT s_client $(s_client_options "$proto $legacycmd $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI") >$TMPFILE 2>$ERRFILE & + pid=$! + ( sleep $((ssl_reneg_attempts*3+3)) && kill $pid && touch $TEMPDIR/was_killed ) >&2 2>/dev/null & + watcher=$! + # Trick to get the return value of the openssl command, output redirection and a timeout. + # Yes, some target hang/block after some tries (some LiteSpeed servers don't answer at all on "R" and block). + wait $pid + tmp_result=$? + pkill -HUP -P $watcher + wait $watcher + # Stop any background wait loop + rm -f $TEMPDIR/allowed_to_loop + # If we are here, we have done the loop. Count the effective renego attempts. + # It could be less than the numbers of "for" iterations (minus one) in case of late server close. + loop_reneg=$(grep -ac '^RENEGOTIATING' $ERRFILE) + # As above, some servers close the connection and return value is zero + if (tail -5 $TMPFILE | grep -qa '^closed'); then + tmp_result=1 + fi + # timeout reached ? + if [[ -f $TEMPDIR/was_killed ]]; then + tmp_result=2 + rm -f $TEMPDIR/was_killed + fi + if [[ $tmp_result -eq 1 ]] && [[ loop_reneg -eq 1 ]]; then + tmp_result=3 + fi + if [[ $SERVICE != HTTP ]]; then + # theoretic possible case + if [[ $loop_reneg -eq 2 ]]; then + tmp_result=0 fi - case "$sec_client_renego" in - 0) # We try again if server is HTTP. This could be either a node.js server or something else. - # Mitigations (default values) for: - # - node.js allows 3x R and then blocks. So then 4x should be tested. - # - F5 BIG-IP ADS allows 5x R and then blocks. So then 6x should be tested. - # - Stormshield allows 9x and then blocks. So then 10x should be tested. - # This way we save a couple seconds as we weeded out the ones which are more robust - # Amount of times tested before breaking is set in SSL_RENEG_ATTEMPTS. - if [[ $SERVICE != HTTP ]]; then - pr_svrty_medium "VULNERABLE (NOT ok)"; outln ", potential DoS threat" - fileout "$jsonID" "MEDIUM" "VULNERABLE, potential DoS threat" "$cve" "$cwe" "$hint" - else - # Clear the log to not get the content of previous run before the execution of the new one. - echo -n > $TMPFILE - #RENEGOTIATING wait loop watchdog file - touch $TEMPDIR/allowed_to_loop - # If we dont wait for the session to be established on slow server, we will try to re-negotiate - # too early losing all the attempts before the session establishment as OpenSSL will not buffer them - # (only the first will be till the establishement of the session). - (j=0; while [[ $(grep -ac '^SSL-Session:' $TMPFILE) -ne 1 ]] && [[ $j -lt 30 ]]; do sleep $ssl_reneg_wait; ((j++)); done; \ - for ((i=0; i < ssl_reneg_attempts; i++ )); do sleep $ssl_reneg_wait; echo R; k=0; \ - while [[ $(grep -ac '^RENEGOTIATING' $ERRFILE) -ne $((i+3)) ]] && [[ -f $TEMPDIR/allowed_to_loop ]] \ - && [[ $(tail -n1 $ERRFILE |grep -acE '^(RENEGOTIATING|depth|verify|notAfter)') -eq 1 ]] \ - && [[ $k -lt 120 ]]; \ - do sleep $ssl_reneg_wait; ((k++)); if (tail -5 $TMPFILE| grep -qa '^closed'); then sleep 1; break; fi; done; \ - done) | \ - $OPENSSL s_client $(s_client_options "$proto $legacycmd $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI") >$TMPFILE 2>>$ERRFILE & - pid=$! - ( sleep $((ssl_reneg_attempts*3)) && kill $pid && touch $TEMPDIR/was_killed ) >&2 2>/dev/null & - watcher=$! - # Trick to get the return value of the openssl command, output redirection and a timeout. - # Yes, some target hang/block after some tries. - wait $pid - tmp_result=$? - pkill -HUP -P $watcher - wait $watcher - rm -f $TEMPDIR/allowed_to_loop - # If we are here, we have done two successful renegotiation (-2) and do the loop - loop_reneg=$(($(grep -ac '^RENEGOTIATING' $ERRFILE)-2)) - # As above, some servers close the connection and return value is zero - if (tail -5 $TMPFILE| grep -qa '^closed'); then - tmp_result=1 - fi - if [[ -f $TEMPDIR/was_killed ]]; then - tmp_result=2 - rm -f $TEMPDIR/was_killed - fi - case $tmp_result in - 0) pr_svrty_high "VULNERABLE (NOT ok)"; outln ", DoS threat ($ssl_reneg_attempts attempts)" - fileout "$jsonID" "HIGH" "VULNERABLE, DoS threat" "$cve" "$cwe" "$hint" - ;; - 1) pr_svrty_good "not vulnerable (OK)"; outln " -- mitigated (disconnect after $loop_reneg/$ssl_reneg_attempts attempts)" - fileout "$jsonID" "OK" "not vulnerable, mitigated" "$cve" "$cwe" - ;; - 2) pr_svrty_good "not vulnerable (OK)"; \ - outln " -- mitigated ($loop_reneg successful reneg within ${ssl_reneg_attempts} in $((${ssl_reneg_attempts}*3))s(timeout))" - fileout "$jsonID" "OK" "not vulnerable, mitigated" "$cve" "$cwe" - ;; - *) prln_warning "FIXME (bug): $sec_client_renego ($ssl_reneg_attempts tries)" - fileout "$jsonID" "DEBUG" "FIXME (bug $ssl_reneg_attempts tries) $sec_client_renego" "$cve" "$cwe" - ret=1 - ;; - esac - fi - ;; - 1) - prln_svrty_good "not vulnerable (OK)" - fileout "$jsonID" "OK" "not vulnerable" "$cve" "$cwe" - ;; - *) - prln_warning "FIXME (bug): $sec_client_renego" - fileout "$jsonID" "DEBUG" "FIXME (bug) $sec_client_renego - Please report" "$cve" "$cwe" - ret=1 - ;; + case $tmp_result in + 0) pr_svrty_medium "VULNERABLE (NOT ok)"; outln ", potential DoS threat" + fileout "$jsonID" "MEDIUM" "VULNERABLE, potential DoS threat" "$cve" "$cwe" "$hint" + ;; + 1|3) prln_svrty_good "not vulnerable (OK)" + fileout "$jsonID" "OK" "not vulnerable" "$cve" "$cwe" + ;; + 2) pr_svrty_good "likely not vulnerable (OK)"; outln ", timed out ($((${ssl_reneg_attempts}*3+3))s)" # it hung + fileout "$jsonID" "OK" "likely not vulnerable (timed out)" "$cve" "$cwe" + ;; + *) prln_warning "FIXME (bug): $sec_client_renego" + fileout "$jsonID" "DEBUG" "FIXME (bug) $sec_client_renego - Please report" "$cve" "$cwe" + ret=1 + ;; + esac + else + case $tmp_result in + 0) pr_svrty_high "VULNERABLE (NOT ok)"; outln ", DoS threat ($ssl_reneg_attempts attempts)" + fileout "$jsonID" "HIGH" "VULNERABLE, DoS threat" "$cve" "$cwe" "$hint" + ;; + 1) pr_svrty_good "not vulnerable (OK)"; outln " -- mitigated (disconnect after $loop_reneg/$ssl_reneg_attempts attempts)" + fileout "$jsonID" "OK" "not vulnerable, mitigated" "$cve" "$cwe" + ;; + 3) prln_svrty_good "not vulnerable (OK)" + fileout "$jsonID" "OK" "not vulnerable" "$cve" "$cwe" + ;; + 2) pr_svrty_good "not vulnerable (OK)"; \ + outln " -- mitigated ($loop_reneg successful reneg within ${ssl_reneg_attempts} in $((${ssl_reneg_attempts}*3+3))s(timeout))" + fileout "$jsonID" "OK" "not vulnerable, mitigated" "$cve" "$cwe" + ;; + *) prln_warning "FIXME (bug): $sec_client_renego ($ssl_reneg_attempts tries)" + fileout "$jsonID" "DEBUG" "FIXME (bug $ssl_reneg_attempts tries) $sec_client_renego" "$cve" "$cwe" + ret=1 + ;; esac fi fi @@ -17907,7 +18114,7 @@ run_tls_fallback_scsv() { elif grep -qa "alert handshake failure" "$TMPFILE"; then pr_svrty_good "Probably OK. " fileout "$jsonID" "OK" "Probably oK" - # see RFC 7507, https://github.com/drwetter/testssl.sh/issues/121 + # see RFC 7507, https://github.com/testssl/testssl.sh/issues/121 # other case reported by Nicolas was F5 and at customer of mine: the same pr_svrty_medium "But received non-RFC-compliant \"handshake failure\" instead of \"inappropriate fallback\"" fileout "$jsonID" "MEDIUM" "received non-RFC-compliant \"handshake failure\" instead of \"inappropriate fallback\"" @@ -19329,7 +19536,7 @@ run_starttls_injection() { esac uds="$TEMPDIR/uds" - $SOCAT FD:5 UNIX-LISTEN:$uds & + $SOCAT FD:5 UNIX-LISTEN:$uds 2>/dev/null & socat_pid=$! if "$HAS_UDS"; then @@ -20236,8 +20443,8 @@ find_openssl_binary() { $OPENSSL s_client -tls1_3 &1 | grep -aiq "unknown option" || HAS_TLS13=true $OPENSSL s_client -no_ssl2 &1 | grep -aiq "unknown option" || HAS_NO_SSL2=true - $OPENSSL genpkey -algorithm X448 2>&1 | grep -aq "not found" || HAS_X448=true - $OPENSSL genpkey -algorithm X25519 2>&1 | grep -aq "not found" || HAS_X25519=true + $OPENSSL genpkey -algorithm X448 2>&1 | grep -Eaq "not found|unsupported" || HAS_X448=true + $OPENSSL genpkey -algorithm X25519 2>&1 | grep -Eaq "not found|unsupported" || HAS_X25519=true $OPENSSL pkey -help 2>&1 | grep -q Error || HAS_PKEY=true $OPENSSL pkeyutl 2>&1 | grep -q Error || HAS_PKUTIL=true @@ -20306,7 +20513,6 @@ find_openssl_binary() { # not check /usr/bin/openssl -- if available. This is more a kludge which we shouldn't use for # every openssl feature. At some point we need to decide which with openssl version we go. # We also check, whether there's /usr/bin/openssl which has TLS 1.3 - OPENSSL2=/usr/bin/openssl if [[ ! "$OSSL_NAME" =~ LibreSSL ]] && [[ ! $OSSL_VER =~ 1.1.1 ]] && [[ ! $OSSL_VER_MAJOR =~ 3 ]]; then if [[ -x $OPENSSL2 ]]; then $OPENSSL2 s_client -help 2>$s_client_has2 @@ -20351,6 +20557,8 @@ find_openssl_binary() { fi fi + OPENSSL_NOTIMEOUT=$OPENSSL + if ! "$do_mass_testing"; then if [[ -n $OPENSSL_TIMEOUT ]]; then OPENSSL="$TIMEOUT_CMD $OPENSSL_TIMEOUT $OPENSSL" @@ -20513,7 +20721,7 @@ single check as ("$PROG_NAME URI" does everything except -E and -g): -e, --each-cipher checks each local cipher remotely -E, --cipher-per-proto checks those per protocol -s, --std, --categories tests standard cipher categories by strength - -f, --fs, --nsa checks forward secrecy settings + -f, --fs, --forward-secrecy checks forward secrecy settings -p, --protocols checks TLS/SSL protocols (including SPDY/HTTP2) -g, --grease tests several server implementation bugs like GREASE and size limitations -S, --server-defaults displays the server's default picks and certificate info @@ -20778,7 +20986,7 @@ prepare_arrays() { if [[ -n "$ossl_ciph" ]]; then TLS_CIPHER_OSSL_SUPPORTED[i]=true [[ "$ossl_ciph" != ${TLS_CIPHER_OSSL_NAME[i]} ]] && TLS_CIPHER_OSSL_NAME[i]="$ossl_ciph" - [[ "${hexc:2:2}" == 13 ]] && TLS13_OSSL_CIPHERS+=":$ossl_ciph" + [[ "${TLS_CIPHER_SSLVERS[i]}" == TLSv1.3 ]] && TLS13_OSSL_CIPHERS+=":$ossl_ciph" fi fi elif [[ $OSSL_VER_MAJOR -lt 1 ]]; then @@ -21024,6 +21232,9 @@ EOF # arg1: text to display before "-->" # arg2: arg needed to accept to continue +# ret=0 : arg was accepted to continue (batch mode doesn't do this,or warnings are turned off) +# 1 : arg was not accepted by user or we're in bacth mode + ignore_no_or_lame() { local a @@ -21182,7 +21393,7 @@ get_local_a() { check_resolver_bins() { local saved_openssl_conf="$OPENSSL_CONF" - OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134 + OPENSSL_CONF="" # see https://github.com/testssl/testssl.sh/issues/134 type -p dig &> /dev/null && HAS_DIG=true type -p host &> /dev/null && HAS_HOST=true type -p drill &> /dev/null && HAS_DRILL=true @@ -21204,7 +21415,7 @@ check_resolver_bins() { HAS_DIG_NOIDNOUT=true fi fi - OPENSSL_CONF="$saved_openssl_conf" # see https://github.com/drwetter/testssl.sh/issues/134 + OPENSSL_CONF="$saved_openssl_conf" # see https://github.com/testssl/testssl.sh/issues/134 return 0 } @@ -21227,7 +21438,7 @@ get_a_record() { echo $1 return 0 fi - OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134 + OPENSSL_CONF="" # see https://github.com/testssl/testssl.sh/issues/134 if [[ "$NODE" == *.local ]]; then if "$HAS_AVAHIRESOLVE"; then ip4=$(filter_ip4_address $(avahi-resolve -4 -n "$1" 2>/dev/null | awk '{ print $2 }')) @@ -21252,7 +21463,7 @@ get_a_record() { if [[ -z "$ip4" ]] && "$HAS_NSLOOKUP"; then ip4=$(filter_ip4_address $(strip_lf "$(nslookup -querytype=a "$1" 2>/dev/null | awk '/^Name/ { getline; print $NF }')")) fi - OPENSSL_CONF="$saved_openssl_conf" # see https://github.com/drwetter/testssl.sh/issues/134 + OPENSSL_CONF="$saved_openssl_conf" # see https://github.com/testssl/testssl.sh/issues/134 echo "$ip4" } @@ -21265,7 +21476,7 @@ get_aaaa_record() { "$HAS_DIG_NOIDNOUT" && noidnout="+noidnout" [[ "$NODNS" == none ]] && return 0 # if no DNS lookup was instructed, leave here - OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134 + OPENSSL_CONF="" # see https://github.com/testssl/testssl.sh/issues/134 if is_ipv6addr "$1"; then # This saves walking through this. Also it avoids hangs e.g. if you run docker locally without reachable DNS echo "$1" @@ -21299,7 +21510,7 @@ get_aaaa_record() { ip6=$(filter_ip6_address $(strip_lf "$(nslookup -type=aaaa "$1" 2>/dev/null | awk '/'"^${a}"'.*AAAA/ { print $NF }')")) fi fi - OPENSSL_CONF="$saved_openssl_conf" # see https://github.com/drwetter/testssl.sh/issues/134 + OPENSSL_CONF="$saved_openssl_conf" # see https://github.com/testssl/testssl.sh/issues/134 echo "$ip6" } @@ -21346,7 +21557,7 @@ get_caa_rrecord() { return 1 # No dig, drill, host, or nslookup --> complaint was elsewhere already fi - OPENSSL_CONF="$saved_openssl_conf" # see https://github.com/drwetter/testssl.sh/issues/134 + OPENSSL_CONF="$saved_openssl_conf" # see https://github.com/testssl/testssl.sh/issues/134 debugme echo $raw_caa if [[ "$raw_caa" =~ \#\ [0-9][0-9] ]]; then @@ -21485,7 +21696,7 @@ get_mx_record() { local noidnout="" "$HAS_DIG_NOIDNOUT" && noidnout="+noidnout" - OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134 + OPENSSL_CONF="" # see https://github.com/testssl/testssl.sh/issues/134 # we need the last two columns here if "$HAS_HOST"; then mx="$(host -t MX "$1" 2>/dev/null | awk '/is handled by/ { print $(NF-1), $NF }')" @@ -21512,7 +21723,7 @@ get_txt_record() { local noidnout="" "$HAS_DIG_NOIDNOUT" && noidnout="+noidnout" - OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134 + OPENSSL_CONF="" # see https://github.com/testssl/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) }')" @@ -21613,7 +21824,7 @@ determine_rdns() { [[ "$NODNS" == none ]] && rDNS="(instructed to skip DNS queries)" && return 0 # No DNS lookups at all [[ "$NODNS" == min ]] && rDNS="(instructed to minimize DNS queries)" && return 0 # PTR records were not asked for local nodeip="$(tr -d '[]' <<< $NODEIP)" # for DNS we do not need the square brackets of IPv6 addresses - OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134 + OPENSSL_CONF="" # see https://github.com/testssl/testssl.sh/issues/134 if [[ "$NODE" == *.local ]]; then if "$HAS_AVAHIRESOLVE"; then rDNS=$(avahi-resolve -a $nodeip 2>/dev/null | awk '{ print $2 }') @@ -21630,7 +21841,7 @@ determine_rdns() { elif "$HAS_NSLOOKUP"; then rDNS=$(strip_lf "$(nslookup -type=PTR $nodeip 2>/dev/null | grep -v 'canonical name =' | grep 'name = ' | awk '{ print $NF }' | sed 's/\.$//')") fi - OPENSSL_CONF="$saved_openssl_conf" # see https://github.com/drwetter/testssl.sh/issues/134 + OPENSSL_CONF="$saved_openssl_conf" # see https://github.com/testssl/testssl.sh/issues/134 # First, rDNS can contain multilines due to multiple PTR DNS records, though this is not recommended. # So we use a loop to check for each FQDN returned. There we remove chars which under weird # circumstances (see #1506) can show up here. The blacklist is taken from RFC 1912 ("Allowable characters in a @@ -22026,7 +22237,7 @@ determine_optimal_proto() { >$ERRFILE if [[ -n "$1" ]]; then - # STARTTLS workaround needed see https://github.com/drwetter/testssl.sh/issues/188 -- kind of odd + # STARTTLS workaround needed see https://github.com/testssl/testssl.sh/issues/188 -- kind of odd for STARTTLS_OPTIMAL_PROTO in -tls1_2 -tls1 -ssl3 -tls1_1 -tls1_3 -ssl2; do sclient_supported "$STARTTLS_OPTIMAL_PROTO" || continue $OPENSSL s_client $(s_client_options "$STARTTLS_OPTIMAL_PROTO $BUGS -connect "$NODEIP:$PORT" $PROXY -msg $STARTTLS $SNI") $TMPFILE 2>>$ERRFILE @@ -22134,21 +22345,26 @@ determine_optimal_proto() { [[ $? -ne 0 ]] && exit $ERR_CLUELESS elif "$all_failed" && ! "$ALL_FAILED_SOCKETS"; then if ! "$HAS_TLS13" && "$TLS13_ONLY"; then - pr_magenta " $NODE:$PORT appears to support TLS 1.3 ONLY. You better use --openssl=" - if ! "$OSSL_SHORTCUT" || [[ ! -x /usr/bin/openssl ]] || /usr/bin/openssl s_client -tls1_3 2>&1 | grep -aiq "unknown option"; then - outln - fileout "$jsonID" "WARN" "$NODE:$PORT appears to support TLS 1.3 ONLY, but $OPENSSL does not support TLS 1.3" - ignore_no_or_lame " Type \"yes\" to proceed with $OPENSSL and accept all scan problems" "yes" - [[ $? -ne 0 ]] && exit $ERR_CLUELESS - MAX_OSSL_FAIL=10 - else - # dirty hack but an idea for the future to be implemented upfront: Now we know, we'll better off - # with the OS supplied openssl binary. We need to initialize variables / arrays again though. - # And the service detection can't be made up for now - outln ", \n proceeding with /usr/bin/openssl" - OPENSSL=/usr/bin/openssl - find_openssl_binary - prepare_arrays + if "$OPENSSL2_HAS_TLS_1_3"; then + if "$OSSL_SHORTCUT" || [[ "$WARNINGS" == batch ]]; then + # switch w/o asking + OPEN_MSG=" $NODE:$PORT appeared to support TLS 1.3 ONLY. Thus switched automagically from\n \"$OPENSSL\" to \"$OPENSSL2\"." + fileout "$jsonID" "INFO" "$NODE:$PORT appears to support TLS 1.3 ONLY, switching from $OPENSSL to $OPENSSL2 automagically" + OPENSSL="$OPENSSL2" + find_openssl_binary + prepare_arrays + else + # now we need to ask the user + ignore_no_or_lame " Type \"yes\" to proceed with \"$OPENSSL2\" OR accept all scan problems" "yes" + if [[ $? -eq 0 ]]; then + fileout "$jsonID" "INFO" "$NODE:$PORT appears to support TLS 1.3 ONLY, switching from $OPENSSL to $OPENSSL2 by the user" + OPENSSL="$OPENSSL2" + find_openssl_binary + prepare_arrays + else + fileout "$jsonID" "WARN" "$NODE:$PORT appears to support TLS 1.3 ONLY, switching from $OPENSSL to $OPENSSL2 was denied by user" + fi + fi fi elif ! "$HAS_SSL3" && [[ "$(has_server_protocol "ssl3")" -eq 0 ]] && [[ "$(has_server_protocol "tls1_3")" -ne 0 ]] && \ [[ "$(has_server_protocol "tls1_2")" -ne 0 ]] && [[ "$(has_server_protocol "tls1_1")" -ne 0 ]] && @@ -22193,7 +22409,6 @@ determine_optimal_proto() { } - dns_https_rr () { local jsonID="DNS_HTTPS_rrecord" local https_rr="" @@ -22221,6 +22436,18 @@ dns_https_rr () { +# Check messages which needed to be processed. I.e. those which would have destroyed the nice +# screen output and thus havve been postponed. This is just an idea and is only used once +# but can be extended in the future. An array might be more handy +# +check_msg() { + if [[ -n "$OPEN_MSG" ]]; then + outln "$OPEN_MSG" + OPEN_MSG="" + fi +} + + # arg1 (optional): ftp smtp, lmtp, pop3, imap, sieve, xmpp, xmpp-server, telnet, ldap, postgres, mysql, irc, nntp (maybe with trailing s) # determine_service() { @@ -22261,6 +22488,7 @@ determine_service() { determine_optimal_proto # returns always 0 and sets $SERVICE service_detection $OPTIMAL_PROTO + check_msg else # STARTTLS if [[ "$1" == postgres ]] || [[ "$1" == sieve ]]; then protocol="$1" @@ -23041,7 +23269,21 @@ run_rating() { pr_headlineln " Rating (experimental) " outln - [[ -n "$STARTTLS_PROTOCOL" ]] && set_grade_cap "T" "Encryption via STARTTLS is not mandatory (opportunistic)." + [[ -n "$STARTTLS_PROTOCOL" ]] && set_grade_cap "T" "STARTTLS is prone to MITM downgrade attacks. A secure TLS upgrade can only be ensured client-side. As per RFC 8314 you should use implicit TLS rather than STARTTLS. For SMTP (port 25) and SIEVE this is not possible." + + # TL;DR: STARTTLS connections are inherently insecure. A MITM can always intercept the connection, unless the client checks e.g. the + # certificate accordingly. A secure STARTTLS client is the key but we can't test for it. Especially e-mail transfer via port 25 is broken + # as message delivery is still more important than security. Amendments like DANE and MTA-STS are duct tape and depend on the client. + + # Explanation: There are active MitM attacks possible when using STARTTLS like https://github.com/tintinweb/striptls or + # https://github.com/libcrack/starttlsstrip. It depends on the client only whether it can detect such downgrade attack. + # As some SMTP servers are still misconfigured with wrong certificates it's is still common practice for SMTP client MTAs to + # accept those wrong certificates -- delivering e-mails is more important. There is an e-mail submission port 587 but a mail server + # cannot just switch to it and continue to receive mail from everyone. Even if you advertise this via SRV record (RFC 6186). + # TLSA Records/DANE and MTA-STS (RFC-8461) on the server side can help too, + # + # For other than SMTP on port 25 and port 587 and SIEVE (there's no implicit TLS port) you should use implicit TLS as per RFC 8314. + # Instead of port 587 (STARTTLS) implicit TLS on port 465 should be considered. pr_bold " Rating specs"; out " (not complete) "; outln "SSL Labs's 'SSL Server Rating Guide' (version 2009q from 2020-01-30)" pr_bold " Specification documentation "; pr_url "https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide" @@ -23227,9 +23469,11 @@ run_rating() { # Pretty print - again, it's just nicer to read for reason in "${sorted_reasons[@]}"; do if [[ $reason_nr -eq 0 ]]; then - pr_bold " Grade cap reasons "; outln "$reason" + pr_bold " Grade cap reasons " + outln "$(out_row_aligned_max_width "$reason" " " $TERM_WIDTH)" else - outln " $reason" + outln "$(out_row_aligned_max_width " $reason" " " $TERM_WIDTH)" + fi ((reason_nr++)) fileout "grade_cap_reason_${reason_nr}" "INFO" "$reason" diff --git a/utils/make-openssl.sh b/utils/make-openssl.sh index 931406a..f2a2bf3 100755 --- a/utils/make-openssl.sh +++ b/utils/make-openssl.sh @@ -69,7 +69,7 @@ testv6_patch() { else echo echo "no IPv6 patch (Fedora) detected!! -- Press ^C and dl & apply from" - echo "https://github.com/drwetter/testssl.sh/blob/master/bin/fedora-dirk-ipv6.diff" + echo "https://github.com/testssl/testssl.sh/blob/master/bin/fedora-dirk-ipv6.diff" echo "or press any key to ignore" echo read a diff --git a/utils/update_client_sim_data.pl b/utils/update_client_sim_data.pl index 61bf0d1..700f553 100755 --- a/utils/update_client_sim_data.pl +++ b/utils/update_client_sim_data.pl @@ -72,6 +72,10 @@ foreach my $client ( @$ssllabs ) { push @ciphersuites, "TLS_AES_128_CCM_SHA256"; } elsif ( $suite == "4869" ) { push @ciphersuites, "TLS_AES_128_CCM_8_SHA256"; } + elsif ( $suite == "49332" ) { + push @ciphersuites, "TLS_SHA256_SHA256"; } + elsif ( $suite == "49333" ) { + push @ciphersuites, "TLS_SHA384_SHA384"; } elsif ( exists $ciphers{$suite} ) { push @ciphers, $ciphers{$suite}; } elsif ( $suite == "255" ) {