pornin / TestSSLServer

MIT License
140 stars 50 forks source link

TestSSLServer

Overview

TestSSLServer is a command-line tool which contacts a SSL/TLS server and obtains some information on its configuration. It aims at providing (part of) the functionality of Internet-based tools like Qualys SSL Server Test, but without the requirement of the server being Internet-reachable. You can use TestSSLServer on your internal network, to test your servers while they are not (yet) accessible from the outside.

Gathered information includes the following:

The analysis is performed by repeatedly connecting to the target server, with different variants of ClientHello messages, and analysing the server's answer. It shall be noted that TestSSLServer includes no cryptographic algorithm whatsoever; as such, it is incapable of completing any SSL/TLS handshake. It sends a ClientHello, then obtains the server's response up to the next ServerHelloDone message, at which points it closes the connection.

Note: although the information which is gathered from the server is nominally public, some server administrators could be somewhat dismayed at your using the tool on their servers, and there may be laws against it (in the same way that port scanning third-party servers with nmap is a matter of delicacy, both morally and legally). You should use TestSSLServer only to scan your own servers, and that's what it was designed to do.

License

License is MIT-like: you acknowledge that the code is provided without any guarantee of anything, and that I am not liable for anything which follows from using it. Subject to these conditions, you can do whatever you want with the code. See the LICENSE file in the source code for the legal wording.

Installation

The source code is obtained from GitHub; use the "Download ZIP" to obtain a fresh snapshot, or use git to clone the repository. In the source tree, you will find the simple build scripts, build.cmd (for Windows) and build.sh (for Linux and OS X).

The Windows script invokes the command-line compiler (csc.exe) that is found in the v2.0.50727 .NET framework. This framework is installed by default on Windows 7. More recent versions of Windows do not have the .NET 2.0 framework, but a more recent version (4.x or later). Though these framework versions are not completely compatible with each other, TestSSLServer uses only features that work identically on both, so you can compile TestSSLServer with either .NET version. The resulting TestSSLServer.exe is stand-alone and needs no further "installation"; you simply copy the file where you want it to be, and run it from a console (cmd.exe) with the appropriate arguments.

The Linux / OS X script tries to invoke the Mono C# compiler under the names mono-csc (which works on Ubuntu) and dmcs (which works on OS X). On Ubuntu, install the mono-devel package; it should pull as dependencies the runtime and the compiler. On OS X, fetch a package from the Mono project and install it; it should provide the mono command-line tool to run compiled asemblies, and dmcs to invoke the C# compiler.

Usage

On Windows, the compiled TestSSLServer.exe file can be launched as is. On Linux and OS X, use mono TestSSLServer.exe.

General usage:

TestSSLServer.exe [ options ] servername [ port ]

The servername is the name of IP address of the target server. If the port is not specified, then 443 is used.

Options are:

For example, to make a text report in file "test.txt" for server "www.example.com" on port 443, use:

TestSSLServer.exe -v -text test.txt www.example.com 443

JSON Format

A single JSON object is produced. It contains the following fields:

Warnings

Each "warning" indicates a condition which may imply a vulnerability of some kind.

Text Output

When use with the -text option (or no output option at all), TestSSLServer produces a text report which contains the same information as the JSON report, with a layout meant for immediate human consumption.

The text report begins with the information about the server name and port, and SNI extension contents. Then follow the supported versions and, for each of them, the supported cipher suites. For instance, you may get this:

  SSLv3:
     server selection: uses client preferences
     3-- (key:  RSA)  RSA_WITH_RC4_128_SHA
     3-- (key:  RSA)  RSA_WITH_3DES_EDE_CBC_SHA
     3f- (key:  RSA)  DHE_RSA_WITH_3DES_EDE_CBC_SHA
     3-- (key:  RSA)  RSA_WITH_AES_128_CBC_SHA
     3f- (key:  RSA)  DHE_RSA_WITH_AES_128_CBC_SHA
     3-- (key:  RSA)  RSA_WITH_AES_256_CBC_SHA
     3f- (key:  RSA)  DHE_RSA_WITH_AES_256_CBC_SHA
     3-- (key:  RSA)  RSA_WITH_CAMELLIA_128_CBC_SHA
     3f- (key:  RSA)  DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
     3-- (key:  RSA)  RSA_WITH_CAMELLIA_256_CBC_SHA
     3f- (key:  RSA)  DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
     3-- (key:  RSA)  RSA_WITH_SEED_CBC_SHA
     3f- (key:  RSA)  DHE_RSA_WITH_SEED_CBC_SHA
     3f- (key:  RSA)  ECDHE_RSA_WITH_RC4_128_SHA
     3f- (key:  RSA)  ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
     3f- (key:  RSA)  ECDHE_RSA_WITH_AES_128_CBC_SHA
     3f- (key:  RSA)  ECDHE_RSA_WITH_AES_256_CBC_SHA
  TLSv1.0: idem

This output means that both SSL 3.0 and TLS 1.0 are supported. For SSL 3.0, TestSSLServer noticed that the server faithfully follows the client preferences; the cipher suites are then listed in no particular order (in fact, they are ordered by their numerical 16-bit identifier). For each cipher suite, the first three characters are synthetic flags about the cipher suite:

This, "3f-" is good, and anything else is worrying to some degree.

The "TLSv1.0: idem" line means that TLS 1.0 is also supported, with exactly the same list of cipher suites (and selection algorithm) as SSL 3.0; otherwise, TestSSLServer would have listed the suite in the same way as it did for SSL 3.0.

