あどけない話

Internet technologies

Releasing tls library version 2.0.0 in Haskell

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":

  • CBC ciphers
  • RC4 and 3DES
  • DSS(digital signature standard)

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 and StritData 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.