{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} module Network.TLS.Handshake.Server.ClientHello13 ( processClientHello13, sendHRR, ) where import Network.TLS.Cipher import Network.TLS.Context.Internal import Network.TLS.Crypto import Network.TLS.Extension import Network.TLS.Handshake.Common import Network.TLS.Handshake.Common13 import Network.TLS.Handshake.Random import Network.TLS.Handshake.State import Network.TLS.Handshake.State13 import Network.TLS.IO import Network.TLS.Imports import Network.TLS.Parameters import Network.TLS.State import Network.TLS.Struct import Network.TLS.Struct13 -- TLS 1.3 or later processClientHello13 :: ServerParams -> Context -> CH -> IO (Maybe KeyShareEntry, (Cipher, Hash, Bool)) processClientHello13 sparams ctx CH{..} = do when (any (\(ExtensionRaw eid _) -> eid == EID_PreSharedKey) $ init chExtensions) $ throwCore $ Error_Protocol "extension pre_shared_key must be last" IllegalParameter -- Deciding cipher. -- The shared cipherlist can become empty after filtering for compatible -- creds, check now before calling onCipherChoosing, which does not handle -- empty lists. when (null ciphersFilteredVersion) $ throwCore $ Error_Protocol "no cipher in common with the TLS 1.3 client" HandshakeFailure let usedCipher = onCipherChoosing (serverHooks sparams) TLS13 ciphersFilteredVersion usedHash = cipherHash usedCipher rtt0 = case extensionLookup EID_EarlyData chExtensions >>= extensionDecode MsgTClientHello of Just (EarlyDataIndication _) -> True Nothing -> False when rtt0 $ -- mark a 0-RTT attempt before a possible HRR, and before updating the -- status again if 0-RTT successful setEstablished ctx (EarlyDataNotAllowed 3) -- hardcoding -- Deciding key exchange from key shares keyShares <- case extensionLookup EID_KeyShare chExtensions of Nothing -> throwCore $ Error_Protocol "key exchange not implemented, expected key_share extension" MissingExtension Just kss -> case extensionDecode MsgTClientHello kss of Just (KeyShareClientHello kses) -> return kses Just _ -> error "processClientHello13: invalid KeyShare value" _ -> throwCore $ Error_Protocol "broken key_share" DecodeError mshare <- findKeyShare keyShares serverGroups return (mshare, (usedCipher, usedHash, rtt0)) where ciphersFilteredVersion = filter ((`elem` chCiphers) . cipherID) serverCiphers serverCiphers = filter (cipherAllowedForVersion TLS13) (supportedCiphers $ serverSupported sparams) serverGroups = supportedGroups (ctxSupported ctx) 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 sendHRR :: Context -> (Cipher, a, b) -> CH -> IO () sendHRR ctx (usedCipher, _, _) CH{..} = do twice <- usingState_ ctx getTLS13HRR when twice $ throwCore $ Error_Protocol "Hello retry not allowed again" HandshakeFailure usingState_ ctx $ setTLS13HRR True failOnEitherError $ usingHState ctx $ setHelloParameters13 usedCipher let clientGroups = case extensionLookup EID_SupportedGroups chExtensions >>= extensionDecode MsgTClientHello of Just (SupportedGroups gs) -> gs Nothing -> [] possibleGroups = serverGroups `intersect` clientGroups case possibleGroups of [] -> throwCore $ Error_Protocol "no group in common with the client for HRR" HandshakeFailure g : _ -> do let serverKeyShare = extensionEncode $ KeyShareHRR g selectedVersion = extensionEncode $ SupportedVersionsServerHello TLS13 extensions = [ ExtensionRaw EID_KeyShare serverKeyShare , ExtensionRaw EID_SupportedVersions selectedVersion ] hrr = ServerHello13 hrrRandom chSession (cipherID usedCipher) extensions usingHState ctx $ setTLS13HandshakeMode HelloRetryRequest runPacketFlight ctx $ do loadPacket13 ctx $ Handshake13 [hrr] sendChangeCipherSpec13 ctx where serverGroups = supportedGroups (ctxSupported ctx)