diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Change log for "tls"
 
+## Version 2.2.2
+
+* A new architecture to calculate receiver's transcript hash with wire
+  format.
+  [#515](https://github.com/haskell-tls/hs-tls/pull/515)
+* Enabling compressed certificate on the client side again.
+
 ## Version 2.2.1
 
 * Disabling compressed certificate on the client side.
diff --git a/Network/TLS/Context.hs b/Network/TLS/Context.hs
--- a/Network/TLS/Context.hs
+++ b/Network/TLS/Context.hs
@@ -112,7 +112,7 @@
     getTLSCommonParams :: a -> CommonParams
     getTLSRole :: a -> Role
     doHandshake :: a -> Context -> IO ()
-    doHandshakeWith :: a -> Context -> Handshake -> IO ()
+    doHandshakeWith :: a -> Context -> HandshakeR -> IO ()
     doRequestCertificate :: a -> Context -> IO Bool
     doPostHandshakeAuthWith :: a -> Context -> Handshake13 -> IO ()
 
diff --git a/Network/TLS/Context/Internal.hs b/Network/TLS/Context/Internal.hs
--- a/Network/TLS/Context/Internal.hs
+++ b/Network/TLS/Context/Internal.hs
@@ -166,7 +166,7 @@
 
 data RoleParams = RoleParams
     { doHandshake_ :: Context -> IO ()
-    , doHandshakeWith_ :: Context -> Handshake -> IO ()
+    , doHandshakeWith_ :: Context -> HandshakeR -> IO ()
     , doRequestCertificate_ :: Context -> IO Bool
     , doPostHandshakeAuthWith_ :: Context -> Handshake13 -> IO ()
     }
@@ -271,11 +271,13 @@
 
 data PendingRecvAction
     = -- | simple pending action. The first 'Bool' is necessity of alignment.
-      -- The second bool is update transcript hash.
-      PendingRecvAction Bool Bool (Handshake13 -> IO ())
+      PendingRecvAction Bool (Handshake13 -> IO ())
+    | PendingRecvActionSelfUpdate Bool (Handshake13R -> IO ())
     | -- | pending action taking transcript hash up to preceding message
       --   The first 'Bool' is necessity of alignment.
-      PendingRecvActionHash Bool (TranscriptHash -> Handshake13 -> IO ())
+      PendingRecvActionHash
+        Bool
+        (TranscriptHash -> Handshake13 -> IO ())
 
 updateMeasure :: Context -> (Measurement -> Measurement) -> IO ()
 updateMeasure ctx = modifyIORef' (ctxMeasurement ctx)
diff --git a/Network/TLS/Core.hs b/Network/TLS/Core.hs
--- a/Network/TLS/Core.hs
+++ b/Network/TLS/Core.hs
@@ -212,10 +212,10 @@
     pkt <- recvPacket12 ctx
     either (onError terminate12) process pkt
   where
-    process (Handshake [ch@ClientHello{}]) =
-        handshakeWith ctx ch >> recvData12 ctx
-    process (Handshake [hr@HelloRequest]) =
-        handshakeWith ctx hr >> recvData12 ctx
+    process (Handshake [ch@ClientHello{}] [b]) =
+        handshakeWith ctx (ch, b) >> recvData12 ctx
+    process (Handshake [hr@HelloRequest] [b]) =
+        handshakeWith ctx (hr, b) >> recvData12 ctx
     -- UserCanceled should be followed by a close_notify.
     -- fixme: is it safe to call recvData12?
     process (Alert [(AlertLevel_Warning, UserCanceled)]) = return B.empty
@@ -260,8 +260,8 @@
                 ("received fatal error: " ++ show desc)
                 (Error_Protocol "remote side fatal error" desc)
             )
-    process (Handshake13 hs) = do
-        loopHandshake13 hs
+    process (Handshake13 hs bs) = do
+        loopHandshake13 $ zip hs bs
         recvData13 ctx
     -- when receiving empty appdata, we just retry to get some data.
     process (AppData13 "") = recvData13 ctx
@@ -299,7 +299,7 @@
     loopHandshake13 [] = return ()
     -- fixme: some implementations send multiple NST at the same time.
     -- Only the first one is used at this moment.
-    loopHandshake13 (NewSessionTicket13 life add nonce (SessionIDorTicket_ ticket) exts : hs) = do
+    loopHandshake13 ((NewSessionTicket13 life add nonce (SessionIDorTicket_ ticket) exts, _b) : hbs) = do
         role <- usingState_ ctx S.getRole
         unless (role == ClientRole) $ do
             let reason = "Session ticket is allowed for client only"
@@ -328,16 +328,16 @@
             let ticket' = B.copy ticket
             void $ sessionEstablish (sharedSessionManager $ ctxShared ctx) ticket' sdata
             modifyTLS13State ctx $ \st -> st{tls13stRecvNST = True}
-        loopHandshake13 hs
-    loopHandshake13 (KeyUpdate13 mode : hs) = do
-        let multipleKeyUpdate = any isKeyUpdate13 hs
+        loopHandshake13 hbs
+    loopHandshake13 ((KeyUpdate13 mode, _b) : hbs) = do
+        let multipleKeyUpdate = any (\(h, _) -> isKeyUpdate13 h) hbs
         when multipleKeyUpdate $ do
             let reason = "Multiple KeyUpdate is not allowed in one record"
             terminate13 ctx (Error_Misc reason) AlertLevel_Fatal UnexpectedMessage reason
         when (ctxQUICMode ctx) $ do
             let reason = "KeyUpdate is not allowed for QUIC"
             terminate13 ctx (Error_Misc reason) AlertLevel_Fatal UnexpectedMessage reason
-        checkAlignment ctx hs
+        checkAlignment ctx
         established <- ctxEstablished ctx
         -- Though RFC 8446 Sec 4.6.3 does not clearly says,
         -- unidirectional key update is legal.
@@ -350,16 +350,16 @@
                 -- packet to be sent by another thread before the Tx state is
                 -- updated.
                 when (mode == UpdateRequested) $ withWriteLock ctx $ do
-                    sendPacket13 ctx $ Handshake13 [KeyUpdate13 UpdateNotRequested]
+                    sendPacket13 ctx $ Handshake13 [KeyUpdate13 UpdateNotRequested] []
                     keyUpdate ctx getTxRecordState setTxRecordState
-                loopHandshake13 hs
+                loopHandshake13 hbs
             else do
                 let reason = "received key update before established"
                 terminate13 ctx (Error_Misc reason) AlertLevel_Fatal UnexpectedMessage reason
     -- Client only
-    loopHandshake13 (h@CertRequest13{} : hs) =
-        postHandshakeAuthWith ctx h >> loopHandshake13 hs
-    loopHandshake13 (h : hs) = do
+    loopHandshake13 ((h@CertRequest13{}, _b) : hbs) =
+        postHandshakeAuthWith ctx h >> loopHandshake13 hbs
+    loopHandshake13 (hb@(h, _) : hbs) = do
         rtt0 <- tls13st0RTT <$> getTLS13State ctx
         when rtt0 $ case h of
             ServerHello13 SH{..} ->
@@ -368,8 +368,8 @@
                     let reason = "HRR is not allowed for 0-RTT"
                     terminate13 ctx (Error_Misc reason) AlertLevel_Fatal UnexpectedMessage reason
             _ -> return ()
-        cont <- popAction ctx h hs
-        when cont $ loopHandshake13 hs
+        cont <- popAction ctx hb
+        when cont $ loopHandshake13 hbs
 
 recvHS13 :: Context -> IO Bool -> IO ()
 recvHS13 ctx breakLoop = do
@@ -380,8 +380,8 @@
     -- UserCanceled MUST be followed by a CloseNotify.
     process (Alert13 [(AlertLevel_Warning, CloseNotify)]) = tryBye ctx >> setEOF ctx
     process (Alert13 [(AlertLevel_Fatal, _desc)]) = setEOF ctx
-    process (Handshake13 hs) = do
-        loopHandshake13 hs
+    process (Handshake13 hs bs) = do
+        loopHandshake13 $ zip hs bs
         stop <- breakLoop
         unless stop $ recvHS13 ctx breakLoop
     process _ = recvHS13 ctx breakLoop
@@ -389,7 +389,7 @@
     loopHandshake13 [] = return ()
     -- fixme: some implementations send multiple NST at the same time.
     -- Only the first one is used at this moment.
-    loopHandshake13 (NewSessionTicket13 life add nonce (SessionIDorTicket_ ticket) exts : hs) = do
+    loopHandshake13 ((NewSessionTicket13 life add nonce (SessionIDorTicket_ ticket) exts, _b) : hbs) = do
         role <- usingState_ ctx S.getRole
         unless (role == ClientRole) $ do
             let reason = "Session ticket is allowed for client only"
@@ -415,17 +415,17 @@
             let ticket' = B.copy ticket
             void $ sessionEstablish (sharedSessionManager $ ctxShared ctx) ticket' sdata
             modifyTLS13State ctx $ \st -> st{tls13stRecvNST = True}
-        loopHandshake13 hs
-    loopHandshake13 (h : hs) = do
-        cont <- popAction ctx h hs
-        when cont $ loopHandshake13 hs
+        loopHandshake13 hbs
+    loopHandshake13 (hb : hbs) = do
+        cont <- popAction ctx hb
+        when cont $ loopHandshake13 hbs
 
 terminate13
     :: Context -> TLSError -> AlertLevel -> AlertDescription -> String -> IO a
 terminate13 ctx = terminateWithWriteLock ctx (sendPacket13 ctx . Alert13)
 
-popAction :: Context -> Handshake13 -> [Handshake13] -> IO Bool
-popAction ctx h hs = do
+popAction :: Context -> Handshake13R -> IO Bool
+popAction ctx hb@(h, _b) = do
     mPendingRecvAction <- popPendingRecvAction ctx
     case mPendingRecvAction of
         Nothing -> return False
@@ -435,14 +435,17 @@
             withWriteLock ctx $
                 handleException ctx $ do
                     case action of
