1
votes

I'm trying to control what TLS/SSL protocols are supported for a HTTPS connections to my webservice, by using a TIdServerIOHandlerSSLOpenSSL component and setting its SSLOptions.Method and SSLOptions.SSLVersions properties (as suggested in this answer).

The default is Method sslvTLSv1 and SSLVersions [sslvTLSv1] (see this answer for the relations between Method and SSLVersions):

enter image description here

I use nmap with the ssl-enum-ciphers.nse script from this answer to check what is actually available, and get this script output:

| ssl-enum-ciphers:
|   TLSv1.0:
|     ciphers:
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_DES_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_IDEA_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_RC4_128_MD5 (rsa 2048) - A
|       TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - A
|       TLS_RSA_WITH_SEED_CBC_SHA (rsa 2048) - A
|     compressors:
|       NULL
|     cipher preference: client
|     warnings:
|       Ciphersuite uses MD5 for message integrity
|       Weak certificate signature: SHA1
|_  least strength: C

But TLS 1.1 and TLS 1.2 are missing.

If I set Method to sslvSSLv23 ("a wildcard that allows dynamic version negotiation in cases where client and server support different SSL/TLS versions. It allows them to figure out and use the highest version common to both parties" (source)) I see sslvSSLv2and sslvSSLv3 become active.
But I do not want SSL 2.0 (deprecated/prohibited in 2011 by RFC 6176) and 3.0 (deprecated in June 2015 by RFC 7568) support (source).
I cannot subtract both sslvTLSv2 and sslvTLSv3 from the set generated by method sslvSSLv23: we revert to the default configuration where only TLS 1.0 is supported.

Note that if I 'only' leave out sslvTLSv2 (Method is sslvSSLv23 and SSLVersions is [sslvSSLv3,sslvTLSv1]), nmap tells me:

| ssl-enum-ciphers:
|   SSLv3:
|     ciphers:
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_DES_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_IDEA_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_RC4_128_MD5 (rsa 2048) - A
|       TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - A
|       TLS_RSA_WITH_SEED_CBC_SHA (rsa 2048) - A
|     compressors:
|       NULL
|     cipher preference: client
|     warnings:
|       CBC-mode cipher in SSLv3 (CVE-2014-3566)
|       Ciphersuite uses MD5 for message integrity
|       Weak certificate signature: SHA1
|   TLSv1.0:
|     ciphers:
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_DES_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_IDEA_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_RC4_128_MD5 (rsa 2048) - A
|       TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - A
|       TLS_RSA_WITH_SEED_CBC_SHA (rsa 2048) - A
|     compressors:
|       NULL
|     cipher preference: client
|     warnings:
|       Ciphersuite uses MD5 for message integrity
|       Weak certificate signature: SHA1
|   TLSv1.1:
|     ciphers:
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_DES_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_IDEA_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_RC4_128_MD5 (rsa 2048) - A
|       TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - A
|       TLS_RSA_WITH_SEED_CBC_SHA (rsa 2048) - A
|     compressors:
|       NULL
|     cipher preference: client
|     warnings:
|       Ciphersuite uses MD5 for message integrity
|       Weak certificate signature: SHA1
|       Weak cipher RC4 in TLSv1.1 or newer not needed for BEAST mitigation
|   TLSv1.2:
|     ciphers:
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
|       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_DES_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_IDEA_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_RC4_128_MD5 (rsa 2048) - A
|       TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - A
|       TLS_RSA_WITH_SEED_CBC_SHA (rsa 2048) - A
|     compressors:
|       NULL
|     cipher preference: client
|     warnings:
|       Ciphersuite uses MD5 for message integrity
|       Weak certificate signature: SHA1
|       Weak cipher RC4 in TLSv1.1 or newer not needed for BEAST mitigation
|_  least strength: C

What can I do so that only all TLS 1.x versions are supported?

This is Delphi XE2 with Indy 10.5.8.0, running on Win7, tested with OpenSSL 1.02f. With OpenSSL 1.02g I get this issue, we are not yet ready for our update to Delphi Seattle (Update 1) where this is solved in the Indy code.

Additional notes:

  • Should I drop TLS 1.0 support as well?

  • SSLOptions.Mode is still at the default sslmUnassigned, I want to look at that later.

  • Note that the nmap script only tests SSLv3/TLS versions, not SSLv2. I used SSLScan in addition, and this shows that if I leave out sslvTLSv3 only, SSL2 is indeed still enabled ;-(

  • Forget the info about weak ciphers, that's the next thing to tackle ;-)

  • I am actually unable to do an nmap test if I run my webservice in the Delphi IDE, this gives all kinds of runtime errors (that do not surface if I run the executable). Maybe these are supposed to happen because the nmap script is firing off all kinds of tests?

    EIdOSSLAcceptError 'Error accepting connection with SSL. EOF was observed that violates the protocol.'
    EIdOSSLUnderlyingCryptoError in ssl3_get_client_hello:no shared cipher
    EIdOSSLUnderlyingCryptoError in ssl3_get_client_hello:wrong version number
1

1 Answers

1
votes

But TLS 1.1 and TLS 1.2 are missing.

Right, because if you set the Method to sslvTLSv1, Indy will only use TLS 1.0 specifically.

Your screenshot of the Object Inspector clearly shows that you are using a version of Indy that does not support TLS 1.1+ (if you were, there would be sslvTLSv1_1 and sslvTLSv1_2 options available in the SSLVersions property).

Note that if I 'only' leave out sslvTLSv2 (Method is sslvSSLv23 and SSLVersions is [sslvSSLv3,sslvTLSv1]), nmap tells me:

When the Method is sslvSSLv23, Indy merely disables unwanted SSL/TLS versions, in this case SSLv2. You are clearly using a version of the OpenSSL library that supports TLS 1.1+. So, because your Indy version does not support TLS 1.1+, it is not disabling them. They are enabled by default. Since you are not disabling TLS 1.0, TLS 1.1+ get left implicitly enabled by OpenSSL itself.

What can I do so that only all TLS 1.x versions are supported?

This is a little bit of an odd workaround, but you can set the SSLVersions to [sslvSSLv23,sslvTLSv1]. That will set the Method to sslvSSLv23 and remove sslvSSLv23 from the SSLVersions. This way, Indy will use the SSLv23 wildcard and disable SSLv2 and SSLv3, leaving TLS 1.0+ enabled.

Unfortunately, you cannot really make this configuration in the Object Inspector at design-time. Well, you can (enable just sslvTLSv1 first, and then enable ssvSSLv23 afterwards), but it won't be saved in the DFM correctly (the SSLVersions will be omitted since [sslvTLSv1] is the default value), and will thus end up re-enabling SSLv2 and SSLv3 at run-time. To avoid that, you will have to assign the SSLVersions in code at run-time, before activating your server:

IdServerIOHandlerSSLOpenSSL1.SSLOptions.SSLVersions := [sslvSSLv23,sslvTLSv1];

Otherwise, the alternative is to upgrade to an up-to-date version of Indy that natively supports TLS 1.1+, then you can just set the SSLVersions to [sslvTLSv1,sslvTLSv1_1,sslvTLSv1_2] (at run-time or design-time) and move on.