tls-2.0.0: Network/TLS/Handshake/Server/ClientHello.hs
{-# LANGUAGE RecordWildCards #-}
module Network.TLS.Handshake.Server.ClientHello (
processClientHello,
) where
import Network.TLS.Context.Internal
import Network.TLS.Extension
import Network.TLS.Handshake.Common
import Network.TLS.Handshake.Process
import Network.TLS.Imports
import Network.TLS.Measurement
import Network.TLS.Parameters
import Network.TLS.State
import Network.TLS.Struct
processClientHello
:: ServerParams -> Context -> Handshake -> IO (Version, CH)
processClientHello sparams ctx clientHello@(ClientHello legacyVersion cran compressions ch@CH{..}) = do
established <- ctxEstablished ctx
-- renego is not allowed in TLS 1.3
when (established /= NotEstablished) $ do
ver <- usingState_ ctx (getVersionWithDefault TLS12)
when (ver == TLS13) $
throwCore $
Error_Protocol "renegotiation is not allowed in TLS 1.3" UnexpectedMessage
-- rejecting client initiated renegotiation to prevent DOS.
eof <- ctxEOF ctx
let renegotiation = established == Established && not eof
when
( renegotiation && not (supportedClientInitiatedRenegotiation $ ctxSupported ctx)
)
$ throwCore
$ Error_Protocol_Warning "renegotiation is not allowed" NoRenegotiation
-- check if policy allow this new handshake to happens
handshakeAuthorized <- withMeasure ctx (onNewHandshake $ serverHooks sparams)
unless
handshakeAuthorized
(throwCore $ Error_HandshakePolicy "server: handshake denied")
updateMeasure ctx incrementNbHandshakes
-- Handle Client hello
hrr <- usingState_ ctx getTLS13HRR
unless hrr $ startHandshake ctx legacyVersion cran
processHandshake12 ctx clientHello
when (legacyVersion /= TLS12) $
throwCore $
Error_Protocol (show legacyVersion ++ " is not supported") ProtocolVersion
-- Fallback SCSV: RFC7507
-- TLS_FALLBACK_SCSV: {0x56, 0x00}
when
( supportedFallbackScsv (ctxSupported ctx)
&& (0x5600 `elem` chCiphers)
&& legacyVersion < TLS12
)
$ throwCore
$ Error_Protocol "fallback is not allowed" InappropriateFallback
-- choosing TLS version
let clientVersions = case extensionLookup EID_SupportedVersions chExtensions
>>= extensionDecode MsgTClientHello of
Just (SupportedVersionsClientHello vers) -> vers -- fixme: vers == []
_ -> []
clientVersion = min TLS12 legacyVersion
serverVersions
| renegotiation = filter (< TLS13) (supportedVersions $ ctxSupported ctx)
| otherwise = supportedVersions $ ctxSupported ctx
mVersion = debugVersionForced $ serverDebug sparams
chosenVersion <- case mVersion of
Just cver -> return cver
Nothing ->
if (TLS13 `elem` serverVersions) && clientVersions /= []
then case findHighestVersionFrom13 clientVersions serverVersions of
Nothing ->
throwCore $
Error_Protocol
("client versions " ++ show clientVersions ++ " is not supported")
ProtocolVersion
Just v -> return v
else case findHighestVersionFrom clientVersion serverVersions of
Nothing ->
throwCore $
Error_Protocol
("client version " ++ show clientVersion ++ " is not supported")
ProtocolVersion
Just v -> return v
-- SNI (Server Name Indication)
let serverName = case extensionLookup EID_ServerName chExtensions >>= extensionDecode MsgTClientHello of
Just (ServerName ns) -> listToMaybe (mapMaybe toHostName ns)
where
toHostName (ServerNameHostName hostName) = Just hostName
toHostName (ServerNameOther _) = Nothing
_ -> Nothing
when (chosenVersion == TLS13) $ do
-- If this is done for TLS12, SSL Labs test does not continue, sigh.
mapM_ ensureNullCompression compressions
maybe (return ()) (usingState_ ctx . setClientSNI) serverName
return (chosenVersion, ch)
processClientHello _ _ _ =
throwCore $
Error_Protocol
"unexpected handshake message received in handshakeServerWith"
HandshakeFailure
findHighestVersionFrom :: Version -> [Version] -> Maybe Version
findHighestVersionFrom clientVersion allowedVersions =
case filter (clientVersion >=) $ sortOn Down allowedVersions of
[] -> Nothing
v : _ -> Just v
findHighestVersionFrom13 :: [Version] -> [Version] -> Maybe Version
findHighestVersionFrom13 clientVersions serverVersions = case svs `intersect` cvs of
[] -> Nothing
v : _ -> Just v
where
svs = sortOn Down serverVersions
cvs = sortOn Down $ filter (>= TLS12) clientVersions