-                        PendingRecvAction needAligned update pa -> do
-                            when needAligned $ checkAlignment ctx hs
-                            when update $ void $ updateTranscriptHash13 ctx h
+                        PendingRecvAction needAligned pa -> do
+                            when needAligned $ checkAlignment ctx
+                            updateTranscriptHash13 ctx hb
                             pa h
+                        PendingRecvActionSelfUpdate needAligned pa -> do
+                            when needAligned $ checkAlignment ctx
+                            pa hb
                         PendingRecvActionHash needAligned pa -> do
-                            when needAligned $ checkAlignment ctx hs
+                            when needAligned $ checkAlignment ctx
                             d <- transcriptHash ctx "Pending action"
-                            void $ updateTranscriptHash13 ctx h
+                            updateTranscriptHash13 ctx hb
                             pa d h
                     -- Client: after receiving SH, app data is coming.
                     -- this loop tries to receive it.
@@ -451,8 +454,8 @@
                     sendCFifNecessary ctx
             return True
 
-checkAlignment :: Context -> [Handshake13] -> IO ()
-checkAlignment ctx _hs = do
+checkAlignment :: Context -> IO ()
+checkAlignment ctx = do
     complete <- isRecvComplete ctx
     unless complete $ do
         let reason = "received message not aligned with record boundary"
diff --git a/Network/TLS/Crypto.hs b/Network/TLS/Crypto.hs
--- a/Network/TLS/Crypto.hs
+++ b/Network/TLS/Crypto.hs
@@ -7,6 +7,7 @@
     HashCtx,
     hashInit,
     hashUpdate,
+    hashUpdates,
     hashUpdateSSL,
     hashFinal,
     module Network.TLS.Crypto.DH,
diff --git a/Network/TLS/Handshake.hs b/Network/TLS/Handshake.hs
--- a/Network/TLS/Handshake.hs
+++ b/Network/TLS/Handshake.hs
@@ -25,9 +25,9 @@
 -- This is called automatically by 'recvData', in a context where the read lock
 -- is already taken.  So contrary to 'handshake' above, here we only need to
 -- call withWriteLock.
-handshakeWith :: MonadIO m => Context -> Handshake -> m ()
-handshakeWith ctx hs =
+handshakeWith :: MonadIO m => Context -> HandshakeR -> m ()
+handshakeWith ctx hsr =
     liftIO $
         withWriteLock ctx $
             handleException ctx $
-                doHandshakeWith_ (ctxRoleParams ctx) ctx hs
+                doHandshakeWith_ (ctxRoleParams ctx) ctx hsr
diff --git a/Network/TLS/Handshake/Client.hs b/Network/TLS/Handshake/Client.hs
--- a/Network/TLS/Handshake/Client.hs
+++ b/Network/TLS/Handshake/Client.hs
@@ -26,8 +26,9 @@
 
 ----------------------------------------------------------------
 
-handshakeClientWith :: ClientParams -> Context -> Handshake -> IO ()
-handshakeClientWith cparams ctx HelloRequest = handshakeClient cparams ctx
+handshakeClientWith
+    :: ClientParams -> Context -> HandshakeR -> IO ()
+handshakeClientWith cparams ctx (HelloRequest, _b) = handshakeClient cparams ctx -- xxx
 handshakeClientWith _ _ _ =
     throwCore $
         Error_Protocol
@@ -76,7 +77,7 @@
     --------------------------------
     -- Receiving ServerHello
     unless async $ do
-        (ver, hss, hrr) <- receiveServerHello cparams ctx mparams
+        (ver, hbs, hrr) <- receiveServerHello cparams ctx mparams
         --------------------------------
         -- Switching to HRR, TLS 1.2 or TLS 1.3
         case ver of
@@ -93,7 +94,7 @@
                             "server denied TLS 1.3 when connecting with early data"
                             HandshakeFailure
                 | otherwise -> do
-                    recvServerFirstFlight12 cparams ctx hss
+                    recvServerFirstFlight12 cparams ctx hbs
                     sendClientSecondFlight12 cparams ctx
                     recvServerSecondFlight12 cparams ctx
   where
diff --git a/Network/TLS/Handshake/Client/ClientHello.hs b/Network/TLS/Handshake/Client/ClientHello.hs
--- a/Network/TLS/Handshake/Client/ClientHello.hs
+++ b/Network/TLS/Handshake/Client/ClientHello.hs
@@ -127,17 +127,22 @@
                 Nothing -> do
                     if hrr
                         then do
-                            chI <- fromJust <$> usingHState ctx getClientHello
+                            (chI, _) <- fromJust <$> usingHState ctx getClientHello
                             let ch0' = ch0{chExtensions = take 1 (chExtensions chI) ++ drop 1 (chExtensions ch0)}
-                            usingHState ctx $ setClientHello ch0'
+                            -- [] will be overridden via
+                            -- encodeUpdateTranscriptHash12
+                            usingHState ctx $ setClientHello ch0' []
                             return ch0'
                         else do
                             gEchExt <- greasingEchExt
                             let ch0' = ch0{chExtensions = gEchExt : drop 1 (chExtensions ch0)}
-                            usingHState ctx $ setClientHello ch0'
+                            -- [] will be overridden via
+                            -- encodeUpdateTranscriptHash12
+                            usingHState ctx $ setClientHello ch0' []
                             return ch0'
                 Just echParams -> do
-                    usingHState ctx $ setClientHello ch0
+                    let encoded = encodeHandshake $ ClientHello ch0
+                    usingHState ctx $ setClientHello ch0 [encoded]
                     mcrandO <- usingHState ctx getOuterClientRandom
                     crandO <- case mcrandO of
                         Nothing -> clientRandom ctx
@@ -148,9 +153,11 @@
                     mpskExt <- randomPreSharedKeyExt
                     createEncryptedClientHello ctx ch0 echParams crandO mpskExt
             else do
-                usingHState ctx $ setClientHello ch0
+                -- [] will be overridden via
+                -- encodeUpdateTranscriptHash12
+                usingHState ctx $ setClientHello ch0 []
                 return ch0
-    sendPacket12 ctx $ Handshake [ClientHello ch]
+    sendPacket12 ctx $ Handshake [ClientHello ch] []
     mEarlySecInfo <- case rtt0info of
         Nothing -> return Nothing
         Just info -> Just <$> getEarlySecretInfo info
@@ -181,8 +188,8 @@
             , {- 0x0d -} signatureAlgExt
             , {- 0x10 -} alpnExt
             , {- 0x17 -} emsExt
-            , --          , {- 0x1b -} compCertExt
-              {- 0x1c -} recordSizeLimitExt
+            , {- 0x1b -} compCertExt
+            , {- 0x1c -} recordSizeLimitExt
             , {- 0x23 -} sessionTicketExt
             , {- 0x2a -} earlyDataExt
             , {- 0x2b -} versionExt
@@ -238,7 +245,7 @@
                 then Nothing
                 else Just $ toExtensionRaw ExtendedMainSecret
 
-    --    compCertExt = return $ Just $ toExtensionRaw (CompressCertificate [CCA_Zlib])
+    compCertExt = return $ Just $ toExtensionRaw (CompressCertificate [CCA_Zlib])
 
     recordSizeLimitExt = case limitRecordSize $ sharedLimit $ ctxShared ctx of
         Nothing -> return Nothing
diff --git a/Network/TLS/Handshake/Client/ServerHello.hs b/Network/TLS/Handshake/Client/ServerHello.hs
--- a/Network/TLS/Handshake/Client/ServerHello.hs
+++ b/Network/TLS/Handshake/Client/ServerHello.hs
@@ -35,12 +35,12 @@
     :: ClientParams
     -> Context
     -> Maybe (ClientRandom, Session, Version)
-    -> IO (Version, [Handshake], Bool)
+    -> IO (Version, [HandshakeR], Bool)
 receiveServerHello cparams ctx mparams = do
     chSentTime <- getCurrentTimeFromBase
-    (sh, hss) <- recvSH
+    (shb@(sh, _), hbs) <- recvSH
     processServerHello cparams ctx sh
-    void $ updateTranscriptHash12 ctx sh
+    updateTranscriptHash12 ctx shb
     setRTT ctx chSentTime
     ver <- usingState_ ctx getVersion
     unless (maybe True (\(_, _, v) -> v == ver) mparams) $
@@ -51,7 +51,7 @@
     -- False otherwise.  For 2nd server hello, getTLS13HR returns
     -- False since it is NOT HRR.
     hrr <- usingState_ ctx getTLS13HRR
-    return (ver, hss, hrr)
+    return (ver, hbs, hrr)
   where
     recvSH = do
         epkt <- recvPacket12 ctx
@@ -59,7 +59,7 @@
             Left e -> throwCore e
             Right pkt -> case pkt of
                 Alert a -> throwAlert a
-                Handshake (h : hs) -> return (h, hs)
+                Handshake (h : hs) (b : bs) -> return ((h, b), zip hs bs)
                 _ -> unexpected (show pkt) (Just "handshake")
     throwAlert a =
         throwCore $
@@ -179,7 +179,7 @@
             transitTranscriptHashI ctx "transitI" usedHash isHRR
             accepted <- checkECHacceptance ctx isHRR usedHash sh
             when accepted $ do
-                CH{..} <- fromJust <$> usingHState ctx getClientHello
+                (CH{..}, _b) <- fromJust <$> usingHState ctx getClientHello
                 usingHState ctx $ setClientRandom chRandom -- inner random
             when (accepted && not isHRR) $ do
                 copyTranscriptHash ctx "copy"
diff --git a/Network/TLS/Handshake/Client/TLS12.hs b/Network/TLS/Handshake/Client/TLS12.hs
--- a/Network/TLS/Handshake/Client/TLS12.hs
+++ b/Network/TLS/Handshake/Client/TLS12.hs
@@ -32,14 +32,15 @@
 
 ----------------------------------------------------------------
 