After the protocol versions and cipher suites, TestSSLServer lists out the certificate chains sent by the server. Most servers will always send the same chain, but some may have alternate chains (e.g. if the server has both a RSA certificate and an ECDSA certificate, and chooses one or the other depending on the selected cipher suite). Each chain is printed out; certificates are given in SSL/TLS order (first certificate is the server's own certificate, followed by the CA certificate which issued it, and so on). For each certificate, the thumbprint, serial number, subject and issuer DN, validity dates, key type, key size, curve name (if appropriate), and hash function for signature, are printed, optionally followed by the full certificate (PEM format) if requested with -certs. The server names (dNSName in SAN extension) are also printed for the first certificate in each chain.

After the certificate chains, TestSSLServer prints some more information, as detailed for the JSON output: compression support, server system time, support for secure renegotiation, minimum sizes for DH and ECDH parameters, and supported named curves.

Finally, the list of warnings is printed, ordered by their 5-character symbolic identifiers.

Some Notes

BEAST Attack

A previous version of TestSSLServer was "testing for BEAST". I removed the explicit test because it was perennially misinterpreted, and the remedy is worse.

BEAST attack is a Chosen Plaintext Attack in which the attacker can both observe the connection from the outside, and dynamically choose part of the data that gets encrypted in the tunnel; the target is a secret data element that also gets encrypted at a predictable place. The practical setup is hostile Javascript that issues requests to an external server, and tries to extract the cookie value sent to that server. The attack applies when using a block cipher in CBC mode with SSL 3.0 or TLS 1.0 (TLS 1.1 and later are immune because they use per-record random IV, while previous versions use the last block of each record as IV for the next).

The BEAST attack no longer works, for two reasons:

  1. Actual exploit requires choosing the exact value of some specific bytes in the plaintext, and a Javascript code running in a Web browser under the cover of the SOP (Same Origin Policy) cannot do that. The demonstration had to resort to using a draft version of the WebSockets protocol, or a hole in the Java VM implementation, to be able to leverage the attacks. Both methods have long been fixed (and if they still apply on your browser, then your browser has not been updated for several years and you have a lot of much bigger holes to worry about).

  2. SSL/TLS libraries have implemented a generic workaround known as the "1/n-1 split", by which each record, upon sending, is split into two successive records, the first one containing a single byte of plaintext. The "1/n-1 split" is, conceptually, reusing a the MAC on each record as a randomization source for the IV for CBC encryption, which prevents the attack.

One should note that the BEAST attack happens on the client side, not on the server. Nevertheless, there is a fashion for testing the server for "BEAST vulnerability". The idea is that the server may save a vulnerable client, by enforcing use of a non-CBC cipher suite even if the client would prefer a CBC cipher suite. Correspondingly, some tools give good grades to servers that act that way.

Unfortunately, this is all wrong. As pointed out above, the BEAST attack should not work, regardless of the server cipher suite selection algorithm. On the other hand, enforcing a non-CBC cipher suite in SSL 3.0 and TLS 1.0 means using RC4, which has very real biases that are not fixed (and not fixable) in modern libraries. Trying to make the server "BEAST secure" really means lowering encryption security, not increasing it. So don't do that.

If someone talks to you about BEAST, point them to the paragraph above. Alternatively, if the auditor hordes prove impermeable to science and just want to tick boxes in their checklists, disable SSL 3.0 and TLS 1.0 support altogether. You should not allow SSL 3.0 anyway.

Weak Suites and Keys

In SSL/TLS, client and server negotiate security parameters. Therefore, if both support strong cipher suites and keys, all should be fine, even if they would potentially support weak cipher suites as well?

Not so fast. The handshake is protected: once the cryptography has occurred, the client and server send verification messages (Finished), protected by the newly negotiated algorithms and keys, and the contents of these messages are basically a hash of all preceding messages, including the ClientHello. Therefore, alterations by attackers, who try to make client and server negotiate a weak cipher suite, should be detected at that point. Unless the weak cipher suite is so weak that it can be broken right away, dynamically, so that the attacker can then unravel the encryption in real time, and "fix" the Finished messages.

This is exactly what was done with the so-called "Logjam" and "FREAK" attacks, that rely on support of export cipher suites with awfully weak key exchange parameters (512-bit RSA or DH).

On a similar note, a recent attack ("DROWN" -- yet another example of that weird fashion of witty acronyms) leverages SSL 2.0 support to break a TLS key exchange that used the same private key. That attack is a clear example of how support for a weak protocol version can be harmful even if normal clients do not use it.

Therefore, all weak cipher suites and keys should be disabled.

Un-warned Conditions

TestSSLServer's warnings are supposed to point at conditions for which an actual vulnerability or possible weakness has been demonstrated. It won't warn about configurations that are merely unfashionable. The most conspicuous example is cipher suites that use MD5. MD5 is very weak with regards to collisions; but when a cipher suite uses MD5 (e.g. RSA_WITH_RC4_128_MD5), it does so as part of HMAC, and there is no known way to break HMAC/MD5. Therefore, TestSSLServer does not emit a warning for MD5 usage in a cipher suite, even though some other SSL-testing tools may give a "bad grade" when MD5 is encountered.

RSA_WITH_RC4_128_MD5 would still get a warning, though, because of its use of RC4. And use of MD5 in the signature of a certificate would also be reported, because that one can be unsafe.

Untested Conditions

TestSSLServer does not try to push the server implementation to its limits. Its goal is not to find implementation flaws, only configuration flaws.

For instance, TestSSLServer does not try to test the quality of the random generation on the server side; it does not either check that the sent DH or ECDH parameters, or the server's public/private key pair, are mathematically sound.

Since TestSSLServer never completes any handshake, it cannot test for post-handshake options, in particular whether the server would allow renegotiations at all.

Some tests that TestSSLServer does not perform right now, but may implement in a future version:

Author

Question and comments can be sent to: Thomas Pornin <pornin@bolet.org>

Sometimes I even answer.