-- |
-- Module      : Network.TLS.Extra.Cipher
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : unknown
--
{-# LANGUAGE CPP #-}
module Network.TLS.Extra.Cipher
    (
    -- * cipher suite
      ciphersuite_default
    , ciphersuite_all
    , ciphersuite_medium
    , ciphersuite_strong
    , ciphersuite_unencrypted
    , ciphersuite_dhe_rsa
    , ciphersuite_dhe_dss
    -- * individual ciphers
    , cipher_null_SHA1
    , cipher_AES128_SHA1
    , cipher_AES256_SHA1
    , cipher_AES128_SHA256
    , cipher_AES256_SHA256
    , cipher_AES128GCM_SHA256
    , cipher_AES256GCM_SHA384
    , cipher_DHE_RSA_AES128_SHA1
    , cipher_DHE_RSA_AES256_SHA1
    , cipher_DHE_RSA_AES128_SHA256
    , cipher_DHE_RSA_AES256_SHA256
    , cipher_DHE_DSS_AES128_SHA1
    , cipher_DHE_DSS_AES256_SHA1
    , cipher_DHE_RSA_AES128GCM_SHA256
    , cipher_DHE_RSA_AES256GCM_SHA384
    , cipher_ECDHE_RSA_AES128GCM_SHA256
    , cipher_ECDHE_RSA_AES256GCM_SHA384
    , cipher_ECDHE_RSA_AES128CBC_SHA256
    , cipher_ECDHE_RSA_AES128CBC_SHA
    , cipher_ECDHE_RSA_AES256CBC_SHA
    , cipher_ECDHE_RSA_AES256CBC_SHA384
    , cipher_ECDHE_ECDSA_AES128CBC_SHA
    , cipher_ECDHE_ECDSA_AES256CBC_SHA
    , cipher_ECDHE_ECDSA_AES128CBC_SHA256
    , cipher_ECDHE_ECDSA_AES256CBC_SHA384
    , cipher_ECDHE_ECDSA_AES128GCM_SHA256
    , cipher_ECDHE_ECDSA_AES256GCM_SHA384
    -- * obsolete and non-standard ciphers
    , cipher_RSA_3DES_EDE_CBC_SHA1
    , cipher_RC4_128_MD5
    , cipher_RC4_128_SHA1
    , cipher_null_MD5
    , cipher_DHE_DSS_RC4_SHA1
    ) where

import qualified Data.ByteString as B

import Network.TLS.Types (Version(..))
import Network.TLS.Cipher
import Network.TLS.Imports
import Data.Tuple (swap)

import Crypto.Cipher.AES
import qualified Crypto.Cipher.RC4 as RC4
import Crypto.Cipher.TripleDES
import Crypto.Cipher.Types hiding (Cipher, cipherName)
import Crypto.Error

takelast :: Int -> B.ByteString -> B.ByteString
takelast i b = B.drop (B.length b - i) b

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))

aes128gcm :: BulkDirection -> BulkKey -> BulkAEAD
aes128gcm BulkEncrypt key =
    let ctx = noFail (cipherInit key) :: AES128
     in (\nonce d ad ->
            let aeadIni = noFail (aeadInit AEAD_GCM ctx nonce)
             in swap $ aeadSimpleEncrypt aeadIni ad d 16)
aes128gcm BulkDecrypt key =
    let ctx = noFail (cipherInit key) :: AES128
     in (\nonce d ad ->
            let aeadIni = noFail (aeadInit AEAD_GCM ctx nonce)
             in simpleDecrypt aeadIni ad d)
  where
    simpleDecrypt aeadIni header input = (output, tag)
      where
            aead                = aeadAppendHeader aeadIni header
            (output, aeadFinal) = aeadDecrypt aead input
            tag                 = aeadFinalize aeadFinal 16

aes256gcm :: BulkDirection -> BulkKey -> BulkAEAD
aes256gcm BulkEncrypt key =
    let ctx = noFail (cipherInit key) :: AES256
     in (\nonce d ad ->
            let aeadIni = noFail (aeadInit AEAD_GCM ctx nonce)
             in swap $ aeadSimpleEncrypt aeadIni ad d 16)