-recvServerFirstFlight12 :: ClientParams -> Context -> [Handshake] -> IO ()
-recvServerFirstFlight12 cparams ctx hs = do
+recvServerFirstFlight12
+    :: ClientParams -> Context -> [HandshakeR] -> IO ()
+recvServerFirstFlight12 cparams ctx hbs = do
     resuming <- usingState_ ctx getTLS12SessionResuming
     if resuming
         then recvNSTandCCSandFinished ctx
         else do
             let st = RecvStateHandshake (expectCertificate cparams ctx)
-            runRecvStateHS ctx st hs
+            runRecvStateHS ctx st hbs
 
 expectCertificate :: ClientParams -> Context -> Handshake -> IO (RecvState IO)
 expectCertificate cparams ctx (Certificate (CertificateChain_ certs)) = do
@@ -151,7 +152,7 @@
             unless (null certs) $
                 usingHState ctx $
                     setClientCertSent True
-            sendPacket12 ctx $ Handshake [Certificate (CertificateChain_ cc)]
+            sendPacket12 ctx $ Handshake [Certificate (CertificateChain_ cc)] []
 
 ----------------------------------------------------------------
 
@@ -167,7 +168,7 @@
         _ ->
             throwCore $
                 Error_Protocol "client key exchange unsupported type" HandshakeFailure
-    sendPacket12 ctx $ Handshake [ClientKeyXchg ckx]
+    sendPacket12 ctx $ Handshake [ClientKeyXchg ckx] []
     mainSecret <- usingHState ctx setMainSec
     logKey ctx (MainSecret mainSecret)
 
@@ -283,4 +284,4 @@
         -- Fetch all handshake messages up to now.
         msgs <- usingHState ctx $ B.concat <$> getHandshakeMessages
         sigDig <- createCertificateVerify ctx ver pubKey mhashSig msgs
-        sendPacket12 ctx $ Handshake [CertVerify sigDig]
+        sendPacket12 ctx $ Handshake [CertVerify sigDig] []
diff --git a/Network/TLS/Handshake/Client/TLS13.hs b/Network/TLS/Handshake/Client/TLS13.hs
--- a/Network/TLS/Handshake/Client/TLS13.hs
+++ b/Network/TLS/Handshake/Client/TLS13.hs
@@ -147,12 +147,13 @@
             Nothing -> do
                 usingHState ctx $ setTLS13HandshakeMode PreSharedKey
                 usingHState ctx $ setTLS13RTT0Status RTT0Rejected
-expectEncryptedExtensions _ p = unexpected (show p) (Just "encrypted extensions")
+expectEncryptedExtensions _ h = unexpected (show h) (Just "encrypted extensions")
 
 ----------------------------------------------------------------
 -- not used in 0-RTT
 expectCertRequest
-    :: MonadIO m => ClientParams -> Context -> Handshake13 -> RecvHandshake13M m ()
+    :: MonadIO m
+    => ClientParams -> Context -> Handshake13 -> RecvHandshake13M m ()
 expectCertRequest cparams ctx (CertRequest13 token exts) = do
     processCertRequest13 ctx token exts
     recvHandshake13 ctx $ expectCertAndVerify cparams ctx
@@ -211,10 +212,11 @@
 ----------------------------------------------------------------
 -- not used in 0-RTT
 expectCertAndVerify
-    :: MonadIO m => ClientParams -> Context -> Handshake13 -> RecvHandshake13M m ()
+    :: MonadIO m
+    => ClientParams -> Context -> Handshake13 -> RecvHandshake13M m ()
 expectCertAndVerify cparams ctx (Certificate13 _ (CertificateChain_ cc) _) = processCertAndVerify cparams ctx cc
 expectCertAndVerify cparams ctx (CompressedCertificate13 _ (CertificateChain_ cc) _) = processCertAndVerify cparams ctx cc
-expectCertAndVerify _ _ p = unexpected (show p) (Just "server certificate")
+expectCertAndVerify _ _ h = unexpected (show h) (Just "server certificate")
 
 processCertAndVerify
     :: MonadIO m
@@ -231,11 +233,12 @@
 ----------------------------------------------------------------
 
 expectCertVerify
-    :: MonadIO m => Context -> PubKey -> TranscriptHash -> Handshake13 -> m ()
+    :: MonadIO m
+    => Context -> PubKey -> TranscriptHash -> Handshake13 -> m ()
 expectCertVerify ctx pubkey (TranscriptHash hChSc) (CertVerify13 (DigitallySigned sigAlg sig)) = do
     ok <- checkCertVerify ctx pubkey sigAlg sig hChSc
     unless ok $ decryptError "cannot verify CertificateVerify"
-expectCertVerify _ _ _ p = unexpected (show p) (Just "certificate verify")
+expectCertVerify _ _ _ h = unexpected (show h) (Just "certificate verify")
 
 ----------------------------------------------------------------
 
@@ -290,7 +293,7 @@
         runPacketFlight ctx $
             sendChangeCipherSpec13 ctx
     when (rtt0accepted && not (ctxQUICMode ctx)) $
-        sendPacket13 ctx (Handshake13 [EndOfEarlyData13])
+        sendPacket13 ctx (Handshake13 [EndOfEarlyData13] [])
     let clientHandshakeSecret = triClient hkey
     setTxRecordState ctx usedHash usedCipher clientHandshakeSecret
     sendClientFlight13 cparams ctx usedHash clientHandshakeSecret
@@ -344,7 +347,7 @@
                 certComp <- usingHState ctx getTLS13CertComp
                 loadClientData13 cc reqtoken certComp
         rawFinished <- makeFinished ctx usedHash baseKey
-        loadPacket13 ctx $ Handshake13 [rawFinished]
+        loadPacket13 ctx $ Handshake13 [rawFinished] []
     when (isJust mcc) $
         modifyTLS13State ctx $
             \st -> st{tls13stSentClientCert = True}
@@ -355,7 +358,7 @@
             cHashSigs = filter isHashSignatureValid13 $ supportedHashSignatures $ ctxSupported ctx
         let certtag = if certComp then CompressedCertificate13 else Certificate13
         loadPacket13 ctx $
-            Handshake13 [certtag token (CertificateChain_ chain) certExts]
+            Handshake13 [certtag token (CertificateChain_ chain) certExts] []
         case certs of
             [] -> return ()
             _ -> do
@@ -364,7 +367,7 @@
                 sigAlg <-
                     liftIO $ getLocalHashSigAlg ctx signatureCompatible13 cHashSigs pubKey
                 vfy <- makeCertVerify ctx pubKey sigAlg hChSc
-                loadPacket13 ctx $ Handshake13 [vfy]
+                loadPacket13 ctx $ Handshake13 [vfy] []
     --
     loadClientData13 _ _ _ =
         throwCore $
@@ -373,10 +376,11 @@
 ----------------------------------------------------------------
 ----------------------------------------------------------------
 
-postHandshakeAuthClientWith :: ClientParams -> Context -> Handshake13 -> IO ()
-postHandshakeAuthClientWith cparams ctx h@(CertRequest13 certReqCtx exts) =
+postHandshakeAuthClientWith
+    :: ClientParams -> Context -> Handshake13 -> IO ()
+postHandshakeAuthClientWith cparams ctx (CertRequest13 certReqCtx exts) =
     bracket (saveHState ctx) (restoreHState ctx) $ \_ -> do
-        void $ updateTranscriptHash13 ctx h
+        --        updateTranscriptHash13 ctx h b
         processCertRequest13 ctx certReqCtx exts
         (usedHash, _, level, applicationSecretN) <- getTxRecordState ctx
         unless (level == CryptApplicationSecret) $
@@ -403,15 +407,15 @@
 asyncServerHello13 cparams ctx groupSent chSentTime = do
     setPendingRecvActions
         ctx
