Red Hat blog
TLS 1.3 is the sixth iteration of the Secure Sockets Layer (SSL) protocol. Originally designed by Netscape in the mid-1990’s to serve the purposes of online shopping, it quickly became the primary security protocol of the Internet. Now not limited just to web browsing, among other things, it secures email transfers, database accesses or business to business communication.
Because it had its roots in the early days of public cryptography, when public knowledge about securely designing cryptographic protocols was limited, the first two iterations: SSLv2 and SSLv3 are now quite thoroughly broken. The next two iterations, TLS 1.0 and TLS 1.1 depend on the security of Message Digest 5 (MD5) and Secure Hash Algorithm 1 (SHA1).
MD5 was broken in 2004 (and known to be weak since 1996). SHA1 was broken in 2017 (and known to be weak since 2005). Because of those known weaknesses, the TLS working group of the Internet Engineering Task Force (IETF) worked on what resulted in the fifth iteration of the protocol, published as TLS 1.2 in 2008. While that version included extensibility features that allow to negotiate the hash algorithms to use (most importantly, it introduced the hashes from the SHA-2 family as an option), it retained a lot of cryptographic constructs from the previous versions.
TLS 1.3 is the first iteration that uses modern, provably1 secure algorithms, cryptographic constructs, and only such algorithms, to protect user data. While the changes from this point of view are quite major (and have consequences for user applications too), the negotiation of the new protocol in the majority of cases will be completely transparent – you may be reading this post over TLS 1.3 already!
Retrospective on introduction of TLS 1.2 in Red Hat Enterprise Linux
When we introduced TLS 1.2 in Red Hat Enterprise Linux 6.5, released in 2013, the protocol was five years old. There were multiple reasons for the delay:
Slow industry pick-up – many Internet servers didn’t support newer versions of the protocol, at that time, according to Qualys' SSL Labs site fewer than 21% Alexa's most popular 150,000 sites supported TLS 1.2, and even fewer supported TLS 1.1.
Slow progress in implementing it among libraries we ship – e.g. OpenSSL didn’t implement it until 2012, four years after it was published as a standard
Lack of urgency – the MD5 and SHA1 weaknesses, as well as the padding issues with the CBC mode of ciphers that later resulted in the BEAST family of attacks, were considered largely theoretical. A number of people thought that implementing the workarounds and fixes in the implementations would be sufficient to address them.
Compatibility issues – many servers had bugs that caused them to either hang or drop the connection when the client advertised support for TLS 1.2, the so called “TLS version intolerance.”
Now we are bringing TLS 1.3 support to Red Hat Enterprise Linux 8 barely half a year after it was published as a standard. We were able to do that because of the different approach IETF took in designing it, much quicker adoption by libraries and more extensive implementations testing.
Different approach in design leads to earlier adoption
Before the protocol was finalised, there were multiple interoperable implementations of it actually deployed. Those experimental versions allowed the engineers working on the standard to examine in practice how disruptive the proposed changes would be.
This allowed the working group to incorporate changes to the protocol to work around problems like TLS version intolerance or incompatibility with intermediate systems that were performing deep packet inspection (so-called “middleboxes”).
From the beginning the working group was aiming for a fundamental redesign of the protocol, therefore a lot of the legacy cryptographic methods and algorithms were removed, even if they had only theoretical weaknesses or just couldn’t be formally proven to be secure.
This caused many of the changes that are noticeable at the application level that we will discuss next. Finally, the design included feedback from cryptographers working on formal analysis of the protocol, making it the first version of TLS that had security proofs published before the final version of the protocol was published.
Bringing a new protocol to production
Based on our experience with bringing the TLS 1.2 protocol in an earlier release of RHEL, we agreed on the following approach. We were targeting to bring the OpenSSL, GnuTLS and NSS implementations with support for TLS 1.3 on Enterprise Linux 8.0.
That required us to collaborate with the upstream communities with the following agenda. Firstly, we wanted to assure ourselves that none of these implementations regresses on older features, i.e., that no existing feature will be lost because of a new protocol addition, nor that the semantics of the previous supported versions will change significantly to disrupt existing software.
Secondly, we wanted the support for the new protocol to be not only compatible with the implementations we were shipping, but also compatible with popular third party implementations which would potentially interoperate with our implementations.
Thirdly, we wanted to make sure that the protocol is usable without changes by the whole set of applications shipped by the operating system.
For the first two goals, we developed a testing tool to check for correctness of TLS implementations that includes a comprehensive test suite for main and corner use-cases of TLS 1.3 and earlier protocols. With the tests for earlier protocols, we believe that none of our implementations regresses in its support for older protocols after the addition of TLS 1.3, and with the TLS 1.3 tests we believe that not only the protocol is implemented correctly, but also that corner cases are handled in a graceful way, and bugs or security issues are detected early.
This tool is named tlsfuzzer and is available as an open source project on GitHub. This testing tool has been not only used to check our shipped implementations and report fixes and issues back to upstream communities, but it is now integrated with the upstream gnutls and NSS projects, making sure that the benefits of such testing are spread in the wider open source ecosystem.
Furthermore, to address our final goal, we tested applications shipped in Red Hat Enterprise Linux 8 test suites with TLS 1.3 enabled. This, although it initially created some friction with multiple development teams who were seeing arbitrary failures to their applications, it was evident to all in the end that the issues uncovered were either existing issues in the test suites, or were issues due to semantic changes in APIs of our security libraries.
The most prominent were the Python test suite failures which were triggered by an implicit enablement of post-handshake authentication in OpenSSL. At the time the pre-released version of OpenSSL (1.1.1pre8) enabled the post-handshake authentication feature in TLS 1.3 implicitly. This, while it made the adoption of the feature transparent, it broke the expectations in applications not written with TLS 1.3 in mind. Our reports to the OpenSSL upstream community, and their prompt reaction helped ship software that is backwards-compatible with existing applications. Most importantly, however, it means that there should be no applications which disable the TLS 1.3 protocol because of incompatibilities with new implicit API changes.
Moreover, this testing uncovered issues with new algorithms used by TLS 1.3, such as Rivest Shamir Adleman Signature Scheme with Appendix - Probabilistic Signature Scheme (RSASSA-PSS) which was unsupported by the open source smart card driver OpenSC, as well as an overall industry-wide problematic treatment of certificates with RSASSA-PSS. The issue with RSASSA-PSS in certificates was quite fundamental due to their unique and complex design, and was ultimately addressed by the TLS working group by making the RSASSA-PSS in certificates optional. On the smart card front, our contributions to the OpenSC project means that smart cards continue to work as expected with TLS 1.3 on Enterprise Linux 8 without requiring any changes to existing applications, provided that the underlying hardware does support RSASSA-PSS.
TLS 1.3 in practice
As previously mentioned, this version of the protocol is a fundamental redesign. What does that mean in practice?
Deprecation of old cryptographic methods
One of the most visible changes is that TLS 1.3 negotiates new ciphersuites. This is caused by the fact that all of the previously defined ciphersuites are unusable in TLS 1.3; they can’t be negotiated.
This is in contrast to TLS 1.2, which was backwards compatible to SSL 3; all ciphers that were defined for use with SSL 3 could be negotiated in a TLS 1.2 connection. This change implies that any application expecting to negotiate a specific ciphersuite will need to be updated to take the negotiated TLS version into account. The upside is that there is only one cipher that is weaker than the rest–the IoT-targeting TLS_AES_128_CCM_8_SHA256 – but it is only weak against online attacks on data integrity, not data confidentiality. This cipher is disabled by default by all core crypto libraries in RHEL, including when the system is using the LEGACY crypto policy mode.
This change in ciphersuites negotiation also removed support for some of the more obscure ciphers, like IDEA, Camellia, ARIA, etc. Given that it’s impossible to implement TLS 1.3 without supporting either AES or Chacha20 based ciphersuites, environments that depend on other ciphers are unlikely to negotiate TLS 1.3, and they will likely automatically downgrade to TLS 1.2.
Additionally, some of the cryptographic key exchange methods were deprecated by this new version of the protocol. The most common one is the RSA key exchange. As this key exchange has been the source of many security vulnerabilities–the original Bleichenbacher attack and many iterations and improvements on it, DROWN, BERserk, etc.–it has been completely removed from TLS 1.3.
In practice this means that it is not possible to decrypt any TLS 1.3 session by using just the server’s private key. It’s still possible to decrypt those connections using the NSS SSLKEYLOGFILE file format. Thankfully, that method was adopted by GnuTLS (using the same environment variable to control its use) and OpenSSL (where a special API needs to be called by the TLS-using application; some applications, like curl, also do use the SSLKEYLOGFILE environment variable to enable it though). Note that because much more of the handshake is encrypted (including server and client certificates), the ability to decrypt the messages is much more important than with previous versions.
Some of the more obscure key exchange methods, like Digital Signature Algorithm (DSA), Kerberos (KRB5) and Secure Remote Password (SRP) were completely removed from the protocol. Applications that depend on these methods, may have to disable support for TLS 1.3. But given that KRB5 wasn’t updated to use AES, SRP does not use the modern AES-GCM ciphers and there are no known publicly trusted DSA certificates, we do not expect significant impact on existing deployments. Similarly to deprecated ciphers, to continue using the deprecated key exchange methods, it will be necessary to downgrade connections to TLS 1.2.
Lastly, RSA signatures included in TLS messages cannot use the original signature scheme defined in the PKCS#1 v1.5 standard, but must use the new RSASSA-PSS defined in 2003 in the PKCS#1 v2.1 standard. For signature verification, that doesn’t change much, as this is an integral part of TLS 1.3, so all implementations are able to verify them.
Signature generation is more problematic, as the private key may be stored in a smartcard or in Hardware Security Module (HSM) that simply does not support this new standard. Again, to work around this issue, it may be necessary to disable TLS 1.3. The longer term solution is to migrate to ECDSA (as that signature format is the same in TLS 1.2 and TLS 1.3), or obtain new hardware that properly supports RSASSA-PSS.
New features in TLS 1.3
The biggest change in TLS 1.3 is the reduction of the number of required round-trips needed to perform a handshake between client and server. With TLS 1.2 and earlier, 2 full round-trips were necessary, while in TLS 1.3 only 1 is needed. This feature will benefit any application right away, as it doesn’t require any code change. This new design also means that more of the handshake is encrypted, including server certificates. For devices monitoring the connection, all TLS 1.3 handshakes will look like session resumption handshakes from earlier versions of the protocol (the protocol version is now negotiated using an extension, not using the version numbers included in the main body of Client Hello and Server Hello messages).
Session resumption using tickets has been slightly changed–while in TLS 1.2 and earlier the ticket was sent in the handshake (applications could expect its presence in session data as soon as the handshake was finished)–in TLS 1.3 the session tickets are sent after the handshake has been completed. In practice, it means that the application needs to read some data from the connection before it will be able to attempt to resume a session.
Another more significant change is that tickets are now single-use; servers that expect the clients to open multiple parallel connections will send multiple tickets, while clients will have to slowly ramp up the number of connections. For example, with a server that sends 2 tickets, the client will have to spend at least 3 round-trips to have at least 4 parallel connections opened. At the same time, session resumption is less critical in TLS 1.3 as its latency and computational requirements are substantially similar as for a full handshake—the only difference is that the server doesn’t sign the handshake and the client doesn’t need to verify a signature—the Diffie-Hellman (DHE) key exchange is still performed in default configurations.
There are also a few new features that require the use of new APIs.
The first is 0-RTT, which allows an application to skip a round-trip by sending application data to the server (like an HTTP GET request) inside the initial handshake during session resumption. It has much weaker replay protections, so it should not be employed in general use cases, only when weaker replay protection does not matter.
The other two, KeyUpdate and client post handshake authentication, are related as they are provided as replacement for session renegotiation – another mechanism removed from TLS 1.3. KeyUpdate messages cause a refresh of the keys used for encrypting and authenticating the connection. When the connection uses AES ciphers, KeyUpdate needs to be used about every 24 million exchanged records (approximately once every 362GiB of data exchanged). Applications that transfer such large amounts of data in a single connection will need to use APIs to request KeyUpdate before reaching those limits.
Post handshake authentication must be explicitly advertised by the client during the handshake. It is currently unsupported in Chrome, will be supported in Firefox 68 (it will be necessary to set the “security.tls.enable_post_handshake_auth” about:config variable to true to enable it), is supported in curl 7.62.0 (and was backported to curl-7.61.1-5.el8) and requires the use of special flag in Python (setting SSLContext.post_handshake_auth to True in python 3.7.1, or python3-3.6.6-19.el8). This means that web sites that require client authentication only for some resources may need to downgrade to TLS 1.2 or require the use of specific client software by the users. Solutions that require client certificate based authentication only for specific virtual hosts will continue to work after the upgrade to TLS 1.3.
Deployment of TLS 1.3 will bring tangible benefits to users in shape of lower latency and guaranteed security baseline. As the first fundamental redesign of the TLS protocol in over 20 years, it does mean that it may require some new approaches for administrators and updates to applications using it. The work we performed at Red Hat together with the greater community of TLS users should reduce the amount of friction that can be expected when deploying TLS 1.3. We encourage you to test your applications using Red Hat Enterprise Linux 8, the first enterprise Linux distribution to ship the TLS 1.3 protocol fully integrated into the operating system.