aes256gcm BulkDecrypt key =
    let ctx = noFail (cipherInit key) :: AES256
     in (\nonce d ad ->
            let aeadIni = noFail (aeadInit AEAD_GCM ctx nonce)
             in simpleDecrypt aeadIni ad d)
  where
    simpleDecrypt aeadIni header input = (output, tag)
      where
            aead                = aeadAppendHeader aeadIni header
            (output, aeadFinal) = aeadDecrypt aead input
            tag                 = aeadFinalize aeadFinal 16

noFail :: CryptoFailable a -> a
noFail = throwCryptoError

makeIV_ :: BlockCipher a => B.ByteString -> IV a
makeIV_ = fromMaybe (error "makeIV_") . makeIV

tripledes_ede :: BulkDirection -> BulkKey -> BulkBlock
tripledes_ede BulkEncrypt key =
    let ctx = noFail $ cipherInit key
     in (\iv input -> let output = cbcEncrypt ctx (tripledes_iv iv) input in (output, takelast 8 output))
tripledes_ede BulkDecrypt key =
    let ctx = noFail $ cipherInit key
     in (\iv input -> let output = cbcDecrypt ctx (tripledes_iv iv) input in (output, takelast 8 input))

tripledes_iv :: BulkIV -> IV DES_EDE3
tripledes_iv iv = fromMaybe (error "tripledes cipher iv internal error") $ makeIV iv

