nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
https://nim-lang.org
Other
16.52k stars 1.46k forks source link

SslProtVersion only supports TLS 1.0 and older. Add TLS 1.2 & TLS 1.3 since TLS 1.1 and older are deprecated. #13884

Open x448 opened 4 years ago

x448 commented 4 years ago

Nim 1.2.0 doesn't allow programmers to specify (require) TLS 1.1, 1.2, or 1.3. Current industry recommendation is to require at least TLS 1.2:

SslProtVersion enumeration in Nim 1.2.0 (April 3, 2020): https://github.com/nim-lang/Nim/blob/7e83adff84be5d0c401a213eccb61e321a3fb1ff/lib/pure/net.nim#L91-L93

Other programming languages make it easy to specify TLS 1.2 or newer. POODLE from 2014 is not the only security issue to consider, see below.

Background

1999. TLS 1.0 was first defined in RFC 2246 in January 1999.

2006. TLS 1.1 was defined in RFC 4346 in April 2006.

2008. TLS 1.2 was defined in RFC 5246 in August 2008.

2014. TLS 1.0 allows downgrading the connection to SSL 3.0, thus weakening security (POODLE SSL Variant). Source:
https://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_1.0

2014. TLS 1.0, TLS 1.1, and TLS 1.2 (if not implemented properly) are vulnerable to POODLE TLS Variant even if SSLv3 is disabled. Source:
https://en.wikipedia.org/wiki/POODLE

2017. Google Chrome set TLS 1.3 as the default version for a short time in 2017. It then removed it as the default, due to incompatible middleboxes such as Blue Coat web proxies. Source:
https://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_1.3

2018. TLS 1.3 was defined in RFC 8446 in August 2018. It mandates use of AEAD ciphers, key exchanges that offer perfect forward secrecy, integrates session hash, and drops support for many insecure or obsolete features. Source:
https://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_1.3

POODLE from 2014 is not the only security issue to consider, see this paper from 2018:

To analyze TLS-encrypted data, network appliances implement a Man-in-the-Middle TLS proxy, by acting as the intended web server to a requesting client (e.g., a browser), and acting as the client to the actual/outside web server. Source:
The Sorry State of TLS Security in Enterprise - Interception Appliances (PDF, arxiv.org)

alaviss commented 4 years ago

The default, protSSLv23 auto negotiates the best method (which does include newer TLS versions, despite the name).

We should update this set of enums however, and deprecate the older methods.

x448 commented 4 years ago

What currently prevents MITM attack from making TLS 1.0 or lower the "best method" during auto negotiation before this change is made?

alaviss commented 4 years ago

Making sure your system have a recent OpenSSL is the way to go for now.

x448 commented 4 years ago

SSLv2 was removed in OpenSSL 1.1.0.

Which "recent OpenSSL" version is required to remove TLS 1.0 and TLS 1.1 from being auto negotiated as the "best method" during MITM attack against software written in Nim 1.2.0?

alaviss commented 4 years ago

Which "recent OpenSSL" version is required to remove TLS 1.0 and TLS 1.1 from being auto negotiated as the "best method" during MITM attack against software written in Nim 1.2.0?

None. In practice all servers should now be POODLE-protected, so you should be fine. But if you're paranoid, then you can configure your openssl to use only TLS 1.2 or newer by default.

Debian got a patch for this: https://sources.debian.org/patches/openssl/1.1.1f-1/Set-systemwide-default-settings-for-libssl-users.patch/

x448 commented 4 years ago

None.

Thanks for confirming.

In practice all servers should now be POODLE-protected, so you should be fine.

Are you saying POODLE (found in 2014) is the only way MITM attacks against a Nim 1.2.0 program can successfully decrypt TLS traffic?

But if you're paranoid, then you can configure your openssl to use only TLS 1.2 or newer by default.

I've updated the issue to make it more clear that requiring TLS 1.2 or newer is an industry recommendation from Apple, Google, Microsoft, and Mozilla about 4 years after POODLE was fixed.

I've also added a Background section to provide more context and a timeline.

