    {-# LANGUAGE PatternGuards #-}

    module Network.TLS.Handshake.Random (
        serverRandom,
        clientRandom,
        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 :: Context -> Version -> [Version] -> IO ServerRandom
    serverRandom Context
    ctx Version
    chosenVer [Version]
    suppVers
        | Version
    TLS13 Version -> [Version] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [Version]
    suppVers = case Version
    chosenVer of
            Version
    TLS13 -> ByteString -> ServerRandom
    ServerRandom (ByteString -> ServerRandom) -> IO ByteString -> IO ServerRandom
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Context -> Int -> IO ByteString
    getStateRNG Context
    ctx Int
    32
            Version
    TLS12 -> ByteString -> ServerRandom
    ServerRandom (ByteString -> ServerRandom) -> IO ByteString -> IO ServerRandom
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> ByteString -> IO ByteString
    genServRand ByteString
    suffix12
            Version
    _ -> ByteString -> ServerRandom
    ServerRandom (ByteString -> ServerRandom) -> IO ByteString -> IO ServerRandom
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> ByteString -> IO ByteString
    genServRand ByteString
    suffix11
        | Version
    TLS12 Version -> [Version] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [Version]
    suppVers = case Version
    chosenVer of
            Version
    TLS13 -> ByteString -> ServerRandom
    ServerRandom (ByteString -> ServerRandom) -> IO ByteString -> IO ServerRandom
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Context -> Int -> IO ByteString
    getStateRNG Context
    ctx Int
    32
            Version
    TLS12 -> ByteString -> ServerRandom
    ServerRandom (ByteString -> ServerRandom) -> IO ByteString -> IO ServerRandom
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Context -> Int -> IO ByteString
    getStateRNG Context
    ctx Int
    32
            Version
    _ -> ByteString -> ServerRandom
    ServerRandom (ByteString -> ServerRandom) -> IO ByteString -> IO ServerRandom
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> ByteString -> IO ByteString
    genServRand ByteString
    suffix11
        | Bool
    otherwise = ByteString -> ServerRandom
    ServerRandom (ByteString -> ServerRandom) -> IO ByteString -> IO ServerRandom
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Context -> Int -> IO ByteString
    getStateRNG Context
    ctx Int
    32
      where
        genServRand :: ByteString -> IO ByteString
    genServRand ByteString
    suff = do
            pref <- Context -> Int -> IO ByteString
    getStateRNG Context
    ctx Int
    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 :: Version -> [Version] -> ServerRandom -> Bool
    isDowngraded Version
    ver [Version]
    suppVers (ServerRandom ByteString
    sr)
        | Version
    ver Version -> Version -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Version
    TLS12
        , Version
    TLS13 Version -> [Version] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [Version]
    suppVers =
            ByteString
    suffix12 ByteString -> ByteString -> Bool
    `B.isSuffixOf` ByteString
    sr
                Bool -> Bool -> Bool
    || ByteString
    suffix11 ByteString -> ByteString -> Bool
    `B.isSuffixOf` ByteString
    sr
        | Version
    ver Version -> Version -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Version
    TLS11
        , Version
    TLS12 Version -> [Version] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [Version]
    suppVers =
            ByteString
    suffix11 ByteString -> ByteString -> Bool
    `B.isSuffixOf` ByteString
    sr
        | Bool
    otherwise = Bool
    False

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

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

    clientRandom :: Context -> IO ClientRandom
    clientRandom :: Context -> IO ClientRandom
    clientRandom Context
    ctx = ByteString -> ClientRandom
    ClientRandom (ByteString -> ClientRandom) -> IO ByteString -> IO ClientRandom
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Context -> Int -> IO ByteString
    getStateRNG Context
    ctx Int
    32