rc4 :: BulkDirection -> BulkKey -> BulkStream
rc4 _ bulkKey = BulkStream (combineRC4 $ RC4.initialize bulkKey)
  where
    combineRC4 ctx input =
        let (ctx', output) = RC4.combine ctx input
         in (output, BulkStream (combineRC4 ctx'))

-- | All AES ciphers supported ordered from strong to weak.  This choice
-- of ciphersuites should satisfy most normal needs.  For otherwise strong
-- ciphers we make little distinction between AES128 and AES256, and list
-- each but the weakest of the AES128 ciphers ahead of the corresponding AES256
-- ciphers.
ciphersuite_default :: [Cipher]
ciphersuite_default =
    [        -- First the PFS + GCM + SHA2 ciphers
      cipher_ECDHE_ECDSA_AES128GCM_SHA256, cipher_ECDHE_ECDSA_AES256GCM_SHA384
    , cipher_ECDHE_RSA_AES128GCM_SHA256, cipher_ECDHE_RSA_AES256GCM_SHA384
    , cipher_DHE_RSA_AES128GCM_SHA256, cipher_DHE_RSA_AES256GCM_SHA384
             -- Next the PFS + CBC + SHA2 ciphers
    , 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
             -- Next the PFS + CBC + SHA1 ciphers
    , cipher_ECDHE_ECDSA_AES128CBC_SHA, cipher_ECDHE_ECDSA_AES256CBC_SHA
    , cipher_ECDHE_RSA_AES128CBC_SHA, cipher_ECDHE_RSA_AES256CBC_SHA
    , cipher_DHE_RSA_AES128_SHA1, cipher_DHE_RSA_AES256_SHA1
             -- Next the non-PFS + GCM + SHA2 ciphers
    , cipher_AES128GCM_SHA256, cipher_AES256GCM_SHA384
             -- Next the non-PFS + CBC + SHA2 ciphers
    , cipher_AES256_SHA256, cipher_AES128_SHA256
             -- Next the non-PFS + CBC + SHA1 ciphers
    , cipher_AES256_SHA1, cipher_AES128_SHA1
             -- Nobody uses or should use DSS, RC4,  3DES or MD5
    -- , cipher_DHE_DSS_AES256_SHA1, cipher_DHE_DSS_AES128_SHA1
    -- , cipher_DHE_DSS_RC4_SHA1, cipher_RC4_128_SHA1, cipher_RC4_128_MD5
    -- , cipher_RSA_3DES_EDE_CBC_SHA1
    ]

{-# WARNING ciphersuite_all "This ciphersuite list contains RC4. Use ciphersuite_strong or ciphersuite_default instead." #-}
-- | The default ciphersuites + some not recommended last resort ciphers.
ciphersuite_all :: [Cipher]
ciphersuite_all = ciphersuite_default ++
    [ cipher_DHE_DSS_AES256_SHA1, cipher_DHE_DSS_AES128_SHA1
    , cipher_RSA_3DES_EDE_CBC_SHA1
    , cipher_RC4_128_SHA1
    ]

{-# DEPRECATED ciphersuite_medium "Use ciphersuite_strong or ciphersuite_default instead." #-}
-- | list of medium ciphers.
ciphersuite_medium :: [Cipher]
ciphersuite_medium = [ cipher_RC4_128_SHA1
                     , cipher_AES128_SHA1
                     ]

-- | The strongest ciphers supported.  For ciphers with PFS, AEAD and SHA2, we
-- list each AES128 variant right after the corresponding AES256 variant.  For
-- weaker constructs, we use just the AES256 form.
ciphersuite_strong :: [Cipher]
ciphersuite_strong =
    [        -- If we have PFS + AEAD + SHA2, then allow AES128, else just 256
      cipher_ECDHE_ECDSA_AES256GCM_SHA384, cipher_ECDHE_ECDSA_AES128GCM_SHA256
    , cipher_ECDHE_RSA_AES256GCM_SHA384, cipher_ECDHE_RSA_AES128GCM_SHA256
    , cipher_DHE_RSA_AES256GCM_SHA384, cipher_DHE_RSA_AES128GCM_SHA256
             -- No AEAD
    , cipher_ECDHE_ECDSA_AES256CBC_SHA384
    , cipher_ECDHE_RSA_AES256CBC_SHA384
    , cipher_DHE_RSA_AES256_SHA256
             -- No SHA2
    , cipher_ECDHE_ECDSA_AES256CBC_SHA
    , cipher_ECDHE_RSA_AES256CBC_SHA
    , cipher_DHE_RSA_AES256_SHA1
             -- No PFS
    , cipher_AES256GCM_SHA384
             -- Neither PFS nor AEAD, just SHA2
    , cipher_AES256_SHA256
             -- Last resort no PFS, AEAD or SHA2
    , cipher_AES256_SHA1
    ]

-- | DHE-RSA cipher suite
ciphersuite_dhe_rsa :: [Cipher]
ciphersuite_dhe_rsa = [ cipher_DHE_RSA_AES256GCM_SHA384, cipher_DHE_RSA_AES128GCM_SHA256
                      , cipher_DHE_RSA_AES256_SHA256, cipher_DHE_RSA_AES128_SHA256
                      , cipher_DHE_RSA_AES256_SHA1, cipher_DHE_RSA_AES128_SHA1
                      ]

ciphersuite_dhe_dss :: [Cipher]
ciphersuite_dhe_dss = [cipher_DHE_DSS_AES256_SHA1, cipher_DHE_DSS_AES128_SHA1, cipher_DHE_DSS_RC4_SHA1]

-- | all unencrypted ciphers, do not use on insecure network.
ciphersuite_unencrypted :: [Cipher]
ciphersuite_unencrypted = [cipher_null_MD5, cipher_null_SHA1]

bulk_null, bulk_rc4, bulk_aes128, bulk_aes256, bulk_tripledes_ede, bulk_aes128gcm, bulk_aes256gcm :: Bulk
bulk_null = Bulk
    { bulkName         = "null"
    , bulkKeySize      = 0
    , bulkIVSize       = 0
    , bulkExplicitIV   = 0
    , bulkAuthTagLen   = 0
    , bulkBlockSize    = 0
    , bulkF            = BulkStreamF passThrough
    }
  where
    passThrough _ _ = BulkStream go where go inp = (inp, BulkStream go)

bulk_rc4 = Bulk
    { bulkName         = "RC4-128"
    , bulkKeySize      = 16
    , bulkIVSize       = 0
    , bulkExplicitIV   = 0
    , bulkAuthTagLen   = 0
    , bulkBlockSize    = 0
    , bulkF            = BulkStreamF rc4
    }

bulk_aes128 = Bulk
    { bulkName         = "AES128"
    , bulkKeySize      = 16
    , bulkIVSize       = 16
    , bulkExplicitIV   = 0
    , bulkAuthTagLen   = 0
    , bulkBlockSize    = 16
    , bulkF            = BulkBlockF aes128cbc
    }

bulk_aes128gcm = Bulk
    { bulkName         = "AES128GCM"
    , bulkKeySize      = 16 -- RFC 5116 Sec 5.1: K_LEN
    , bulkIVSize       = 4  -- RFC 5288 GCMNonce.salt, fixed_iv_length
    , bulkExplicitIV   = 8
    , bulkAuthTagLen   = 16
    , bulkBlockSize    = 0  -- dummy, not used
    , bulkF            = BulkAeadF aes128gcm
    }

bulk_aes256gcm = Bulk
    { bulkName         = "AES256GCM"
    , bulkKeySize      = 32 -- RFC 5116 Sec 5.1: K_LEN
    , bulkIVSize       = 4  -- RFC 5288 GCMNonce.salt, fixed_iv_length
    , bulkExplicitIV   = 8
    , bulkAuthTagLen   = 16
    , bulkBlockSize    = 0  -- dummy, not used
    , bulkF            = BulkAeadF aes256gcm
    }

bulk_aes256 = Bulk
    { bulkName         = "AES256"
    , bulkKeySize      = 32
    , bulkIVSize       = 16
    , bulkExplicitIV   = 0
    , bulkAuthTagLen   = 0
    , bulkBlockSize    = 16
    , bulkF            = BulkBlockF aes256cbc
    }

bulk_tripledes_ede = Bulk
    { bulkName      = "3DES-EDE-CBC"
    , bulkKeySize   = 24
    , bulkIVSize    = 8
    , bulkExplicitIV = 0
    , bulkAuthTagLen = 0
    , bulkBlockSize = 8
    , bulkF         = BulkBlockF tripledes_ede
    }

-- | unencrypted cipher using RSA for key exchange and MD5 for digest
cipher_null_MD5 :: Cipher
cipher_null_MD5 = Cipher
    { cipherID           = 0x0001
    , cipherName         = "RSA-null-MD5"
    , cipherBulk         = bulk_null
    , cipherHash         = MD5
    , cipherPRFHash      = Nothing
    , cipherKeyExchange  = CipherKeyExchange_RSA
    , cipherMinVer       = Nothing
    }

-- | unencrypted cipher using RSA for key exchange and SHA1 for digest
cipher_null_SHA1 :: Cipher
cipher_null_SHA1 = Cipher
    { cipherID           = 0x0002
    , cipherName         = "RSA-null-SHA1"
    , cipherBulk         = bulk_null
    , cipherHash         = SHA1
    , cipherPRFHash      = Nothing
    , cipherKeyExchange  = CipherKeyExchange_RSA
    , cipherMinVer       = Nothing
    }

-- | RC4 cipher, RSA key exchange and MD5 for digest
cipher_RC4_128_MD5 :: Cipher
cipher_RC4_128_MD5 = Cipher
    { cipherID           = 0x0004
    , cipherName         = "RSA-rc4-128-md5"
    , cipherBulk         = bulk_rc4
    , cipherHash         = MD5
    , cipherPRFHash      = Nothing
    , cipherKeyExchange  = CipherKeyExchange_RSA
    , cipherMinVer       = Nothing
    }

-- | RC4 cipher, RSA key exchange and SHA1 for digest
cipher_RC4_128_SHA1 :: Cipher
cipher_RC4_128_SHA1 = Cipher
    { cipherID           = 0x0005
    , cipherName         = "RSA-rc4-128-sha1"
    , cipherBulk         = bulk_rc4
    , cipherHash         = SHA1
    , cipherPRFHash      = Nothing
    , cipherKeyExchange  = CipherKeyExchange_RSA
    , cipherMinVer       = Nothing
    }

-- | 3DES cipher (168 bit key), RSA key exchange and SHA1 for digest
cipher_RSA_3DES_EDE_CBC_SHA1 :: Cipher
cipher_RSA_3DES_EDE_CBC_SHA1 = Cipher
    { cipherID           = 0x000A
    , cipherName         = "RSA-3DES-EDE-CBC-SHA1"
    , cipherBulk         = bulk_tripledes_ede
    , cipherHash         = SHA1
    , cipherPRFHash      = Nothing
    , cipherKeyExchange  = CipherKeyExchange_RSA
    , cipherMinVer       = Nothing
    }

-- | AES cipher (128 bit key), RSA key exchange and SHA1 for digest
cipher_AES128_SHA1 :: Cipher
cipher_AES128_SHA1 = Cipher
    { cipherID           = 0x002F
    , cipherName         = "RSA-AES128-SHA1"
    , cipherBulk         = bulk_aes128
    , cipherHash         = SHA1
    , cipherPRFHash      = Nothing
    , cipherKeyExchange  = CipherKeyExchange_RSA
    , cipherMinVer       = Just SSL3
    }

-- | AES cipher (128 bit key), DHE key exchanged signed by DSA and SHA1 for digest
cipher_DHE_DSS_AES128_SHA1 :: Cipher
cipher_DHE_DSS_AES128_SHA1 = Cipher
    { cipherID           = 0x0032
    , cipherName         = "DHE-DSA-AES128-SHA1"
    , cipherBulk         = bulk_aes128
    , cipherHash         = SHA1
    , cipherPRFHash      = Nothing
    , cipherKeyExchange  = CipherKeyExchange_DHE_DSS
    , cipherMinVer       = Nothing
    }

-- | AES cipher (128 bit key), DHE key exchanged signed by RSA and SHA1 for digest
cipher_DHE_RSA_AES128_SHA1 :: Cipher
cipher_DHE_RSA_AES128_SHA1 = Cipher
    { cipherID           = 0x0033
    , cipherName         = "DHE-RSA-AES128-SHA1"
    , cipherBulk         = bulk_aes128
    , cipherHash         = SHA1
    , cipherPRFHash      = Nothing
    , cipherKeyExchange  = CipherKeyExchange_DHE_RSA
    , cipherMinVer       = Nothing
    }

-- | AES cipher (256 bit key), RSA key exchange and SHA1 for digest
cipher_AES256_SHA1 :: Cipher
cipher_AES256_SHA1 = Cipher
    { cipherID           = 0x0035
    , cipherName         = "RSA-AES256-SHA1"
    , cipherBulk         = bulk_aes256
    , cipherHash         = SHA1
    , cipherPRFHash      = Nothing
    , cipherKeyExchange  = CipherKeyExchange_RSA
    , cipherMinVer       = Just SSL3
    }

-- | AES cipher (256 bit key), DHE key exchanged signed by DSA and SHA1 for digest
cipher_DHE_DSS_AES256_SHA1 :: Cipher
cipher_DHE_DSS_AES256_SHA1 = cipher_DHE_DSS_AES128_SHA1
    { cipherID           = 0x0038
    , cipherName         = "DHE-DSA-AES256-SHA1"
    , cipherBulk         = bulk_aes256
    }

-- | AES cipher (256 bit key), DHE key exchanged signed by RSA and SHA1 for digest
cipher_DHE_RSA_AES256_SHA1 :: Cipher
cipher_DHE_RSA_AES256_SHA1 = cipher_DHE_RSA_AES128_SHA1
    { cipherID           = 0x0039
    , cipherName         = "DHE-RSA-AES256-SHA1"
    , cipherBulk         = bulk_aes256
    }

-- | AES cipher (128 bit key), RSA key exchange and SHA256 for digest
cipher_AES128_SHA256 :: Cipher
cipher_AES128_SHA256 = Cipher
    { cipherID           = 0x003C
    , cipherName         = "RSA-AES128-SHA256"
    , cipherBulk         = bulk_aes128
    , cipherHash         = SHA256
    , cipherPRFHash      = Just SHA256
    , cipherKeyExchange  = CipherKeyExchange_RSA
    , cipherMinVer       = Just TLS12
    }

-- | AES cipher (256 bit key), RSA key exchange and SHA256 for digest
cipher_AES256_SHA256 :: Cipher
cipher_AES256_SHA256 = Cipher
    { cipherID           = 0x003D
    , cipherName         = "RSA-AES256-SHA256"
    , cipherBulk         = bulk_aes256
    , cipherHash         = SHA256
    , cipherPRFHash      = Just SHA256
    , cipherKeyExchange  = CipherKeyExchange_RSA
    , cipherMinVer       = Just TLS12
    }

-- This is not registered in IANA.
-- So, this will be removed in the next major release.
cipher_DHE_DSS_RC4_SHA1 :: Cipher
cipher_DHE_DSS_RC4_SHA1 = cipher_DHE_DSS_AES128_SHA1
    { cipherID           = 0x0066
    , cipherName         = "DHE-DSA-RC4-SHA1"
    , cipherBulk         = bulk_rc4
    }

cipher_DHE_RSA_AES128_SHA256 :: Cipher
cipher_DHE_RSA_AES128_SHA256 = cipher_DHE_RSA_AES128_SHA1
    { cipherID           = 0x0067
    , cipherName         = "DHE-RSA-AES128-SHA256"
    , cipherHash         = SHA256
    , cipherPRFHash      = Just SHA256
    , cipherMinVer       = Just TLS12
    }

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
    }

-- | AESGCM cipher (128 bit key), RSA key exchange.
-- The SHA256 digest is used as a PRF, not as a MAC.
cipher_AES128GCM_SHA256 :: Cipher
cipher_AES128GCM_SHA256 = Cipher
    { cipherID           = 0x009C
    , cipherName         = "RSA-AES128GCM-SHA256"
    , cipherBulk         = bulk_aes128gcm
    , cipherHash         = SHA256
    , cipherPRFHash      = Just SHA256
    , cipherKeyExchange  = CipherKeyExchange_RSA
    , cipherMinVer       = Just TLS12
    }

-- | AESGCM cipher (256 bit key), RSA key exchange.
-- The SHA384 digest is used as a PRF, not as a MAC.
cipher_AES256GCM_SHA384 :: Cipher
cipher_AES256GCM_SHA384 = Cipher
    { cipherID           = 0x009D
    , cipherName         = "RSA-AES256GCM-SHA384"
    , cipherBulk         = bulk_aes256gcm
    , cipherHash         = SHA384
    , cipherPRFHash      = Just SHA384
    , cipherKeyExchange  = CipherKeyExchange_RSA
    , cipherMinVer       = Just TLS12
    }

cipher_DHE_RSA_AES128GCM_SHA256 :: Cipher
cipher_DHE_RSA_AES128GCM_SHA256 = Cipher
    { cipherID           = 0x009E
    , cipherName         = "DHE-RSA-AES128GCM-SHA256"
    , cipherBulk         = bulk_aes128gcm
    , cipherHash         = SHA256
    , cipherPRFHash      = Just SHA256
    , cipherKeyExchange  = CipherKeyExchange_DHE_RSA
    , cipherMinVer       = Just TLS12 -- RFC 5288 Sec 4
    }

cipher_DHE_RSA_AES256GCM_SHA384 :: Cipher
cipher_DHE_RSA_AES256GCM_SHA384 = Cipher
    { cipherID           = 0x009F
    , cipherName         = "DHE-RSA-AES256GCM-SHA384"
    , cipherBulk         = bulk_aes256gcm
    , cipherHash         = SHA384
    , cipherPRFHash      = Just SHA384
    , cipherKeyExchange  = CipherKeyExchange_DHE_RSA
    , cipherMinVer       = Just TLS12
    }

cipher_ECDHE_ECDSA_AES128CBC_SHA :: Cipher
cipher_ECDHE_ECDSA_AES128CBC_SHA = Cipher
    { cipherID           = 0xC009
    , cipherName         = "ECDHE-ECDSA-AES128CBC-SHA"
    , cipherBulk         = bulk_aes128
    , cipherHash         = SHA1
    , cipherPRFHash      = Nothing
    , cipherKeyExchange  = CipherKeyExchange_ECDHE_ECDSA
    , cipherMinVer       = Just TLS10
    }

cipher_ECDHE_ECDSA_AES256CBC_SHA :: Cipher
cipher_ECDHE_ECDSA_AES256CBC_SHA = Cipher
    { cipherID           = 0xC00A
    , cipherName         = "ECDHE-ECDSA-AES256CBC-SHA"
    , cipherBulk         = bulk_aes256
    , cipherHash         = SHA1
    , cipherPRFHash      = Nothing
    , cipherKeyExchange  = CipherKeyExchange_ECDHE_ECDSA
    , cipherMinVer       = Just TLS10
    }

cipher_ECDHE_RSA_AES128CBC_SHA :: Cipher
cipher_ECDHE_RSA_AES128CBC_SHA = Cipher
    { cipherID           = 0xC013
    , cipherName         = "ECDHE-RSA-AES128CBC-SHA"
    , cipherBulk         = bulk_aes128
    , cipherHash         = SHA1
    , cipherPRFHash      = Nothing
    , cipherKeyExchange  = CipherKeyExchange_ECDHE_RSA
    , cipherMinVer       = Just TLS10
    }

cipher_ECDHE_RSA_AES256CBC_SHA :: Cipher
cipher_ECDHE_RSA_AES256CBC_SHA = Cipher
    { cipherID           = 0xC014
    , cipherName         = "ECDHE-RSA-AES256CBC-SHA"
    , cipherBulk         = bulk_aes256
    , cipherHash         = SHA1
    , cipherPRFHash      = Nothing
    , cipherKeyExchange  = CipherKeyExchange_ECDHE_RSA
    , cipherMinVer       = Just TLS10
    }

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
    }

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
    }

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
    }

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
    }