-        [ PendingRecvAction True False expectServerHello
-        , PendingRecvAction True True (expectEncryptedExtensions ctx)
+        [ PendingRecvActionSelfUpdate True expectServerHello
+        , PendingRecvAction True (expectEncryptedExtensions ctx)
         , PendingRecvActionHash True expectFinishedAndSet
         ]
   where
-    expectServerHello sh = do
+    expectServerHello shb@(sh, _) = do
         setRTT ctx chSentTime
         processServerHello13 cparams ctx sh
-        void $ updateTranscriptHash13 ctx sh -- update by myself
+        updateTranscriptHash13 ctx shb -- update by myself
         void $ prepareSecondFlight13 ctx groupSent
     expectFinishedAndSet h sf = do
         expectFinished cparams ctx h sf
diff --git a/Network/TLS/Handshake/Common.hs b/Network/TLS/Handshake/Common.hs
--- a/Network/TLS/Handshake/Common.hs
+++ b/Network/TLS/Handshake/Common.hs
@@ -31,6 +31,7 @@
     --
     setPeerRecordSizeLimit,
     generateFinished,
+    encodeUpdateTranscriptHash12,
     updateTranscriptHash12,
     --
     startHandshake,
@@ -132,7 +133,7 @@
     enablePeerRecordLimit ctx
     ver <- usingState_ ctx getVersion
     verifyData <- VerifyData <$> generateFinished ctx ver role
-    sendPacket12 ctx (Handshake [Finished verifyData])
+    sendPacket12 ctx (Handshake [Finished verifyData] [])
     usingState_ ctx $ setVerifyDataForSend verifyData
     contextFlush ctx
 
@@ -141,11 +142,11 @@
     | RecvStateHandshake (Handshake -> m (RecvState m))
     | RecvStateDone
 
-recvPacketHandshake :: Context -> IO [Handshake]
+recvPacketHandshake :: Context -> IO [HandshakeR]
 recvPacketHandshake ctx = do
     pkts <- recvPacket12 ctx
     case pkts of
-        Right (Handshake l) -> return l
+        Right (Handshake hss bss) -> return $ zip hss bss
         Right x@(AppData _) -> do
             -- If a TLS13 server decides to reject RTT0 data, the server should
             -- skip records for RTT0 data up to the maximum limit.
@@ -161,16 +162,18 @@
 
 -- | process a list of handshakes message in the recv state machine.
 onRecvStateHandshake
-    :: Context -> RecvState IO -> [Handshake] -> IO (RecvState IO)
+    :: Context -> RecvState IO -> [HandshakeR] -> IO (RecvState IO)
 onRecvStateHandshake _ recvState [] = return recvState
-onRecvStateHandshake _ (RecvStatePacket f) hms = f (Handshake hms)
-onRecvStateHandshake ctx (RecvStateHandshake f) (x : xs) = do
-    let finished = isFinished x
-    unless finished $ void $ updateTranscriptHash12 ctx x
-    nstate <- f x
-    when finished $ void $ updateTranscriptHash12 ctx x
-    onRecvStateHandshake ctx nstate xs
-onRecvStateHandshake _ RecvStateDone _xs = unexpected "spurious handshake" Nothing
+onRecvStateHandshake _ (RecvStatePacket f) hbs = do
+    let (hss, bss) = unzip hbs
+    f (Handshake hss bss)
+onRecvStateHandshake ctx (RecvStateHandshake f) (hb@(h, _) : hbs) = do
+    let finished = isFinished h
+    unless finished $ void $ updateTranscriptHash12 ctx hb
+    nstate <- f h
+    when finished $ void $ updateTranscriptHash12 ctx hb
+    onRecvStateHandshake ctx nstate hbs
+onRecvStateHandshake _ _ _ = unexpected "spurious handshake" Nothing
 
 isFinished :: Handshake -> Bool
 isFinished Finished{} = True
@@ -184,8 +187,9 @@
         >>= onRecvStateHandshake ctx iniState
         >>= runRecvState ctx
 
-runRecvStateHS :: Context -> RecvState IO -> [Handshake] -> IO ()
-runRecvStateHS ctx iniState hs = onRecvStateHandshake ctx iniState hs >>= runRecvState ctx
+runRecvStateHS
+    :: Context -> RecvState IO -> [HandshakeR] -> IO ()
+runRecvStateHS ctx iniState hbs = onRecvStateHandshake ctx iniState hbs >>= runRecvState ctx
 
 ensureRecvComplete :: MonadIO m => Context -> m ()
 ensureRecvComplete ctx = do
diff --git a/Network/TLS/Handshake/Common13.hs b/Network/TLS/Handshake/Common13.hs
--- a/Network/TLS/Handshake/Common13.hs
+++ b/Network/TLS/Handshake/Common13.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE OverloadedStrings #-}
@@ -68,7 +69,6 @@
 import Network.TLS.Imports
 import Network.TLS.KeySchedule
 import Network.TLS.MAC
-import Network.TLS.Packet
 import Network.TLS.Packet13
 import Network.TLS.Parameters
 import Network.TLS.State
@@ -373,7 +373,8 @@
 
 ----------------------------------------------------------------
 
-newtype RecvHandshake13M m a = RecvHandshake13M (StateT [Handshake13] m a)
+newtype RecvHandshake13M m a
+    = RecvHandshake13M (StateT [Handshake13R] m a)
     deriving (Functor, Applicative, Monad, MonadIO)
 
 recvHandshake13
@@ -381,7 +382,7 @@
     => Context
     -> (Handshake13 -> RecvHandshake13M m a)
     -> RecvHandshake13M m a
-recvHandshake13 ctx f = getHandshake13 ctx >>= f
+recvHandshake13 ctx f = getHandshake13 ctx >>= \(h, _b) -> f h
 
 recvHandshake13hash
     :: MonadIO m
@@ -391,21 +392,22 @@
     -> RecvHandshake13M m a
 recvHandshake13hash ctx label f = do
     d <- transcriptHash ctx label
-    getHandshake13 ctx >>= f d
+    getHandshake13 ctx >>= \(h, _b) -> f d h
 
-getHandshake13 :: MonadIO m => Context -> RecvHandshake13M m Handshake13
+getHandshake13
+    :: MonadIO m => Context -> RecvHandshake13M m Handshake13R
 getHandshake13 ctx = RecvHandshake13M $ do
     currentState <- get
     case currentState of
-        (h : hs) -> found h hs
-        [] -> recvLoop
+        hb : hbs -> found hb hbs
+        _ -> recvLoop
   where
-    found h hs = liftIO (void $ updateTranscriptHash13 ctx h) >> put hs >> return h
+    found hb hbs = liftIO (updateTranscriptHash13 ctx hb) >> put hbs >> return hb
     recvLoop = do
         epkt <- liftIO (recvPacket13 ctx)
         case epkt of
-            Right (Handshake13 []) -> error "invalid recvPacket13 result"
-            Right (Handshake13 (h : hs)) -> found h hs
+            Right (Handshake13 [] _) -> error "invalid recvPacket13 result"
+            Right (Handshake13 (h : hs) (b : bs)) -> found (h, b) $ zip hs bs
             Right ChangeCipherSpec13 -> do
                 alreadyReceived <- liftIO $ usingHState ctx getCCS13Recv
                 if alreadyReceived
@@ -462,8 +464,8 @@
     -> Either ByteString (BaseSecret EarlySecret)
     -> IO (SecretPair EarlySecret)
 calculateEarlySecret ctx choice maux = do
-    ch <- fromJust <$> usingHState ctx getClientHello
-    let hCh = TranscriptHash $ hash usedHash $ encodeHandshake $ ClientHello ch
+    (_ch, b) <- fromJust <$> usingHState ctx getClientHello
+    let hCh = TranscriptHash $ hashChunks usedHash b
     let earlySecret = case maux of
             Right (BaseSecret sec) -> sec
             Left psk -> hkdfExtract usedHash zero psk
@@ -591,7 +593,7 @@
     :: (MonadFail m, MonadIO m)
     => Context -> Hash -> ServerHello -> ByteString -> m ByteString
 computeConfirm ctx usedHash sh label = do
-    CH{..} <- fromJust <$> liftIO (usingHState ctx getClientHello)
+    (CH{..}, _b) <- fromJust <$> liftIO (usingHState ctx getClientHello)
     TranscriptHash echConf <-
         transcriptHashWith ctx "ECH acceptance" $ encodeHandshake13 $ ServerHello13 sh
     let prk = hkdfExtract usedHash "" $ unClientRandom chRandom
diff --git a/Network/TLS/Handshake/Server.hs b/Network/TLS/Handshake/Server.hs
--- a/Network/TLS/Handshake/Server.hs
+++ b/Network/TLS/Handshake/Server.hs
@@ -31,12 +31,13 @@
 -- and call handshakeServerWith.
 handshakeServer :: ServerParams -> Context -> IO ()
 handshakeServer sparams ctx = liftIO $ do
-    hss <- recvPacketHandshake ctx
-    case hss of
-        [ch] -> handshake sparams ctx ch
-        _ -> unexpected (show hss) (Just "client hello")
+    hbs <- recvPacketHandshake ctx
+    case hbs of
+        chb : _ -> handshake sparams ctx chb
+        _ -> unexpected (show $ fst $ unzip hbs) (Just "client hello")
 
-handshakeServerWith :: ServerParams -> Context -> Handshake -> IO ()
+handshakeServerWith
+    :: ServerParams -> Context -> HandshakeR -> IO ()
 handshakeServerWith = handshake
 
 -- | Put the server context in handshake mode.
@@ -46,13 +47,14 @@
 --
 -- When the function returns, a new handshake has been succesfully negociated.
 -- On any error, a HandshakeFailed exception is raised.
-handshake :: ServerParams -> Context -> Handshake -> IO ()
-handshake sparams ctx (ClientHello ch) = do
-    (chosenVersion, chI, mcrnd) <- processClientHello sparams ctx ch
+handshake :: ServerParams -> Context -> HandshakeR -> IO ()
+handshake sparams ctx chb@(ClientHello ch, bs) = do
+    (chosenVersion, chI, mcrnd) <- processClientHello sparams ctx ch bs
     if chosenVersion == TLS13
         then do
             -- fixme: we should check if the client random is the same as
             -- that in the first client hello in the case of hello retry.
+            -- r0 :: Cipher, Hash, Bool
             (mClientKeyShare, r0, r1) <-
                 processClientHello13 sparams ctx chI
             case mClientKeyShare of
@@ -62,12 +64,17 @@
                     -- would be comming, which should be ignored.
                     handshakeServer sparams ctx
                 Just cliKeyShare -> do
+                    -- r2 :: ( SecretTriple ApplicationSecret
+                    --       , ClientTrafficSecret HandshakeSecret
+                    --       , Bool  -- authenticated
+                    --       , Bool) -- rtt0OK
                     r2 <-
                         sendServerHello13 sparams ctx cliKeyShare r0 r1 chI mcrnd
                     recvClientSecondFlight13 sparams ctx r2 chI
         else do
             r <-
                 processClientHello12 sparams ctx chI
+            updateTranscriptHash12 ctx chb
             resumeSessionData <-
                 sendServerHello12 sparams ctx r chI
             recvClientSecondFlight12 sparams ctx resumeSessionData
diff --git a/Network/TLS/Handshake/Server/ClientHello.hs b/Network/TLS/Handshake/Server/ClientHello.hs
--- a/Network/TLS/Handshake/Server/ClientHello.hs
+++ b/Network/TLS/Handshake/Server/ClientHello.hs
@@ -29,12 +29,13 @@
     :: ServerParams
     -> Context
     -> ClientHello
+    -> [ByteString]
     -> IO
         ( Version
         , ClientHello
         , Maybe ClientRandom -- Just for ECH to keep the outer one for key log
         )
-processClientHello sparams ctx ch@CH{..} = do
+processClientHello sparams ctx ch@CH{..} b = do
     established <- ctxEstablished ctx
     -- renego is not allowed in TLS 1.3
     when (established /= NotEstablished) $ do
@@ -127,10 +128,12 @@
             else return (Nothing, False)
     case mClientHello' of
         Just chI -> do
-            setupI ctx chI
+            -- chI is created from diff.
+            -- encodeHandshake is a MUST.
+            setupI ctx chI $ [encodeHandshake $ ClientHello chI]
             return (chosenVersion, chI, Just chRandom)
         _ -> do
-            setupO ctx ch
+            setupO ctx ch b
             when (chosenVersion == TLS13) $ do
                 let hasECHConf = not (null (sharedECHConfigList (serverShared sparams)))
                 when (hasECHConf && not receivedECH) $
@@ -141,19 +144,19 @@
                         setECHEE True
             return (chosenVersion, ch, Nothing)
 
-setupI :: Context -> ClientHello -> IO ()
-setupI ctx chI@CH{..} = do
+setupI :: Context -> ClientHello -> [ByteString] -> IO ()
+setupI ctx chI@CH{..} b = do
     hrr <- usingState_ ctx getTLS13HRR
     unless hrr $ startHandshake ctx TLS13 chRandom
-    usingHState ctx $ setClientHello chI
+    usingHState ctx $ setClientHello chI b
     let serverName = getServerName chExtensions
     maybe (return ()) (usingState_ ctx . setClientSNI) serverName
 
-setupO :: Context -> ClientHello -> IO ()
-setupO ctx ch@CH{..} = do
+setupO :: Context -> ClientHello -> [ByteString] -> IO ()
+setupO ctx ch@CH{..} b = do
     hrr <- usingState_ ctx getTLS13HRR
     unless hrr $ startHandshake ctx chVersion chRandom
-    usingHState ctx $ setClientHello ch
+    usingHState ctx $ setClientHello ch b
     let serverName = getServerName chExtensions
     maybe (return ()) (usingState_ ctx . setClientSNI) serverName
 
diff --git a/Network/TLS/Handshake/Server/ClientHello12.hs b/Network/TLS/Handshake/Server/ClientHello12.hs
--- a/Network/TLS/Handshake/Server/ClientHello12.hs
+++ b/Network/TLS/Handshake/Server/ClientHello12.hs
@@ -13,7 +13,6 @@
 import Network.TLS.Extension
 import Network.TLS.Handshake.Server.Common
 import Network.TLS.Handshake.Signature
-import Network.TLS.IO.Encode
 import Network.TLS.Imports
 import Network.TLS.Parameters
 import Network.TLS.State
@@ -46,7 +45,6 @@
             Error_Protocol "no cipher in common with the TLS 1.2 client" HandshakeFailure
     let usedCipher = onCipherChoosing hooks TLS12 ciphersFilteredVersion
     mcred <- chooseCreds usedCipher creds signatureCreds
-    void $ updateTranscriptHash12 ctx $ ClientHello ch
     return (usedCipher, mcred)
 
 checkSecureRenegotiation :: Context -> ClientHello -> IO ()
diff --git a/Network/TLS/Handshake/Server/ClientHello13.hs b/Network/TLS/Handshake/Server/ClientHello13.hs
--- a/Network/TLS/Handshake/Server/ClientHello13.hs
+++ b/Network/TLS/Handshake/Server/ClientHello13.hs
@@ -16,7 +16,6 @@
 import Network.TLS.Handshake.State
 import Network.TLS.IO.Encode
 import Network.TLS.Imports
-import Network.TLS.Packet
 import Network.TLS.Parameters
 import Network.TLS.Session
 import Network.TLS.State
@@ -30,8 +29,8 @@
     -> ClientHello
     -> IO
         ( Maybe KeyShareEntry
-        , (Cipher, Hash, Bool)
-        , (SecretPair EarlySecret, [ExtensionRaw], Bool, Bool)
+        , (Cipher, Hash, Bool) -- rtt0
+        , (SecretPair EarlySecret, [ExtensionRaw], Bool, Bool) -- authenticated, is0RTTvalid
         )
 processClientHello13 sparams ctx ch@CH{..} = do
     when
@@ -76,8 +75,8 @@
     mshare <- findKeyShare keyShares serverGroups
     let triple = (usedCipher, usedHash, rtt0)
     pskEarlySecret <- pskAndEarlySecret sparams ctx triple ch
-    clientHello <- fromJust <$> usingHState ctx getClientHello
-    void $ updateTranscriptHash12 ctx $ ClientHello clientHello
+    (ich, b) <- fromJust <$> usingHState ctx getClientHello
+    updateTranscriptHash12 ctx (ClientHello ich, b)
     return (mshare, triple, pskEarlySecret)
   where
     ciphersFilteredVersion = intersectCiphers chCiphers serverCiphers
@@ -104,9 +103,9 @@
 pskAndEarlySecret
     :: ServerParams
     -> Context
-    -> (Cipher, Hash, Bool)
+    -> (Cipher, Hash, Bool) -- rtt0
     -> ClientHello
-    -> IO (SecretPair EarlySecret, [ExtensionRaw], Bool, Bool)
+    -> IO (SecretPair EarlySecret, [ExtensionRaw], Bool, Bool) -- authenticated, is0RTTvalid
 pskAndEarlySecret sparams ctx (usedCipher, usedHash, rtt0) CH{..} = do
     (psk, binderInfo, is0RTTvalid) <- choosePSK
     earlyKey <- calculateEarlySecret ctx choice (Left psk)
@@ -156,9 +155,8 @@
 
     checkBinder _ Nothing = return []
     checkBinder earlySecret (Just (binder, n, tlen)) = do
-        ch <- fromJust <$> usingHState ctx getClientHello
-        let ech = encodeHandshake $ ClientHello ch
-            binder' = makePSKBinder earlySecret usedHash tlen ech
+        (_, b) <- fromJust <$> usingHState ctx getClientHello
+        let binder' = makePSKBinder earlySecret usedHash tlen $ B.concat b --- xxx
         unless (binder == binder') $
             decryptError "PSK binder validation failed"
         return [toExtensionRaw $ PreSharedKeyServerHello $ fromIntegral n]
diff --git a/Network/TLS/Handshake/Server/ServerHello12.hs b/Network/TLS/Handshake/Server/ServerHello12.hs
--- a/Network/TLS/Handshake/Server/ServerHello12.hs
+++ b/Network/TLS/Handshake/Server/ServerHello12.hs
@@ -42,7 +42,7 @@
             sh <- makeServerHello sparams ctx usedCipher mcred chExtensions serverSession
             build <- sendServerFirstFlight sparams ctx usedCipher mcred chExtensions
             let ff = ServerHello sh : build [ServerHelloDone]
-            sendPacket12 ctx $ Handshake ff
+            sendPacket12 ctx $ Handshake ff []
             contextFlush ctx
         Just sessionData -> do
             usingState_ ctx $ do
@@ -50,7 +50,7 @@
                 setTLS12SessionResuming True
             sh <-
                 makeServerHello sparams ctx usedCipher mcred chExtensions chSession
-            sendPacket12 ctx $ Handshake [ServerHello sh]
+            sendPacket12 ctx $ Handshake [ServerHello sh] []
             let mainSecret = sessionSecret sessionData
             usingHState ctx $ setMainSecret TLS12 ServerRole mainSecret
             logKey ctx $ MainSecret mainSecret
diff --git a/Network/TLS/Handshake/Server/ServerHello13.hs b/Network/TLS/Handshake/Server/ServerHello13.hs
--- a/Network/TLS/Handshake/Server/ServerHello13.hs
+++ b/Network/TLS/Handshake/Server/ServerHello13.hs
@@ -36,15 +36,15 @@
     :: ServerParams
     -> Context
     -> KeyShareEntry
-    -> (Cipher, Hash, Bool)
-    -> (SecretPair EarlySecret, [ExtensionRaw], Bool, Bool)
+    -> (Cipher, Hash, Bool) -- rtt0
+    -> (SecretPair EarlySecret, [ExtensionRaw], Bool, Bool) -- authenticated, is0RTTvalid
     -> ClientHello
     -> Maybe ClientRandom
     -> IO
         ( SecretTriple ApplicationSecret
         , ClientTrafficSecret HandshakeSecret
-        , Bool
-        , Bool
+        , Bool -- authenticated
+        , Bool -- rtt0OK
         )
 sendServerHello13 sparams ctx clientKeyShare (usedCipher, usedHash, rtt0) (earlyKey, preSharedKeyExt, authenticated, is0RTTvalid) CH{..} mOuterClientRandom = do
     let clientEarlySecret = pairClient earlyKey
@@ -120,7 +120,7 @@
             Just (cred, hashSig) -> sendCertAndVerify cred hashSig zlib
         let ServerTrafficSecret shs = serverHandshakeSecret
         rawFinished <- makeFinished ctx usedHash shs
-        loadPacket13 ctx $ Handshake13 [rawFinished]
+        loadPacket13 ctx $ Handshake13 [rawFinished] []
         return (clientHandshakeSecret, handSecret)
     ----------------------------------------------------------------
     hChSf <- transcriptHash ctx "CH..SF"
@@ -204,7 +204,7 @@
                             , shExtensions = shExts
                             }
                 usingHState ctx $ setECHAccepted True
-                loadPacket13 ctx $ Handshake13 [ServerHello13 sh']
+                loadPacket13 ctx $ Handshake13 [ServerHello13 sh'] []
             else do
                 srand <-
                     liftIO $
@@ -220,26 +220,26 @@
                             , shComp = 0
                             , shExtensions = shExts
                             }
-                loadPacket13 ctx $ Handshake13 [ServerHello13 sh]
+                loadPacket13 ctx $ Handshake13 [ServerHello13 sh] []
 
     sendCertAndVerify cred@(certChain, _) hashSig zlib = do
         storePrivInfoServer ctx cred
         when (serverWantClientCert sparams) $ do
             let certReqCtx = "" -- this must be zero length here.
                 certReq = makeCertRequest sparams ctx certReqCtx True
-            loadPacket13 ctx $ Handshake13 [certReq]
+            loadPacket13 ctx $ Handshake13 [certReq] []
             usingHState ctx $ setCertReqSent True
 
         let CertificateChain cs = certChain
             ess = replicate (length cs) []
         let certtag = if zlib then CompressedCertificate13 else Certificate13
         loadPacket13 ctx $
-            Handshake13 [certtag "" (CertificateChain_ certChain) ess]
+            Handshake13 [certtag "" (CertificateChain_ certChain) ess] []
         liftIO $ usingState_ ctx $ setServerCertificateChain certChain
         hChSc <- transcriptHash ctx "CH..SC"
         pubkey <- getLocalPublicKey ctx
         vrfy <- makeCertVerify ctx pubkey hashSig hChSc
-        loadPacket13 ctx $ Handshake13 [vrfy]
+        loadPacket13 ctx $ Handshake13 [vrfy] []
 
     sendExtensions rtt0OK alpnExt recodeSizeLimitExt = do
         msni <- liftIO $ usingState_ ctx getClientSNI
@@ -285,7 +285,7 @@
                         ]
         eeExtensions' <-
             liftIO $ onEncryptedExtensionsCreating (serverHooks sparams) eeExtensions
-        loadPacket13 ctx $ Handshake13 [EncryptedExtensions13 eeExtensions']
+        loadPacket13 ctx $ Handshake13 [EncryptedExtensions13 eeExtensions'] []
 
 credentialsFindForSigning13
     :: [HashAndSignatureAlgorithm]
@@ -337,7 +337,7 @@
             hrr <- makeHRR ctx usedCipher usedHash chSession g isEch
             usingHState ctx $ setTLS13HandshakeMode HelloRetryRequest
             runPacketFlight ctx $ do
-                loadPacket13 ctx $ Handshake13 [ServerHello13 hrr]
+                loadPacket13 ctx $ Handshake13 [ServerHello13 hrr] []
                 sendChangeCipherSpec13 ctx
   where
     serverGroups = supportedGroups (ctxSupported ctx)
diff --git a/Network/TLS/Handshake/Server/TLS12.hs b/Network/TLS/Handshake/Server/TLS12.hs
--- a/Network/TLS/Handshake/Server/TLS12.hs
+++ b/Network/TLS/Handshake/Server/TLS12.hs
@@ -40,7 +40,7 @@
                 Nothing -> return ()
                 Just ticket -> do
                     let life = adjustLifetime $ serverTicketLifetime sparams
-                    sendPacket12 ctx $ Handshake [NewSessionTicket life ticket]
+                    sendPacket12 ctx $ Handshake [NewSessionTicket life ticket] []
             sendCCSandFinished ctx ServerRole
         Just _ -> do
             _ <- sessionEstablished ctx
diff --git a/Network/TLS/Handshake/Server/TLS13.hs b/Network/TLS/Handshake/Server/TLS13.hs
--- a/Network/TLS/Handshake/Server/TLS13.hs
+++ b/Network/TLS/Handshake/Server/TLS13.hs
@@ -71,7 +71,7 @@
                 then
                     setPendingRecvActions
                         ctx
-                        [ PendingRecvAction True True $ expectEndOfEarlyData ctx clientHandshakeSecret
+                        [ PendingRecvAction True $ expectEndOfEarlyData ctx clientHandshakeSecret
                         , PendingRecvActionHash True $
                             expectFinished sparams ctx chExtensions appKey clientHandshakeSecret sfSentTime
                         ]
@@ -104,7 +104,10 @@
 expectFinished _ _ _ _ _ _ _ hs = unexpected (show hs) (Just "finished 13")
 
 expectEndOfEarlyData
-    :: Context -> ClientTrafficSecret HandshakeSecret -> Handshake13 -> IO ()
+    :: Context
+    -> ClientTrafficSecret HandshakeSecret
+    -> Handshake13
+    -> IO ()
 expectEndOfEarlyData ctx clientHandshakeSecret EndOfEarlyData13 = do
     (usedHash, usedCipher, _, _) <- getRxRecordState ctx
     setRxRecordState ctx usedHash usedCipher clientHandshakeSecret
@@ -145,7 +148,7 @@
         psk = derivePSK choice resumptionSecret nonce
     (identity, add) <- generateSession life psk rtt0max rtt
     let nst = createNewSessionTicket life add nonce identity rtt0max
-    sendPacket13 ctx $ Handshake13 [nst]
+    sendPacket13 ctx $ Handshake13 [nst] []
   where
     choice = makeCipherChoice TLS13 usedCipher
     rtt0max = safeNonNegative32 $ serverEarlyDataSize sparams
@@ -179,7 +182,8 @@
         | otherwise = fromIntegral i
 
 expectCertVerify
-    :: MonadIO m => ServerParams -> Context -> TranscriptHash -> Handshake13 -> m ()
+    :: MonadIO m
+    => ServerParams -> Context -> TranscriptHash -> Handshake13 -> m ()
 expectCertVerify sparams ctx (TranscriptHash hChCc) (CertVerify13 (DigitallySigned sigAlg sig)) = liftIO $ do
     certs@(CertificateChain cc) <-
         checkValidClientCertChain ctx "invalid client certificate chain"
@@ -237,26 +241,26 @@
         let certReq13 = makeCertRequest sparams ctx origCertReqCtx False
         _ <- withWriteLock ctx $ do
             bracket (saveHState ctx) (restoreHState ctx) $ \_ -> do
-                sendPacket13 ctx $ Handshake13 [certReq13]
+                sendPacket13 ctx $ Handshake13 [certReq13] []
         withReadLock ctx $ do
-            clientCert13 <- getHandshake ctx ref
+            (clientCert13, bClientCert13) <- getHandshake ctx ref
             emptyCert <- expectClientCertificate sparams ctx origCertReqCtx clientCert13
             baseHState <- saveHState ctx
-            void $ updateTranscriptHash13 ctx certReq13
-            void $ updateTranscriptHash13 ctx clientCert13
+            updateTranscriptHash13 ctx (clientCert13, bClientCert13)
             th <- transcriptHash ctx "CH..Cert"
             unless emptyCert $ do
-                certVerify13 <- getHandshake ctx ref
+                (certVerify13, bCertVerify13) <- getHandshake ctx ref
                 expectCertVerify sparams ctx th certVerify13
-                void $ updateTranscriptHash13 ctx certVerify13
-            finished13 <- getHandshake ctx ref
+                updateTranscriptHash13 ctx (certVerify13, bCertVerify13)
+            (finished13, _bFinished13) <- getHandshake ctx ref
             expectClientFinished ctx finished13
             void $ restoreHState ctx baseHState -- fixme
         return True
 
 -- saving appdata and key update?
 -- error handling
-getHandshake :: Context -> IORef [Handshake13] -> IO Handshake13
+getHandshake
+    :: Context -> IORef [Handshake13R] -> IO Handshake13R
 getHandshake ctx ref = do
     hhs <- readIORef ref
     if null hhs
@@ -265,23 +269,23 @@
             either (terminate ctx) process ex
         else chk hhs
   where
-    process (Handshake13 iss) = chk iss
+    process (Handshake13 hss bss) = chk $ zip hss bss
     process _ =
         terminate ctx $
             Error_Protocol "post handshake authenticated" UnexpectedMessage
     chk [] = getHandshake ctx ref
-    chk (KeyUpdate13 mode : hs) = do
+    chk ((KeyUpdate13 mode, _) : hbs) = do
         keyUpdate ctx getRxRecordState setRxRecordState
         -- Write lock wraps both actions because we don't want another
         -- packet to be sent by another thread before the Tx state is
         -- updated.
         when (mode == UpdateRequested) $ withWriteLock ctx $ do
-            sendPacket13 ctx $ Handshake13 [KeyUpdate13 UpdateNotRequested]
+            sendPacket13 ctx $ Handshake13 [KeyUpdate13 UpdateNotRequested] []
             keyUpdate ctx getTxRecordState setTxRecordState
-        chk hs
-    chk (h : hs) = do
-        writeIORef ref hs
-        return h
+        chk hbs
+    chk (hb : hbs) = do
+        writeIORef ref hbs
+        return hb
 
 expectClientCertificate
     :: ServerParams -> Context -> CertReqContext -> Handshake13 -> IO Bool
@@ -379,6 +383,6 @@
         -- Write lock wraps both actions because we don't want another packet to
         -- be sent by another thread before the Tx state is updated.
         withWriteLock ctx $ do
-            sendPacket13 ctx $ Handshake13 [KeyUpdate13 req]
+            sendPacket13 ctx $ Handshake13 [KeyUpdate13 req] []
             keyUpdate ctx getTxRecordState setTxRecordState
     return tls13
diff --git a/Network/TLS/Handshake/State.hs b/Network/TLS/Handshake/State.hs
--- a/Network/TLS/Handshake/State.hs
+++ b/Network/TLS/Handshake/State.hs
@@ -104,7 +104,7 @@
     = -- | Initial state
       TransHashState0
     | -- | A raw CH is stored since hash algo is not chosen yet.
-      TransHashState1 ByteString
+      TransHashState1 [ByteString]
     | -- | Hashed
       TransHashState2 HashCtx
 
@@ -161,7 +161,7 @@
     , hstCCS13Recv :: Bool
     , hstTLS13OuterClientRandom :: Maybe ClientRandom
     -- ^ Used for key logging in the case of ECH.
-    , hstTLS13ClientHello :: Maybe ClientHello
+    , hstTLS13ClientHello :: Maybe (ClientHello, [ByteString])
     -- ^ Inner client hello in the case of ECH.
     , hstTLS13ECHAccepted :: Bool
     , hstTLS13ECHEE :: Bool
@@ -403,11 +403,11 @@
 setOuterClientRandom :: Maybe ClientRandom -> HandshakeM ()
 setOuterClientRandom mcr = modify' (\hst -> hst{hstTLS13OuterClientRandom = mcr})
 
-getClientHello :: HandshakeM (Maybe ClientHello)
+getClientHello :: HandshakeM (Maybe (ClientHello, [ByteString]))
 getClientHello = gets hstTLS13ClientHello
 
-setClientHello :: ClientHello -> HandshakeM ()
-setClientHello ch = modify' $ \hst -> hst{hstTLS13ClientHello = Just ch}
+setClientHello :: ClientHello -> [ByteString] -> HandshakeM ()
+setClientHello ch b = modify' $ \hst -> hst{hstTLS13ClientHello = Just (ch, b)}
 
 getECHAccepted :: HandshakeM Bool
 getECHAccepted = gets hstTLS13ECHAccepted
diff --git a/Network/TLS/Handshake/TranscriptHash.hs b/Network/TLS/Handshake/TranscriptHash.hs
--- a/Network/TLS/Handshake/TranscriptHash.hs
+++ b/Network/TLS/Handshake/TranscriptHash.hs
@@ -40,11 +40,11 @@
 transit :: String -> Hash -> Bool -> TransHashState -> TransHashState
 transit label _ _ st0@TransHashState0 = error $ "transitTranscriptHash " ++ label ++ " " ++ show st0
 transit _ _ _ st2@(TransHashState2 _) = st2
-transit _ hashAlg isHRR (TransHashState1 ch)
-    | isHRR = TransHashState2 $ newWith hsMsg
-    | otherwise = TransHashState2 $ newWith ch
+transit _ hashAlg isHRR (TransHashState1 chs)
+    | isHRR = TransHashState2 $ hashUpdate (hashInit hashAlg) hsMsg
+    | otherwise = TransHashState2 $ hashUpdates (hashInit hashAlg) ch
   where
-    newWith = hashUpdate $ hashInit hashAlg
+    ch = reverse chs
     hsMsg =
         -- Handshake message:
         -- typ <-len-> body
@@ -55,7 +55,7 @@
             , hashedCH
             ]
       where
-        hashedCH = hash hashAlg ch
+        hashedCH = hashChunks hashAlg ch
         len = fromIntegral $ B.length hashedCH
 
 ----------------------------------------------------------------
@@ -73,9 +73,9 @@
     traceTranscriptHash ctx label hstTransHashStateI
 
 update :: ByteString -> String -> TransHashState -> TransHashState
-update eh _ TransHashState0 = TransHashState1 eh
+update eh _ TransHashState0 = TransHashState1 [eh]
+update eh _ (TransHashState1 bss) = TransHashState1 (eh : bss)
 update eh _ (TransHashState2 hctx) = TransHashState2 $ hashUpdate hctx eh
-update _ label st = error $ "updateTranscriptHash " ++ label ++ " " ++ show st
 
 ----------------------------------------------------------------
 
diff --git a/Network/TLS/IO.hs b/Network/TLS/IO.hs
--- a/Network/TLS/IO.hs
+++ b/Network/TLS/IO.hs
@@ -114,9 +114,10 @@
                             -- stHandshakeRecordCont
                             loop (count + 1)
                         else case pktRecv of
-                            Right (Handshake hss) -> do
-                                pktRecv'@(Right pkt) <- ctxWithHooks ctx $ \hooks ->
-                                    Right . Handshake <$> mapM (hookRecvHandshake hooks) hss
+                            Right (Handshake hss bss) -> do
+                                pktRecv'@(Right pkt) <- ctxWithHooks ctx $ \hooks -> do
+                                    hss' <- mapM (hookRecvHandshake hooks) hss
+                                    return $ Right $ Handshake hss' bss
                                 logPacket ctx $ show pkt
                                 return pktRecv'
                             Right pkt -> do
@@ -131,7 +132,7 @@
 isCCS _ = False
 
 isEmptyHandshake :: Either TLSError Packet -> Bool
-isEmptyHandshake (Right (Handshake [])) = True
+isEmptyHandshake (Right (Handshake [] _)) = True
 isEmptyHandshake _ = False
 
 logPacket :: Context -> String -> IO ()
@@ -174,9 +175,10 @@
                         loop (count + 1)
                     else do
                         case pktRecv of
-                            Right (Handshake13 hss) -> do
-                                pktRecv'@(Right pkt) <- ctxWithHooks ctx $ \hooks ->
-                                    Right . Handshake13 <$> mapM (hookRecvHandshake13 hooks) hss
+                            Right (Handshake13 hss bss) -> do
+                                pktRecv'@(Right pkt) <- ctxWithHooks ctx $ \hooks -> do
+                                    hss' <- mapM (hookRecvHandshake13 hooks) hss
+                                    return $ Right $ Handshake13 hss' bss
                                 logPacket ctx $ show pkt
                                 return pktRecv'
                             Right pkt -> do
@@ -187,7 +189,7 @@
                                 return pktRecv
 
 isEmptyHandshake13 :: Either TLSError Packet13 -> Bool
-isEmptyHandshake13 (Right (Handshake13 [])) = True
+isEmptyHandshake13 (Right (Handshake13 [] _)) = True
 isEmptyHandshake13 _ = False
 
 ----------------------------------------------------------------
@@ -196,7 +198,7 @@
 isRecvComplete ctx = usingState_ ctx $ do
     cont12 <- gets stHandshakeRecordCont12
     cont13 <- gets stHandshakeRecordCont13
-    return $ isNothing cont12 && isNothing cont13
+    return $ isNothing (fst cont12) && isNothing (fst cont13)
 
 checkValid :: Context -> IO ()
 checkValid ctx = do
diff --git a/Network/TLS/IO/Decode.hs b/Network/TLS/IO/Decode.hs
--- a/Network/TLS/IO/Decode.hs
+++ b/Network/TLS/IO/Decode.hs
@@ -7,6 +7,7 @@
 
 import Control.Concurrent.MVar
 import Control.Monad.State.Strict
+import qualified Data.ByteString as BS
 
 import Network.TLS.Cipher
 import Network.TLS.Context.Internal
@@ -41,22 +42,30 @@
                     , cParamsKeyXchgType = keyxchg
                     }
         -- get back the optional continuation, and parse as many handshake record as possible.
-        mCont <- gets stHandshakeRecordCont12
-        modify' (\st -> st{stHandshakeRecordCont12 = Nothing})
-        hss <- parseMany currentParams mCont (fragmentGetBytes fragment)
-        return $ Handshake hss
+        (mCont, wirebytes) <- gets stHandshakeRecordCont12
+        modify' (\st -> st{stHandshakeRecordCont12 = (Nothing, [])})
+        (hss, bss) <-
+            unzip <$> parseMany currentParams mCont wirebytes (fragmentGetBytes fragment)
+        return $ Handshake hss bss
   where
-    parseMany currentParams mCont bs =
+    parseMany currentParams mCont wirebytes bs =
         case fromMaybe decodeHandshakeRecord mCont bs of
             GotError err -> throwError err
-            GotPartial cont ->
-                modify' (\st -> st{stHandshakeRecordCont12 = Just cont}) >> return []
+            GotPartial cont -> do
+                modify' (\st -> st{stHandshakeRecordCont12 = (Just cont, bs : wirebytes)})
+                return []
             GotSuccess (ty, content) ->
-                either throwError (return . (: [])) $ decodeHandshake currentParams ty content
+                case decodeHandshake currentParams ty content of
+                    Left err -> throwError err
+                    Right h -> return [(h, reverse (bs : wirebytes))]
             GotSuccessRemaining (ty, content) left ->
                 case decodeHandshake currentParams ty content of
                     Left err -> throwError err
-                    Right hh -> (hh :) <$> parseMany currentParams Nothing left
+                    Right h -> do
+                        hbs <- parseMany currentParams Nothing [] left
+                        let len = BS.length bs - BS.length left
+                            bs' = BS.take len bs
+                        return ((h, reverse (bs' : wirebytes)) : hbs)
 decodePacket12 _ _ = return $ Left (Error_Packet_Parsing "unknown protocol type")
 
 switchRxEncryption :: Context -> IO ()
@@ -74,20 +83,27 @@
 decodePacket13 _ (Record ProtocolType_AppData _ fragment) = return $ Right $ AppData13 $ fragmentGetBytes fragment
 decodePacket13 _ (Record ProtocolType_Alert _ fragment) = return (Alert13 `fmapEither` decodeAlerts (fragmentGetBytes fragment))
 decodePacket13 ctx (Record ProtocolType_Handshake _ fragment) = usingState ctx $ do
-    mCont <- gets stHandshakeRecordCont13
-    modify' (\st -> st{stHandshakeRecordCont13 = Nothing})
-    hss <- parseMany mCont (fragmentGetBytes fragment)
-    return $ Handshake13 hss
+    (mCont, wirebytes) <- gets stHandshakeRecordCont13
+    modify' (\st -> st{stHandshakeRecordCont13 = (Nothing, [])})
+    (hss, bss) <- unzip <$> parseMany mCont wirebytes (fragmentGetBytes fragment)
+    return $ Handshake13 hss bss
   where
-    parseMany mCont bs =
+    parseMany mCont wirebytes bs =
         case fromMaybe decodeHandshakeRecord13 mCont bs of
             GotError err -> throwError err
-            GotPartial cont ->
-                modify' (\st -> st{stHandshakeRecordCont13 = Just cont}) >> return []
+            GotPartial cont -> do
+                modify' (\st -> st{stHandshakeRecordCont13 = (Just cont, bs : wirebytes)})
+                return []
             GotSuccess (ty, content) ->
-                either throwError (return . (: [])) $ decodeHandshake13 ty content
+                case decodeHandshake13 ty content of
+                    Left err -> throwError err
+                    Right h -> return [(h, reverse (bs : wirebytes))]
             GotSuccessRemaining (ty, content) left ->
                 case decodeHandshake13 ty content of
                     Left err -> throwError err
-                    Right hh -> (hh :) <$> parseMany Nothing left
+                    Right h -> do
+                        hbs <- parseMany Nothing [] left
+                        let len = BS.length bs - BS.length left
+                            bs' = BS.take len bs
+                        return ((h, reverse (bs' : wirebytes)) : hbs)
 decodePacket13 _ _ = return $ Left (Error_Packet_Parsing "unknown protocol type")
diff --git a/Network/TLS/IO/Encode.hs b/Network/TLS/IO/Encode.hs
--- a/Network/TLS/IO/Encode.hs
+++ b/Network/TLS/IO/Encode.hs
@@ -2,7 +2,9 @@
     encodePacket12,
     encodePacket13,
     updateTranscriptHash12,
+    encodeUpdateTranscriptHash12,
     updateTranscriptHash13,
+    encodeUpdateTranscriptHash13,
 ) where
 
 import Control.Concurrent.MVar
@@ -47,8 +49,8 @@
 -- packets are not fragmented here but by callers of sendPacket, so that the
 -- empty-packet countermeasure may be applied to each fragment independently.
 packetToFragments12 :: Context -> Maybe Int -> Packet -> IO [ByteString]
-packetToFragments12 ctx mlen (Handshake hss) =
-    getChunks mlen . B.concat <$> mapM (updateTranscriptHash12 ctx) hss
+packetToFragments12 ctx mlen (Handshake hss _) =
+    getChunks mlen . B.concat <$> mapM (encodeUpdateTranscriptHash12 ctx) hss
 packetToFragments12 _ _ (Alert a) = return [encodeAlerts a]
 packetToFragments12 _ _ ChangeCipherSpec = return [encodeChangeCipherSpec]
 packetToFragments12 _ _ (AppData x) = return [x]
@@ -73,17 +75,32 @@
   where
     isCBC tx = maybe False (\c -> bulkBlockSize (cipherBulk c) > 0) (stCipher tx)
 
-updateTranscriptHash12 :: Context -> Handshake -> IO ByteString
-updateTranscriptHash12 ctx hs = do
+encodeUpdateTranscriptHash12 :: Context -> Handshake -> IO ByteString
+encodeUpdateTranscriptHash12 ctx hs = do
     when (certVerifyHandshakeMaterial hs) $
         usingHState ctx $
             addHandshakeMessage encoded
     let label = show $ typeOfHandshake hs
     when (finishedHandshakeMaterial hs) $ updateTranscriptHash ctx label encoded
+    when (isClientHello hs) $ do
+        usingHState ctx $ do
+            (ch, b) <- fromJust <$> getClientHello
+            when (null b) $ setClientHello ch [encoded]
     return encoded
   where
     encoded = encodeHandshake hs
+    isClientHello (ClientHello _) = True
+    isClientHello _ = False
 
+updateTranscriptHash12 :: Context -> HandshakeR -> IO ()
+updateTranscriptHash12 ctx (hs, bss) = do
+    when (certVerifyHandshakeMaterial hs) $
+        usingHState ctx $
+            mapM_ addHandshakeMessage bss
+    let label = show $ typeOfHandshake hs
+    when (finishedHandshakeMaterial hs) $ do
+        mapM_ (updateTranscriptHash ctx label) bss
+
 ----------------------------------------------------------------
 
 encodePacket13
@@ -100,14 +117,14 @@
     fmap mconcat <$> forEitherM records (recordEncode13 recordLayer ctx)
 
 packetToFragments13 :: Context -> Maybe Int -> Packet13 -> IO [ByteString]
-packetToFragments13 ctx mlen (Handshake13 hss) =
-    getChunks mlen . B.concat <$> mapM (updateTranscriptHash13 ctx) hss
+packetToFragments13 ctx mlen (Handshake13 hss _) =
+    getChunks mlen . B.concat <$> mapM (encodeUpdateTranscriptHash13 ctx) hss
 packetToFragments13 _ _ (Alert13 a) = return [encodeAlerts a]
 packetToFragments13 _ _ (AppData13 x) = return [x]
 packetToFragments13 _ _ ChangeCipherSpec13 = return [encodeChangeCipherSpec]
 
-updateTranscriptHash13 :: Context -> Handshake13 -> IO ByteString
-updateTranscriptHash13 ctx hs
+encodeUpdateTranscriptHash13 :: Context -> Handshake13 -> IO ByteString
+encodeUpdateTranscriptHash13 ctx hs
     | isIgnored hs = return encoded
     | otherwise = do
         let label = show $ typeOfHandshake13 hs
@@ -117,6 +134,15 @@
   where
     encoded = encodeHandshake13 hs
 
-    isIgnored NewSessionTicket13{} = True
-    isIgnored KeyUpdate13{} = True
-    isIgnored _ = False
+updateTranscriptHash13 :: Context -> Handshake13R -> IO ()
+updateTranscriptHash13 ctx (hs, bss)
+    | isIgnored hs = return ()
+    | otherwise = do
+        let label = show $ typeOfHandshake13 hs
+        mapM_ (updateTranscriptHash ctx label) bss
+        usingHState ctx $ mapM_ addHandshakeMessage bss
+
+isIgnored :: Handshake13 -> Bool
+isIgnored NewSessionTicket13{} = True
+isIgnored KeyUpdate13{} = True
+isIgnored _ = False
diff --git a/Network/TLS/State.hs b/Network/TLS/State.hs
--- a/Network/TLS/State.hs
+++ b/Network/TLS/State.hs
@@ -79,7 +79,7 @@
 import Network.TLS.Imports
 import Network.TLS.RNG
 import Network.TLS.Struct
-import Network.TLS.Types (HostName, Role (..), Ticket)
+import Network.TLS.Types (HostName, Role (..), Ticket, WireBytes)
 import Network.TLS.Wire (GetContinuation)
 
 data TLSState = TLSState
@@ -93,8 +93,10 @@
       stServerCertificateChain :: Maybe CertificateChain
     , stExtensionALPN :: Bool -- RFC 7301
     , stNegotiatedProtocol :: Maybe ByteString -- ALPN protocol
-    , stHandshakeRecordCont12 :: Maybe (GetContinuation (HandshakeType, ByteString))
-    , stHandshakeRecordCont13 :: Maybe (GetContinuation (HandshakeType, ByteString))
+    , stHandshakeRecordCont12
+        :: (Maybe (GetContinuation (HandshakeType, ByteString)), WireBytes)
+    , stHandshakeRecordCont13
+        :: (Maybe (GetContinuation (HandshakeType, ByteString)), WireBytes)
     , stClientALPNSuggest :: Maybe [ByteString]
     , stClientGroupSuggest :: Maybe [Group]
     , stClientEcPointFormatSuggest :: Maybe [EcPointFormat]
@@ -136,8 +138,8 @@
         , stServerCertificateChain = Nothing
         , stExtensionALPN = False
         , stNegotiatedProtocol = Nothing
-        , stHandshakeRecordCont12 = Nothing
-        , stHandshakeRecordCont13 = Nothing
+        , stHandshakeRecordCont12 = (Nothing, [])
+        , stHandshakeRecordCont13 = (Nothing, [])
         , stClientALPNSuggest = Nothing
         , stClientGroupSuggest = Nothing
         , stClientEcPointFormatSuggest = Nothing
diff --git a/Network/TLS/Struct.hs b/Network/TLS/Struct.hs
--- a/Network/TLS/Struct.hs
+++ b/Network/TLS/Struct.hs
@@ -118,6 +118,7 @@
     hrrRandom,
     ClientHello (..),
     ServerHello (..),
+    HandshakeR,
 ) where
 
 import Data.X509 (
@@ -231,14 +232,14 @@
 ----------------------------------------------------------------
 
 data Packet
-    = Handshake [Handshake]
+    = Handshake [Handshake] [WireBytes]
     | Alert [(AlertLevel, AlertDescription)]
     | ChangeCipherSpec
     | AppData ByteString
     deriving (Eq)
 
 instance Show Packet where
-    show (Handshake hs) = "Handshake " ++ show hs
+    show (Handshake hs _) = "Handshake " ++ show hs
     show (Alert as) = "Alert " ++ show as
     show ChangeCipherSpec = "ChangeCipherSpec"
     show (AppData bs) = "AppData " ++ showBytesHex bs
@@ -478,7 +479,7 @@
 
 {- FOURMOLU_DISABLE -}
 packetType :: Packet -> ProtocolType
-packetType (Handshake _)    = ProtocolType_Handshake
+packetType (Handshake _ _)  = ProtocolType_Handshake
 packetType (Alert _)        = ProtocolType_Alert
 packetType ChangeCipherSpec = ProtocolType_ChangeCipherSpec
 packetType (AppData _)      = ProtocolType_AppData
@@ -496,3 +497,5 @@
 typeOfHandshake Finished{}         = HandshakeType_Finished
 typeOfHandshake NewSessionTicket{} = HandshakeType_NewSessionTicket
 {- FOURMOLU_ENABLE -}
+
+type HandshakeR = (Handshake, WireBytes)
diff --git a/Network/TLS/Struct13.hs b/Network/TLS/Struct13.hs
--- a/Network/TLS/Struct13.hs
+++ b/Network/TLS/Struct13.hs
@@ -8,6 +8,7 @@
     isKeyUpdate13,
     TicketNonce (..),
     SessionIDorTicket_ (..),
+    Handshake13R,
 ) where
 
 import Network.TLS.Imports
@@ -15,7 +16,7 @@
 import Network.TLS.Types
 
 data Packet13
-    = Handshake13 [Handshake13]
+    = Handshake13 [Handshake13] [WireBytes]
     | Alert13 [(AlertLevel, AlertDescription)]
     | ChangeCipherSpec13
     | AppData13 ByteString
@@ -76,3 +77,5 @@
 isKeyUpdate13 :: Handshake13 -> Bool
 isKeyUpdate13 (KeyUpdate13 _) = True
 isKeyUpdate13 _ = False
+
+type Handshake13R = (Handshake13, WireBytes)
diff --git a/Network/TLS/Types.hs b/Network/TLS/Types.hs
--- a/Network/TLS/Types.hs
+++ b/Network/TLS/Types.hs
@@ -12,6 +12,7 @@
     bigNumFromInteger,
     defaultRecordSizeLimit,
     TranscriptHash (..),
+    WireBytes,
 ) where
 
 import Network.Socket (HostName)
@@ -64,3 +65,7 @@
 
 instance Show TranscriptHash where
     show (TranscriptHash bs) = showBytesHex bs
+
+----------------------------------------------------------------
+
+type WireBytes = [ByteString]
diff --git a/tls.cabal b/tls.cabal
--- a/tls.cabal
+++ b/tls.cabal
@@ -1,6 +1,6 @@
 cabal-version:      >=1.10
 name:               tls
-version:            2.2.1
+version:            2.2.2
 license:            BSD3
 license-file:       LICENSE
 copyright:          Vincent Hanquez <vincent@snarc.org>
