{-# LANGUAGE PatternGuards #-}

module Network.TLS.Handshake.Random (
    serverRandom,
    clientRandom,
    hrrRandom,
    isHelloRetryRequest,
    isDowngraded,
) where

import qualified Data.ByteString as B
import Network.TLS.Context.Internal
import Network.TLS.Struct

-- | Generate a server random suitable for the version selected by the server
-- and its supported versions.  We use an 8-byte downgrade suffix when the
-- selected version is lowered because of incomplete client support, but also
-- when a version downgrade has been forced with 'debugVersionForced'.  This
-- second part allows to test that the client implementation correctly detects
-- downgrades.  The suffix is not used when forcing TLS13 to a server not
-- officially supporting TLS13 (this is not a downgrade scenario but only the
-- consequence of our debug API allowing this).
serverRandom :: Context -> Version -> [Version] -> IO ServerRandom
serverRandom ctx chosenVer suppVers
    | TLS13 `elem` suppVers = case chosenVer of
        TLS13 -> ServerRandom <$> getStateRNG ctx 32
        TLS12 -> ServerRandom <$> genServRand suffix12
        _ -> ServerRandom <$> genServRand suffix11
    | TLS12 `elem` suppVers = case chosenVer of
        TLS13 -> ServerRandom <$> getStateRNG ctx 32
        TLS12 -> ServerRandom <$> getStateRNG ctx 32
        _ -> ServerRandom <$> genServRand suffix11
    | otherwise = ServerRandom <$> getStateRNG ctx 32
  where
    genServRand suff = do
        pref <- getStateRNG ctx 24
        return (pref `B.append` suff)

-- | Test if the negotiated version was artificially downgraded (that is, for
-- other reason than the versions supported by the client).
isDowngraded :: Version -> [Version] -> ServerRandom -> Bool
isDowngraded ver suppVers (ServerRandom sr)
    | ver <= TLS12
    , TLS13 `elem` suppVers =
        suffix12 `B.isSuffixOf` sr
            || suffix11 `B.isSuffixOf` sr
    | ver <= TLS11
    , TLS12 `elem` suppVers =
        suffix11 `B.isSuffixOf` sr
    | otherwise = False

suffix12 :: B.ByteString
suffix12 = B.pack [0x44, 0x4F, 0x57, 0x4E, 0x47, 0x52, 0x44, 0x01]

suffix11 :: B.ByteString
suffix11 = B.pack [0x44, 0x4F, 0x57, 0x4E, 0x47, 0x52, 0x44, 0x00]

clientRandom :: Context -> IO ClientRandom
clientRandom ctx = ClientRandom <$> getStateRNG ctx 32

hrrRandom :: ServerRandom
hrrRandom =
    ServerRandom $
        B.pack
            [ 0xCF
            , 0x21
            , 0xAD
            , 0x74
            , 0xE5
            , 0x9A
            , 0x61
            , 0x11
            , 0xBE
            , 0x1D
            , 0x8C
            , 0x02
            , 0x1E
            , 0x65
            , 0xB8
            , 0x91
            , 0xC2
            , 0xA2
            , 0x11
            , 0x16
            , 0x7A
            , 0xBB
            , 0x8C
            , 0x5E
            , 0x07
            , 0x9E
            , 0x09
            , 0xE2
            , 0xC8
            , 0xA8
            , 0x33
            , 0x9C
            ]

isHelloRetryRequest :: ServerRandom -> Bool
isHelloRetryRequest = (== hrrRandom)