dom96 commented 4 years ago

Just as an FYI, here is what protSSLv23 maps to: https://github.com/nim-lang/Nim/blob/devel/lib/wrappers/openssl.nim#L261-L262. It seems to automagically use the most secure method :)

Edit: it's actually far more complex, and funnily enough I'm running into bugs in this code now, the above link is just for the static linking :( (see #13903)

nitely commented 4 years ago

Which "recent OpenSSL" version is required to remove TLS 1.0 and TLS 1.1 from being auto negotiated as the "best method" during MITM attack against software written in Nim 1.2.0?

IIRC, SSLv23_method will use openssl.conf to select the min/max TLS version. I implemented a way to select the min version used a while ago -> https://github.com/nim-lang/Nim/pull/11323 , then I learned about openssl.conf.

x448 commented 4 years ago

@dom96 I've not done a code review but at a glance, the code snippet you pointed to does not appear to block TLS versions below TLS 1.2. Also this is still my 1st hour with Nim which I haven't installed yet so please forgive (and point out) any mistakes I make interpreting nim code.

These 2 lines in openssl.nim says SSLv23_method() calls TLS_method(). https://github.com/nim-lang/Nim/blob/92c4aad2059a350e95bc7a64932873b41b085976/lib/wrappers/openssl.nim#L261-L262

These comments in openssl.nim say TLS_method() enables SSLv3, TLS 1.0, TLS 1.1, TLS 1.2: https://github.com/nim-lang/Nim/blob/92c4aad2059a350e95bc7a64932873b41b085976/lib/wrappers/openssl.nim#L243-L246

Here's a simple test that does not require performing MITM attacks on TLS:

  1. setup a web server (nginx, etc.) and configure it to only allow SSLv3, TLS 1.0, and TLS 1.1 using a valid domain and a free LetsEncrypt certificate.
  2. write a client in Nim 1.2.0 that forbids old TLS versions below TLS 1.2 and request a page from the web server using HTTPS.
  3. EXPECTED: client should report an error saying no matching TLS protocol.

Also repeat the test using TLS 1.3 for step 2 and the same expected connection error.

Before writing the client, you can use ssltest (Qualys) or Firefox to confirm if nginx TLS settings are working as expected. Firefox has about:config URL to access these settings:

4 is TLS 1.3 3 is TLS 1.2 ... etc.

x448 commented 4 years ago

@nitely although openssl.conf is useful on servers, I've always avoided it on desktops for client apps because it can be messed up by end users and etc.

x448 commented 4 years ago

Example of C++ network library requiring TLS 1.2 using OpenSSL.

    void requireMinimumProtocol(Protocols protocol);
        /// Disables all protocol version lower than the given one.
        /// To require at least TLS 1.2 or later:
        ///
        ///   context.requireMinimumProtocol(PROTO_TLSV1_2);

Source: https://github.com/pocoproject/poco/blob/3fc3e5f5b8462f7666952b43381383a79b8b5d92/NetSSL_OpenSSL/include/Poco/Net/Context.h#L388-L393

alaviss commented 4 years ago

I'll work on this.

The biggest problem right now is how OpenSSL and LibreSSL have different idea on how this is implemented at the ABI level (OpenSSL uses macros, and LibreSSL uses actual functions), so I'll have to find a common ground to base the feature on.

It's possible to do this in Nim 1.2.0, but it would be rather hacky.

x448 commented 4 years ago

@alaviss Thanks for tackling this. What you said about OpenSSL and LibreSSL sounds great.

I hope these ideas are useful and saves you time (you may already know these):

Thanks again for tackling this.

libtls: rethinking the TLS/SSL API (2017 presentation) Bob Beck's libtls resources

x448 commented 4 years ago

@alaviss I reported a similar TLS issue with crystal-lang/crystal and they're resolving it by using Mozilla's recommended settings for TLS version, ciphersuite, etc.

FedericoCeratto commented 4 years ago

Be aware of the set of tests against the https://badssl.com service: https://github.com/nim-lang/Nim/blob/devel/tests/untestable/thttpclient_ssl.nim