When `certificate_info()` is given a certificate with a DH public key it displays something like:
```
Server key size fixme: dhKeyAgreement 3072 bits (FIXME: can't tell whether this is good or not)
```
This PR fixes that so that the output is:
```
Server key size DH 3072 bits
```
This PR is in response to issue #454. I tried repeating the reported problem by creating a certificate in which the extendedKeyUsage extension was present and only included the anyExtendedKeyUsage OID. In running the test, I discovered two problems.
First, when `determine_trust()` is calling `verify_retcode_helper()` to display the reason that path validation failed, it assumes that there are at least two certificate bundles provided. (I was running the test using just one certificate bundle, containing my local root.) So, I changed `determine_trust()` to use `${verify_retcode[1]}` rather than `${verify_retcode[2]}` in the case that all bundles failed (it seems that 2 vs. 1 was an arbitrary choice).
Once that was fixed, testssl.sh output "NOT ok (unknown, pls report) 26". So, the second thing this PR fixes is to output "NOT ok (unsupported certificate purpose)" if OpenSSL responds with an unsupported certificate purpose error.
With OpenSSL 1.1.0, `s_client -no_ssl2` fails with an "unknown option" error. At the moment the `-no_ssl2` option is only used in two functions, `run_client_simulation()` and `run_crime()`. In `run_crime()`, the `-no_ssl2` option is only included if the OpenSSL version is 0.9.8.
This PR checks whether the OpenSSL version in use supports the `-no_ssl2` option, and if it doesn't, it removes it from the calls to `s_client` in `run_client_simulation()`.
If the version of OpenSSL being used doesn't support `s_client -ssl3` (e.g., OpenSSL 1.1.0), `run_beast()` doesn't display a warning that testing for CBC in SSLv3 isn't locally supported.
This PR adds a "Local problem" warning if the OpenSSL being used doesn't support `s_client -ssl3`.
The test for whether a server only supports SSLv2 was broken, since `$OPTIMAL_PROTO` will be `-ssl2` whether SSLv2 is the only protocol that succeeds or no protocol succeeds.
This PR sets $OPTIMAL_PROTO (or $STARTTLS_OPTIMAL_PROTO) to "" if no protocol succeeds.
If the version of OpenSSL being used doesn't support `s_client -ssl3` (e.g., OpenSSL 1.1.0), `run_ssl_poodle()` displays `not vulnerable (OK)` even though it can't test whether the server is vulnerable.
This PR fixes it so that a "Local problem" warning is displayed is `s_client -ssl3` isn't supported.
The PR also removes the `$SNI` from the call to `$OPENSSL s_client` since OpenSSL ignores the `-servername` directive for `-ssl3` anyways.
If testssl.sh is called with `--devel 22` and the response from `sslv2_sockets()` is not 0, then `tls_sockets()` will be called, and the result of the `tls_sockets()` command will be output rather than the result of the `sslv2_sockets()` command.
This PR addresses the "FIXME" in `run_protocols()`:
```
sslv2_sockets #FIXME: messages/output need to be moved to this (higher) level
```
It also changes `run_drown()` to call `sslv2_sockets()` in order to avoid duplicate code.
This PR is in response to issue #352, where it was noted that Bash does not support binary data in strings.
I replaced all calls to `sockread()` with calls to `sockread_serverhello()`, and then, since is now used everywhere and not just to read ServerHello messages, I renamed `sockread_serverhello()` to `sockread()`.
I tested the revised code against several servers, including one that is vulnerable to CCS and Heartbleed, and got the same results as with the current code (although the hexdumps displayed in debug mode differ).
One concern I have is the code in `run_ccs_injection()`. The current code is:
```
byte6=$(echo "$SOCKREPLY" | "${HEXDUMPPLAIN[@]}" | sed 's/^..........//')
lines=$(echo "$SOCKREPLY" | "${HEXDUMP[@]}" | count_lines )
debugme echo "lines: $lines, byte6: $byte6"
if [[ "$byte6" == "0a" ]] || [[ "$lines" -gt 1 ]]; then
pr_done_best "not vulnerable (OK)"
...
```
I revised this to:
```
if [[ -s "$SOCK_REPLY_FILE" ]]; then
byte6=$(hexdump -ve '1/1 "%.2x"' "$SOCK_REPLY_FILE" | sed 's/^..........//')
lines=$(hexdump -ve '16/1 "%02x " " \n"' "$SOCK_REPLY_FILE" | count_lines )
debugme echo "lines: $lines, byte6: $byte6"
fi
rm "$SOCK_REPLY_FILE"
if [[ "$byte6" == "0a" ]] || [[ "$lines" -gt 1 ]]; then
...
```
In the revised code `byte6` is initialized to `0a` so that the response is `not vulnerable (OK)` if `$SOCK_REPLY_FILE` is empty. This has worked okay since for all of the servers that I tested that weren't vulnerable `$SOCK_REPLY_FILE` was empty. Since I haven't seen any other examples, I don't understand why check for vulnerability was written the way it was. So, I'm a bit concerned that the test in the revised code may produce incorrect results now that `hexdump -ve '1/1 "%.2x"' "$SOCK_REPLY_FILE"` is an accurate hexdump of the reply.
In the check for old versions of OpenSSL, the results of the call to `ignore_no_or_lame()` are ignored, and so the program continues even if the user enters `no`.
This PR makes three changes to `determine_optimal_proto()`:
* It no longer tries an empty string for `$OPTIMAL_PROTO` twice.
* It does not include `-servername` for `-ssl2` or `-ssl3`, since some versions of OpenSSL that support SSLv2 will fail if `s_client` is provided both the `-ssl2` and `-servername` options.
* It displays a warning if `$OPTIMAL_PROTO` is `-ssl2`, since some tests in testssl.sh will not work correctly for SSLv2-only servers.
This PR addresses two issues related to SSLv2 for "--server-preference" checks.
First, some versions of OpenSSL that support SSLv2 will fail if `s_client` is provided both the `-ssl2` and `-servername` options.
Second, the line for extracting the chosen cipher,`cipher=$(awk '/Cipher.*:/ { print $3 }' $TMPFILE)`, fails for SSLv2. For SSLv2, the output from `$OPENSSL s_client` is as shown below, and the `cipher=` line extracts the word `between` from `Ciphers common between both SSL endpoints:` rather than `IDEA-CBC-MD5` from ` Cipher : IDEA-CBC-MD5`.
```
...
Ciphers common between both SSL endpoints:
RC4-MD5 RC2-CBC-MD5 IDEA-CBC-MD5
DES-CBC-MD5 DES-CBC3-MD5
---
SSL handshake has read 1191 bytes and written 373 bytes
---
New, SSLv2, Cipher is IDEA-CBC-MD5
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : SSLv2
Cipher : IDEA-CBC-MD5
...
```
This PR changes test_just_one() to correctly handle SSLv2 ciphers.
As with PR #424, this PR addresses the problem in which servers that do not implement SSLv2, but that implement RC4-MD5, EXP-RC2-CBC-MD5, EXP-RC4-MD5, or NULL-MD5 are shown as implementing both the SSLv2 and SSLv3 versions of the ciphers, and that any SSLv2 ciphers that a server does implement are not shown as being implemented.
This PR changes run_rc4() to correctly handle SSLv2 ciphers.
It addresses the problem in which servers that do not implement SSLv2, but that implement SSLv3 ciphers that share an OpenSSL name with an SSLv2 cipher (RC4-MD5 and EXP-RC4-MD5), are not incorrectly shown as having implemented the SSLv2 cipher.
It also addresses the problem that if a server does implement SSLv2 with an RC4 SSLv2-cipher suite, then that cipher suite it not shown as being implemented.
It is OK for a site to pin a CA that is not part of the chain (like github.com does)
This is a provision against a CA compromise (like diginotar) which could lead to a
briked site in case of CA compromise.
GitHub has built in multiple levels of security they have both backup pins for host
certs and back pins for CAs (and I wouldn;t be surprised if they have a backup
intermediate pin too).
`certificate_info()` does not correctly display the Issuer name for CAs that use domain component attributes.
There is a server on the NIST intra-net that I test against that has a certificate issued by a NIST CA, and the issuer name in the certificate is of the form: `/DC=net/DC=example/DC=internal/CN=CAname`
Since there is no organizational name, testssl.sh displays the name as:
```
Issuer "CAname" ("")
```
In this PR, if the Issuer name has 'DC=' attributes, but does not have an 'O=' attribute, the "DC=" attributes are combined into a DNS name that is used as if it were the organizational name:
```
Issuer "CAname" ("internal.example.net")
```
I should note, however, that I have not been able to find any other examples of TLS server certificates that have been issued by CAs that have domain components ("DC=") in their names. So, it may not be worthwhile to change the code to try to accommodate such CAs.
`certificate_info()` currently outputs `$issuer` to the JSON file, where is should be outputting `$issuer_CN` in order for the information in the JSON file to match the information that is displayed.
This PR also fixes the problem that if an Issuer name contains a domain component attribute (DC=) then it will be mistakenly treated as a country attribute (C=).
Rather than try each curve one at a time, follow model in `cipher_pref_check()`. First include all curves in ClientHello, then successively remove from the ClientHello those curves that have been offered by the server until the connection fails. This makes the number of calls to `$OPENSSL s_client` one more than the number of supported curves rather than the number of curves in NamedCurve supported by $OPENSSL.
Note, however, that OpenSSL defines MAX_CURVELIST as 28 and fails if the `-curves` option includes more than 28 curves. Since OpenSSL 1.1.0 offers 29 curves from NamedCurve, this PR breaks the list of supported curves in 2. At the cost of one additional calls to `$OPENSSL s_client` it ensures that the number of curves provides to the `-curves` option is below the limit.
Found another NPN test (for the case where server doesn't specify cipher order?) that wasn't using SNI.
Also found a comment saying proxies don't support NPN => removed `$PROXY` from all modified lines.
I noticed the NPN parts of this test were not returning any ECDSA ciphers where I expected them to match the results of the immediately preceding TLS 1.2 test. Found it wasn't using SNI so my test server was using the default domain (snakeoil RSA certificate) instead of the tested domain (dual ECDSA/RSA certificates).
On FreeBSD, sed does not support "\n" in the replacement string of a substitution. The SANs are currently output all together inside a single pair of quotes and each separated with an "n" character, needless to say this is very difficult to read.
After a little digging, it seems this is a somewhat recent regression of the fix in #173. I believe `tr` would be a more cross-platform way to do this, and several sources (including the author of that PR) would seem to agree - assuming the newline is now necessary.
It doesn't appear to matter what order the newline replacement happens amongst all the other replacements, so I have placed it first simply to avoid extending any already-long lines. Please correct me if this deduction is false.
This PR should address issue #399.
I created the list of ciphers using the CIPHERS_BY_STRENGTH file from PR #373, making a list of all ciphers that had "CBC" in the RFC name and for which I had been able to find a corresponding OpenSSL name. Then, since that list contained more than 128 ciphers, I removed any ciphers from the list where the name ended in "-SHA256" or "-SHA384", as it is my understanding that those ciphers can only be used with TLS 1.2.
Changed code for run_client_simulation() so that cipher is output when sockets are used even if $MAPPING_FILE_RFC is missing. Also, updated the client data.