I needed to implement the session ticket mechanism for my project. In addition to this coding, I decided to improve the tls
library in Haskell drastically. So, I have spent three months to do so and finally released tls
vresion 2.0.0. This version is secure by default and its code readability is improved. This article explains what changed.
Removing insecure stuff
tls
version 1.9.0 supports TLS 1.0 and TLS 1.1 in addition to TLS 1.2 and TLS 1.3. RFC 8996 deprecates TLS 1.0 and TLS 1.1. So, they are removed from tls
.
TLS 1.2 is considered secure if configured correctly while TLS 1.3 is considered secure by design. To ensure secure configuration, the followings are removed according to "Deprecating Obsolete Key Exchange Methods in TLS 1.2":
The current cipher suites for TLS 1.2 are only:
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_AES_128_CCM
- TLS_ECDHE_ECDSA_WITH_AES_256_CCM
- TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
- TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
To prevent the triple handshake attack, the extended main secret defined by RFC7627 is necessary. supportedExtendedMasterSec
was default to AllowEMS
. It is renamed to supportedExtendedMainSecret
and its default value is set to RequireEMS
.
I believe that your code can be built without any modifications if you don't customize parameters heavily. If your code cannot be built, I'm sorry, but this breaking changes are intentional to tell that you are using insure parameters for TLS 1.2.
Catching up RFC8446bis
TLS 1.3 is defined in RFC8466 and it is being revised in RFC8466bis. Important changes are:
- The word "master" is renamed to "main".
general_error
alert is defined.
tls
v2.0.0 catches up RFC8466 bis as much as possible.
Improving API
To send early data in TLS 1.3, clientEarlyData
should be used in tls
version 1.9.0. Fixed string can be passed through this interface but it is not feasible for real usage since applications decide early data dynamically. With tls
version 2.0.0, sendData
can now send early data if clientUseEarlyData
is set to True
.
Client's handshake
for TLS 1.3 can now receive the alert of client authentication failure.
Client's bye
can now receive NewSessionTicket in TLS 1.3.
Refactoring
handshake
was monolithic. To follow the handshake diagram of TLS 1.2 and 1.3, its internal is divided. The result code for TLS 1.2 client looks:
handshake cparams ctx groups mparams = do ... crand <- sendClientHello cparams ctx groups mparams pskinfo ... (ver, hss, hrr) <- receiveServerHello cparams ctx mparams ... case ver of TLS13 -> ... _ -> do recvServerFirstFlight12 cparams ctx hss sendClientSecondFlight12 cparams ctx recvServerSecondFlight12 ctx
The test framework is switched from tasty
to hspec
. The quality of each test case is improved.
Also, the following modifications are done:
- The code is now formatted with
fourmolu
. PatternSynonyms
is introduced for extensibility.- The
Strict
andStritData
pragma are specified.
Session Manager
tls
1.9.0 has an abstraction for session management called SessionManager
:
data SessionManager { sessionResume :: SessionID -> IO (Maybe SessionData) , sessionResumeOnlyOnce :: SessionID -> IO (Maybe SessionData) , sessionEstablish :: SessionID -> SessionData -> IO () , sessionInvalidate :: SessionID -> IO () }
Network.TLS.SessionManager
in tls-session-manager
version 0.0.4 provides SessionManager
for in-memory session DB. When implementing the session ticket mechanism, it appeared that this abstraction is not good enough since there are no way to return tickets. So, SessionManager
in tls
version 2.0.0 is now:
data SessionManager { sessionResume :: SessionID -> IO (Maybe SessionData) , sessionResumeOnlyOnce :: SessionID -> IO (Maybe SessionData) , sessionEstablish :: SessionID -> SessionData -> IO (Myabe Ticket) , sessionInvalidate :: SessionID -> IO () , sessionUseTicket :: Bool }
Network.TLS.SessionTicket
is finally implemented in version 0.0.5.
Interoperability test
To test interoperability with other implementation, I use tls-simpleclient
and tls-simpleserver
in tls-debug
. Unfortunately, I don't have the upload permission for tls-debug
to Hackage. Also, it's very inconvenient to build them since they are in the separate package. So, I imported them into the util
directory of tls
and renamed to client
and server
. To build them, specify the devel
flag to cabal
or your favorite command.
client
and server
are tested with OpenSSL and gnutls both for TLS 1.2 and 1.3.