cipher_ECDHE_ECDSA_AES128GCM_SHA256 :: Cipher
cipher_ECDHE_ECDSA_AES128GCM_SHA256 = Cipher
    { cipherID           = 0xC02B
    , cipherName         = "ECDHE-ECDSA-AES128GCM-SHA256"
    , cipherBulk         = bulk_aes128gcm
    , cipherHash         = SHA256
    , cipherPRFHash      = Just SHA256
    , cipherKeyExchange  = CipherKeyExchange_ECDHE_ECDSA
    , cipherMinVer       = Just TLS12 -- RFC 5289
    }

cipher_ECDHE_ECDSA_AES256GCM_SHA384 :: Cipher
cipher_ECDHE_ECDSA_AES256GCM_SHA384 = Cipher
    { cipherID           = 0xC02C
    , cipherName         = "ECDHE-ECDSA-AES256GCM-SHA384"
    , cipherBulk         = bulk_aes256gcm
    , cipherHash         = SHA384
    , cipherPRFHash      = Just SHA384
    , cipherKeyExchange  = CipherKeyExchange_ECDHE_ECDSA
    , cipherMinVer       = Just TLS12 -- RFC 5289
    }

cipher_ECDHE_RSA_AES128GCM_SHA256 :: Cipher
cipher_ECDHE_RSA_AES128GCM_SHA256 = Cipher
    { cipherID           = 0xC02F
    , cipherName         = "ECDHE-RSA-AES128GCM-SHA256"
    , cipherBulk         = bulk_aes128gcm
    , cipherHash         = SHA256
    , cipherPRFHash      = Just SHA256
    , cipherKeyExchange  = CipherKeyExchange_ECDHE_RSA
    , cipherMinVer       = Just TLS12 -- RFC 5288 Sec 4
    }

cipher_ECDHE_RSA_AES256GCM_SHA384 :: Cipher
cipher_ECDHE_RSA_AES256GCM_SHA384 = Cipher
    { cipherID           = 0xC030
    , cipherName         = "ECDHE-RSA-AES256GCM-SHA384"
    , cipherBulk         = bulk_aes256gcm
    , cipherHash         = SHA384
    , cipherPRFHash      = Just SHA384
    , cipherKeyExchange  = CipherKeyExchange_ECDHE_RSA
    , cipherMinVer       = Just TLS12 -- RFC 5289
    }

-- A list of cipher suite is found from:
-- https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4