packages feed

tls 2.1.14 → 2.4.3

raw patch · 59 files changed

Files

CHANGELOG.md view
@@ -1,5 +1,55 @@ # Change log for "tls" +## Version 2.4.3++* A server checks clientAuth of ExtendedKeyUsage in a client+  certificate on client authentication.++## Version 2.4.2++* The `Network.TLS.Extra.CipherCBC` module is added.+  [#526](https://github.com/haskell-tls/hs-tls/pull/526)++## Version 2.4.1++* Ensure same `supported_groups` before/after HRR.+* New `clientWantTicket` parameter makes it possible to opt-out of soliciting+  session tickets from servers.++## Version 2.4.0++* Identical to v2.3.1 but major version up as v2.3.1 breaks "quic".++## Version 2.3.1 (deprecated)++* Using ScrubbedBytes for secrets.+* Key echange with ML-KEM.+  [#517](https://github.com/haskell-tls/hs-tls/pull/517)+* Expose get certificate chain function+  [#520](https://github.com/haskell-tls/hs-tls/pull/520)++## Version 2.3.0++* Using "ram" instead of "memory".++## 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.+  [#514](https://github.com/haskell-tls/hs-tls/issues/514)++## Version 2.2.0++* Using crypton-asn1-* and time-hourglass.+  [#512](https://github.com/haskell-tls/hs-tls/pull/512)+* Major version up due to re-exports.+ ## Version 2.1.14  * Supporting P384 and P521 curves.@@ -51,14 +101,14 @@   This feature is automatically used if the peer supports it. * More tests with `tlsfuzzer` especially for client authentication   and 0-RTT.-* Implementing a utility funcation, `validateClientCertificate`, for+* Implementing a utility function, `validateClientCertificate`, for   client authentication. * Bug fix for echo back logic of Cookie extension. * More pretty show for the internal `Handshake` structure for debugging.  ## Version 2.1.6 -* Testing with "tlsfuzzer" again. Now don't send an alert agaist to+* Testing with "tlsfuzzer" again. Now don't send an alert against to   peer's alert. Double locking (aka self dead-lock) is fixed. Sending   an alert for known-but-cannot-parse extensions. Other corner cases   are also fixed.@@ -322,7 +372,7 @@ API CHANGES:  - `SessionManager` implementations need to provide a `sessionResumeOnlyOnce`-  function to accomodate resumption scenarios with 0-RTT data.  The function is+  function to accommodate resumption scenarios with 0-RTT data.  The function is   called only on the server side. - Data type `SessionData` is extended with four new fields for TLS version 1.3.   `SessionManager` implementations that serializes/deserializes `SessionData`
Network/TLS.hs view
@@ -11,7 +11,7 @@ -- protocol, and support RSA and Ephemeral (Elliptic curve and -- regular) Diffie Hellman key exchanges, and many extensions. ----- The tipical usage is:+-- The typical usage is: -- -- > socket <- ... -- > ctx <- contextNew socket <params>@@ -46,6 +46,7 @@     clientUseServerNameIndication,     clientWantSessionResume,     clientWantSessionResumeList,+    clientWantTicket,     clientShared,     clientHooks,     clientSupported,@@ -88,6 +89,7 @@     onSuggestALPN,     onCustomFFDHEGroup,     onServerFinished,+    onSelectKeyShareGroups,      -- ** Server hooks     ServerHooks,@@ -100,6 +102,7 @@     onNewHandshake,     onALPNClientSuggest,     onEncryptedExtensionsCreating,+    onSelectKeyShare,     Measurement,     nbHandshakes,     bytesReceived,@@ -119,6 +122,7 @@     supportedFallbackScsv,     supportedEmptyPacket,     supportedGroups,+    supportedGroupsTLS13,      -- ** Debug parameters     DebugParams,@@ -236,6 +240,7 @@     unServerRandom,     HandshakeMode13 (..),     getClientCertificateChain,+    getServerCertificateChain,      -- ** Negotiated     getNegotiatedProtocol,@@ -321,10 +326,10 @@ import Network.TLS.Crypto (     DHParams,     DHPublic,-    Group (..),     KxError (..),     supportedNamedGroups,  )+import Network.TLS.Extension import Network.TLS.Handshake.State (HandshakeMode13 (..)) import Network.TLS.Hooks import Network.TLS.Imports@@ -361,6 +366,9 @@ --   both cases of full-negotiation and resumption. getClientCertificateChain :: Context -> IO (Maybe CertificateChain) getClientCertificateChain ctx = usingState_ ctx S.getClientCertificateChain++getServerCertificateChain :: Context -> IO (Maybe CertificateChain)+getServerCertificateChain ctx = usingState_ ctx S.getServerCertificateChain  -- $exceptions --     Since 1.8.0, this library only throws exceptions of type 'TLSException'.
Network/TLS/Compression.hs view
@@ -51,7 +51,7 @@     (==) c1 c2 = compressionID c1 == compressionID c2  -- | intersect a list of ids commonly given by the other side with a list of compression--- the function keeps the list of compression in order, to be able to find quickly the prefered+-- the function keeps the list of compression in order, to be able to find quickly the preferred -- compression. compressionIntersectID :: [Compression] -> [Word8] -> [Compression] compressionIntersectID l ids = filter (\c -> compressionID c `elem` ids) l
Network/TLS/Context.hs view
@@ -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 () 
Network/TLS/Context/Internal.hs view
@@ -88,6 +88,8 @@ import Control.Concurrent.MVar import Control.Exception (throwIO) import Control.Monad.State.Strict+import Data.ByteArray (convert)+import qualified Data.ByteArray as BA import qualified Data.ByteString as B import Data.IORef import Data.Tuple@@ -166,7 +168,7 @@  data RoleParams = RoleParams     { doHandshake_ :: Context -> IO ()-    , doHandshakeWith_ :: Context -> Handshake -> IO ()+    , doHandshakeWith_ :: Context -> HandshakeR -> IO ()     , doRequestCertificate_ :: Context -> IO Bool     , doPostHandshakeAuthWith_ :: Context -> Handshake13 -> IO ()     }@@ -185,7 +187,7 @@     { cVersion :: Version     , cCipher :: Cipher     , cHash :: Hash-    , cZero :: ByteString+    , cZero :: Secret     }     deriving (Show) @@ -193,7 +195,7 @@ makeCipherChoice ver cipher = CipherChoice ver cipher h zero   where     h = cipherHash cipher-    zero = B.replicate (hashDigestSize h) 0+    zero = BA.replicate (hashDigestSize h) 0  data TLS13State = TLS13State     { tls13stRecvNST :: Bool -- client@@ -209,7 +211,7 @@     , tls13stClientExtensions :: [ExtensionRaw] -- client     , tls13stChoice :: ~CipherChoice -- client     , tls13stHsKey :: Maybe (SecretTriple HandshakeSecret) -- client-    -- Actuall session id for TLS 1.2, random value for TLS 1.3+    -- Actual session id for TLS 1.2, random value for TLS 1.3     , tls13stSession :: Session     , tls13stSentExtensions :: [ExtensionID]     }@@ -271,11 +273,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)@@ -322,7 +326,7 @@                         { infoVersion = v                         , infoCipher = c                         , infoCompression = comp-                        , infoMainSecret = ms+                        , infoMainSecret = convert <$> ms                         , infoExtendedMainSecret = ems                         , infoClientRandom = cr                         , infoServerRandom = sr
Network/TLS/Core.hs view
@@ -188,7 +188,7 @@         -- All chunks are protected with the same write lock because we don't         -- want to interleave writes from other threads in the middle of our         -- possibly large write.-        mlen <- getPeerRecordLimit ctx -- plaintext, dont' adjust for TLS 1.3+        mlen <- getPeerRecordLimit ctx -- plaintext, don't adjust for TLS 1.3         mapM_ (mapChunks_ mlen sendP) (L.toChunks dataToSend)  -- | Get data out of Data packet, and automatically renegotiate if a Handshake@@ -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"
Network/TLS/Crypto.hs view
@@ -7,6 +7,7 @@     HashCtx,     hashInit,     hashUpdate,+    hashUpdates,     hashUpdateSSL,     hashFinal,     module Network.TLS.Crypto.DH,@@ -60,7 +61,8 @@ import Data.ASN1.BinaryEncoding (BER (..), DER (..)) import Data.ASN1.Encoding import Data.ASN1.Types-import qualified Data.ByteArray as B (convert)+import Data.ByteArray (ByteArray, ByteArrayAccess, ScrubbedBytes, convert)+import qualified Data.ByteArray as BA import qualified Data.ByteString as B import Data.Proxy import Data.X509 (@@ -77,6 +79,8 @@ import Network.TLS.Crypto.Types import Network.TLS.Imports +----------------------------------------------------------------+ {-# DEPRECATED PublicKey "use PubKey" #-} type PublicKey = PubKey {-# DEPRECATED PrivateKey "use PrivKey" #-}@@ -160,9 +164,9 @@     HashContextSSL (H.hashUpdate sha1Ctx b2) (H.hashUpdate md5Ctx b1)  hashFinal :: HashCtx -> ByteString-hashFinal (HashContext (ContextSimple h)) = B.convert $ H.hashFinalize h+hashFinal (HashContext (ContextSimple h)) = convert $ H.hashFinalize h hashFinal (HashContextSSL sha1Ctx md5Ctx) =-    B.concat [B.convert (H.hashFinalize md5Ctx), B.convert (H.hashFinalize sha1Ctx)]+    B.concat [convert (H.hashFinalize md5Ctx), convert (H.hashFinalize sha1Ctx)]  data Hash = MD5 | SHA1 | SHA224 | SHA256 | SHA384 | SHA512 | SHA1_MD5     deriving (Show, Eq)@@ -179,20 +183,14 @@  type HashCtx = HashContext -hash :: Hash -> ByteString -> ByteString-hash MD5 b = B.convert . (H.hash :: ByteString -> H.Digest H.MD5) $ b-hash SHA1 b = B.convert . (H.hash :: ByteString -> H.Digest H.SHA1) $ b-hash SHA224 b = B.convert . (H.hash :: ByteString -> H.Digest H.SHA224) $ b-hash SHA256 b = B.convert . (H.hash :: ByteString -> H.Digest H.SHA256) $ b-hash SHA384 b = B.convert . (H.hash :: ByteString -> H.Digest H.SHA384) $ b-hash SHA512 b = B.convert . (H.hash :: ByteString -> H.Digest H.SHA512) $ b-hash SHA1_MD5 b =-    B.concat [B.convert (md5Hash b), B.convert (sha1Hash b)]-  where-    sha1Hash :: ByteString -> H.Digest H.SHA1-    sha1Hash = H.hash-    md5Hash :: ByteString -> H.Digest H.MD5-    md5Hash = H.hash+hash :: (ByteArray ba, ByteArrayAccess ba) => Hash -> ba -> ba+hash MD5 b = convert (H.hash b :: H.Digest H.MD5)+hash SHA1 b = convert (H.hash b :: H.Digest H.SHA1)+hash SHA224 b = convert (H.hash b :: H.Digest H.SHA224)+hash SHA256 b = convert (H.hash b :: H.Digest H.SHA256)+hash SHA384 b = convert (H.hash b :: H.Digest H.SHA384)+hash SHA512 b = convert (H.hash b :: H.Digest H.SHA512)+hash SHA1_MD5 b = BA.concat [hash MD5 b, hash SHA1 b]  hashName :: Hash -> String hashName = show@@ -223,12 +221,12 @@ generalizeRSAError (Right x) = Right x  kxEncrypt-    :: MonadRandom r => PublicKey -> ByteString -> r (Either KxError ByteString)+    :: MonadRandom r => PublicKey -> ScrubbedBytes -> r (Either KxError ByteString) kxEncrypt (PubKeyRSA pk) b = generalizeRSAError <$> RSA.encrypt pk b kxEncrypt _ _ = return (Left KxUnsupported)  kxDecrypt-    :: MonadRandom r => PrivateKey -> ByteString -> r (Either KxError ByteString)+    :: MonadRandom r => PrivateKey -> ByteString -> r (Either KxError ScrubbedBytes) kxDecrypt (PrivKeyRSA pk) b = generalizeRSAError <$> RSA.decryptSafer pk b kxDecrypt _ _ = return (Left KxUnsupported) @@ -365,9 +363,9 @@             Just sign -> Right (ECDSA.signatureToIntegers prx sign)     unsupported = return $ Left KxUnsupported kxSign (PrivKeyEd25519 pk) (PubKeyEd25519 pub) Ed25519Params msg =-    return $ Right $ B.convert $ Ed25519.sign pk pub msg+    return $ Right $ convert $ Ed25519.sign pk pub msg kxSign (PrivKeyEd448 pk) (PubKeyEd448 pub) Ed448Params msg =-    return $ Right $ B.convert $ Ed448.sign pk pub msg+    return $ Right $ convert $ Ed448.sign pk pub msg kxSign _ _ _ _ =     return (Left KxUnsupported) 
Network/TLS/Crypto/DH.hs view
@@ -21,14 +21,15 @@  import Crypto.Number.Basic (numBits) import qualified Crypto.PubKey.DH as DH-import qualified Data.ByteArray as B+import Data.ByteArray (ScrubbedBytes)+import qualified Data.ByteArray as BA  import Network.TLS.RNG  type DHPublic = DH.PublicNumber type DHPrivate = DH.PrivateNumber type DHParams = DH.Params-type DHKey = DH.SharedKey+type DHKey = ScrubbedBytes  dhPublic :: Integer -> DHPublic dhPublic = DH.PublicNumber@@ -46,12 +47,12 @@     return (priv, pub)  dhGetShared :: DHParams -> DHPrivate -> DHPublic -> DHKey-dhGetShared params priv pub =-    stripLeadingZeros (DH.getShared params priv pub)+dhGetShared params priv pub = stripLeadingZeros sec   where+    DH.SharedKey sec = DH.getShared params priv pub     -- strips leading zeros from the result of DH.getShared, as required     -- for DH(E) pre-main secret in SSL/TLS before version 1.3.-    stripLeadingZeros (DH.SharedKey sb) = DH.SharedKey (snd $ B.span (== 0) sb)+    stripLeadingZeros sb = snd $ BA.span (== 0) sb  -- Check that group element in not in the 2-element subgroup { 1, p - 1 }. -- See RFC 7919 section 3 and NIST SP 56A rev 2 section 5.6.2.3.1.
Network/TLS/Crypto/IES.hs view
@@ -1,4 +1,5 @@ -- | (Elliptic Curve) Integrated Encryption Scheme+--   KEM(Key Encapsulation Mechanism) based APIs -- -- Module      : Network.TLS.Crypto.IES -- License     : BSD-style@@ -6,16 +7,19 @@ -- Stability   : experimental -- Portability : unknown module Network.TLS.Crypto.IES (-    GroupPublic,+    GroupPublicA,+    GroupPublicB,     GroupPrivate,     GroupKey,      -- * Group methods     groupGenerateKeyPair,-    groupGetPubShared,-    groupGetShared,-    encodeGroupPublic,-    decodeGroupPublic,+    groupEncapsulate,+    groupDecapsulate,+    groupEncodePublicA,+    groupDecodePublicA,+    groupEncodePublicB,+    groupDecodePublicB,      -- * Compatibility with 'Network.TLS.Crypto.DH'     dhParamsForGroup,@@ -24,12 +28,16 @@ ) where  import Control.Arrow-import Crypto.ECC+import Crypto.ECC as ECC import Crypto.Error import Crypto.Number.Generate-import Crypto.PubKey.DH hiding (generateParams)+import Crypto.PubKey.DH (PrivateNumber (..), PublicNumber (..))+import qualified Crypto.PubKey.DH as DH import Crypto.PubKey.ECIES-import qualified Data.ByteArray as B+import Crypto.PubKey.ML_KEM (ML_KEM_1024, ML_KEM_512, ML_KEM_768)+import qualified Crypto.PubKey.ML_KEM as ML+import Data.ByteArray (ScrubbedBytes, convert)+import qualified Data.ByteArray as BA import Data.Proxy  import Network.TLS.Crypto.Types@@ -38,6 +46,7 @@ import Network.TLS.RNG import Network.TLS.Util.Serialization (i2ospOf_, os2ip) +{- FOURMOLU_DISABLE -} data GroupPrivate     = GroupPri_P256 (Scalar Curve_P256R1)     | GroupPri_P384 (Scalar Curve_P384R1)@@ -49,23 +58,59 @@     | GroupPri_FFDHE4096 PrivateNumber     | GroupPri_FFDHE6144 PrivateNumber     | GroupPri_FFDHE8192 PrivateNumber+    | GroupPri_MLKEM512       (ML.DecapsulationKey ML_KEM_512)+    | GroupPri_MLKEM768       (ML.DecapsulationKey ML_KEM_768)+    | GroupPri_MLKEM1024      (ML.DecapsulationKey ML_KEM_1024)+    | GroupPri_X25519MLKEM768 (Scalar Curve_X25519, ML.DecapsulationKey ML_KEM_768)+    | GroupPri_P256MLKEM768   (Scalar Curve_P256R1, ML.DecapsulationKey ML_KEM_768)+    | GroupPri_P384MLKEM1024  (Scalar Curve_P384R1, ML.DecapsulationKey ML_KEM_1024)     deriving (Eq, Show)+{- FOURMOLU_ENABLE -} -data GroupPublic-    = GroupPub_P256 (Point Curve_P256R1)-    | GroupPub_P384 (Point Curve_P384R1)-    | GroupPub_P521 (Point Curve_P521R1)-    | GroupPub_X255 (Point Curve_X25519)-    | GroupPub_X448 (Point Curve_X448)-    | GroupPub_FFDHE2048 PublicNumber-    | GroupPub_FFDHE3072 PublicNumber-    | GroupPub_FFDHE4096 PublicNumber-    | GroupPub_FFDHE6144 PublicNumber-    | GroupPub_FFDHE8192 PublicNumber+{- FOURMOLU_DISABLE -}+data GroupPublicA+    = GroupPubA_P256 (Point Curve_P256R1)+    | GroupPubA_P384 (Point Curve_P384R1)+    | GroupPubA_P521 (Point Curve_P521R1)+    | GroupPubA_X255 (Point Curve_X25519)+    | GroupPubA_X448 (Point Curve_X448)+    | GroupPubA_FFDHE2048 PublicNumber+    | GroupPubA_FFDHE3072 PublicNumber+    | GroupPubA_FFDHE4096 PublicNumber+    | GroupPubA_FFDHE6144 PublicNumber+    | GroupPubA_FFDHE8192 PublicNumber+    | GroupPubA_MLKEM512       (ML.EncapsulationKey ML_KEM_512)+    | GroupPubA_MLKEM768       (ML.EncapsulationKey ML_KEM_768)+    | GroupPubA_MLKEM1024      (ML.EncapsulationKey ML_KEM_1024)+    | GroupPubA_X25519MLKEM768 (Point Curve_X25519, ML.EncapsulationKey ML_KEM_768)+    | GroupPubA_P256MLKEM768   (Point Curve_P256R1, ML.EncapsulationKey ML_KEM_768)+    | GroupPubA_P384MLKEM1024  (Point Curve_P384R1, ML.EncapsulationKey ML_KEM_1024)     deriving (Eq, Show)+{- FOURMOLU_ENABLE -} -type GroupKey = SharedSecret+{- FOURMOLU_DISABLE -}+data GroupPublicB+    = GroupPubB_P256 (Point Curve_P256R1)+    | GroupPubB_P384 (Point Curve_P384R1)+    | GroupPubB_P521 (Point Curve_P521R1)+    | GroupPubB_X255 (Point Curve_X25519)+    | GroupPubB_X448 (Point Curve_X448)+    | GroupPubB_FFDHE2048 PublicNumber+    | GroupPubB_FFDHE3072 PublicNumber+    | GroupPubB_FFDHE4096 PublicNumber+    | GroupPubB_FFDHE6144 PublicNumber+    | GroupPubB_FFDHE8192 PublicNumber+    | GroupPubB_MLKEM512       (ML.Ciphertext ML_KEM_512)+    | GroupPubB_MLKEM768       (ML.Ciphertext ML_KEM_768)+    | GroupPubB_MLKEM1024      (ML.Ciphertext ML_KEM_1024)+    | GroupPubB_X25519MLKEM768 (Point Curve_X25519, ML.Ciphertext ML_KEM_768)+    | GroupPubB_P256MLKEM768   (Point Curve_P256R1, ML.Ciphertext ML_KEM_768)+    | GroupPubB_P384MLKEM1024  (Point Curve_P384R1, ML.Ciphertext ML_KEM_1024)+    deriving (Eq, Show)+{- FOURMOLU_ENABLE -} +type GroupKey = ScrubbedBytes+ p256 :: Proxy Curve_P256R1 p256 = Proxy @@ -81,7 +126,16 @@ x448 :: Proxy Curve_X448 x448 = Proxy -dhParamsForGroup :: Group -> Maybe Params+mlkem512 :: Proxy ML_KEM_512+mlkem512 = Proxy++mlkem768 :: Proxy ML_KEM_768+mlkem768 = Proxy++mlkem1024 :: Proxy ML_KEM_1024+mlkem1024 = Proxy++dhParamsForGroup :: Group -> Maybe DH.Params dhParamsForGroup FFDHE2048 = Just ffdhe2048 dhParamsForGroup FFDHE3072 = Just ffdhe3072 dhParamsForGroup FFDHE4096 = Just ffdhe4096@@ -89,26 +143,47 @@ dhParamsForGroup FFDHE8192 = Just ffdhe8192 dhParamsForGroup _ = Nothing -groupGenerateKeyPair :: MonadRandom r => Group -> r (GroupPrivate, GroupPublic)+groupGenerateKeyPair :: MonadRandom r => Group -> r (GroupPrivate, GroupPublicA) groupGenerateKeyPair P256 =-    (GroupPri_P256, GroupPub_P256) `fs` curveGenerateKeyPair p256+    (GroupPri_P256, GroupPubA_P256) `fs` curveGenerateKeyPair p256 groupGenerateKeyPair P384 =-    (GroupPri_P384, GroupPub_P384) `fs` curveGenerateKeyPair p384+    (GroupPri_P384, GroupPubA_P384) `fs` curveGenerateKeyPair p384 groupGenerateKeyPair P521 =-    (GroupPri_P521, GroupPub_P521) `fs` curveGenerateKeyPair p521+    (GroupPri_P521, GroupPubA_P521) `fs` curveGenerateKeyPair p521 groupGenerateKeyPair X25519 =-    (GroupPri_X255, GroupPub_X255) `fs` curveGenerateKeyPair x25519+    (GroupPri_X255, GroupPubA_X255) `fs` curveGenerateKeyPair x25519 groupGenerateKeyPair X448 =-    (GroupPri_X448, GroupPub_X448) `fs` curveGenerateKeyPair x448-groupGenerateKeyPair FFDHE2048 = gen ffdhe2048 exp2048 GroupPri_FFDHE2048 GroupPub_FFDHE2048-groupGenerateKeyPair FFDHE3072 = gen ffdhe3072 exp3072 GroupPri_FFDHE3072 GroupPub_FFDHE3072-groupGenerateKeyPair FFDHE4096 = gen ffdhe4096 exp4096 GroupPri_FFDHE4096 GroupPub_FFDHE4096-groupGenerateKeyPair FFDHE6144 = gen ffdhe6144 exp6144 GroupPri_FFDHE6144 GroupPub_FFDHE6144-groupGenerateKeyPair FFDHE8192 = gen ffdhe8192 exp8192 GroupPri_FFDHE8192 GroupPub_FFDHE8192+    (GroupPri_X448, GroupPubA_X448) `fs` curveGenerateKeyPair x448+groupGenerateKeyPair FFDHE2048 = gen ffdhe2048 exp2048 GroupPri_FFDHE2048 GroupPubA_FFDHE2048+groupGenerateKeyPair FFDHE3072 = gen ffdhe3072 exp3072 GroupPri_FFDHE3072 GroupPubA_FFDHE3072+groupGenerateKeyPair FFDHE4096 = gen ffdhe4096 exp4096 GroupPri_FFDHE4096 GroupPubA_FFDHE4096+groupGenerateKeyPair FFDHE6144 = gen ffdhe6144 exp6144 GroupPri_FFDHE6144 GroupPubA_FFDHE6144+groupGenerateKeyPair FFDHE8192 = gen ffdhe8192 exp8192 GroupPri_FFDHE8192 GroupPubA_FFDHE8192+groupGenerateKeyPair MLKEM512 = do+    (e, d) <- ML.generate mlkem512+    return (GroupPri_MLKEM512 d, GroupPubA_MLKEM512 e)+groupGenerateKeyPair MLKEM768 = do+    (e, d) <- ML.generate mlkem768+    return (GroupPri_MLKEM768 d, GroupPubA_MLKEM768 e)+groupGenerateKeyPair MLKEM1024 = do+    (e, d) <- ML.generate mlkem1024+    return (GroupPri_MLKEM1024 d, GroupPubA_MLKEM1024 e)+groupGenerateKeyPair X25519MLKEM768 = do+    (d1, e1) <- fs' $ curveGenerateKeyPair x25519+    (e2, d2) <- ML.generate mlkem768+    return (GroupPri_X25519MLKEM768 (d1, d2), GroupPubA_X25519MLKEM768 (e1, e2))+groupGenerateKeyPair P256MLKEM768 = do+    (d1, e1) <- fs' $ curveGenerateKeyPair p256+    (e2, d2) <- ML.generate mlkem768+    return (GroupPri_P256MLKEM768 (d1, d2), GroupPubA_P256MLKEM768 (e1, e2))+groupGenerateKeyPair P384MLKEM1024 = do+    (d1, e1) <- fs' $ curveGenerateKeyPair p384+    (e2, d2) <- ML.generate mlkem1024+    return (GroupPri_P384MLKEM1024 (d1, d2), GroupPubA_P384MLKEM1024 (e1, e2)) groupGenerateKeyPair _ = error "groupGenerateKeyPair"  dhGroupGenerateKeyPair-    :: MonadRandom r => Group -> r (Params, PrivateNumber, PublicNumber)+    :: MonadRandom r => Group -> r (DH.Params, PrivateNumber, PublicNumber) dhGroupGenerateKeyPair FFDHE2048 = addParams ffdhe2048 (gen' ffdhe2048 exp2048) dhGroupGenerateKeyPair FFDHE3072 = addParams ffdhe3072 (gen' ffdhe3072 exp3072) dhGroupGenerateKeyPair FFDHE4096 = addParams ffdhe4096 (gen' ffdhe4096 exp4096)@@ -116,148 +191,320 @@ dhGroupGenerateKeyPair FFDHE8192 = addParams ffdhe8192 (gen' ffdhe8192 exp8192) dhGroupGenerateKeyPair grp = error ("invalid FFDHE group: " ++ show grp) -addParams :: Functor f => Params -> f (a, b) -> f (Params, a, b)+addParams :: Functor f => DH.Params -> f (a, b) -> f (DH.Params, a, b) addParams params = fmap $ \(a, b) -> (params, a, b)  fs     :: MonadRandom r-    => (Scalar a -> GroupPrivate, Point a -> GroupPublic)+    => (Scalar a -> GroupPrivate, Point a -> GroupPublicA)     -> r (KeyPair a)-    -> r (GroupPrivate, GroupPublic)+    -> r (GroupPrivate, GroupPublicA) (t1, t2) `fs` action = do     keypair <- action     let pub = keypairGetPublic keypair         pri = keypairGetPrivate keypair     return (t1 pri, t2 pub) +fs' :: Monad m => m (KeyPair curve) -> m (Scalar curve, Point curve)+fs' action = do+    keypair <- action+    let pub = keypairGetPublic keypair+        pri = keypairGetPrivate keypair+    return (pri, pub)+ gen     :: MonadRandom r-    => Params+    => DH.Params     -> Int     -> (PrivateNumber -> GroupPrivate)-    -> (PublicNumber -> GroupPublic)-    -> r (GroupPrivate, GroupPublic)+    -> (PublicNumber -> GroupPublicA)+    -> r (GroupPrivate, GroupPublicA) gen params expBits priTag pubTag = (priTag *** pubTag) <$> gen' params expBits  gen'     :: MonadRandom r-    => Params+    => DH.Params     -> Int     -> r (PrivateNumber, PublicNumber)-gen' params expBits = (id &&& calculatePublic params) <$> generatePriv expBits+gen' params expBits = (id &&& DH.calculatePublic params) <$> generatePriv expBits -groupGetPubShared-    :: MonadRandom r => GroupPublic -> r (Maybe (GroupPublic, GroupKey))-groupGetPubShared (GroupPub_P256 pub) =-    fmap (first GroupPub_P256) . maybeCryptoError <$> deriveEncrypt p256 pub-groupGetPubShared (GroupPub_P384 pub) =-    fmap (first GroupPub_P384) . maybeCryptoError <$> deriveEncrypt p384 pub-groupGetPubShared (GroupPub_P521 pub) =-    fmap (first GroupPub_P521) . maybeCryptoError <$> deriveEncrypt p521 pub-groupGetPubShared (GroupPub_X255 pub) =-    fmap (first GroupPub_X255) . maybeCryptoError <$> deriveEncrypt x25519 pub-groupGetPubShared (GroupPub_X448 pub) =-    fmap (first GroupPub_X448) . maybeCryptoError <$> deriveEncrypt x448 pub-groupGetPubShared (GroupPub_FFDHE2048 pub) = getPubShared ffdhe2048 exp2048 pub GroupPub_FFDHE2048-groupGetPubShared (GroupPub_FFDHE3072 pub) = getPubShared ffdhe3072 exp3072 pub GroupPub_FFDHE3072-groupGetPubShared (GroupPub_FFDHE4096 pub) = getPubShared ffdhe4096 exp4096 pub GroupPub_FFDHE4096-groupGetPubShared (GroupPub_FFDHE6144 pub) = getPubShared ffdhe6144 exp6144 pub GroupPub_FFDHE6144-groupGetPubShared (GroupPub_FFDHE8192 pub) = getPubShared ffdhe8192 exp8192 pub GroupPub_FFDHE8192+groupEncapsulate+    :: MonadRandom r => GroupPublicA -> r (Maybe (GroupPublicB, GroupKey))+groupEncapsulate (GroupPubA_P256 pub) = getECDHPubShared GroupPubB_P256 p256 pub+groupEncapsulate (GroupPubA_P384 pub) = getECDHPubShared GroupPubB_P384 p384 pub+groupEncapsulate (GroupPubA_P521 pub) = getECDHPubShared GroupPubB_P521 p521 pub+groupEncapsulate (GroupPubA_X255 pub) = getECDHPubShared GroupPubB_X255 x25519 pub+groupEncapsulate (GroupPubA_X448 pub) = getECDHPubShared GroupPubB_X448 x448 pub+groupEncapsulate (GroupPubA_FFDHE2048 pub) = getDHPubShared ffdhe2048 exp2048 pub GroupPubB_FFDHE2048+groupEncapsulate (GroupPubA_FFDHE3072 pub) = getDHPubShared ffdhe3072 exp3072 pub GroupPubB_FFDHE3072+groupEncapsulate (GroupPubA_FFDHE4096 pub) = getDHPubShared ffdhe4096 exp4096 pub GroupPubB_FFDHE4096+groupEncapsulate (GroupPubA_FFDHE6144 pub) = getDHPubShared ffdhe6144 exp6144 pub GroupPubB_FFDHE6144+groupEncapsulate (GroupPubA_FFDHE8192 pub) = getDHPubShared ffdhe8192 exp8192 pub GroupPubB_FFDHE8192+groupEncapsulate (GroupPubA_MLKEM512 pub) = do+    (sec, ct) <- ML.encapsulate pub+    return $ Just (GroupPubB_MLKEM512 ct, convert sec)+groupEncapsulate (GroupPubA_MLKEM768 pub) = do+    (sec, ct) <- ML.encapsulate pub+    return $ Just (GroupPubB_MLKEM768 ct, convert sec)+groupEncapsulate (GroupPubA_MLKEM1024 pub) = do+    (sec, ct) <- ML.encapsulate pub+    return $ Just (GroupPubB_MLKEM1024 ct, convert sec)+groupEncapsulate (GroupPubA_X25519MLKEM768 (e1, e2)) = do+    (c1, k1) <- fromJust <$> getECDHPubShared' x25519 e1+    (k2, c2) <- ML.encapsulate e2+    -- Sec 4.1: Specifically, the order of shares in the concatenation+    -- has been reversed.+    return $ Just (GroupPubB_X25519MLKEM768 (c1, c2), convert k2 <> k1)+groupEncapsulate (GroupPubA_P256MLKEM768 (e1, e2)) = do+    (c1, k1) <- fromJust <$> getECDHPubShared' p256 e1+    (k2, c2) <- ML.encapsulate e2+    return $ Just (GroupPubB_P256MLKEM768 (c1, c2), k1 <> convert k2)+groupEncapsulate (GroupPubA_P384MLKEM1024 (e1, e2)) = do+    (c1, k1) <- fromJust <$> getECDHPubShared' p384 e1+    (k2, c2) <- ML.encapsulate e2+    return $ Just (GroupPubB_P384MLKEM1024 (c1, c2), k1 <> convert k2)  dhGroupGetPubShared-    :: MonadRandom r => Group -> PublicNumber -> r (Maybe (PublicNumber, SharedKey))-dhGroupGetPubShared FFDHE2048 pub = getPubShared' ffdhe2048 exp2048 pub-dhGroupGetPubShared FFDHE3072 pub = getPubShared' ffdhe3072 exp3072 pub-dhGroupGetPubShared FFDHE4096 pub = getPubShared' ffdhe4096 exp4096 pub-dhGroupGetPubShared FFDHE6144 pub = getPubShared' ffdhe6144 exp6144 pub-dhGroupGetPubShared FFDHE8192 pub = getPubShared' ffdhe8192 exp8192 pub+    :: MonadRandom r => Group -> PublicNumber -> r (Maybe (PublicNumber, GroupKey))+dhGroupGetPubShared FFDHE2048 pub = getDHPubShared' ffdhe2048 exp2048 pub+dhGroupGetPubShared FFDHE3072 pub = getDHPubShared' ffdhe3072 exp3072 pub+dhGroupGetPubShared FFDHE4096 pub = getDHPubShared' ffdhe4096 exp4096 pub+dhGroupGetPubShared FFDHE6144 pub = getDHPubShared' ffdhe6144 exp6144 pub+dhGroupGetPubShared FFDHE8192 pub = getDHPubShared' ffdhe8192 exp8192 pub dhGroupGetPubShared _ _ = return Nothing -getPubShared+getECDHPubShared+    :: (MonadRandom m, EllipticCurveDH curve)+    => (Point curve -> GroupPublicB)+    -> proxy curve+    -> Point curve+    -> m (Maybe (GroupPublicB, GroupKey))+getECDHPubShared tag proxy pub = do+    mx <- maybeCryptoError <$> deriveEncrypt proxy pub+    case mx of+        Nothing -> return Nothing+        Just (p, ECC.SharedSecret s) -> return $ Just (tag p, s)++getECDHPubShared'+    :: (MonadRandom m, EllipticCurveDH curve)+    => proxy curve+    -> Point curve+    -> m (Maybe (Point curve, GroupKey))+getECDHPubShared' proxy pub = do+    mx <- maybeCryptoError <$> deriveEncrypt proxy pub+    case mx of+        Nothing -> return Nothing+        Just (p, ECC.SharedSecret s) -> return $ Just (p, s)++getDHPubShared     :: MonadRandom r-    => Params+    => DH.Params     -> Int     -> PublicNumber-    -> (PublicNumber -> GroupPublic)-    -> r (Maybe (GroupPublic, GroupKey))-getPubShared params expBits pub pubTag+    -> (PublicNumber -> GroupPublicB)+    -> r (Maybe (GroupPublicB, GroupKey))+getDHPubShared params expBits pub pubTag     | not (valid params pub) = return Nothing     | otherwise = do         mypri <- generatePriv expBits-        let mypub = calculatePublic params mypri-        let SharedKey share = getShared params mypri pub-        return $ Just (pubTag mypub, SharedSecret share)+        let mypub = DH.calculatePublic params mypri+            DH.SharedKey share = DH.getShared params mypri pub+        return $ Just (pubTag mypub, share) -getPubShared'+getDHPubShared'     :: MonadRandom r-    => Params+    => DH.Params     -> Int     -> PublicNumber-    -> r (Maybe (PublicNumber, SharedKey))-getPubShared' params expBits pub+    -> r (Maybe (PublicNumber, GroupKey))+getDHPubShared' params expBits pub     | not (valid params pub) = return Nothing     | otherwise = do         mypri <- generatePriv expBits-        let share = stripLeadingZeros (getShared params mypri pub)-        return $ Just (calculatePublic params mypri, SharedKey share)+        let share = stripLeadingZeros (DH.getShared params mypri pub)+        return $ Just (DH.calculatePublic params mypri, convert share) -groupGetShared :: GroupPublic -> GroupPrivate -> Maybe GroupKey-groupGetShared (GroupPub_P256 pub) (GroupPri_P256 pri) = maybeCryptoError $ deriveDecrypt p256 pub pri-groupGetShared (GroupPub_P384 pub) (GroupPri_P384 pri) = maybeCryptoError $ deriveDecrypt p384 pub pri-groupGetShared (GroupPub_P521 pub) (GroupPri_P521 pri) = maybeCryptoError $ deriveDecrypt p521 pub pri-groupGetShared (GroupPub_X255 pub) (GroupPri_X255 pri) = maybeCryptoError $ deriveDecrypt x25519 pub pri-groupGetShared (GroupPub_X448 pub) (GroupPri_X448 pri) = maybeCryptoError $ deriveDecrypt x448 pub pri-groupGetShared (GroupPub_FFDHE2048 pub) (GroupPri_FFDHE2048 pri) = calcShared ffdhe2048 pub pri-groupGetShared (GroupPub_FFDHE3072 pub) (GroupPri_FFDHE3072 pri) = calcShared ffdhe3072 pub pri-groupGetShared (GroupPub_FFDHE4096 pub) (GroupPri_FFDHE4096 pri) = calcShared ffdhe4096 pub pri-groupGetShared (GroupPub_FFDHE6144 pub) (GroupPri_FFDHE6144 pri) = calcShared ffdhe6144 pub pri-groupGetShared (GroupPub_FFDHE8192 pub) (GroupPri_FFDHE8192 pri) = calcShared ffdhe8192 pub pri-groupGetShared _ _ = Nothing+unwrap :: SharedSecret -> GroupKey+unwrap (ECC.SharedSecret sec) = sec -calcShared :: Params -> PublicNumber -> PrivateNumber -> Maybe SharedSecret-calcShared params pub pri-    | valid params pub = Just $ SharedSecret share+groupDecapsulate :: GroupPublicB -> GroupPrivate -> Maybe GroupKey+groupDecapsulate (GroupPubB_P256 pub) (GroupPri_P256 pri) = (unwrap <$>) . maybeCryptoError $ deriveDecrypt p256 pub pri+groupDecapsulate (GroupPubB_P384 pub) (GroupPri_P384 pri) = (unwrap <$>) . maybeCryptoError $ deriveDecrypt p384 pub pri+groupDecapsulate (GroupPubB_P521 pub) (GroupPri_P521 pri) = (unwrap <$>) . maybeCryptoError $ deriveDecrypt p521 pub pri+groupDecapsulate (GroupPubB_X255 pub) (GroupPri_X255 pri) = (unwrap <$>) . maybeCryptoError $ deriveDecrypt x25519 pub pri+groupDecapsulate (GroupPubB_X448 pub) (GroupPri_X448 pri) = (unwrap <$>) . maybeCryptoError $ deriveDecrypt x448 pub pri+groupDecapsulate (GroupPubB_FFDHE2048 pub) (GroupPri_FFDHE2048 pri) = calcDHShared ffdhe2048 pub pri+groupDecapsulate (GroupPubB_FFDHE3072 pub) (GroupPri_FFDHE3072 pri) = calcDHShared ffdhe3072 pub pri+groupDecapsulate (GroupPubB_FFDHE4096 pub) (GroupPri_FFDHE4096 pri) = calcDHShared ffdhe4096 pub pri+groupDecapsulate (GroupPubB_FFDHE6144 pub) (GroupPri_FFDHE6144 pri) = calcDHShared ffdhe6144 pub pri+groupDecapsulate (GroupPubB_FFDHE8192 pub) (GroupPri_FFDHE8192 pri) = calcDHShared ffdhe8192 pub pri+groupDecapsulate (GroupPubB_MLKEM512 p) (GroupPri_MLKEM512 s) =+    Just $ convert $ ML.decapsulate s p+groupDecapsulate (GroupPubB_MLKEM768 p) (GroupPri_MLKEM768 s) =+    Just $ convert $ ML.decapsulate s p+groupDecapsulate (GroupPubB_MLKEM1024 p) (GroupPri_MLKEM1024 s) =+    Just $ convert $ ML.decapsulate s p+groupDecapsulate (GroupPubB_X25519MLKEM768 (p1, p2)) (GroupPri_X25519MLKEM768 (s1, s2)) = do+    bs1 <- (unwrap <$>) . maybeCryptoError $ deriveDecrypt x25519 p1 s1+    let bs2 = convert $ ML.decapsulate s2 p2+    return (bs2 <> bs1)+groupDecapsulate (GroupPubB_P256MLKEM768 (p1, p2)) (GroupPri_P256MLKEM768 (s1, s2)) = do+    bs1 <- (unwrap <$>) . maybeCryptoError $ deriveDecrypt p256 p1 s1+    let bs2 = convert $ ML.decapsulate s2 p2+    return (bs1 <> bs2)+groupDecapsulate (GroupPubB_P384MLKEM1024 (p1, p2)) (GroupPri_P384MLKEM1024 (s1, s2)) = do+    bs1 <- (unwrap <$>) . maybeCryptoError $ deriveDecrypt p384 p1 s1+    let bs2 = convert $ ML.decapsulate s2 p2+    return (bs1 <> bs2)+groupDecapsulate _ _ = Nothing++calcDHShared :: DH.Params -> PublicNumber -> PrivateNumber -> Maybe GroupKey+calcDHShared params pub pri+    | valid params pub = Just $ convert share     | otherwise = Nothing   where-    SharedKey share = getShared params pri pub+    share = DH.getShared params pri pub -encodeGroupPublic :: GroupPublic -> ByteString-encodeGroupPublic (GroupPub_P256 p) = encodePoint p256 p-encodeGroupPublic (GroupPub_P384 p) = encodePoint p384 p-encodeGroupPublic (GroupPub_P521 p) = encodePoint p521 p-encodeGroupPublic (GroupPub_X255 p) = encodePoint x25519 p-encodeGroupPublic (GroupPub_X448 p) = encodePoint x448 p-encodeGroupPublic (GroupPub_FFDHE2048 p) = enc ffdhe2048 p-encodeGroupPublic (GroupPub_FFDHE3072 p) = enc ffdhe3072 p-encodeGroupPublic (GroupPub_FFDHE4096 p) = enc ffdhe4096 p-encodeGroupPublic (GroupPub_FFDHE6144 p) = enc ffdhe6144 p-encodeGroupPublic (GroupPub_FFDHE8192 p) = enc ffdhe8192 p+groupEncodePublicA :: GroupPublicA -> ByteString+groupEncodePublicA (GroupPubA_P256 p) = encodePoint p256 p+groupEncodePublicA (GroupPubA_P384 p) = encodePoint p384 p+groupEncodePublicA (GroupPubA_P521 p) = encodePoint p521 p+groupEncodePublicA (GroupPubA_X255 p) = encodePoint x25519 p+groupEncodePublicA (GroupPubA_X448 p) = encodePoint x448 p+groupEncodePublicA (GroupPubA_FFDHE2048 p) = enc ffdhe2048 p+groupEncodePublicA (GroupPubA_FFDHE3072 p) = enc ffdhe3072 p+groupEncodePublicA (GroupPubA_FFDHE4096 p) = enc ffdhe4096 p+groupEncodePublicA (GroupPubA_FFDHE6144 p) = enc ffdhe6144 p+groupEncodePublicA (GroupPubA_FFDHE8192 p) = enc ffdhe8192 p+groupEncodePublicA (GroupPubA_MLKEM512 p) = ML.encode p+groupEncodePublicA (GroupPubA_MLKEM768 p) = ML.encode p+groupEncodePublicA (GroupPubA_MLKEM1024 p) = ML.encode p+groupEncodePublicA (GroupPubA_X25519MLKEM768 (p1, p2)) =+    ML.encode p2 <> encodePoint x25519 p1+groupEncodePublicA (GroupPubA_P256MLKEM768 (p1, p2)) =+    encodePoint p256 p1 <> ML.encode p2+groupEncodePublicA (GroupPubA_P384MLKEM1024 (p1, p2)) =+    encodePoint p384 p1 <> ML.encode p2 -enc :: Params -> PublicNumber -> ByteString-enc params (PublicNumber p) = i2ospOf_ ((params_bits params + 7) `div` 8) p+groupEncodePublicB :: GroupPublicB -> ByteString+groupEncodePublicB (GroupPubB_P256 p) = encodePoint p256 p+groupEncodePublicB (GroupPubB_P384 p) = encodePoint p384 p+groupEncodePublicB (GroupPubB_P521 p) = encodePoint p521 p+groupEncodePublicB (GroupPubB_X255 p) = encodePoint x25519 p+groupEncodePublicB (GroupPubB_X448 p) = encodePoint x448 p+groupEncodePublicB (GroupPubB_FFDHE2048 p) = enc ffdhe2048 p+groupEncodePublicB (GroupPubB_FFDHE3072 p) = enc ffdhe3072 p+groupEncodePublicB (GroupPubB_FFDHE4096 p) = enc ffdhe4096 p+groupEncodePublicB (GroupPubB_FFDHE6144 p) = enc ffdhe6144 p+groupEncodePublicB (GroupPubB_FFDHE8192 p) = enc ffdhe8192 p+groupEncodePublicB (GroupPubB_MLKEM512 p) = convert p+groupEncodePublicB (GroupPubB_MLKEM768 p) = convert p+groupEncodePublicB (GroupPubB_MLKEM1024 p) = convert p+groupEncodePublicB (GroupPubB_X25519MLKEM768 (p1, p2)) =+    convert p2 <> encodePoint x25519 p1+groupEncodePublicB (GroupPubB_P256MLKEM768 (p1, p2)) =+    encodePoint p256 p1 <> convert p2+groupEncodePublicB (GroupPubB_P384MLKEM1024 (p1, p2)) =+    encodePoint p384 p1 <> convert p2 -decodeGroupPublic :: Group -> ByteString -> Either CryptoError GroupPublic-decodeGroupPublic P256 bs = eitherCryptoError $ GroupPub_P256 <$> decodePoint p256 bs-decodeGroupPublic P384 bs = eitherCryptoError $ GroupPub_P384 <$> decodePoint p384 bs-decodeGroupPublic P521 bs = eitherCryptoError $ GroupPub_P521 <$> decodePoint p521 bs-decodeGroupPublic X25519 bs = eitherCryptoError $ GroupPub_X255 <$> decodePoint x25519 bs-decodeGroupPublic X448 bs = eitherCryptoError $ GroupPub_X448 <$> decodePoint x448 bs-decodeGroupPublic FFDHE2048 bs = Right . GroupPub_FFDHE2048 . PublicNumber $ os2ip bs-decodeGroupPublic FFDHE3072 bs = Right . GroupPub_FFDHE3072 . PublicNumber $ os2ip bs-decodeGroupPublic FFDHE4096 bs = Right . GroupPub_FFDHE4096 . PublicNumber $ os2ip bs-decodeGroupPublic FFDHE6144 bs = Right . GroupPub_FFDHE6144 . PublicNumber $ os2ip bs-decodeGroupPublic FFDHE8192 bs = Right . GroupPub_FFDHE8192 . PublicNumber $ os2ip bs-decodeGroupPublic _ _ = error "decodeGroupPublic"+enc :: DH.Params -> PublicNumber -> ByteString+enc params (PublicNumber p) = i2ospOf_ ((DH.params_bits params + 7) `div` 8) p +groupDecodePublicA :: Group -> ByteString -> Either CryptoError GroupPublicA+groupDecodePublicA P256 bs = eitherCryptoError $ GroupPubA_P256 <$> decodePoint p256 bs+groupDecodePublicA P384 bs = eitherCryptoError $ GroupPubA_P384 <$> decodePoint p384 bs+groupDecodePublicA P521 bs = eitherCryptoError $ GroupPubA_P521 <$> decodePoint p521 bs+groupDecodePublicA X25519 bs = eitherCryptoError $ GroupPubA_X255 <$> decodePoint x25519 bs+groupDecodePublicA X448 bs = eitherCryptoError $ GroupPubA_X448 <$> decodePoint x448 bs+groupDecodePublicA FFDHE2048 bs = Right . GroupPubA_FFDHE2048 . PublicNumber $ os2ip bs+groupDecodePublicA FFDHE3072 bs = Right . GroupPubA_FFDHE3072 . PublicNumber $ os2ip bs+groupDecodePublicA FFDHE4096 bs = Right . GroupPubA_FFDHE4096 . PublicNumber $ os2ip bs+groupDecodePublicA FFDHE6144 bs = Right . GroupPubA_FFDHE6144 . PublicNumber $ os2ip bs+groupDecodePublicA FFDHE8192 bs = Right . GroupPubA_FFDHE8192 . PublicNumber $ os2ip bs+groupDecodePublicA MLKEM512 bs = case ML.decode mlkem512 bs of+    Nothing -> Left CryptoError_PointFormatInvalid+    Just p -> Right $ GroupPubA_MLKEM512 p+groupDecodePublicA MLKEM768 bs = case ML.decode mlkem768 bs of+    Nothing -> Left CryptoError_PointFormatInvalid+    Just p -> Right $ GroupPubA_MLKEM768 p+groupDecodePublicA MLKEM1024 bs = case ML.decode mlkem1024 bs of+    Nothing -> Left CryptoError_PointFormatInvalid+    Just p -> Right $ GroupPubA_MLKEM1024 p+groupDecodePublicA X25519MLKEM768 bs =+    let (bs1, bs2) = BA.splitAt 1184 bs+     in case ML.decode mlkem768 bs1 of+            Nothing -> Left CryptoError_PointFormatInvalid+            Just p1 -> case maybeCryptoError $ decodePoint x25519 bs2 of+                Nothing -> Left CryptoError_PointFormatInvalid+                Just p2 -> Right $ GroupPubA_X25519MLKEM768 (p2, p1)+groupDecodePublicA P256MLKEM768 bs =+    let (bs1, bs2) = BA.splitAt 65 bs+     in case ML.decode mlkem768 bs2 of+            Nothing -> Left CryptoError_PointFormatInvalid+            Just p1 -> case maybeCryptoError $ decodePoint p256 bs1 of+                Nothing -> Left CryptoError_PointFormatInvalid+                Just p2 -> Right $ GroupPubA_P256MLKEM768 (p2, p1)+groupDecodePublicA P384MLKEM1024 bs =+    let (bs1, bs2) = BA.splitAt 97 bs+     in case ML.decode mlkem1024 bs2 of+            Nothing -> Left CryptoError_PointFormatInvalid+            Just p1 -> case maybeCryptoError $ decodePoint p384 bs1 of+                Nothing -> Left CryptoError_PointFormatInvalid+                Just p2 -> Right $ GroupPubA_P384MLKEM1024 (p2, p1)+groupDecodePublicA _ _ = error "groupDecodePublicA"++groupDecodePublicB :: Group -> ByteString -> Either CryptoError GroupPublicB+groupDecodePublicB P256 bs = eitherCryptoError $ GroupPubB_P256 <$> decodePoint p256 bs+groupDecodePublicB P384 bs = eitherCryptoError $ GroupPubB_P384 <$> decodePoint p384 bs+groupDecodePublicB P521 bs = eitherCryptoError $ GroupPubB_P521 <$> decodePoint p521 bs+groupDecodePublicB X25519 bs = eitherCryptoError $ GroupPubB_X255 <$> decodePoint x25519 bs+groupDecodePublicB X448 bs = eitherCryptoError $ GroupPubB_X448 <$> decodePoint x448 bs+groupDecodePublicB FFDHE2048 bs = Right . GroupPubB_FFDHE2048 . PublicNumber $ os2ip bs+groupDecodePublicB FFDHE3072 bs = Right . GroupPubB_FFDHE3072 . PublicNumber $ os2ip bs+groupDecodePublicB FFDHE4096 bs = Right . GroupPubB_FFDHE4096 . PublicNumber $ os2ip bs+groupDecodePublicB FFDHE6144 bs = Right . GroupPubB_FFDHE6144 . PublicNumber $ os2ip bs+groupDecodePublicB FFDHE8192 bs = Right . GroupPubB_FFDHE8192 . PublicNumber $ os2ip bs+groupDecodePublicB MLKEM512 bs = case ML.decode mlkem512 bs of+    Nothing -> Left CryptoError_PointFormatInvalid+    Just p -> Right $ GroupPubB_MLKEM512 p+groupDecodePublicB MLKEM768 bs = case ML.decode mlkem768 bs of+    Nothing -> Left CryptoError_PointFormatInvalid+    Just p -> Right $ GroupPubB_MLKEM768 p+groupDecodePublicB MLKEM1024 bs = case ML.decode mlkem1024 bs of+    Nothing -> Left CryptoError_PointFormatInvalid+    Just p -> Right $ GroupPubB_MLKEM1024 p+groupDecodePublicB X25519MLKEM768 bs =+    let (bs1, bs2) = BA.splitAt 1088 bs+     in case ML.decode mlkem768 bs1 of+            Nothing -> Left CryptoError_PointFormatInvalid+            Just p1 -> case maybeCryptoError $ decodePoint x25519 bs2 of+                Nothing -> Left CryptoError_PointFormatInvalid+                Just p2 -> Right $ GroupPubB_X25519MLKEM768 (p2, p1)+groupDecodePublicB P256MLKEM768 bs =+    let (bs1, bs2) = BA.splitAt 65 bs+     in case ML.decode mlkem768 bs2 of+            Nothing -> Left CryptoError_PointFormatInvalid+            Just p1 -> case maybeCryptoError $ decodePoint p256 bs1 of+                Nothing -> Left CryptoError_PointFormatInvalid+                Just p2 -> Right $ GroupPubB_P256MLKEM768 (p2, p1)+groupDecodePublicB P384MLKEM1024 bs =+    let (bs1, bs2) = BA.splitAt 97 bs+     in case ML.decode mlkem1024 bs2 of+            Nothing -> Left CryptoError_PointFormatInvalid+            Just p1 -> case maybeCryptoError $ decodePoint p384 bs1 of+                Nothing -> Left CryptoError_PointFormatInvalid+                Just p2 -> Right $ GroupPubB_P384MLKEM1024 (p2, p1)+groupDecodePublicB _ _ = error "groupDecodePublicB"+ -- Check that group element in not in the 2-element subgroup { 1, p - 1 }. -- See RFC 7919 section 3 and NIST SP 56A rev 2 section 5.6.2.3.1.-valid :: Params -> PublicNumber -> Bool-valid (Params p _ _) (PublicNumber y) = 1 < y && y < p - 1+valid :: DH.Params -> PublicNumber -> Bool+valid (DH.Params p _ _) (PublicNumber y) = 1 < y && y < p - 1  -- strips leading zeros from the result of getShared, as required -- for DH(E) pre-main secret in SSL/TLS before version 1.3.-stripLeadingZeros :: SharedKey -> B.ScrubbedBytes-stripLeadingZeros (SharedKey sb) = snd $ B.span (== 0) sb+stripLeadingZeros :: DH.SharedKey -> ScrubbedBytes+stripLeadingZeros (DH.SharedKey sb) = snd $ BA.span (== 0) sb  -- Use short exponents as optimization, see RFC 7919 section 5.2. generatePriv :: MonadRandom r => Int -> r PrivateNumber
Network/TLS/Crypto/Types.hs view
@@ -19,11 +19,19 @@         FFDHE3072,         FFDHE4096,         FFDHE6144,-        FFDHE8192+        FFDHE8192,+        MLKEM512,+        MLKEM768,+        MLKEM1024,+        X25519MLKEM768,+        P256MLKEM768,+        P384MLKEM1024     ),     availableFFGroups,     availableECGroups,+    availableHybridGroups,     supportedNamedGroups,+    supportedNamedGroupsTLS13,     KeyExchangeSignatureAlg (..), ) where @@ -55,6 +63,18 @@ pattern FFDHE6144  = Group 259 pattern FFDHE8192 :: Group pattern FFDHE8192  = Group 260+pattern MLKEM512  :: Group+pattern MLKEM512   = Group 512+pattern MLKEM768  :: Group+pattern MLKEM768   = Group 513+pattern MLKEM1024 :: Group+pattern MLKEM1024  = Group 514+pattern X25519MLKEM768 :: Group+pattern X25519MLKEM768  = Group 4588+pattern P256MLKEM768   :: Group+pattern P256MLKEM768    = Group 4587+pattern P384MLKEM1024  :: Group+pattern P384MLKEM1024   = Group 4589  instance Show Group where     show P256      = "P256"@@ -67,6 +87,12 @@     show FFDHE4096 = "FFDHE4096"     show FFDHE6144 = "FFDHE6144"     show FFDHE8192 = "FFDHE8192"+    show MLKEM512  = "MLKEM512"+    show MLKEM768  = "MLKEM768"+    show MLKEM1024 = "MLKEM1024"+    show X25519MLKEM768 = "X25519MLKEM768"+    show P256MLKEM768   = "P256MLKEM768"+    show P384MLKEM1024  = "P384MLKEM1024"     show (Group x) = "Group " ++ show x {- FOURMOLU_ENABLE -} @@ -76,18 +102,39 @@ availableECGroups :: [Group] availableECGroups = [P256, P384, P521, X25519, X448] +availableHybridGroups :: [Group]+availableHybridGroups = [X25519MLKEM768, P256MLKEM768, P384MLKEM1024]++-- | A list for named groups.  The ordering is for client preference+--   because server preference is not used in our server+--   implementation. supportedNamedGroups :: [Group] supportedNamedGroups =-    [ X25519-    , X448-    , P256-    , FFDHE2048-    , FFDHE3072-    , FFDHE4096-    , P384-    , FFDHE6144-    , FFDHE8192-    , P521+    [ X25519 -- 128 bits security+    , P256 -- 128 bits security+    , P384 -- 192 bits security+    , X448 -- 224 bits security+    , P521 -- 256 bits security+    --    , FFDHE2048 -- 103 bits security+    , FFDHE3072 -- 125 bits security+    , FFDHE4096 -- 150 bits security+    , FFDHE6144 -- 175 bits security+    , FFDHE8192 -- 192 bits security+    , X25519MLKEM768+    , P256MLKEM768+    , P384MLKEM1024+    , -- , MLKEM512+      MLKEM768+    , MLKEM1024+    ]++supportedNamedGroupsTLS13 :: [[Group]]+supportedNamedGroupsTLS13 =+    [ [X25519MLKEM768, P256MLKEM768, P384MLKEM1024]+    , [X25519, P256]+    , [P384, X448, P521]+    , [FFDHE2048, FFDHE3072, FFDHE4096, FFDHE6144, FFDHE8192]+    , [MLKEM768, MLKEM1024]     ]  -- Key-exchange signature algorithm, in close relation to ciphers
Network/TLS/Extension.hs view
@@ -443,7 +443,7 @@ ------------------------------------------------------------  -- | Server Name extension including the name type and the associated name.--- the associated name decoding is dependant of its name type.+-- the associated name decoding is dependent of its name type. -- name type = 0 : hostname newtype ServerName = ServerName [ServerNameType] deriving (Show, Eq) 
+ Network/TLS/Extra/CipherCBC.hs view
@@ -0,0 +1,201 @@+module Network.TLS.Extra.CipherCBC (+    -- * TLS 1.2 CBC ciphers with PFS and SHA2+    ciphersuite_pfs_sha2_cbc,+    ciphersuite_ecdhe_sha2_cbc,+    ciphersuite_dhe_rsa_sha2_cbc,++    -- ** Individual CBC ciphers+    cipher_DHE_RSA_AES128_SHA256,+    cipher_DHE_RSA_AES256_SHA256,+    cipher_ECDHE_RSA_AES128CBC_SHA256,+    cipher_ECDHE_RSA_AES256CBC_SHA384,+    cipher_ECDHE_ECDSA_AES128CBC_SHA256,+) where++import Crypto.Cipher.AES+import Crypto.Cipher.Types hiding (Cipher, cipherName)+import Crypto.Error+-- import Crypto.System.CPU+import qualified Data.ByteString as B++import Network.TLS.Cipher+import Network.TLS.Imports+import Network.TLS.Types hiding (IV)++----------------------------------------------------------------++-- | TLS 1.2 AES CBC ciphers with DHE or ECDHE key exchange, ECDSA or RSA+-- authentication and a SHA256 or SHA2384 MAC.+-- For legacy applications only, deprecated in HTTPS.+ciphersuite_pfs_sha2_cbc :: [Cipher]+ciphersuite_pfs_sha2_cbc =+    [ cipher_ECDHE_ECDSA_AES128CBC_SHA256+    , cipher_ECDHE_ECDSA_AES256CBC_SHA384+    , cipher_ECDHE_RSA_AES128CBC_SHA256+    , cipher_ECDHE_RSA_AES256CBC_SHA384+    , cipher_DHE_RSA_AES128_SHA256+    , cipher_DHE_RSA_AES256_SHA256+    ]++-- | TLS 1.2 AES CBC ciphers with ECDHE key exchange, ECDSA or RSA+-- authentication and a SHA256 or SHA2384 MAC.+-- For legacy applications only, deprecated in HTTPS.+ciphersuite_ecdhe_sha2_cbc :: [Cipher]+ciphersuite_ecdhe_sha2_cbc =+    [ cipher_ECDHE_ECDSA_AES128CBC_SHA256+    , cipher_ECDHE_ECDSA_AES256CBC_SHA384+    , cipher_ECDHE_RSA_AES128CBC_SHA256+    , cipher_ECDHE_RSA_AES256CBC_SHA384+    ]++-- | TLS 1.2 AES CBC ciphers with DHE key exchange, RSA authentication and a+-- SHA256 MAC.+-- For legacy applications only, deprecated in HTTPS.+ciphersuite_dhe_rsa_sha2_cbc :: [Cipher]+ciphersuite_dhe_rsa_sha2_cbc =+    [ cipher_DHE_RSA_AES256_SHA256+    , cipher_DHE_RSA_AES128_SHA256+    ]++----------------------------------------------------------------++-- | TLS 1.2 AES128 CBC, with DHE key exchange, RSA authentication and a SHA256 MAC.+-- For legacy applications only, deprecated in HTTPS.+cipher_DHE_RSA_AES128_SHA256 :: Cipher+cipher_DHE_RSA_AES128_SHA256 =+    Cipher+        { cipherID = 0x0067+        , cipherName = "DHE-RSA-AES128-SHA256"+        , cipherBulk = bulk_aes128+        , cipherHash = SHA256+        , cipherPRFHash = Just SHA256+        , cipherKeyExchange = CipherKeyExchange_DHE_RSA+        , cipherMinVer = Just TLS12 -- RFC 5288 Sec 4+        }++-- | TLS 1.2 AES256 CBC, with DHE key exchange, RSA authentication and a SHA256 MAC.+-- For legacy applications only, deprecated in HTTPS.+cipher_DHE_RSA_AES256_SHA256 :: Cipher+cipher_DHE_RSA_AES256_SHA256 =+    cipher_DHE_RSA_AES128_SHA256+        { cipherID = 0x006B+        , cipherName = "DHE-RSA-AES256-SHA256"+        , cipherBulk = bulk_aes256+        }++-- | TLS 1.2 AES128 CBC, with ECDHE key exchange, RSA authentication and a SHA256 MAC.+-- For legacy applications only, deprecated in HTTPS.+cipher_ECDHE_RSA_AES128CBC_SHA256 :: Cipher+cipher_ECDHE_RSA_AES128CBC_SHA256 =+    Cipher+        { cipherID = 0xC027+        , cipherName = "ECDHE-RSA-AES128CBC-SHA256"+        , cipherBulk = bulk_aes128+        , cipherHash = SHA256+        , cipherPRFHash = Just SHA256+        , cipherKeyExchange = CipherKeyExchange_ECDHE_RSA+        , cipherMinVer = Just TLS12 -- RFC 5288 Sec 4+        }++-- | TLS 1.2 AES256 CBC, with ECDHE key exchange, RSA authentication and a SHA384 MAC.+-- For legacy applications only, deprecated in HTTPS.+cipher_ECDHE_RSA_AES256CBC_SHA384 :: Cipher+cipher_ECDHE_RSA_AES256CBC_SHA384 =+    Cipher+        { cipherID = 0xC028+        , cipherName = "ECDHE-RSA-AES256CBC-SHA384"+        , cipherBulk = bulk_aes256+        , cipherHash = SHA384+        , cipherPRFHash = Just SHA384+        , cipherKeyExchange = CipherKeyExchange_ECDHE_RSA+        , cipherMinVer = Just TLS12 -- RFC 5288 Sec 4+        }++-- | TLS 1.2 AES128 CBC, with ECDHE key exchange, ECDSA authentication and a SHA256 MAC.+-- For legacy applications only, deprecated in HTTPS.+cipher_ECDHE_ECDSA_AES128CBC_SHA256 :: Cipher+cipher_ECDHE_ECDSA_AES128CBC_SHA256 =+    Cipher+        { cipherID = 0xc023+        , cipherName = "ECDHE-ECDSA-AES128CBC-SHA256"+        , cipherBulk = bulk_aes128+        , cipherHash = SHA256+        , cipherPRFHash = Just SHA256+        , cipherKeyExchange = CipherKeyExchange_ECDHE_ECDSA+        , cipherMinVer = Just TLS12 -- RFC 5289+        }++-- | TLS 1.2 AES256 CBC, with ECDHE key exchange, ECDSA authentication and a SHA384 MAC.+-- For legacy applications only, deprecated in HTTPS.+cipher_ECDHE_ECDSA_AES256CBC_SHA384 :: Cipher+cipher_ECDHE_ECDSA_AES256CBC_SHA384 =+    Cipher+        { cipherID = 0xC024+        , cipherName = "ECDHE-ECDSA-AES256CBC-SHA384"+        , cipherBulk = bulk_aes256+        , cipherHash = SHA384+        , cipherPRFHash = Just SHA384+        , cipherKeyExchange = CipherKeyExchange_ECDHE_ECDSA+        , cipherMinVer = Just TLS12 -- RFC 5289+        }++----------------------------------------------------------------++aes128cbc :: BulkDirection -> BulkKey -> BulkBlock+aes128cbc BulkEncrypt key =+    let ctx = noFail (cipherInit key) :: AES128+     in ( \iv input ->+            let output = cbcEncrypt ctx (makeIV_ iv) input in (output, takelast 16 output)+        )+aes128cbc BulkDecrypt key =+    let ctx = noFail (cipherInit key) :: AES128+     in ( \iv input ->+            let output = cbcDecrypt ctx (makeIV_ iv) input in (output, takelast 16 input)+        )++aes256cbc :: BulkDirection -> BulkKey -> BulkBlock+aes256cbc BulkEncrypt key =+    let ctx = noFail (cipherInit key) :: AES256+     in ( \iv input ->+            let output = cbcEncrypt ctx (makeIV_ iv) input in (output, takelast 16 output)+        )+aes256cbc BulkDecrypt key =+    let ctx = noFail (cipherInit key) :: AES256+     in ( \iv input ->+            let output = cbcDecrypt ctx (makeIV_ iv) input in (output, takelast 16 input)+        )++makeIV_ :: BlockCipher a => B.ByteString -> IV a+makeIV_ = fromMaybe (error "makeIV_") . makeIV++takelast :: Int -> B.ByteString -> B.ByteString+takelast i b = B.drop (B.length b - i) b++noFail :: CryptoFailable a -> a+noFail = throwCryptoError++----------------------------------------------------------------++bulk_aes128 :: Bulk+bulk_aes128 =+    Bulk+        { bulkName = "AES128"+        , bulkKeySize = 16+        , bulkIVSize = 16+        , bulkExplicitIV = 0+        , bulkAuthTagLen = 0+        , bulkBlockSize = 16+        , bulkF = BulkBlockF aes128cbc+        }++bulk_aes256 :: Bulk+bulk_aes256 =+    Bulk+        { bulkName = "AES256"+        , bulkKeySize = 32+        , bulkIVSize = 16+        , bulkExplicitIV = 0+        , bulkAuthTagLen = 0+        , bulkBlockSize = 16+        , bulkF = BulkBlockF aes256cbc+        }
Network/TLS/Handshake.hs view
@@ -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
Network/TLS/Handshake/Certificate.hs view
@@ -3,13 +3,20 @@     badCertificate,     rejectOnException,     verifyLeafKeyUsage,+    verifyLeafKeyUsagePurpose,     extractCAname, ) where  import Control.Exception (SomeException) import Control.Monad (unless) import Control.Monad.State.Strict-import Data.X509 (ExtKeyUsage (..), ExtKeyUsageFlag, extensionGet)+import Data.X509 (+    ExtExtendedKeyUsage (..),+    ExtKeyUsage (..),+    ExtKeyUsageFlag,+    ExtKeyUsagePurpose (..),+    extensionGet,+ )  import Network.TLS.Context.Internal import Network.TLS.Struct@@ -46,6 +53,19 @@         case extensionGet (certExtensions cert) of             Nothing -> True -- unrestricted cert             Just (ExtKeyUsage flags) -> any (`elem` validFlags) flags++verifyLeafKeyUsagePurpose+    :: MonadIO m => ExtKeyUsagePurpose -> CertificateChain -> m ()+verifyLeafKeyUsagePurpose _ (CertificateChain []) = return ()+verifyLeafKeyUsagePurpose validPurpose (CertificateChain (signed : _)) =+    unless verified $+        badCertificate $+            "certificate is not allowed for " ++ show validPurpose+  where+    cert = getCertificate signed+    verified = case extensionGet (certExtensions cert) of+        Nothing -> True+        Just (ExtExtendedKeyUsage purposes) -> validPurpose `elem` purposes  extractCAname :: SignedCertificate -> DistinguishedName extractCAname cert = certSubjectDN $ getCertificate cert
Network/TLS/Handshake/Client.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}  module Network.TLS.Handshake.Client (     handshakeClient,@@ -26,8 +27,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@@ -38,16 +40,34 @@ -- values intertwined with response from the server. handshakeClient :: ClientParams -> Context -> IO () handshakeClient cparams ctx = do-    groups <- case clientSessions cparams of-        [] -> return groupsSupported+    grps <- case clientSessions cparams of+        [] ->+            return $+                Groups+                    { grpsSupported = groupsSupported+                    , grpsSelected = groupsSelected+                    }         (_, sdata) : _ -> case sessionGroup sdata of-            Nothing -> return [] -- TLS 1.2 or earlier+            Nothing ->+                -- TLS 1.2 or earlier+                return $+                    Groups+                        { grpsSupported = groupsSupported -- for ciphers+                        , grpsSelected = []+                        }             Just grp-                | grp `elem` groupsSupported -> return $ grp : filter (/= grp) groupsSupported+                | grp `elem` groupsSupported -> do+                    let supported = grp : filter (/= grp) groupsSupported+                    return $+                        Groups+                            { grpsSupported = supported+                            , grpsSelected = [grp]+                            }                 | otherwise -> throwCore $ Error_Misc "groupsSupported is incorrect"-    handshake cparams ctx groups Nothing+    handshake cparams ctx grps Nothing   where     groupsSupported = supportedGroups (ctxSupported ctx)+    groupsSelected = onSelectKeyShareGroups (clientHooks cparams) groupsSupported  -- https://tools.ietf.org/html/rfc8446#section-4.1.2 says: -- "The client will also send a@@ -59,10 +79,10 @@ handshake     :: ClientParams     -> Context-    -> [Group]+    -> Groups     -> Maybe (ClientRandom, Session, Version)     -> IO ()-handshake cparams ctx groups mparams = do+handshake cparams ctx grps@Groups{..} mparams = do     --------------------------------     -- Sending ClientHello     pskinfo@(_, _, rtt0) <- getPreSharedKeyInfo cparams ctx@@ -70,21 +90,21 @@     let async = rtt0 && not (ctxQUICMode ctx)     when async $ do         chSentTime <- getCurrentTimeFromBase-        asyncServerHello13 cparams ctx groupToSend chSentTime+        asyncServerHello13 cparams ctx grpsSelected chSentTime     updateMeasure ctx incrementNbHandshakes-    crand <- sendClientHello cparams ctx groups mparams pskinfo+    crand <-+        sendClientHello cparams ctx grps mparams pskinfo     --------------------------------     -- 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             TLS13                 | hrr ->-                    helloRetry cparams ctx mparams ver crand $ drop 1 groups+                    helloRetry cparams ctx mparams ver crand grpsSupported grpsSelected                 | otherwise -> do-                    recvServerSecondFlight13 cparams ctx groupToSend+                    recvServerSecondFlight13 cparams ctx grpsSelected                     sendClientSecondFlight13 cparams ctx             _                 | rtt0 ->@@ -93,11 +113,9 @@                             "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-    groupToSend = listToMaybe groups  ---------------------------------------------------------------- @@ -108,24 +126,46 @@     -> Version     -> ClientRandom     -> [Group]+    -> [Group]     -> IO ()-helloRetry cparams ctx mparams ver crand groups = do-    when (null groups) $+helloRetry cparams ctx mparams ver crand groupsSupported groupsSelected = do+    when (null groupsSupported) $         throwCore $-            Error_Protocol "group is exhausted in the client side" IllegalParameter+            Error_Protocol "no supported groups on the client side" IllegalParameter     when (isJust mparams) $         throwCore $             Error_Protocol "server sent too many hello retries" UnexpectedMessage     mks <- usingState_ ctx getTLS13KeyShare     case mks of         Just (KeyShareHRR selectedGroup)-            | selectedGroup `elem` groups -> do+            -- RFC 8446 Sec 4.1.4: the selected_group MUST be in supported_groups+            -- and MUST NOT already have been offered in the initial key_share.+            | selectedGroup `elem` groupsSupported+                && selectedGroup `notElem` groupsSelected -> do                 usingHState ctx $ setTLS13HandshakeMode HelloRetryRequest                 clearTxRecordState ctx                 let cparams' = cparams{clientUseEarlyData = False}                 runPacketFlight ctx $ sendChangeCipherSpec13 ctx                 clientSession <- tls13stSession <$> getTLS13State ctx-                handshake cparams' ctx [selectedGroup] (Just (crand, clientSession, ver))+                -- RFC 8446 Sec 4.1.2: the second ClientHello MUST be identical+                -- to the first except for the specific listed changes.+                -- supported_groups is NOT on that list, so it must be unchanged.+                let grps =+                        Groups+                            { grpsSupported = groupsSupported+                            , grpsSelected = [selectedGroup]+                            }++                handshake+                    cparams'+                    ctx+                    grps+                    (Just (crand, clientSession, ver))+            | selectedGroup `elem` groupsSelected ->+                throwCore $+                    Error_Protocol+                        "server selected a group already offered in key_share"+                        IllegalParameter             | otherwise ->                 throwCore $                     Error_Protocol "server-selected group is not supported" IllegalParameter
Network/TLS/Handshake/Client/ClientHello.hs view
@@ -5,10 +5,13 @@ module Network.TLS.Handshake.Client.ClientHello (     sendClientHello,     getPreSharedKeyInfo,+    Groups (..), ) where  import qualified Control.Exception as E-import Crypto.HPKE+import Crypto.HPKE hiding (CipherText, PlainText)+import Data.ByteArray (convert)+import qualified Data.ByteArray as BA import qualified Data.ByteString as B import Network.TLS.ECH.Config import System.Random@@ -41,16 +44,26 @@  ---------------------------------------------------------------- +data Groups = Groups+    { grpsSupported :: [Group]+    -- ^ For supported_group, head is identical to key_share+    , grpsSelected :: [Group]+    -- ^ For key_share+    }+    deriving (Eq, Show)++----------------------------------------------------------------+ sendClientHello     :: ClientParams     -> Context-    -> [Group]+    -> Groups     -> Maybe (ClientRandom, Session, Version)     -> PreSharedKeyInfo     -> IO ClientRandom-sendClientHello cparams ctx groups mparams pskinfo = do+sendClientHello cparams ctx grps mparams pskinfo = do     crand <- generateClientHelloParams mparams -- Inner for ECH-    sendClientHello' cparams ctx groups crand pskinfo+    sendClientHello' cparams ctx grps crand pskinfo     return crand   where     highestVer = maximum $ supportedVersions $ ctxSupported ctx@@ -89,14 +102,14 @@ sendClientHello'     :: ClientParams     -> Context-    -> [Group]+    -> Groups     -> ClientRandom     -> ( Maybe ([ByteString], SessionData, CipherChoice, Word32)        , Maybe CipherChoice        , Bool        )     -> IO ()-sendClientHello' cparams ctx groups crand (pskInfo, rtt0info, rtt0) = do+sendClientHello' cparams ctx Groups{..} crand (pskInfo, rtt0info, rtt0) = do     let ver = if tls13 then TLS12 else highestVer     clientSession <- tls13stSession <$> getTLS13State ctx     hrr <- usingState_ ctx getTLS13HRR@@ -127,17 +140,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 +166,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@@ -162,7 +182,6 @@     highestVer = maximum $ supportedVersions $ ctxSupported ctx     tls13 = highestVer >= TLS13     ems = supportedExtendedMainSecret $ ctxSupported ctx-    groupToSend = listToMaybe groups      -- List of extensions to send in ClientHello, ordered such that we never     -- terminate with a zero-length extension.  Some buggy implementations@@ -204,11 +223,10 @@                 return $ Just $ toExtensionRaw $ ServerName [ServerNameHostName sni]             else return Nothing -    groupExt =-        return $-            Just $-                toExtensionRaw $-                    SupportedGroups (supportedGroups $ ctxSupported ctx)+    -- RFC 8446 Sec 4.2.8 says: Each KeyShareEntry value MUST correspond+    -- to a group offered in the "supported_groups" extension and MUST+    -- appear in the same order.+    groupExt = return $ Just $ toExtensionRaw $ SupportedGroups grpsSupported      ecPointExt =         return $@@ -244,11 +262,12 @@         Nothing -> return Nothing         Just siz -> return $ Just $ toExtensionRaw $ RecordSizeLimit $ fromIntegral siz -    sessionTicketExt = do+    sessionTicketExt =         case clientSessions cparams of             (sidOrTkt, _) : _                 | isTicket sidOrTkt -> return $ Just $ toExtensionRaw $ SessionTicket sidOrTkt-            _ -> return $ Just $ toExtensionRaw $ SessionTicket ""+            _   | clientWantTicket cparams -> return $ Just $ toExtensionRaw $ SessionTicket ""+                | otherwise -> return $ Nothing      earlyDataExt         | rtt0 = return $ Just $ toExtensionRaw (EarlyDataIndication Nothing)@@ -282,14 +301,11 @@         | tls13 = return $ Just $ toExtensionRaw PostHandshakeAuth         | otherwise = return Nothing -    -- FIXME     keyShareExt-        | tls13 = case groupToSend of-            Nothing -> return Nothing-            Just grp -> do-                (cpri, ent) <- makeClientKeyShare ctx grp-                usingHState ctx $ setGroupPrivate cpri-                return $ Just $ toExtensionRaw $ KeyShareClientHello [ent]+        | tls13 = do+            (grpCpris, ents) <- unzip <$> mapM (makeClientKeyShare ctx) grpsSelected+            usingHState ctx $ setGroupPrivate grpCpris+            return $ Just $ toExtensionRaw $ KeyShareClientHello ents         | otherwise = return Nothing      secureRenegExt =@@ -312,7 +328,7 @@                     pskIdentities = map (\x -> PskIdentity x obfAge) identities                     -- [zero] is a place holds.                     -- adjustPreSharedKeyExt will replace them.-                    binders = replicate (length pskIdentities) zero+                    binders = replicate (length pskIdentities) $ convert zero                     offeredPsks = PreSharedKeyClientHello pskIdentities binders                 return $ Just $ toExtensionRaw offeredPsks @@ -322,7 +338,7 @@             Nothing -> return Nothing             Just (identities, _, choice, _) -> do                 let zero = cZero choice-                zeroR <- getStdRandom $ uniformByteString $ B.length zero+                zeroR <- getStdRandom $ uniformByteString $ BA.length zero                 obfAgeR <- getStdRandom genWord32                 let genPskId x = do                         xR <- getStdRandom $ uniformByteString $ B.length x
Network/TLS/Handshake/Client/ServerHello.hs view
@@ -6,6 +6,7 @@     processServerHello13, ) where +import Data.ByteArray (convert) import qualified Data.ByteString as B  import Network.TLS.Cipher@@ -35,12 +36,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 +52,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 +60,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 +180,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"@@ -245,7 +246,7 @@             when (ems /= emsSession) $                 let err = "server resumes a session which is not EMS consistent"                  in throwCore $ Error_Protocol err HandshakeFailure-            let mainSecret = sessionSecret sessionData+            let mainSecret = convert $ sessionSecret sessionData             usingHState ctx $ setMainSecret TLS12 ClientRole mainSecret             logKey ctx (MainSecret mainSecret) 
Network/TLS/Handshake/Client/TLS12.hs view
@@ -8,6 +8,7 @@ ) where  import Control.Monad.State.Strict+import Data.ByteArray (convert) import qualified Data.ByteString as B  import Network.TLS.Cipher@@ -32,14 +33,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 +153,7 @@             unless (null certs) $                 usingHState ctx $                     setClientCertSent True-            sendPacket12 ctx $ Handshake [Certificate (CertificateChain_ cc)]+            sendPacket12 ctx $ Handshake [Certificate (CertificateChain_ cc)] []  ---------------------------------------------------------------- @@ -167,19 +169,19 @@         _ ->             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)  --------------------------------  getCKX_RSA-    :: Context -> IO (ClientKeyXchgAlgorithmData, HandshakeM ByteString)+    :: Context -> IO (ClientKeyXchgAlgorithmData, HandshakeM Secret) getCKX_RSA ctx = do     clientVersion <- usingHState ctx $ gets hstClientVersion     (xver, prerand) <- usingState_ ctx $ (,) <$> getVersion <*> genRandom 46 -    let preMain = encodePreMainSecret clientVersion prerand+    let preMain = convert $ encodePreMainSecret clientVersion prerand         setMainSec = setMainSecretFromPre xver ClientRole preMain     encryptedPreMain <- do         -- SSL3 implementation generally forget this length field since it's redundant,@@ -194,7 +196,7 @@ getCKX_DHE     :: ClientParams     -> Context-    -> IO (ClientKeyXchgAlgorithmData, HandshakeM ByteString)+    -> IO (ClientKeyXchgAlgorithmData, HandshakeM Secret) getCKX_DHE cparams ctx = do     xver <- usingState_ ctx getVersion     serverParams <- usingHState ctx getServerDHParams@@ -241,12 +243,12 @@ --------------------------------  getCKX_ECDHE-    :: Context -> IO (ClientKeyXchgAlgorithmData, HandshakeM ByteString)+    :: Context -> IO (ClientKeyXchgAlgorithmData, HandshakeM Secret) getCKX_ECDHE ctx = do     ServerECDHParams grp srvpub <- usingHState ctx getServerECDHParams     checkSupportedGroup ctx grp     usingHState ctx $ setSupportedGroup grp-    ecdhePair <- generateECDHEShared ctx srvpub+    ecdhePair <- encapsulateGroup ctx srvpub     case ecdhePair of         Nothing ->             throwCore $@@ -254,7 +256,7 @@         Just (clipub, preMain) -> do             xver <- usingState_ ctx getVersion             let setMainSec = setMainSecretFromPre xver ClientRole preMain-            return (CKX_ECDH $ encodeGroupPublic clipub, setMainSec)+            return (CKX_ECDH $ groupEncodePublicB clipub, setMainSec)  ---------------------------------------------------------------- @@ -283,4 +285,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] []
Network/TLS/Handshake/Client/TLS13.hs view
@@ -9,7 +9,7 @@  import Control.Exception (bracket) import Control.Monad.State.Strict-import qualified Data.ByteString as B+import qualified Data.ByteArray as BA import Data.IORef  import Network.TLS.Cipher@@ -39,7 +39,7 @@ ---------------------------------------------------------------- ---------------------------------------------------------------- -recvServerSecondFlight13 :: ClientParams -> Context -> Maybe Group -> IO ()+recvServerSecondFlight13 :: ClientParams -> Context -> [Group] -> IO () recvServerSecondFlight13 cparams ctx groupSent = do     resuming <- prepareSecondFlight13 ctx groupSent     runRecvHandshake13 $ do@@ -50,14 +50,14 @@ ----------------------------------------------------------------  prepareSecondFlight13-    :: Context -> Maybe Group -> IO Bool+    :: Context -> [Group] -> IO Bool prepareSecondFlight13 ctx groupSent = do     choice <- makeCipherChoice TLS13 <$> usingHState ctx getPendingCipher     prepareSecondFlight13' ctx groupSent choice  prepareSecondFlight13'     :: Context-    -> Maybe Group+    -> [Group]     -> CipherChoice     -> IO Bool prepareSecondFlight13' ctx groupSent choice = do@@ -100,10 +100,10 @@                             "key exchange not implemented, expected key_share extension"                             HandshakeFailure         let grp = keyShareEntryGroup serverKeyShare-        unless (checkKeyShareKeyLength serverKeyShare) $+        unless (checkServerKeyShareKeyLength serverKeyShare) $             throwCore $                 Error_Protocol "broken key_share" IllegalParameter-        unless (groupSent == Just grp) $+        unless (grp `elem` groupSent) $             throwCore $                 Error_Protocol "received incompatible group for (EC)DHE" IllegalParameter         usingHState ctx $ setSupportedGroup grp@@ -119,7 +119,7 @@                     Nothing ->                         return (initEarlySecret choice Nothing, False)                     Just (PreSharedKeyServerHello 0) -> do-                        unless (B.length sec == hashSize) $+                        unless (BA.length sec == hashSize) $                             throwCore $                                 Error_Protocol                                     "selected cipher is incompatible with selected PSK"@@ -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) $@@ -399,19 +403,19 @@ ----------------------------------------------------------------  asyncServerHello13-    :: ClientParams -> Context -> Maybe Group -> Millisecond -> IO ()+    :: ClientParams -> Context -> [Group] -> Millisecond -> IO () 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
Network/TLS/Handshake/Common.hs view
@@ -31,6 +31,7 @@     --     setPeerRecordSizeLimit,     generateFinished,+    encodeUpdateTranscriptHash12,     updateTranscriptHash12,     --     startHandshake,@@ -41,6 +42,7 @@ import Control.Concurrent.MVar import Control.Exception (IOException, fromException, handle, throwIO) import Control.Monad.State.Strict+import Data.ByteArray (convert) import qualified Data.ByteString as B  import Network.TLS.Cipher@@ -132,7 +134,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 +143,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 +163,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 +188,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@@ -239,7 +244,7 @@                         , sessionCipher = cipher                         , sessionCompression = compression                         , sessionClientSNI = sni-                        , sessionSecret = ms+                        , sessionSecret = convert ms                         , sessionGroup = Nothing                         , sessionTicketInfo = Nothing                         , sessionALPN = alpn@@ -359,15 +364,15 @@                 generateServerFinished ver cipher mainSecret thash  generateFinished'-    :: PRF -> ByteString -> ByteString -> TranscriptHash -> ByteString-generateFinished' prf label mainSecret (TranscriptHash thash) = prf mainSecret seed 12+    :: PRF -> ByteString -> Secret -> TranscriptHash -> ByteString+generateFinished' prf label mainSecret (TranscriptHash thash) = convert $ prf mainSecret seed 12   where     seed = label <> thash  generateClientFinished     :: Version     -> Cipher-    -> ByteString+    -> Secret     -> TranscriptHash     -> ByteString generateClientFinished ver ciph =@@ -376,7 +381,7 @@ generateServerFinished     :: Version     -> Cipher-    -> ByteString+    -> Secret     -> TranscriptHash     -> ByteString generateServerFinished ver ciph =
Network/TLS/Handshake/Common13.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-}@@ -36,7 +37,8 @@     calculateApplicationSecret,     calculateResumptionSecret,     derivePSK,-    checkKeyShareKeyLength,+    checkClientKeyShareKeyLength,+    checkServerKeyShareKeyLength,     setRTT,     computeConfirm,     updateTranscriptHash13,@@ -46,7 +48,7 @@  import Control.Concurrent.MVar import Control.Monad.State.Strict-import qualified Data.ByteArray as BA+import Data.ByteArray (convert) import qualified Data.ByteString as B import Data.UnixTime import Foreign.C.Types (CTime (..))@@ -68,7 +70,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@@ -79,7 +80,7 @@  ---------------------------------------------------------------- -makeFinished :: MonadIO m => Context -> Hash -> ByteString -> m Handshake13+makeFinished :: MonadIO m => Context -> Hash -> Secret -> m Handshake13 makeFinished ctx usedHash baseKey = do     verifyData <-         VerifyData . makeVerifyData usedHash baseKey@@ -89,7 +90,7 @@  checkFinished     :: MonadIO m-    => Context -> Hash -> ByteString -> TranscriptHash -> VerifyData -> m ()+    => Context -> Hash -> Secret -> TranscriptHash -> VerifyData -> m () checkFinished ctx usedHash baseKey (TranscriptHash hashValue) vd@(VerifyData verifyData) = do     let verifyData' = makeVerifyData usedHash baseKey $ TranscriptHash hashValue     when (B.length verifyData /= B.length verifyData') $@@ -98,7 +99,7 @@     unless (verifyData' == verifyData) $ decryptError "finished verification failed"     liftIO $ usingState_ ctx $ setVerifyDataForRecv vd -makeVerifyData :: Hash -> ByteString -> TranscriptHash -> ByteString+makeVerifyData :: Hash -> Secret -> TranscriptHash -> ByteString makeVerifyData usedHash baseKey (TranscriptHash th) =     hmac usedHash finishedKey th   where@@ -107,38 +108,41 @@  ---------------------------------------------------------------- -makeServerKeyShare :: Context -> KeyShareEntry -> IO (ByteString, KeyShareEntry)+makeClientKeyShare+    :: Context -> Group -> IO ((Group, IES.GroupPrivate), KeyShareEntry)+makeClientKeyShare ctx grp = do+    (cpri, cpub) <- generateGroup ctx grp+    let wcpub = IES.groupEncodePublicA cpub+        clientKeyShare = KeyShareEntry grp wcpub+    return ((grp, cpri), clientKeyShare)++makeServerKeyShare :: Context -> KeyShareEntry -> IO (Secret, KeyShareEntry) makeServerKeyShare ctx (KeyShareEntry grp wcpub) = case ecpub of     Left e -> throwCore $ Error_Protocol (show e) IllegalParameter     Right cpub -> do-        ecdhePair <- generateECDHEShared ctx cpub+        ecdhePair <- encapsulateGroup ctx cpub         case ecdhePair of             Nothing -> throwCore $ Error_Protocol msgInvalidPublic IllegalParameter             Just (spub, share) ->-                let wspub = IES.encodeGroupPublic spub+                let wspub = IES.groupEncodePublicB spub                     serverKeyShare = KeyShareEntry grp wspub-                 in return (BA.convert share, serverKeyShare)+                 in return (share, serverKeyShare)   where-    ecpub = IES.decodeGroupPublic grp wcpub+    ecpub = IES.groupDecodePublicA grp wcpub     msgInvalidPublic = "invalid client " ++ show grp ++ " public key" -makeClientKeyShare :: Context -> Group -> IO (IES.GroupPrivate, KeyShareEntry)-makeClientKeyShare ctx grp = do-    (cpri, cpub) <- generateECDHE ctx grp-    let wcpub = IES.encodeGroupPublic cpub-        clientKeyShare = KeyShareEntry grp wcpub-    return (cpri, clientKeyShare)--fromServerKeyShare :: KeyShareEntry -> IES.GroupPrivate -> IO ByteString-fromServerKeyShare (KeyShareEntry grp wspub) cpri = case espub of+fromServerKeyShare+    :: KeyShareEntry -> [(Group, IES.GroupPrivate)] -> IO Secret+fromServerKeyShare (KeyShareEntry grp wspub) grpCpris = case espub of     Left e -> throwCore $ Error_Protocol (show e) IllegalParameter-    Right spub -> case IES.groupGetShared spub cpri of-        Just shared -> return $ BA.convert shared-        Nothing ->-            throwCore $-                Error_Protocol "cannot generate a shared secret on (EC)DH" IllegalParameter+    Right spub -> case lookup grp grpCpris of+        Nothing -> throwCore err+        Just cpri -> case IES.groupDecapsulate spub cpri of+            Just shared -> return shared+            Nothing -> throwCore err   where-    espub = IES.decodeGroupPublic grp wspub+    err = Error_Protocol "cannot generate a shared secret on (EC)DH" IllegalParameter+    espub = IES.groupDecodePublicB grp wspub  ---------------------------------------------------------------- @@ -373,7 +377,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 +386,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 +396,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,11 +468,11 @@     -> 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+            Left psk -> hkdfExtract usedHash zero (convert psk)         clientEarlySecret = deriveSecret usedHash earlySecret "c e traffic" hCh         cets = ClientTrafficSecret clientEarlySecret :: ClientTrafficSecret EarlySecret     logKey ctx cets@@ -481,13 +487,13 @@     sec = hkdfExtract usedHash zero zeroOrPSK     usedHash = cHash choice     zero = cZero choice-    zeroOrPSK = fromMaybe zero mpsk+    zeroOrPSK = fromMaybe zero (convert <$> mpsk)  calculateHandshakeSecret     :: Context     -> CipherChoice     -> BaseSecret EarlySecret-    -> ByteString+    -> Secret     -> IO (SecretTriple HandshakeSecret) calculateHandshakeSecret ctx choice (BaseSecret sec) ecdhe = do     hChSh <- transcriptHash ctx "CH..SH"@@ -561,25 +567,60 @@  ---------------------------------------------------------------- -checkKeyShareKeyLength :: KeyShareEntry -> Bool-checkKeyShareKeyLength ks = keyShareKeyLength grp == B.length key+checkClientKeyShareKeyLength :: KeyShareEntry -> Bool+checkClientKeyShareKeyLength ks = clientKeyShareKeyLength grp == B.length key   where     grp = keyShareEntryGroup ks     key = keyShareEntryKeyExchange ks -keyShareKeyLength :: Group -> Int-keyShareKeyLength P256 = 65 -- 32 * 2 + 1-keyShareKeyLength P384 = 97 -- 48 * 2 + 1-keyShareKeyLength P521 = 133 -- 66 * 2 + 1-keyShareKeyLength X25519 = 32-keyShareKeyLength X448 = 56-keyShareKeyLength FFDHE2048 = 256-keyShareKeyLength FFDHE3072 = 384-keyShareKeyLength FFDHE4096 = 512-keyShareKeyLength FFDHE6144 = 768-keyShareKeyLength FFDHE8192 = 1024-keyShareKeyLength _ = error "keyShareKeyLength"+{- FOURMOLU_DISABLE -}+clientKeyShareKeyLength :: Group -> Int+clientKeyShareKeyLength P256   = 65  -- 32 * 2 + 1+clientKeyShareKeyLength P384   = 97  -- 48 * 2 + 1+clientKeyShareKeyLength P521   = 133 -- 66 * 2 + 1+clientKeyShareKeyLength X25519 = 32+clientKeyShareKeyLength X448   = 56+clientKeyShareKeyLength FFDHE2048 = 256+clientKeyShareKeyLength FFDHE3072 = 384+clientKeyShareKeyLength FFDHE4096 = 512+clientKeyShareKeyLength FFDHE6144 = 768+clientKeyShareKeyLength FFDHE8192 = 1024+clientKeyShareKeyLength MLKEM512  = 800+clientKeyShareKeyLength MLKEM768  = 1184+clientKeyShareKeyLength MLKEM1024 = 1568+clientKeyShareKeyLength X25519MLKEM768 = 1216+clientKeyShareKeyLength P256MLKEM768   = 1249+clientKeyShareKeyLength P384MLKEM1024  = 1665+clientKeyShareKeyLength _ = error "clientKeyShareKeyLength"+{- FOURMOLU_ENABLE -} +checkServerKeyShareKeyLength :: KeyShareEntry -> Bool+checkServerKeyShareKeyLength ks = serverKeyShareKeyLength grp == B.length key+  where+    grp = keyShareEntryGroup ks+    key = keyShareEntryKeyExchange ks++{- FOURMOLU_DISABLE -}+serverKeyShareKeyLength :: Group -> Int+serverKeyShareKeyLength P256   = 65  -- 32 * 2 + 1+serverKeyShareKeyLength P384   = 97  -- 48 * 2 + 1+serverKeyShareKeyLength P521   = 133 -- 66 * 2 + 1+serverKeyShareKeyLength X25519 = 32+serverKeyShareKeyLength X448   = 56+serverKeyShareKeyLength FFDHE2048 = 256+serverKeyShareKeyLength FFDHE3072 = 384+serverKeyShareKeyLength FFDHE4096 = 512+serverKeyShareKeyLength FFDHE6144 = 768+serverKeyShareKeyLength FFDHE8192 = 1024+serverKeyShareKeyLength MLKEM512  = 768+serverKeyShareKeyLength MLKEM768  = 1088+serverKeyShareKeyLength MLKEM1024 = 1568+serverKeyShareKeyLength X25519MLKEM768 = 1120+serverKeyShareKeyLength P256MLKEM768   = 1153+serverKeyShareKeyLength P384MLKEM1024  = 1665+serverKeyShareKeyLength _ = error "clientKeyShareKeyLength"+{- FOURMOLU_ENABLE -}+ setRTT :: Context -> Millisecond -> IO () setRTT ctx chSentTime = do     shRecvTime <- getCurrentTimeFromBase@@ -591,11 +632,11 @@     :: (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-    return $ hkdfExpandLabel usedHash prk label echConf 8+    return $ hkdfExpandLabel usedHash (convert prk) label echConf 8  ---------------------------------------------------------------- 
Network/TLS/Handshake/Key.hs view
@@ -7,8 +7,8 @@     decryptRSA,     verifyPublic,     generateDHE,-    generateECDHE,-    generateECDHEShared,+    generateGroup,+    encapsulateGroup,     generateFFDHE,     generateFFDHEShared,     versionCompatible,@@ -20,6 +20,7 @@ ) where  import Control.Monad.State.Strict+import Data.ByteArray (convert) import qualified Data.ByteString as B  import Network.TLS.Context.Internal@@ -35,7 +36,7 @@ {- if the RSA encryption fails we just return an empty bytestring, and let the protocol  - fail by itself; however it would be probably better to just report it since it's an internal problem.  -}-encryptRSA :: Context -> ByteString -> IO ByteString+encryptRSA :: Context -> Secret -> IO ByteString encryptRSA ctx content = do     publicKey <- usingHState ctx getRemotePublicKey     usingState_ ctx $ do@@ -53,7 +54,7 @@             Left err -> error ("sign failed: " ++ show err)             Right econtent -> return econtent -decryptRSA :: Context -> ByteString -> IO (Either KxError ByteString)+decryptRSA :: Context -> ByteString -> IO (Either KxError Secret) decryptRSA ctx econtent = do     (_, privateKey) <- usingHState ctx getLocalPublicPrivateKeys     usingState_ ctx $ do@@ -69,12 +70,12 @@ generateDHE :: Context -> DHParams -> IO (DHPrivate, DHPublic) generateDHE ctx dhp = usingState_ ctx $ withRNG $ dhGenerateKeyPair dhp -generateECDHE :: Context -> Group -> IO (GroupPrivate, GroupPublic)-generateECDHE ctx grp = usingState_ ctx $ withRNG $ groupGenerateKeyPair grp+generateGroup :: Context -> Group -> IO (GroupPrivate, GroupPublicA)+generateGroup ctx grp = usingState_ ctx $ withRNG $ groupGenerateKeyPair grp -generateECDHEShared-    :: Context -> GroupPublic -> IO (Maybe (GroupPublic, GroupKey))-generateECDHEShared ctx pub = usingState_ ctx $ withRNG $ groupGetPubShared pub+encapsulateGroup+    :: Context -> GroupPublicA -> IO (Maybe (GroupPublicB, GroupKey))+encapsulateGroup ctx pub = usingState_ ctx $ withRNG $ groupEncapsulate pub  generateFFDHE :: Context -> Group -> IO (DHParams, DHPrivate, DHPublic) generateFFDHE ctx grp = usingState_ ctx $ withRNG $ dhGroupGenerateKeyPair grp@@ -144,7 +145,7 @@ ----------------------------------------------------------------  class LogLabel a where-    labelAndKey :: a -> (String, ByteString)+    labelAndKey :: a -> (String, Secret)  instance LogLabel MainSecret where     labelAndKey (MainSecret key) = ("CLIENT_RANDOM", key)@@ -175,6 +176,7 @@             let crm = fromMaybe (hstClientRandom hst) (hstTLS13OuterClientRandom hst)                 cr = unClientRandom crm                 (label, key) = labelAndKey logkey-            debugKeyLogger (ctxDebug ctx) $ label ++ " " ++ dump cr ++ " " ++ dump key+            debugKeyLogger (ctxDebug ctx) $+                label ++ " " ++ dump cr ++ " " ++ dump (convert key)   where     dump = init . drop 1 . showBytesHex
Network/TLS/Handshake/Server.hs view
@@ -14,6 +14,7 @@  import Network.TLS.Context.Internal import Network.TLS.Handshake.Common+import Network.TLS.Handshake.Common13 import Network.TLS.Handshake.Server.ClientHello import Network.TLS.Handshake.Server.ClientHello12 import Network.TLS.Handshake.Server.ClientHello13@@ -21,6 +22,7 @@ import Network.TLS.Handshake.Server.ServerHello13 import Network.TLS.Handshake.Server.TLS12 import Network.TLS.Handshake.Server.TLS13+import Network.TLS.Imports import Network.TLS.Struct  -- Put the server context in handshake mode.@@ -31,43 +33,56 @@ -- 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. -- -- Expect a client hello message as parameter.--- This is useful when the client hello has been already poped from the recv layer to inspect the packet.+-- This is useful when the client hello has been already popped from the recv layer to inspect the packet. ----- When the function returns, a new handshake has been succesfully negociated.+-- When the function returns, a new handshake has been successfully negotiated. -- 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.-            (mClientKeyShare, r0, r1) <-+            -- r0 :: Cipher, Hash, Bool+            (keyShareResult, r0, r1) <-                 processClientHello13 sparams ctx chI-            case mClientKeyShare of-                Nothing -> do-                    sendHRR ctx r0 chI $ isJust mcrnd+            case keyShareResult of+                SelectKeyShareNotFound ->+                    throwCore $+                        Error_Protocol "no group in common with the client for HRR" HandshakeFailure+                SelectKeyShareHRR g -> do+                    sendHRR ctx g r0 chI $ isJust mcrnd                     -- Don't reset ctxEstablished since 0-RTT data-                    -- would be comming, which should be ignored.+                    -- would be coming, which should be ignored.                     handshakeServer sparams ctx-                Just cliKeyShare -> do+                SelectKeyShareFound cliKeyShare -> do+                    unless (checkClientKeyShareKeyLength cliKeyShare) $+                        throwCore $+                            Error_Protocol "broken key_share" IllegalParameter+                    -- 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
Network/TLS/Handshake/Server/ClientHello.hs view
@@ -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 
Network/TLS/Handshake/Server/ClientHello12.hs view
@@ -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 ()@@ -103,7 +101,7 @@      -- Cipher selection is performed in two steps: first server credentials     -- are flagged as not suitable for signature if not compatible with-    -- negotiated signature parameters.  Then ciphers are evalutated from+    -- negotiated signature parameters.  Then ciphers are evaluated from     -- the resulting credentials.      supported = serverSupported sparams
Network/TLS/Handshake/Server/ClientHello13.hs view
@@ -3,6 +3,7 @@  module Network.TLS.Handshake.Server.ClientHello13 (     processClientHello13,+    SelectKeyShareResult (..), ) where  import qualified Data.ByteString as B@@ -16,22 +17,24 @@ 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 import Network.TLS.Struct import Network.TLS.Types +limitSupportedGroups :: Int+limitSupportedGroups = 64+ -- TLS 1.3 or later processClientHello13     :: ServerParams     -> Context     -> ClientHello     -> IO-        ( Maybe KeyShareEntry-        , (Cipher, Hash, Bool)-        , (SecretPair EarlySecret, [ExtensionRaw], Bool, Bool)+        ( SelectKeyShareResult+        , (Cipher, Hash, Bool) -- rtt0+        , (SecretPair EarlySecret, [ExtensionRaw], Bool, Bool) -- authenticated, is0RTTvalid         ) processClientHello13 sparams ctx ch@CH{..} = do     when@@ -73,40 +76,57 @@         extract _ = require     keyShares <-         lookupAndDecodeAndDo EID_KeyShare MsgTClientHello chExtensions require extract-    mshare <- findKeyShare keyShares serverGroups+    let clientGroups =+            take limitSupportedGroups $+                lookupAndDecode+                    EID_SupportedGroups+                    MsgTClientHello+                    chExtensions+                    []+                    (\(SupportedGroups gs) -> gs)+    (mgroup, doHRR) <-+        onSelectKeyShare+            (serverHooks sparams)+            serverGroups+            clientGroups+            $ map keyShareEntryGroup keyShares+    keyshareResult <- case mgroup of+        Nothing -> return SelectKeyShareNotFound+        Just g+            | doHRR -> return $ SelectKeyShareHRR g+            | otherwise -> case filter (\e -> keyShareEntryGroup e == g) keyShares of+                [] -> return SelectKeyShareNotFound+                [x] -> return $ SelectKeyShareFound x+                _ -> throwCore $ Error_Protocol "duplicated key_share" IllegalParameter+     let triple = (usedCipher, usedHash, rtt0)     pskEarlySecret <- pskAndEarlySecret sparams ctx triple ch-    clientHello <- fromJust <$> usingHState ctx getClientHello-    void $ updateTranscriptHash12 ctx $ ClientHello clientHello-    return (mshare, triple, pskEarlySecret)+    (ich, b) <- fromJust <$> usingHState ctx getClientHello+    updateTranscriptHash12 ctx (ClientHello ich, b)+    return (keyshareResult, triple, pskEarlySecret)   where     ciphersFilteredVersion = intersectCiphers chCiphers serverCiphers     serverCiphers =         filter             (cipherAllowedForVersion TLS13)             (supportedCiphers $ serverSupported sparams)-    serverGroups = supportedGroups (ctxSupported ctx)+    serverGroups = supportedGroupsTLS13 $ serverSupported sparams -findKeyShare :: [KeyShareEntry] -> [Group] -> IO (Maybe KeyShareEntry)-findKeyShare ks ggs = go ggs-  where-    go [] = return Nothing-    go (g : gs) = case filter (grpEq g) ks of-        [] -> go gs-        [k] -> do-            unless (checkKeyShareKeyLength k) $-                throwCore $-                    Error_Protocol "broken key_share" IllegalParameter-            return $ Just k-        _ -> throwCore $ Error_Protocol "duplicated key_share" IllegalParameter-    grpEq g ent = g == keyShareEntryGroup ent+data SelectKeyShareResult+    = -- | Negotiation failure+      SelectKeyShareNotFound+    | -- | Send a hello retry request with this group+      SelectKeyShareHRR Group+    | -- | Use this key share+      SelectKeyShareFound KeyShareEntry+    deriving (Eq, Show)  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 +176,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]
Network/TLS/Handshake/Server/Common.hs view
@@ -15,7 +15,7 @@ ) where  import Control.Monad.State.Strict-import Data.X509 (ExtKeyUsageFlag (..))+import Data.X509 (ExtKeyUsageFlag (..), ExtKeyUsagePurpose (..))  import Network.TLS.Context.Internal import Network.TLS.Credentials@@ -151,7 +151,9 @@                 (onClientCertificate (serverHooks sparams) certs)                 rejectOnException     case usage of-        CertificateUsageAccept -> verifyLeafKeyUsage [KeyUsage_digitalSignature] certs+        CertificateUsageAccept -> do+            verifyLeafKeyUsage [KeyUsage_digitalSignature] certs+            verifyLeafKeyUsagePurpose KeyUsagePurpose_ClientAuth certs         CertificateUsageReject reason -> certificateRejected reason      -- Remember cert chain for later use.
Network/TLS/Handshake/Server/ServerHello12.hs view
@@ -5,6 +5,8 @@     sendServerHello12, ) where +import Data.ByteArray (convert)+ import Network.TLS.Cipher import Network.TLS.Compression import Network.TLS.Context.Internal@@ -42,7 +44,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,8 +52,8 @@                 setTLS12SessionResuming True             sh <-                 makeServerHello sparams ctx usedCipher mcred chExtensions chSession-            sendPacket12 ctx $ Handshake [ServerHello sh]-            let mainSecret = sessionSecret sessionData+            sendPacket12 ctx $ Handshake [ServerHello sh] []+            let mainSecret = convert $ sessionSecret sessionData             usingHState ctx $ setMainSecret TLS12 ServerRole mainSecret             logKey ctx $ MainSecret mainSecret             sendCCSandFinished ctx ServerRole@@ -91,7 +93,7 @@     | TLS12 < sessionVersion sd = return Nothing -- fixme     | CipherId (sessionCipher sd) `notElem` ciphers =         throwCore $-            Error_Protocol "new cipher is diffrent from the old one" IllegalParameter+            Error_Protocol "new cipher is different from the old one" IllegalParameter     | isJust sni && sessionClientSNI sd /= sni = do         usingState_ ctx clearClientSNI         return Nothing@@ -202,10 +204,10 @@      setup_ECDHE grp = do         usingHState ctx $ setSupportedGroup grp-        (srvpri, srvpub) <- generateECDHE ctx grp+        (srvpri, srvpub) <- generateGroup ctx grp         let serverParams = ServerECDHParams grp srvpub         usingHState ctx $ setServerECDHParams serverParams-        usingHState ctx $ setGroupPrivate srvpri+        usingHState ctx $ setGroupPrivate [(grp, srvpri)]         return serverParams      generateSKX_ECDHE kxsAlg = do
Network/TLS/Handshake/Server/ServerHello13.hs view
@@ -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]@@ -313,34 +313,19 @@  ---------------------------------------------------------------- -sendHRR :: Context -> (Cipher, Hash, c) -> ClientHello -> Bool -> IO ()-sendHRR ctx (usedCipher, usedHash, _) CH{..} isEch = do+sendHRR :: Context -> Group -> (Cipher, Hash, c) -> ClientHello -> Bool -> IO ()+sendHRR ctx g (usedCipher, usedHash, _) CH{..} isEch = do     twice <- usingState_ ctx getTLS13HRR     when twice $         throwCore $             Error_Protocol "Hello retry not allowed again" HandshakeFailure     usingState_ ctx $ setTLS13HRR True     failOnEitherError $ setServerHelloParameters13 ctx usedCipher True-    let clientGroups =-            lookupAndDecode-                EID_SupportedGroups-                MsgTClientHello-                chExtensions-                []-                (\(SupportedGroups gs) -> gs)-        possibleGroups = serverGroups `intersect` clientGroups-    case possibleGroups of-        [] ->-            throwCore $-                Error_Protocol "no group in common with the client for HRR" HandshakeFailure-        g : _ -> do-            hrr <- makeHRR ctx usedCipher usedHash chSession g isEch-            usingHState ctx $ setTLS13HandshakeMode HelloRetryRequest-            runPacketFlight ctx $ do-                loadPacket13 ctx $ Handshake13 [ServerHello13 hrr]-                sendChangeCipherSpec13 ctx-  where-    serverGroups = supportedGroups (ctxSupported ctx)+    hrr <- makeHRR ctx usedCipher usedHash chSession g isEch+    usingHState ctx $ setTLS13HandshakeMode HelloRetryRequest+    runPacketFlight ctx $ do+        loadPacket13 ctx $ Handshake13 [ServerHello13 hrr] []+        sendChangeCipherSpec13 ctx  makeHRR     :: Context -> Cipher -> Hash -> Session -> Group -> Bool -> IO ServerHello
Network/TLS/Handshake/Server/TLS12.hs view
@@ -5,6 +5,7 @@ ) where  import Control.Monad.State.Strict (gets)+import Data.ByteArray (convert) import qualified Data.ByteString as B  import Network.TLS.Context.Internal@@ -40,7 +41,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@@ -142,10 +143,11 @@             -- BadRecordMac is nonsense but for tlsfuzzer             throwCore $                 Error_Protocol "invalid client public key" BadRecordMac-        Right preMain -> case decodePreMainSecret preMain of-            Left _ -> usingHState ctx $ setMainSecretFromPre rver role random+        Right preMain -> case decodePreMainSecret $ convert preMain of+            Left _ -> usingHState ctx $ setMainSecretFromPre rver role $ convert random             Right (ver, _)-                | ver /= expectedVer -> usingHState ctx $ setMainSecretFromPre rver role random+                | ver /= expectedVer ->+                    usingHState ctx $ setMainSecretFromPre rver role $ convert random                 | otherwise -> usingHState ctx $ setMainSecretFromPre rver role preMain     logKey ctx (MainSecret mainSecret) processClientKeyXchg ctx (CKX_DH clientDHValue) = do@@ -164,21 +166,23 @@     logKey ctx (MainSecret mainSecret) processClientKeyXchg ctx (CKX_ECDH bytes) = do     ServerECDHParams grp _ <- usingHState ctx getServerECDHParams-    case decodeGroupPublic grp bytes of+    case groupDecodePublicB grp bytes of         Left _ ->             throwCore $                 Error_Protocol "client public key cannot be decoded" IllegalParameter         Right clipub -> do-            srvpri <- usingHState ctx getGroupPrivate-            case groupGetShared clipub srvpri of-                Just preMain -> do-                    rver <- usingState_ ctx getVersion-                    role <- usingState_ ctx getRole-                    mainSecret <- usingHState ctx $ setMainSecretFromPre rver role preMain-                    logKey ctx (MainSecret mainSecret)-                Nothing ->-                    throwCore $-                        Error_Protocol "cannot generate a shared secret on ECDH" IllegalParameter+            grpSpris <- usingHState ctx getGroupPrivate+            case lookup grp grpSpris of+                Nothing -> throwCore err+                Just srvpri -> case groupDecapsulate clipub srvpri of+                    Just preMain -> do+                        rver <- usingState_ ctx getVersion+                        role <- usingState_ ctx getRole+                        mainSecret <- usingHState ctx $ setMainSecretFromPre rver role preMain+                        logKey ctx (MainSecret mainSecret)+                    Nothing -> throwCore err+  where+    err = Error_Protocol "cannot generate a shared secret on ECDH" IllegalParameter  ---------------------------------------------------------------- 
Network/TLS/Handshake/Server/TLS13.hs view
@@ -11,7 +11,6 @@  import Control.Exception import Control.Monad.State.Strict-import qualified Data.ByteString.Char8 as C8 import Data.IORef  import Network.TLS.Cipher@@ -71,7 +70,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 +103,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 +147,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 +181,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 +240,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 +268,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@@ -343,7 +346,7 @@  keyUpdate     :: Context-    -> (Context -> IO (Hash, Cipher, CryptLevel, C8.ByteString))+    -> (Context -> IO (Hash, Cipher, CryptLevel, Secret))     -> (Context -> Hash -> Cipher -> AnyTrafficSecret ApplicationSecret -> IO ())     -> IO () keyUpdate ctx getState setState = do@@ -366,7 +369,7 @@       TwoWay     deriving (Eq, Show) --- | Updating appication traffic secrets for TLS 1.3.+-- | Updating application traffic secrets for TLS 1.3. --   If this API is called for TLS 1.3, 'True' is returned. --   Otherwise, 'False' is returned. updateKey :: MonadIO m => Context -> KeyUpdateRequest -> m Bool@@ -379,6 +382,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
Network/TLS/Handshake/State.hs view
@@ -81,7 +81,7 @@ ) where  import Control.Monad.State.Strict-import Data.ByteArray (ByteArrayAccess)+import Data.ByteArray (convert) import Data.X509 (CertificateChain)  import Network.TLS.Cipher@@ -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 @@ -120,12 +120,12 @@     , hstClientRandom :: ClientRandom     -- ^ For ECH, inner client random.     , hstServerRandom :: Maybe ServerRandom-    , hstMainSecret :: Maybe ByteString+    , hstMainSecret :: Maybe Secret     , hstKeyState :: HandshakeKeyState     , hstServerDHParams :: Maybe ServerDHParams     , hstDHPrivate :: Maybe DHPrivate     , hstServerECDHParams :: Maybe ServerECDHParams-    , hstGroupPrivate :: Maybe GroupPrivate+    , hstGroupPrivate :: [(Group, GroupPrivate)]     , hstTransHashState :: TransHashState     , hstTransHashStateI :: TransHashState -- Inner CH for client ECH     , hstHandshakeMessages :: [ByteString]@@ -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@@ -236,7 +236,7 @@         , hstServerDHParams = Nothing         , hstDHPrivate = Nothing         , hstServerECDHParams = Nothing-        , hstGroupPrivate = Nothing+        , hstGroupPrivate = []         , hstTransHashState = TransHashState0         , hstTransHashStateI = TransHashState0         , hstHandshakeMessages = []@@ -303,11 +303,11 @@ getDHPrivate :: HandshakeM DHPrivate getDHPrivate = fromJust <$> gets hstDHPrivate -getGroupPrivate :: HandshakeM GroupPrivate-getGroupPrivate = fromJust <$> gets hstGroupPrivate+getGroupPrivate :: HandshakeM [(Group, GroupPrivate)]+getGroupPrivate = gets hstGroupPrivate -setGroupPrivate :: GroupPrivate -> HandshakeM ()-setGroupPrivate shp = modify' (\hst -> hst{hstGroupPrivate = Just shp})+setGroupPrivate :: [(Group, GroupPrivate)] -> HandshakeM ()+setGroupPrivate shp = modify' (\hst -> hst{hstGroupPrivate = shp})  setExtendedMainSecret :: Bool -> HandshakeM () setExtendedMainSecret b = modify' (\hst -> hst{hstExtendedMainSecret = b})@@ -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@@ -463,14 +463,13 @@  -- | Generate the main secret from the pre-main secret. setMainSecretFromPre-    :: ByteArrayAccess preMain-    => Version+    :: Version     -- ^ chosen transmission version     -> Role     -- ^ the role (Client or Server) of the generating side-    -> preMain+    -> Secret     -- ^ the pre-main secret-    -> HandshakeM ByteString+    -> HandshakeM Secret setMainSecretFromPre ver role preMainSecret = do     ems <- getExtendedMainSecret     secret <- if ems then get >>= genExtendedSecret else genSecret <$> get@@ -499,7 +498,7 @@  -- | Set main secret and as a side effect generate the key block -- with all the right parameters, and setup the pending tx/rx state.-setMainSecret :: Version -> Role -> ByteString -> HandshakeM ()+setMainSecret :: Version -> Role -> Secret -> HandshakeM () setMainSecret ver role mainSecret = modify' $ \hst ->     let (pendingTx, pendingRx) = computeKeyBlock hst mainSecret ver role      in hst@@ -509,7 +508,7 @@             }  computeKeyBlock-    :: HandshakeState -> ByteString -> Version -> Role -> (RecordState, RecordState)+    :: HandshakeState -> Secret -> Version -> Role -> (RecordState, RecordState) computeKeyBlock hst mainSecret ver cc = (pendingTx, pendingRx)   where     cipher = fromJust $ hstPendingCipher hst@@ -538,13 +537,13 @@     cstClient =         CryptState             { cstKey = bulkInit bulk (BulkEncrypt `orOnServer` BulkDecrypt) cWriteKey-            , cstIV = cWriteIV+            , cstIV = convert $ cWriteIV             , cstMacSecret = cMACSecret             }     cstServer =         CryptState             { cstKey = bulkInit bulk (BulkDecrypt `orOnServer` BulkEncrypt) sWriteKey-            , cstIV = sWriteIV+            , cstIV = convert $ sWriteIV             , cstMacSecret = sMACSecret             }     msClient = MacState{msSequence = 0}
Network/TLS/Handshake/State13.hs view
@@ -31,16 +31,16 @@ import Network.TLS.Record.State import Network.TLS.Types -getTxRecordState :: Context -> IO (Hash, Cipher, CryptLevel, ByteString)+getTxRecordState :: Context -> IO (Hash, Cipher, CryptLevel, Secret) getTxRecordState ctx = getXState ctx ctxTxRecordState -getRxRecordState :: Context -> IO (Hash, Cipher, CryptLevel, ByteString)+getRxRecordState :: Context -> IO (Hash, Cipher, CryptLevel, Secret) getRxRecordState ctx = getXState ctx ctxRxRecordState  getXState     :: Context     -> (Context -> MVar RecordState)-    -> IO (Hash, Cipher, CryptLevel, ByteString)+    -> IO (Hash, Cipher, CryptLevel, Secret) getXState ctx func = do     tx <- readMVar (func ctx)     let usedCipher = fromJust $ stCipher tx@@ -66,7 +66,7 @@     return $ stCryptLevel tx  class TrafficSecret ty where-    fromTrafficSecret :: ty -> (CryptLevel, ByteString)+    fromTrafficSecret :: ty -> (CryptLevel, Secret)  instance HasCryptLevel a => TrafficSecret (AnyTrafficSecret a) where     fromTrafficSecret prx@(AnyTrafficSecret s) = (getCryptLevel prx, s)@@ -103,7 +103,7 @@     -> Hash     -> Cipher     -> CryptLevel-    -> ByteString+    -> Secret     -> IO () setXState' func encOrDec ctx h cipher lvl secret =     modifyMVar_ (func ctx) (\_ -> return rt)
Network/TLS/Handshake/TranscriptHash.hs view
@@ -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  ---------------------------------------------------------------- 
Network/TLS/IO.hs view
@@ -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
Network/TLS/IO/Decode.hs view
@@ -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")
Network/TLS/IO/Encode.hs view
@@ -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
Network/TLS/KeySchedule.hs view
@@ -8,7 +8,7 @@  import qualified Crypto.Hash as H import Crypto.KDF.HKDF-import Data.ByteArray (convert)+import Data.ByteArray (ByteArray, ByteArrayAccess, convert) import qualified Data.ByteString as BS  import Network.TLS.Crypto@@ -20,7 +20,8 @@  -- | @HKDF-Extract@ function.  Returns the pseudorandom key (PRK) from salt and -- input keying material (IKM).-hkdfExtract :: Hash -> ByteString -> ByteString -> ByteString+hkdfExtract+    :: (ByteArray ba, ByteArrayAccess ba) => Hash -> ba -> ba -> ba hkdfExtract SHA1 salt ikm = convert (extract salt ikm :: PRK H.SHA1) hkdfExtract SHA256 salt ikm = convert (extract salt ikm :: PRK H.SHA256) hkdfExtract SHA384 salt ikm = convert (extract salt ikm :: PRK H.SHA384)@@ -29,7 +30,7 @@  ---------------------------------------------------------------- -deriveSecret :: Hash -> ByteString -> ByteString -> TranscriptHash -> ByteString+deriveSecret :: Hash -> Secret -> ByteString -> TranscriptHash -> Secret deriveSecret h secret label (TranscriptHash hashedMsgs) =     hkdfExpandLabel h secret label hashedMsgs outlen   where@@ -40,12 +41,13 @@ -- | @HKDF-Expand-Label@ function.  Returns output keying material of the -- specified length from the PRK, customized for a TLS label and context. hkdfExpandLabel-    :: Hash-    -> ByteString+    :: (ByteArray ba, ByteArrayAccess ba)+    => Hash+    -> Secret     -> ByteString     -> ByteString     -> Int-    -> ByteString+    -> ba hkdfExpandLabel h secret label ctx outlen = expand' h secret hkdfLabel outlen   where     hkdfLabel = runPut $ do@@ -53,7 +55,8 @@         putOpaque8 ("tls13 " `BS.append` label)         putOpaque8 ctx -expand' :: Hash -> ByteString -> ByteString -> Int -> ByteString+expand'+    :: (ByteArray ba, ByteArrayAccess ba) => Hash -> Secret -> ByteString -> Int -> ba expand' SHA1 secret label len = expand (extractSkip secret :: PRK H.SHA1) label len expand' SHA256 secret label len = expand (extractSkip secret :: PRK H.SHA256) label len expand' SHA384 secret label len = expand (extractSkip secret :: PRK H.SHA384) label len
Network/TLS/MAC.hs view
@@ -6,24 +6,25 @@     prf_SHA256,     prf_TLS,     prf_MD5SHA1,+    PRF, ) where -import qualified Data.ByteArray as B (xor)-import qualified Data.ByteString as B+import Data.ByteArray (ByteArray, ByteArrayAccess)+import qualified Data.ByteArray as BA  import Network.TLS.Crypto import Network.TLS.Imports import Network.TLS.Types -type HMAC = ByteString -> ByteString -> ByteString+type HMAC = Secret -> ByteString -> Secret  macSSL :: Hash -> HMAC macSSL alg secret msg =     f $-        B.concat+        BA.concat             [ secret-            , B.replicate padLen 0x5c-            , f $ B.concat [secret, B.replicate padLen 0x36, msg]+            , BA.replicate padLen 0x5c+            , f $ BA.concat [secret, BA.replicate padLen 0x36, BA.convert msg]             ]   where     padLen = case alg of@@ -32,49 +33,51 @@         _ -> error ("internal error: macSSL called with " ++ show alg)     f = hash alg -hmac :: Hash -> HMAC-hmac alg secret msg = f $ B.append opad (f $ B.append ipad msg)+hmac :: (ByteArray ba, ByteArrayAccess ba) => Hash -> ba -> ByteString -> ba+hmac alg secret msg = f $ BA.append opad (f $ BA.append ipad $ BA.convert msg)   where-    opad = B.map (xor 0x5c) k'-    ipad = B.map (xor 0x36) k'+    opad = BA.map (0x5c `xor`) k'+    ipad = BA.map (0x36 `xor`) k'      f = hash alg     bl = hashBlockSize alg -    k' = B.append kt pad+    k' = BA.append kt pad       where-        kt = if B.length secret > fromIntegral bl then f secret else secret-        pad = B.replicate (fromIntegral bl - B.length kt) 0+        kt = if BA.length secret > fromIntegral bl then f secret else secret+        pad = BA.replicate (fromIntegral bl - BA.length kt) 0  hmacIter-    :: HMAC -> ByteString -> ByteString -> ByteString -> Int -> [ByteString]+    :: HMAC -> Secret -> ByteString -> ByteString -> Int -> [Secret] hmacIter f secret seed aprev len =     let an = f secret aprev-     in let out = f secret (B.concat [an, seed])-         in let digestsize = B.length out+     in let out = f secret (BA.concat [an, BA.convert seed])+         in let digestsize = BA.length out              in if digestsize >= len-                    then [B.take (fromIntegral len) out]-                    else out : hmacIter f secret seed an (len - digestsize)+                    then [BA.take (fromIntegral len) out]+                    else out : hmacIter f secret seed (BA.convert an) (len - digestsize) -prf_SHA1 :: ByteString -> ByteString -> Int -> ByteString-prf_SHA1 secret seed len = B.concat $ hmacIter (hmac SHA1) secret seed seed len+type PRF = Secret -> ByteString -> Int -> Secret -prf_MD5 :: ByteString -> ByteString -> Int -> ByteString-prf_MD5 secret seed len = B.concat $ hmacIter (hmac MD5) secret seed seed len+prf_SHA1 :: PRF+prf_SHA1 secret seed len = BA.concat $ hmacIter (hmac SHA1) secret seed seed len -prf_MD5SHA1 :: ByteString -> ByteString -> Int -> ByteString+prf_MD5 :: PRF+prf_MD5 secret seed len = BA.concat $ hmacIter (hmac MD5) secret seed seed len++prf_MD5SHA1 :: PRF prf_MD5SHA1 secret seed len =-    B.xor (prf_MD5 s1 seed len) (prf_SHA1 s2 seed len)+    BA.xor (prf_MD5 s1 seed len) (prf_SHA1 s2 seed len)   where-    slen = B.length secret-    s1 = B.take (slen `div` 2 + slen `mod` 2) secret-    s2 = B.drop (slen `div` 2) secret+    slen = BA.length secret+    s1 = BA.take (slen `div` 2 + slen `mod` 2) secret+    s2 = BA.drop (slen `div` 2) secret -prf_SHA256 :: ByteString -> ByteString -> Int -> ByteString-prf_SHA256 secret seed len = B.concat $ hmacIter (hmac SHA256) secret seed seed len+prf_SHA256 :: PRF+prf_SHA256 secret seed len = BA.concat $ hmacIter (hmac SHA256) secret seed seed len  -- | For now we ignore the version, but perhaps some day the PRF will depend -- not only on the cipher PRF algorithm, but also on the protocol version.-prf_TLS :: Version -> Hash -> ByteString -> ByteString -> Int -> ByteString+prf_TLS :: Version -> Hash -> PRF prf_TLS _ halg secret seed len =-    B.concat $ hmacIter (hmac halg) secret seed seed len+    BA.concat $ hmacIter (hmac halg) secret seed seed len
Network/TLS/Packet.hs view
@@ -61,8 +61,7 @@     getPRF, ) where -import Data.ByteArray (ByteArrayAccess)-import qualified Data.ByteArray as B (convert)+import Data.ByteArray (ByteArrayAccess, convert) import qualified Data.ByteString as B import Data.X509 (     CertificateChain,@@ -518,7 +517,7 @@             -- ECParameters ECCurveType: curve name type             grp <- Group <$> getWord16 -- ECParameters NamedCurve             mxy <- getOpaque8 -- ECPoint-            case decodeGroupPublic grp mxy of+            case groupDecodePublicA grp mxy of                 Left e -> fail $ "getServerECDHParams: " ++ show e                 Right grppub -> return $ ServerECDHParams grp grppub         _ -> fail "getServerECDHParams: unknown type for ECDH Params"@@ -528,7 +527,7 @@ putServerECDHParams (ServerECDHParams (Group grp) grppub) = do     putWord8 3 -- ECParameters ECCurveType     putWord16 grp -- ECParameters NamedCurve-    putOpaque8 $ encodeGroupPublic grppub -- ECPoint+    putOpaque8 $ groupEncodePublicA grppub -- ECPoint  ------------------------------------------------------------ @@ -556,8 +555,6 @@ ------------------------------------------------------------ -- generate things for packet content -type PRF = ByteString -> ByteString -> Int -> ByteString- -- | The TLS12 PRF is cipher specific, and some TLS12 algorithms use SHA384 -- instead of the default SHA256. getPRF :: Version -> Cipher -> PRF@@ -567,25 +564,23 @@     | otherwise = prf_TLS ver $ fromMaybe SHA256 $ cipherPRFHash ciph  generateMainSecret_TLS-    :: ByteArrayAccess preMain-    => PRF-    -> preMain+    :: PRF+    -> Secret     -> ClientRandom     -> ServerRandom-    -> ByteString+    -> Secret generateMainSecret_TLS prf preMainSecret (ClientRandom c) (ServerRandom s) =-    prf (B.convert preMainSecret) seed 48+    prf preMainSecret seed 48   where     seed = B.concat ["master secret", c, s]  generateMainSecret-    :: ByteArrayAccess preMain-    => Version+    :: Version     -> Cipher-    -> preMain+    -> Secret     -> ClientRandom     -> ServerRandom-    -> ByteString+    -> Secret generateMainSecret v c = generateMainSecret_TLS $ getPRF v c  generateExtendedMainSecret@@ -594,14 +589,14 @@     -> Cipher     -> preMain     -> ByteString-    -> ByteString+    -> Secret generateExtendedMainSecret v c preMainSecret sessionHash =-    getPRF v c (B.convert preMainSecret) seed 48+    getPRF v c (convert preMainSecret) seed 48   where     seed = B.append "extended master secret" sessionHash  generateKeyBlock_TLS-    :: PRF -> ClientRandom -> ServerRandom -> ByteString -> Int -> ByteString+    :: PRF -> ClientRandom -> ServerRandom -> Secret -> Int -> Secret generateKeyBlock_TLS prf (ClientRandom c) (ServerRandom s) mainSecret kbsize =     prf mainSecret seed kbsize   where@@ -612,9 +607,9 @@     -> Cipher     -> ClientRandom     -> ServerRandom-    -> ByteString+    -> Secret     -> Int-    -> ByteString+    -> Secret generateKeyBlock v c = generateKeyBlock_TLS $ getPRF v c  ------------------------------------------------------------
Network/TLS/Parameters.hs view
@@ -65,7 +65,7 @@     --     -- Default: 'Nothing'     , debugPrintSeed :: Seed -> IO ()-    -- ^ Add a way to print the seed that was randomly generated. re-using the same seed+    -- ^ Add a way to print the seed that was randomly generated. reusing the same seed     -- will reproduce the same randomness with 'debugSeed'     --     -- Default: no printing@@ -153,6 +153,16 @@     -- specified for TLS 1.2 but only the first entry is used.     --     -- Default: '[]'+    , clientWantTicket :: Bool+    -- ^ Whether to solicit TLS 1.2 session tickets (or TLS 1.3+    -- resumption PSKs) from servers.  With a 'False' setting,+    -- stateless clients that never do resumption can avoid+    -- wasting server and client resources used to generate,+    -- transmit and process tickets that will never be used.+    --+    -- Default: 'True'+    --+    -- @since 2.4.1     , clientShared :: Shared     -- ^ See the default value of 'Shared'.     , clientHooks :: ClientHooks@@ -192,6 +202,7 @@         , clientUseServerNameIndication = True         , clientWantSessionResume = Nothing         , clientWantSessionResumeList = []+        , clientWantTicket = True         , clientShared = def         , clientHooks = def         , clientSupported = def@@ -274,7 +285,7 @@     -- the server side, the highest version that is less or equal than     -- the client version will be chosen.     ---    -- Versions should be listed in preference order, i.e. higher+    -- Versions should be listed in preferred order, i.e. higher     -- versions first.     --     -- Default: @[TLS13,TLS12]@@@ -373,10 +384,23 @@     -- secure, but might help in rare cases.     --     --   Default: 'True'+    , supportedHPKE :: [(KEM_ID, KDF_ID, AEAD_ID)]+    -- ^ Client only.+    --+    -- @since 2.1.9     , supportedGroups :: [Group]     -- ^ A list of supported elliptic curves and finite-field groups-    --   in the preferred order.+    --   in preferred order.     --+    --   * TLS 1.3 client: this list is used as the 1st argument to+    --     'onSelectKeyShareGroups' to select groups in "key_share".+    --     This list is also used as values of "supported_groups".+    --   * TLS 1.3 server: this list is not used.+    --   * TLS 1.2 client: this list is also used as values of+    --     "supported_groups".+    --   * TLS 1.2 server: this list is used to select a key exchange+    --     mechanism.+    --     --   The list is sent to the server as part of the     --   "supported_groups" extension.  It is used in both clients and     --   servers to restrict accepted groups in DH key exchange.  Up@@ -386,11 +410,18 @@     --   The default value includes all groups with security strength     --   of 128 bits or more.     ---    --   Default: @[X25519,X448,P256,FFDHE2048,FFDHE3072,FFDHE4096,P384,FFDHE6144,FFDHE8192,P521]@-    , supportedHPKE :: [(KEM_ID, KDF_ID, AEAD_ID)]-    -- ^ Client only.+    --   Default: @[X25519,P256,P384,X448,P521,FFDHE3072,FFDHE4096,FFDHE6144,FFDHE8192,X25519MLKEM768,P256MLKEM768,P384MLKEM1024,MLKEM768,MLKEM1024]@+    , supportedGroupsTLS13 :: [[Group]]+    -- ^ The inside @[Group]@ is the list of @Group@ at the same level+    -- in preferred order.  The inside @[Group]@s are also listed in+    -- preferred order.     ---    -- @since 2.1.9+    -- TLS 1.3 server: this is used as the 1st argument to+    -- 'onSelectKeyShare'.+    --+    -- Default: @[[X25519MLKEM768,P256MLKEM768,P384MLKEM1024],[X25519,P256],[P384,X448,P521],[FFDHE2048,FFDHE3072,FFDHE4096,FFDHE6144,FFDHE8192],[MLKEM768,MLKEM1024]]@+    --+    -- @since 2.2.3     }     deriving (Show, Eq) @@ -427,8 +458,9 @@         , supportedSession = True         , supportedFallbackScsv = True         , supportedEmptyPacket = True-        , supportedGroups = supportedNamedGroups         , supportedHPKE = defaultHPKE+        , supportedGroups = supportedNamedGroups+        , supportedGroupsTLS13 = supportedNamedGroupsTLS13         }  instance Default Supported where@@ -637,11 +669,44 @@     --   (3) rejecting unless 1 < dh_p && pub < dh_p - 1     --   (4) rejecting if dh_size < 1024 (to prevent Logjam attack)     ---    --   See RFC 7919 section 3.1 for recommandations.+    --   See RFC 7919 section 3.1 for recommendations.     , onServerFinished :: Information -> IO ()     -- ^ When a handshake is done, this hook can check `Information`.+    , onSelectKeyShareGroups :: [Group] -> [Group]+    -- ^ A function to select groups in "key_share" by TLS 1.3 client.+    --+    --   Client's 'supportedGroups' is passed as the 1st argument.+    --+    --   The default function specifies a pair of hybrid (classical ++    --   post quantum) group and classical group to transit from+    --   classical key exchange to hybrid key exchange. With the+    --   default value of 'supportedGroups', X25519MLKEM and X25519+    --   are chosen.+    --+    --   Middleboxes may drop a ClientHello that contains large+    --   X2219MLKEM. In such environment, @take 1@, which selects+    --   X22519 only with the default value, is maybe a good+    --   candidate.+    --+    --   In the case where X22519 is only contained in "key_share", a+    --   wise-server without nasty middleboxes may ask the client to+    --   send X2219MLKEM via HelloRetryRequest as X2219MLKEM is+    --   specified in "supported_groups".+    --+    --   @since 2.2.3     } +defaultOnSelectKeyShareGroups :: [Group] -> [Group]+defaultOnSelectKeyShareGroups groups = take 1 hs ++ take 1 es+  where+    (hs, es) = partition isHybrid groups++isHybrid :: Group -> Bool+isHybrid X25519MLKEM768 = True+isHybrid P256MLKEM768 = True+isHybrid P384MLKEM1024 = True+isHybrid _ = False+ defaultClientHooks :: ClientHooks defaultClientHooks =     ClientHooks@@ -650,6 +715,7 @@         , onSuggestALPN = return Nothing         , onCustomFFDHEGroup = defaultGroupUsage 1024         , onServerFinished = \_ -> return ()+        , onSelectKeyShareGroups = defaultOnSelectKeyShareGroups         }  instance Show ClientHooks where@@ -668,7 +734,7 @@     -- of the certificate.  This verification is performed by the     -- library internally.     ---    -- Default: returns the followings:+    -- Default: returns the following:     --     -- @     -- CertificateUsageReject (CertificateRejectOther "no client certificates expected")@@ -684,7 +750,7 @@     -- client version and the client list of ciphers.     --     -- This could be useful with old clients and as a workaround to-    -- the BEAST (where RC4 is sometimes prefered with TLS < 1.1)+    -- the BEAST (where RC4 is sometimes preferred with TLS < 1.1)     --     -- The client cipher list cannot be empty.     --@@ -719,6 +785,29 @@     --  of TLS 1.3.     --     -- Default: 'return'+    , onSelectKeyShare+        :: [[Group]]+        -> [Group]+        -> [Group]+        -> IO (Maybe Group, Bool)+    -- ^ A function to select one key share by TLS 1.3 server.+    --+    -- The 1st argument is server's 'supportedGroupsTLS13'.+    -- The 2nd arguments is client's groups in "supported_groups"+    -- The 3rd arguments is client's groups in "key_share".+    --+    -- 'True' in the result indicates sending a hello retry request+    -- with this group.+    --+    -- The default function targets @[Group]@ in the first argument in+    -- order.  If there is a common group among the "key_share"+    -- groups, it will use that group for key exchange.+    -- Alternatively, if there is a common group among the+    -- "supported_groups" groups, it will instruct to send the+    -- HelloRetryRequest using that group.  Otherwise, it will check+    -- the next @[Group]@.+    --+    -- @since 2.2.3     }  -- | Default value for 'ServerHooks'@@ -737,12 +826,27 @@         , onNewHandshake = \_ -> return True         , onALPNClientSuggest = Nothing         , onEncryptedExtensionsCreating = return+        , onSelectKeyShare = defaultOnSelectKeyShare         }  instance Show ServerHooks where     show _ = "ServerHooks" instance Default ServerHooks where     def = defaultServerHooks++defaultOnSelectKeyShare+    :: [[Group]] -- Server groups+    -> [Group] -- Client's groups in "supported_groups"+    -> [Group] -- Client's groups in "key_share"+    -> IO (Maybe Group, Bool)+defaultOnSelectKeyShare serverSupportedLoL clientSupportedGroups clientKeyShareGroups = go serverSupportedLoL+  where+    go [] = return (Nothing, False)+    go (gs : gss) = case gs `intersect` clientKeyShareGroups of+        [] -> case gs `intersect` clientSupportedGroups of+            [] -> go gss+            h : _ -> return (Just h, True)+        g : _ -> return (Just g, False)  -- | Information related to a running context, e.g. current cipher data Information = Information
Network/TLS/QUIC.hs view
@@ -116,7 +116,7 @@     { quicSend :: [(CryptLevel, ByteString)] -> IO ()     -- ^ Called by TLS so that QUIC sends one or more handshake fragments. The     -- content transiting on this API is the plaintext of the fragments and-    -- QUIC responsability is to encrypt this payload with the key material+    -- QUIC responsibility is to encrypt this payload with the key material     -- given for the specified level and an appropriate encryption scheme.     --     -- The size of the fragments may exceed QUIC datagram limits so QUIC may@@ -194,7 +194,7 @@         let qexts = filterQTP exts         when (null qexts) $ do             throwCore $-                Error_Protocol "QUIC transport parameters are mssing" MissingExtension+                Error_Protocol "QUIC transport parameters are missing" MissingExtension         quicNotifyExtensions callbacks ctx qexts         quicInstallKeys callbacks ctx (InstallApplicationKeys appSecInfo) @@ -222,7 +222,7 @@         let qexts = filterQTP exts         when (null qexts) $ do             throwCore $-                Error_Protocol "QUIC transport parameters are mssing" MissingExtension+                Error_Protocol "QUIC transport parameters are missing" MissingExtension         quicNotifyExtensions callbacks ctx qexts         quicInstallKeys callbacks ctx (InstallEarlyKeys mEarlySecInfo)         quicInstallKeys callbacks ctx (InstallHandshakeKeys handSecInfo)
Network/TLS/Record/Decrypt.hs view
@@ -6,7 +6,8 @@  import Control.Monad.State.Strict import Crypto.Cipher.Types (AuthTag (..))-import qualified Data.ByteArray as B (convert, xor)+import Data.ByteArray (convert)+import qualified Data.ByteArray as BA import qualified Data.ByteString as B  import Network.TLS.Cipher@@ -180,11 +181,11 @@                 | otherwise = B.concat [encodedSeq, encodeHeader hdr]             sqnc = B.replicate (ivlen - 8) 0 `B.append` encodedSeq             nonce-                | nonceExpLen == 0 = B.xor iv sqnc+                | nonceExpLen == 0 = BA.xor iv sqnc                 | otherwise = iv `B.append` enonce             (content, authTag2) = decryptF nonce econtent' ad -        when (AuthTag (B.convert authTag) /= authTag2) $+        when (AuthTag (convert authTag) /= authTag2) $             throwError $                 Error_Protocol "bad record mac on AEAD" BadRecordMac 
Network/TLS/Record/Encrypt.hs view
@@ -13,7 +13,8 @@  import Control.Monad.State.Strict import Crypto.Cipher.Types (AuthTag (..))-import qualified Data.ByteArray as B (convert, xor)+import Data.ByteArray (convert)+import qualified Data.ByteArray as BA import qualified Data.ByteString as B  import Network.TLS.Cipher@@ -117,12 +118,12 @@             | otherwise = B.concat [encodedSeq, encodeHeader hdr]         sqnc = B.replicate (ivlen - 8) 0 `B.append` encodedSeq         nonce-            | nonceExpLen == 0 = B.xor iv sqnc+            | nonceExpLen == 0 = BA.xor iv sqnc             | otherwise = B.concat [iv, encodedSeq]         (e, AuthTag authtag) = encryptF nonce content ad         econtent-            | nonceExpLen == 0 = e `B.append` B.convert authtag-            | otherwise = B.concat [encodedSeq, e, B.convert authtag]+            | nonceExpLen == 0 = e `B.append` convert authtag+            | otherwise = B.concat [encodedSeq, e, convert authtag]     modify' incrRecordState     return econtent 
Network/TLS/Record/State.hs view
@@ -22,6 +22,7 @@ ) where  import Control.Monad.State.Strict+import qualified Data.ByteArray as BA import qualified Data.ByteString as B  import Network.TLS.Cipher@@ -36,10 +37,10 @@  data CryptState = CryptState     { cstKey :: BulkState-    , cstIV :: ByteString+    , cstIV :: IV     , -- In TLS 1.2 or earlier, this holds mac secret.       -- In TLS 1.3, this holds application traffic secret N.-      cstMacSecret :: ByteString+      cstMacSecret :: Secret     }     deriving (Show) @@ -130,7 +131,7 @@         { stCipher = Nothing         , stCompression = nullCompression         , stCryptLevel = CryptInitial-        , stCryptState = CryptState BulkStateUninitialized B.empty B.empty+        , stCryptState = CryptState BulkStateUninitialized B.empty BA.empty         , stMacState = MacState 0         } @@ -153,7 +154,7 @@     :: Version -> RecordState -> Header -> ByteString -> (ByteString, RecordState) computeDigest _ver tstate hdr content = (digest, incrRecordState tstate)   where-    digest = macF (cstMacSecret cst) msg+    digest = BA.convert $ macF (cstMacSecret cst) msg     cst = stCryptState tstate     cipher = fromJust $ stCipher tstate     hashA = cipherHash cipher
Network/TLS/State.hs view
@@ -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 (..), Secret, 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]@@ -111,7 +113,7 @@     , stTLS13PreSharedKey :: Maybe PreSharedKey     , stTLS13HRR :: Bool     , stTLS13Cookie :: Maybe Cookie-    , stTLS13ExporterSecret :: Maybe ByteString+    , stTLS13ExporterSecret :: Maybe Secret     , stTLS13ClientSupportsPHA :: Bool -- Post-Handshake Authentication     } @@ -136,8 +138,8 @@         , stServerCertificateChain = Nothing         , stExtensionALPN = False         , stNegotiatedProtocol = Nothing-        , stHandshakeRecordCont12 = Nothing-        , stHandshakeRecordCont13 = Nothing+        , stHandshakeRecordCont12 = (Nothing, [])+        , stHandshakeRecordCont13 = (Nothing, [])         , stClientALPNSuggest = Nothing         , stClientGroupSuggest = Nothing         , stClientEcPointFormatSuggest = Nothing@@ -335,10 +337,10 @@ getTLS12SessionTicket :: TLSSt (Maybe Ticket) getTLS12SessionTicket = gets stTLS12SessionTicket -setTLS13ExporterSecret :: ByteString -> TLSSt ()+setTLS13ExporterSecret :: Secret -> TLSSt () setTLS13ExporterSecret key = modify' (\st -> st{stTLS13ExporterSecret = Just key}) -getTLS13ExporterSecret :: TLSSt (Maybe ByteString)+getTLS13ExporterSecret :: TLSSt (Maybe Secret) getTLS13ExporterSecret = gets stTLS13ExporterSecret  setTLS13KeyShare :: Maybe KeyShare -> TLSSt ()
Network/TLS/Struct.hs view
@@ -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@@ -362,7 +363,7 @@  ---------------------------------------------------------------- -data ServerECDHParams = ServerECDHParams Group GroupPublic+data ServerECDHParams = ServerECDHParams Group GroupPublicA     deriving (Show, Eq)  ----------------------------------------------------------------@@ -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)
Network/TLS/Struct13.hs view
@@ -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)
Network/TLS/Types.hs view
@@ -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]
Network/TLS/Types/Cipher.hs view
@@ -4,6 +4,7 @@ module Network.TLS.Types.Cipher where  import Crypto.Cipher.Types (AuthTag)+import Data.ByteArray (ScrubbedBytes) import Data.IORef import GHC.Generics import System.IO.Unsafe (unsafePerformIO)@@ -15,6 +16,16 @@  ---------------------------------------------------------------- +type PlainText = ByteString+type CipherText = ByteString+type Secret = ScrubbedBytes+type Key = ScrubbedBytes+type IV = ByteString+type Nonce = ByteString -- aka IV+type AddDat = ByteString++----------------------------------------------------------------+ -- | Cipher identification type CipherID = Word16 @@ -106,12 +117,12 @@ data BulkDirection = BulkEncrypt | BulkDecrypt     deriving (Show, Eq) -type BulkBlock = BulkIV -> ByteString -> (ByteString, BulkIV)--type BulkKey = ByteString-type BulkIV = ByteString-type BulkNonce = ByteString+type BulkKey = Secret+type BulkIV = Nonce+type BulkNonce = Nonce type BulkAdditionalData = ByteString++type BulkBlock = BulkIV -> ByteString -> (ByteString, BulkIV)  newtype BulkStream = BulkStream (ByteString -> (ByteString, BulkStream)) 
Network/TLS/Types/Secret.hs view
@@ -1,6 +1,8 @@ module Network.TLS.Types.Secret where +import Data.ByteArray (convert) import Network.TLS.Imports+import Network.TLS.Types.Cipher  -- | Phantom type indicating early traffic secret. data EarlySecret@@ -13,29 +15,29 @@  data ResumptionSecret -newtype BaseSecret a = BaseSecret ByteString+newtype BaseSecret a = BaseSecret Secret  instance Show (BaseSecret a) where-    show (BaseSecret bs) = showBytesHex bs+    show (BaseSecret bs) = showBytesHex $ convert bs -newtype AnyTrafficSecret a = AnyTrafficSecret ByteString+newtype AnyTrafficSecret a = AnyTrafficSecret Secret  instance Show (AnyTrafficSecret a) where-    show (AnyTrafficSecret bs) = showBytesHex bs+    show (AnyTrafficSecret bs) = showBytesHex $ convert bs  -- | A client traffic secret, typed with a parameter indicating a step in the -- TLS key schedule.-newtype ClientTrafficSecret a = ClientTrafficSecret ByteString+newtype ClientTrafficSecret a = ClientTrafficSecret Secret  instance Show (ClientTrafficSecret a) where-    show (ClientTrafficSecret bs) = showBytesHex bs+    show (ClientTrafficSecret bs) = showBytesHex $ convert bs  -- | A server traffic secret, typed with a parameter indicating a step in the -- TLS key schedule.-newtype ServerTrafficSecret a = ServerTrafficSecret ByteString+newtype ServerTrafficSecret a = ServerTrafficSecret Secret  instance Show (ServerTrafficSecret a) where-    show (ServerTrafficSecret bs) = showBytesHex bs+    show (ServerTrafficSecret bs) = showBytesHex $ convert bs  data SecretTriple a = SecretTriple     { triBase :: BaseSecret a@@ -54,7 +56,7 @@ type TrafficSecrets a = (ClientTrafficSecret a, ServerTrafficSecret a)  -- Main secret for TLS 1.2 or earlier.-newtype MainSecret = MainSecret ByteString+newtype MainSecret = MainSecret Secret  instance Show MainSecret where-    show (MainSecret bs) = showBytesHex bs+    show (MainSecret bs) = showBytesHex $ convert bs
Network/TLS/Types/Session.hs view
@@ -38,7 +38,8 @@     , sessionCipher :: CipherID     , sessionCompression :: CompressionID     , sessionClientSNI :: Maybe HostName-    , sessionSecret :: ByteString+    , -- ScrubbedBytes is not an instance of Generic, sigh.+      sessionSecret :: ByteString     , sessionGroup :: Maybe Group     , sessionTicketInfo :: Maybe TLS13TicketInfo     , sessionALPN :: Maybe ByteString
Network/TLS/Util.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE ScopedTypeVariables #-}+{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}  module Network.TLS.Util (     sub,@@ -19,6 +20,8 @@ import Control.Concurrent.MVar import Control.Exception (SomeAsyncException (..)) import qualified Control.Exception as E+import Data.ByteArray (ScrubbedBytes)+import qualified Data.ByteArray as BA import qualified Data.ByteString as B  import Network.TLS.Imports@@ -46,18 +49,24 @@     (p3, _) = B.splitAt d3 r2  partition6-    :: ByteString+    :: ScrubbedBytes     -> (Int, Int, Int, Int, Int, Int)-    -> Maybe (ByteString, ByteString, ByteString, ByteString, ByteString, ByteString)-partition6 bytes (d1, d2, d3, d4, d5, d6) = if B.length bytes < s then Nothing else Just (p1, p2, p3, p4, p5, p6)+    -> Maybe+        ( ScrubbedBytes+        , ScrubbedBytes+        , ScrubbedBytes+        , ScrubbedBytes+        , ScrubbedBytes+        , ScrubbedBytes+        )+partition6 bytes (d1, d2, d3, d4, d5, d6) = if BA.length bytes < s then Nothing else Just (p1, p2, p3, p4, p5, p6)   where-    s = sum [d1, d2, d3, d4, d5, d6]-    (p1, r1) = B.splitAt d1 bytes-    (p2, r2) = B.splitAt d2 r1-    (p3, r3) = B.splitAt d3 r2-    (p4, r4) = B.splitAt d4 r3-    (p5, r5) = B.splitAt d5 r4-    (p6, _) = B.splitAt d6 r5+    slice' (beg, len) = BA.unsafeSlice bytes beg len+    lens = [d1, d2, d3, d4, d5, d6]+    s = sum lens+    begs = scanl (+) 0 lens+    ys = zip begs lens+    [p1, p2, p3, p4, p5, p6] = map slice' ys  -- | This is a strict version of &&. (&&!) :: Bool -> Bool -> Bool
test/Arbitrary.hs view
@@ -380,8 +380,9 @@                         { supportedCiphers = serverCiphers                         , supportedVersions = serverVersions                         , supportedSecureRenegotiation = secNeg-                        , supportedGroups = serverGroups                         , supportedHashSignatures = serverHashSignatures+                        , supportedGroups = serverGroups+                        , supportedGroupsTLS13 = [serverGroups]                         }                 , serverShared = defaultShared{sharedCredentials = Credentials creds}                 }
test/CiphersSpec.hs view
@@ -1,5 +1,6 @@ module CiphersSpec where +import qualified Data.ByteArray as BA import Data.ByteString (ByteString) import qualified Data.ByteString as B import Network.TLS.Cipher@@ -52,8 +53,8 @@     decrypted `shouldBe` t     at `shouldBe` at2 -arbitraryKey :: Bulk -> Gen B.ByteString-arbitraryKey bulk = B.pack `fmap` vector (bulkKeySize bulk)+arbitraryKey :: Bulk -> Gen BA.ScrubbedBytes+arbitraryKey bulk = BA.pack `fmap` vector (bulkKeySize bulk)  arbitraryIV :: Bulk -> Gen B.ByteString arbitraryIV bulk = B.pack `fmap` vector (bulkIVSize bulk + bulkExplicitIV bulk)@@ -61,7 +62,8 @@ arbitraryText :: Bulk -> Gen B.ByteString arbitraryText bulk = B.pack `fmap` vector (bulkBlockSize bulk) -data BulkTest = BulkTest Bulk B.ByteString B.ByteString B.ByteString B.ByteString+data BulkTest+    = BulkTest Bulk BA.ScrubbedBytes B.ByteString B.ByteString B.ByteString     deriving (Show, Eq)  instance Arbitrary BulkTest where
test/ECHSpec.hs view
@@ -56,6 +56,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [X25519]+                , supportedGroupsTLS13 = [[X25519]]                 }         params =             setParams@@ -75,6 +76,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [X25519]+                , supportedGroupsTLS13 = [[X25519]]                 }         params =             setParams@@ -94,6 +96,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [X25519]+                , supportedGroupsTLS13 = [[X25519]]                 }         params0 =             setParams@@ -126,6 +129,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [X25519]+                , supportedGroupsTLS13 = [[X25519]]                 }         params0 =             setParams@@ -162,6 +166,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [X25519]+                , supportedGroupsTLS13 = [[X25519]]                 }         params0 =             setParams@@ -187,6 +192,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_CCM_SHA256]                 , supportedGroups = [P256]+                , supportedGroupsTLS13 = [[P256]]                 }      runTLSSimple13ECH (cli2, srv2') HelloRetryRequest@@ -202,6 +208,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [X25519]+                , supportedGroupsTLS13 = [[X25519]]                 }         cliHooks =             defaultClientHooks@@ -256,6 +263,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [group0]+                , supportedGroupsTLS13 = [[group0]]                 }         params =             setParams@@ -286,6 +294,7 @@                     defaultSupported                         { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                         , supportedGroups = [group1]+                        , supportedGroupsTLS13 = [[group1]]                         }                 params1 =                     ( pc{clientUseEarlyData = True}@@ -319,7 +328,11 @@     EC cgrps <- generate arbitrary     EC sgrps <- generate arbitrary     let cliSupported = (clientSupported cli){supportedGroups = cgrps}-        svrSupported = (serverSupported srv){supportedGroups = sgrps}+        svrSupported =+            (serverSupported srv)+                { supportedGroups = sgrps+                , supportedGroupsTLS13 = [sgrps]+                }         params =             setParams                 ( cli{clientSupported = cliSupported}@@ -332,7 +345,12 @@     FFDHE cgrps <- generate arbitrary     FFDHE sgrps <- generate arbitrary     let cliSupported = (clientSupported cli){supportedGroups = cgrps}-        svrSupported = (serverSupported srv){supportedGroups = sgrps}+        svrSupported =+            (serverSupported srv)+                { supportedGroups = sgrps+                , supportedGroupsTLS13 = [sgrps]+                }+         params =             setParams                 ( cli{clientSupported = cliSupported}@@ -351,6 +369,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [X25519]+                , supportedGroupsTLS13 = [[X25519]]                 }         params =             ( cli@@ -379,6 +398,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [X25519]+                , supportedGroupsTLS13 = [[X25519]]                 }         params =             ( cli
test/HandshakeSpec.hs view
@@ -11,6 +11,7 @@ import Data.X509 (ExtKeyUsageFlag (..)) import Network.TLS import Network.TLS.Extra.Cipher+import Network.TLS.Extra.CipherCBC import Network.TLS.Internal import Test.Hspec import Test.Hspec.QuickCheck@@ -47,6 +48,7 @@         prop "can resume with extended main secret" handshake_resumption_ems         prop "can handle ALPN" handshake_alpn         prop "can handle SNI" handshake_sni+        prop "can handshake with TLS 1.2 CBC" handshake_cbc         prop "can re-negotiate with TLS 1.2" handshake12_renegotiation         prop "can resume session with TLS 1.2" handshake12_session_resumption         prop "can resume session ticket with TLS 1.2" handshake12_session_ticket@@ -102,6 +104,48 @@  -------------------------------------------------------------- +handshake_cbc :: IO ()+handshake_cbc = do+    clientCiphers <- generate $ cipherGen >>= shuffle+    serverCiphers <- generate $ cipherGen >>= shuffle+    clientGroups <- generate $ groupGen >>= shuffle+    serverGroups <- generate $ groupGen >>= shuffle+    (clientParam, serverParam) <- generate $+        arbitraryPairParamsWithVersionsAndCiphers+            ([TLS12], [TLS12])+            (clientCiphers, serverCiphers)+    let clientParam' = clientParam {+            clientSupported = (clientSupported clientParam)+                { supportedGroups = clientGroups } }+        serverParam' = serverParam {+            serverSupported = (serverSupported serverParam)+                { supportedGroups = serverGroups } }+    let ciphers = clientCiphers `intersect` serverCiphers+        groups = clientGroups `intersect` serverGroups+     in if compat ciphers groups+        then runTLSSimple (clientParam', serverParam')+        else runTLSFailure (clientParam', serverParam') handshake handshake+  where+    groupGen :: Gen [Group]+    groupGen = sublistOf grps `suchThat` (not . null)+      where+        grps = [X25519, P256, P384, FFDHE2048, FFDHE3072, FFDHE4096]++    cipherGen :: Gen [Cipher]+    cipherGen = sublistOf ciphersuite_pfs_sha2_cbc `suchThat` (not . null)++    compat :: [Cipher] -> [Group] -> Bool+    compat [] _ = False+    compat _ [] = False+    compat ciphers groups =+        let mustdh = all (== CipherKeyExchange_DHE_RSA) $ map cipherKeyExchange ciphers+            mustec = all (/= CipherKeyExchange_DHE_RSA) $ map cipherKeyExchange ciphers+            havedh = any (`elem` [FFDHE2048, FFDHE3072, FFDHE4096]) groups+            haveec = any (`elem` [X25519, P256, P384]) groups+         in ((not mustdh || havedh) && (not mustec || haveec))++--------------------------------------------------------------+ handshake13_downgrade :: (ClientParams, ServerParams) -> IO () handshake13_downgrade (cparam, sparam) = do     versionForced <-@@ -209,6 +253,7 @@                 { serverSupported =                     (serverSupported serverParam)                         { supportedGroups = serverGroups+                        , supportedGroupsTLS13 = [serverGroups]                         }                 }         commonGroups = clientGroups `intersect` serverGroups@@ -258,6 +303,7 @@                 { serverSupported =                     (serverSupported serverParam)                         { supportedGroups = sigGroups+                        , supportedGroupsTLS13 = [sigGroups]                         , supportedHashSignatures = serverHashSignatures                         }                 , serverShared =@@ -680,6 +726,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [X25519]+                , supportedGroupsTLS13 = [[X25519]]                 }         params =             ( cli{clientSupported = cliSupported}@@ -698,6 +745,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [X25519]+                , supportedGroupsTLS13 = [[X25519]]                 }         params =             ( cli{clientSupported = cliSupported}@@ -716,6 +764,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [X25519]+                , supportedGroupsTLS13 = [[X25519]]                 }         params0 =             ( cli{clientSupported = cliSupported}@@ -747,6 +796,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [X25519]+                , supportedGroupsTLS13 = [[X25519]]                 }         params0 =             ( cli{clientSupported = cliSupported}@@ -782,6 +832,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [X25519]+                , supportedGroupsTLS13 = [[X25519]]                 }         params0 =             ( cli{clientSupported = cliSupported}@@ -801,11 +852,13 @@     sessionParams <- readClientSessionRef sessionRefs     expectJust "session param should be Just" sessionParams     let (cli2, srv2) = setPairParamsSessionResuming (fromJust sessionParams) params-        srv2' = srv2{serverSupported = svrSupported'}+        srv2' =+            srv2{serverSupported = svrSupported'}         svrSupported' =             defaultSupported                 { supportedCiphers = [cipher13_AES_128_CCM_SHA256]                 , supportedGroups = [P256]+                , supportedGroupsTLS13 = [[P256]]                 }      runTLSSimple13 (cli2, srv2') HelloRetryRequest@@ -821,6 +874,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [X25519]+                , supportedGroupsTLS13 = [[X25519]]                 }         cliHooks =             defaultClientHooks@@ -874,6 +928,7 @@             defaultSupported                 { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                 , supportedGroups = [group0]+                , supportedGroupsTLS13 = [[group0]]                 }         params =             ( cli{clientSupported = cliSupported}@@ -903,6 +958,7 @@                     defaultSupported                         { supportedCiphers = [cipher13_AES_128_GCM_SHA256]                         , supportedGroups = [group1]+                        , supportedGroupsTLS13 = [[group1]]                         }                 params1 =                     ( pc{clientUseEarlyData = True}@@ -936,13 +992,17 @@     let -- The client prefers P256         cliSupported = (clientSupported cli){supportedGroups = [P256, X25519]}         -- The server prefers X25519-        svrSupported = (serverSupported srv){supportedGroups = [X25519, P256]}+        svrSupported =+            (serverSupported srv)+                { supportedGroups = [X25519, P256]+                , supportedGroupsTLS13 = [[X25519, P256]]+                }         params =             ( cli{clientSupported = cliSupported}             , srv{serverSupported = svrSupported}             )     (_, serverMessages) <- runTLSCapture13 params-    -- The server should tell X25519 in supported_groups in EE to clinet+    -- The server should tell X25519 in supported_groups in EE to client     let isSupportedGroups (ExtensionRaw eid _) = eid == EID_SupportedGroups         eeMessagesHaveExt =             [ any isSupportedGroups exts@@ -955,7 +1015,11 @@     EC cgrps <- generate arbitrary     EC sgrps <- generate arbitrary     let cliSupported = (clientSupported cli){supportedGroups = cgrps}-        svrSupported = (serverSupported srv){supportedGroups = sgrps}+        svrSupported =+            (serverSupported srv)+                { supportedGroups = sgrps+                , supportedGroupsTLS13 = [sgrps]+                }         params =             ( cli{clientSupported = cliSupported}             , srv{serverSupported = svrSupported}@@ -967,7 +1031,11 @@     FFDHE cgrps <- generate arbitrary     FFDHE sgrps <- generate arbitrary     let cliSupported = (clientSupported cli){supportedGroups = cgrps}-        svrSupported = (serverSupported srv){supportedGroups = sgrps}+        svrSupported =+            (serverSupported srv)+                { supportedGroups = sgrps+                , supportedGroupsTLS13 = [sgrps]+                }         params =             ( cli{clientSupported = cliSupported}             , srv{serverSupported = svrSupported}
tls.cabal view
@@ -1,6 +1,6 @@ cabal-version:      >=1.10 name:               tls-version:            2.1.14+version:            2.4.3 license:            BSD3 license-file:       LICENSE copyright:          Vincent Hanquez <vincent@snarc.org>@@ -34,6 +34,7 @@         Network.TLS.Internal         Network.TLS.Extra         Network.TLS.Extra.Cipher+        Network.TLS.Extra.CipherCBC         Network.TLS.Extra.FFDHE         Network.TLS.QUIC @@ -113,69 +114,32 @@         Network.TLS.Wire         Network.TLS.X509 +    default-language:   Haskell2010     default-extensions: Strict StrictData-    default-language: Haskell2010-    ghc-options:      -Wall+    ghc-options:        -Wall     build-depends:         base >=4.9 && <5,-        asn1-encoding >= 0.9 && < 0.10,-        asn1-types >= 0.3 && < 0.4,         base16-bytestring,-        bytestring >= 0.10 && < 0.13,-        cereal >= 0.5.3 && < 0.6,-        crypton >= 0.34,-        crypton-x509 >= 1.7 && < 1.8,-        crypton-x509-store >= 1.6 && < 1.7,-        crypton-x509-validation >= 1.6.13 && < 1.7,+        bytestring >=0.10 && <0.13,+        cereal >=0.5.3 && <0.6,+        crypton >=1.1.2 && <1.2,+        crypton-asn1-encoding >= 0.10.0 && < 0.11,+        crypton-asn1-types >= 0.4.1 && < 0.5,+        crypton-x509 >=1.9 && <1.10,+        crypton-x509-store >=1.9 && <1.10,+        crypton-x509-validation >=1.9 && <1.10,         data-default,         ech-config,-        hpke,-        memory >= 0.18 && < 0.19,-        mtl >= 2.2 && < 2.4,-        network >= 3.1,-        random >= 1.2 && < 1.4,-        serialise >= 0.2 && < 0.3,-        transformers >= 0.5 && < 0.7,-        unix-time >= 0.4.11 && < 0.5,-        zlib >= 0.7 && < 0.8--test-suite spec-    type:               exitcode-stdio-1.0-    main-is:            Spec.hs-    build-tool-depends: hspec-discover:hspec-discover-    hs-source-dirs:     test-    other-modules:-        API-        Arbitrary-        Certificate-        CiphersSpec-        ECHSpec-        EncodeSpec-        HandshakeSpec-        PipeChan-        PubKey-        Run-        Session-        ThreadSpec--    default-extensions: Strict StrictData-    default-language:   Haskell2010-    ghc-options:        -Wall -threaded -rtsopts-    build-depends:-        base >=4.9 && <5,-        QuickCheck,-        asn1-types,-        async,-        base64-bytestring,-        bytestring,-        crypton,-        crypton-x509,-        crypton-x509-validation,-        ech-config,-        hourglass,-        hspec,-        serialise,-        tls+        hpke >=0.1.0 && <0.2,+        mlkem >= 0.2.0 && <0.3,+        mtl >=2.2 && <2.4,+        network >=3.1,+        ram >=0.22.0 && <0.23,+        random >=1.2 && <1.4,+        serialise >=0.2 && <0.3,+        transformers >=0.5 && <0.7,+        unix-time >=0.4.11 && <0.6,+        zlib >=0.7 && <0.8  executable tls-server     main-is:            tls-server.hs@@ -190,8 +154,8 @@     ghc-options:        -Wall -threaded -rtsopts     build-depends:         base >=4.9 && <5,-        bytestring,         base16-bytestring,+        bytestring,         containers,         crypton,         crypton-x509-store,@@ -226,7 +190,7 @@         crypton-x509-system,         ech-config,         network,-        network-run >= 0.5,+        network-run >=0.5,         tls      if flag(devel)@@ -234,9 +198,11 @@     else         buildable: False -benchmark tls-bench-    main-is: Benchmarks.hs-    type: exitcode-stdio-1.0+test-suite spec+    type:               exitcode-stdio-1.0+    main-is:            Spec.hs+    build-tool-depends: hspec-discover:hspec-discover+    hs-source-dirs:     test     other-modules:         API         Arbitrary@@ -250,29 +216,65 @@         Run         Session         ThreadSpec-    hs-source-dirs:-        Benchmarks-        test+     default-language:   Haskell2010-    ghc-options: -Wall+    default-extensions: Strict StrictData+    ghc-options:        -Wall -threaded -rtsopts     build-depends:         base >=4.9 && <5,+        QuickCheck,+        async,+        base64-bytestring,         bytestring,+        crypton,+        crypton-asn1-types,+        crypton-x509,+        crypton-x509-validation,+        ech-config,+        hspec,+        ram,+        serialise,+        time-hourglass,+        tls++benchmark tls-bench+    type:             exitcode-stdio-1.0+    main-is:          Benchmarks.hs+    hs-source-dirs:   Benchmarks test+    other-modules:+        API+        Arbitrary+        Certificate+        CiphersSpec+        ECHSpec+        EncodeSpec+        HandshakeSpec+        PipeChan+        PubKey+        Run+        Session+        ThreadSpec++    default-language: Haskell2010+    ghc-options:      -Wall+    build-depends:+        base >=4.9 && <5,+        QuickCheck,+        async,         base64-bytestring,+        bytestring,         containers,-        async,-        data-default,-        hourglass,         crypton,+        crypton-asn1-types,         crypton-x509,         crypton-x509-store,         crypton-x509-validation,+        data-default,         ech-config,+        hspec,         network,         network-run,-        tls,-        asn1-types,-        tasty-bench,-        QuickCheck,         serialise,-        hspec+        tasty-bench,+        time-hourglass,+        tls
util/Common.hs view
@@ -36,19 +36,27 @@     , ("ffdhe8192", ffdhe8192)     ] +{- FOURMOLU_DISABLE -} namedGroups :: [(String, Group)] namedGroups =-    [ ("ffdhe2048", FFDHE2048)-    , ("ffdhe3072", FFDHE3072)-    , ("ffdhe4096", FFDHE4096)-    , ("ffdhe6144", FFDHE6144)-    , ("ffdhe8192", FFDHE8192)-    , ("p256", P256)-    , ("p384", P384)-    , ("p521", P521)-    , ("x25519", X25519)-    , ("x448", X448)+    [ ("ffdhe2048",      FFDHE2048)+    , ("ffdhe3072",      FFDHE3072)+    , ("ffdhe4096",      FFDHE4096)+    , ("ffdhe6144",      FFDHE6144)+    , ("ffdhe8192",      FFDHE8192)+    , ("p256",           P256)+    , ("p384",           P384)+    , ("p521",           P521)+    , ("x25519",         X25519)+    , ("x448",           X448)+    , ("mlkem512",       MLKEM512)+    , ("mlkem768",       MLKEM768)+    , ("mlkem1024",      MLKEM1024)+    , ("x25519mlkem768", X25519MLKEM768)+    , ("p256mlkem768",   P256MLKEM768)+    , ("p384mlkem1024",  P384MLKEM1024)     ]+{- FOURMOLU_ENABLE -}  readNumber :: (Num a, Read a) => String -> Maybe a readNumber s@@ -103,7 +111,7 @@     minfo <- contextGetInformation ctx     case minfo of         Nothing -> do-            putStrLn "Erro: information cannot be obtained"+            putStrLn "Error: information cannot be obtained"             exitFailure         Just info -> return info