hs-tls/core/Network/TLS/Packet.hs

556 lines
22 KiB
Haskell
Raw Normal View History

{-# LANGUAGE OverloadedStrings #-}
2010-09-09 21:47:19 +00:00
-- |
-- Module : Network.TLS.Packet
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : unknown
--
-- the Packet module contains everything necessary to serialize and deserialize things
-- with only explicit parameters, no TLS state is involved here.
--
module Network.TLS.Packet
2012-03-27 07:57:51 +00:00
(
-- * params for encoding and decoding
CurrentParams(..)
-- * marshall functions for header messages
, decodeHeader
, decodeDeprecatedHeaderLength
, decodeDeprecatedHeader
2012-03-27 07:57:51 +00:00
, encodeHeader
, encodeHeaderNoVer -- use for SSL3
-- * marshall functions for alert messages
, decodeAlert
, decodeAlerts
, encodeAlerts
-- * marshall functions for handshake messages
, decodeHandshakes
, decodeHandshake
, decodeDeprecatedHandshake
2012-03-27 07:57:51 +00:00
, encodeHandshake
, encodeHandshakes
, encodeHandshakeHeader
, encodeHandshakeContent
-- * marshall functions for change cipher spec message
, decodeChangeCipherSpec
, encodeChangeCipherSpec
, decodePreMasterSecret
, encodePreMasterSecret
-- * generate things for packet content
, generateMasterSecret
, generateKeyBlock
, generateClientFinished
, generateServerFinished
2012-07-28 12:22:16 +00:00
, generateCertificateVerify_SSL
2012-03-27 07:57:51 +00:00
) where
2010-09-09 21:47:19 +00:00
import Network.TLS.Struct
2010-09-09 21:47:19 +00:00
import Network.TLS.Wire
import Network.TLS.Cap
import Data.Maybe (fromJust)
import Data.Word
import Data.Bits ((.|.))
2010-09-19 09:49:42 +00:00
import Control.Applicative ((<$>))
2010-09-09 21:47:19 +00:00
import Control.Monad
2013-05-19 07:05:46 +00:00
import Data.ASN1.Types (fromASN1, toASN1)
import Data.ASN1.Encoding (decodeASN1', encodeASN1')
import Data.ASN1.BinaryEncoding (DER(..))
import Data.X509 (CertificateChainRaw(..), encodeCertificateChain, decodeCertificateChain)
2010-09-09 21:47:19 +00:00
import Network.TLS.Crypto
import Network.TLS.MAC
import Network.TLS.Cipher (CipherKeyExchangeType(..))
import Data.ByteString (ByteString)
2010-09-09 21:47:19 +00:00
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as BC
2010-09-09 21:47:19 +00:00
import qualified Crypto.Hash.SHA1 as SHA1
import qualified Crypto.Hash.MD5 as MD5
data CurrentParams = CurrentParams
2012-03-27 07:57:51 +00:00
{ cParamsVersion :: Version -- ^ current protocol version
, cParamsKeyXchgType :: CipherKeyExchangeType -- ^ current key exchange type
, cParamsSupportNPN :: Bool -- ^ support Next Protocol Negotiation extension
} deriving (Show,Eq)
{- marshall helpers -}
getVersion :: Get Version
getVersion = do
2012-03-27 07:57:51 +00:00
major <- getWord8
minor <- getWord8
case verOfNum (major, minor) of
Nothing -> fail ("invalid version : " ++ show major ++ "," ++ show minor)
Just v -> return v
putVersion :: Version -> Put
putVersion ver = putWord8 major >> putWord8 minor
2012-03-27 07:57:51 +00:00
where (major, minor) = numericalVer ver
getHeaderType :: Get ProtocolType
getHeaderType = do
2012-03-27 07:57:51 +00:00
ty <- getWord8
case valToType ty of
Nothing -> fail ("invalid header type: " ++ show ty)
Just t -> return t
2011-05-12 08:07:19 +00:00
putHeaderType :: ProtocolType -> Put
putHeaderType = putWord8 . valOfType
getHandshakeType :: Get HandshakeType
getHandshakeType = do
2012-03-27 07:57:51 +00:00
ty <- getWord8
case valToType ty of
Nothing -> fail ("invalid handshake type: " ++ show ty)
Just t -> return t
2010-09-09 21:47:19 +00:00
{-
- decode and encode headers
-}
decodeHeader :: ByteString -> Either TLSError Header
2011-08-12 19:59:14 +00:00
decodeHeader = runGetErr "header" $ liftM3 Header getHeaderType getVersion getWord16
2010-09-09 21:47:19 +00:00
decodeDeprecatedHeaderLength :: ByteString -> Either TLSError Word16
decodeDeprecatedHeaderLength = runGetErr "deprecatedheaderlength" $ subtract 0x8000 <$> getWord16
decodeDeprecatedHeader :: Word16 -> ByteString -> Either TLSError Header
decodeDeprecatedHeader size =
runGetErr "deprecatedheader" $ do
1 <- getWord8
version <- getVersion
return $ Header ProtocolType_DeprecatedHandshake version size
2010-09-09 21:47:19 +00:00
encodeHeader :: Header -> ByteString
encodeHeader (Header pt ver len) = runPut (putHeaderType pt >> putVersion ver >> putWord16 len)
2012-03-27 07:57:51 +00:00
{- FIXME check len <= 2^14 -}
2010-09-09 21:47:19 +00:00
encodeHeaderNoVer :: Header -> ByteString
encodeHeaderNoVer (Header pt _ len) = runPut (putHeaderType pt >> putWord16 len)
2012-03-27 07:57:51 +00:00
{- FIXME check len <= 2^14 -}
2010-09-09 21:47:19 +00:00
{-
- decode and encode ALERT
-}
decodeAlert :: Get (AlertLevel, AlertDescription)
decodeAlert = do
2012-03-27 07:57:51 +00:00
al <- getWord8
ad <- getWord8
case (valToType al, valToType ad) of
(Just a, Just d) -> return (a, d)
(Nothing, _) -> fail "cannot decode alert level"
(_, Nothing) -> fail "cannot decode alert description"
2010-09-09 21:47:19 +00:00
decodeAlerts :: ByteString -> Either TLSError [(AlertLevel, AlertDescription)]
2011-06-12 20:38:42 +00:00
decodeAlerts = runGetErr "alerts" $ loop
2012-03-27 07:57:51 +00:00
where loop = do
r <- remaining
if r == 0
then return []
else liftM2 (:) decodeAlert loop
encodeAlerts :: [(AlertLevel, AlertDescription)] -> ByteString
encodeAlerts l = runPut $ mapM_ encodeAlert l
2012-03-27 07:57:51 +00:00
where encodeAlert (al, ad) = putWord8 (valOfType al) >> putWord8 (valOfType ad)
2010-09-09 21:47:19 +00:00
{- decode and encode HANDSHAKE -}
decodeHandshakeHeader :: Get (HandshakeType, Bytes)
decodeHandshakeHeader = do
2012-03-27 07:57:51 +00:00
ty <- getHandshakeType
content <- getOpaque24
return (ty, content)
2010-09-09 21:47:19 +00:00
decodeHandshakes :: ByteString -> Either TLSError [(HandshakeType, Bytes)]
2011-06-12 20:38:42 +00:00
decodeHandshakes b = runGetErr "handshakes" getAll b where
2012-03-27 07:57:51 +00:00
getAll = do
x <- decodeHandshakeHeader
empty <- isEmpty
if empty
then return [x]
else liftM ((:) x) getAll
decodeHandshake :: CurrentParams -> HandshakeType -> ByteString -> Either TLSError Handshake
2011-06-12 20:38:42 +00:00
decodeHandshake cp ty = runGetErr "handshake" $ case ty of
2012-03-27 07:57:51 +00:00
HandshakeType_HelloRequest -> decodeHelloRequest
HandshakeType_ClientHello -> decodeClientHello
HandshakeType_ServerHello -> decodeServerHello
HandshakeType_Certificate -> decodeCertificates
HandshakeType_ServerKeyXchg -> decodeServerKeyXchg cp
HandshakeType_CertRequest -> decodeCertRequest cp
HandshakeType_ServerHelloDone -> decodeServerHelloDone
HandshakeType_CertVerify -> decodeCertVerify cp
2012-03-27 07:57:51 +00:00
HandshakeType_ClientKeyXchg -> decodeClientKeyXchg
HandshakeType_Finished -> decodeFinished
HandshakeType_NPN -> do
unless (cParamsSupportNPN cp) $ fail "unsupported handshake type"
decodeNextProtocolNegotiation
2010-09-09 21:47:19 +00:00
decodeDeprecatedHandshake :: ByteString -> Either TLSError Handshake
decodeDeprecatedHandshake b = runGetErr "deprecatedhandshake" getDeprecated b where
getDeprecated = do
1 <- getWord8
ver <- getVersion
cipherSpecLen <- fromEnum <$> getWord16
sessionIdLen <- fromEnum <$> getWord16
challengeLen <- fromEnum <$> getWord16
ciphers <- getCipherSpec cipherSpecLen
session <- getSessionId sessionIdLen
random <- getChallenge challengeLen
let compressions = [0]
return $ ClientHello ver random session ciphers compressions [] (Just b)
getCipherSpec len | len < 3 = return []
getCipherSpec len = do
[c0,c1,c2] <- map fromEnum <$> replicateM 3 getWord8
([ toEnum $ c1 * 0x100 + c2 | c0 == 0 ] ++) <$> getCipherSpec (len - 3)
getSessionId 0 = return $ Session Nothing
getSessionId len = Session . Just <$> getBytes len
getChallenge len | 32 < len = getBytes (len - 32) >> getChallenge 32
getChallenge len = ClientRandom . B.append (B.replicate (32 - len) 0) <$> getBytes len
2010-09-09 21:47:19 +00:00
decodeHelloRequest :: Get Handshake
decodeHelloRequest = return HelloRequest
decodeClientHello :: Get Handshake
decodeClientHello = do
2012-03-27 07:57:51 +00:00
ver <- getVersion
random <- getClientRandom32
session <- getSession
ciphers <- getWords16
compressions <- getWords8
r <- remaining
exts <- if hasHelloExtensions ver && r > 0
then fmap fromIntegral getWord16 >>= getExtensions
else return []
return $ ClientHello ver random session ciphers compressions exts Nothing
2010-09-09 21:47:19 +00:00
decodeServerHello :: Get Handshake
decodeServerHello = do
2012-03-27 07:57:51 +00:00
ver <- getVersion
random <- getServerRandom32
session <- getSession
cipherid <- getWord16
compressionid <- getWord8
r <- remaining
exts <- if hasHelloExtensions ver && r > 0
then fmap fromIntegral getWord16 >>= getExtensions
else return []
return $ ServerHello ver random session cipherid compressionid exts
2010-09-09 21:47:19 +00:00
decodeServerHelloDone :: Get Handshake
decodeServerHelloDone = return ServerHelloDone
decodeCertificates :: Get Handshake
decodeCertificates = do
2013-05-19 07:05:46 +00:00
certsRaw <- CertificateChainRaw <$> (getWord24 >>= \len -> getList (fromIntegral len) getCertRaw)
case decodeCertificateChain certsRaw of
Left (i, s) -> fail ("error certificate parsing " ++ show i ++ ":" ++ s)
Right cc -> return $ Certificates cc
2012-08-27 14:05:23 +00:00
where getCertRaw = getOpaque24 >>= \cert -> return (3 + B.length cert, cert)
2010-09-09 21:47:19 +00:00
decodeFinished :: Get Handshake
decodeFinished = Finished <$> (remaining >>= getBytes)
2010-09-09 21:47:19 +00:00
2012-02-13 18:54:04 +00:00
decodeNextProtocolNegotiation :: Get Handshake
decodeNextProtocolNegotiation = do
2012-03-27 07:57:51 +00:00
opaque <- getOpaque8
_ <- getOpaque8 -- ignore padding
return $ HsNextProtocolNegotiation opaque
2012-02-07 21:24:30 +00:00
2012-08-27 14:05:23 +00:00
getSignatureHashAlgorithm :: Get HashAndSignatureAlgorithm
getSignatureHashAlgorithm = do
2012-03-27 07:57:51 +00:00
h <- fromJust . valToType <$> getWord8
s <- fromJust . valToType <$> getWord8
return (h,s)
decodeCertRequest :: CurrentParams -> Get Handshake
decodeCertRequest cp = do
2012-03-27 07:57:51 +00:00
certTypes <- map (fromJust . valToType . fromIntegral) <$> getWords8
sigHashAlgs <- if cParamsVersion cp >= TLS12
2012-08-27 14:05:23 +00:00
then Just <$> (getWord16 >>= getSignatureHashAlgorithms)
else return Nothing
2012-03-27 07:57:51 +00:00
dNameLen <- getWord16
2012-07-28 12:40:11 +00:00
-- FIXME: Decide whether to remove this check completely or to make it an option.
-- when (cParamsVersion cp < TLS12 && dNameLen < 3) $ fail "certrequest distinguishname not of the correct size"
2012-08-27 14:05:23 +00:00
dNames <- getList (fromIntegral dNameLen) getDName
return $ CertRequest certTypes sigHashAlgs dNames
2012-08-27 14:05:23 +00:00
where
getSignatureHashAlgorithms len = getList (fromIntegral len) (getSignatureHashAlgorithm >>= \sh -> return (2, sh))
getDName = do
dName <- getOpaque16
when (B.length dName == 0) $ fail "certrequest: invalid DN length"
2013-05-19 07:05:46 +00:00
dn <- case decodeASN1' DER dName of
Left e -> fail ("cert request decoding DistinguishedName ASN1 failed: " ++ show e)
Right asn1s -> case fromASN1 asn1s of
Left e -> fail ("cert request parsing DistinguishedName ASN1 failed: " ++ show e)
Right (d,_) -> return d
2012-08-27 14:05:23 +00:00
return (2 + B.length dName, dn)
decodeCertVerify :: CurrentParams -> Get Handshake
decodeCertVerify cp = do
mbHashSig <- if cParamsVersion cp >= TLS12
then Just <$> getSignatureHashAlgorithm
else return Nothing
bs <- getOpaque16
2012-07-28 12:40:11 +00:00
return $ CertVerify mbHashSig (CertVerifyData bs)
2010-09-09 21:47:19 +00:00
decodeClientKeyXchg :: Get Handshake
decodeClientKeyXchg = ClientKeyXchg <$> (remaining >>= getBytes)
2010-09-09 21:47:19 +00:00
os2ip :: ByteString -> Integer
os2ip = B.foldl' (\a b -> (256 * a) .|. (fromIntegral b)) 0
2010-09-09 21:47:19 +00:00
decodeServerKeyXchg_DH :: Get ServerDHParams
decodeServerKeyXchg_DH = do
2012-03-27 07:57:51 +00:00
p <- getOpaque16
g <- getOpaque16
y <- getOpaque16
return $ ServerDHParams { dh_p = os2ip p, dh_g = os2ip g, dh_Ys = os2ip y }
2010-09-09 21:47:19 +00:00
decodeServerKeyXchg_RSA :: Get ServerRSAParams
decodeServerKeyXchg_RSA = do
2012-03-27 07:57:51 +00:00
modulus <- getOpaque16
expo <- getOpaque16
return $ ServerRSAParams { rsa_modulus = os2ip modulus, rsa_exponent = os2ip expo }
2010-09-09 21:47:19 +00:00
decodeServerKeyXchg :: CurrentParams -> Get Handshake
decodeServerKeyXchg cp = ServerKeyXchg <$> case cParamsKeyXchgType cp of
2012-03-27 07:57:51 +00:00
CipherKeyExchange_RSA -> SKX_RSA . Just <$> decodeServerKeyXchg_RSA
CipherKeyExchange_DH_Anon -> SKX_DH_Anon <$> decodeServerKeyXchg_DH
CipherKeyExchange_DHE_RSA -> do
dhparams <- decodeServerKeyXchg_DH
signature <- getOpaque16
return $ SKX_DHE_RSA dhparams (B.unpack signature)
CipherKeyExchange_DHE_DSS -> do
dhparams <- decodeServerKeyXchg_DH
signature <- getOpaque16
return $ SKX_DHE_DSS dhparams (B.unpack signature)
_ -> do
bs <- remaining >>= getBytes
return $ SKX_Unknown bs
2010-09-09 21:47:19 +00:00
encodeHandshake :: Handshake -> ByteString
encodeHandshake o =
2012-03-27 07:57:51 +00:00
let content = runPut $ encodeHandshakeContent o in
let len = fromIntegral $ B.length content in
let header = case o of
ClientHello _ _ _ _ _ _ (Just _) -> "" -- SSLv2 ClientHello message
_ -> runPut $ encodeHandshakeHeader (typeOfHandshake o) len in
2012-03-27 07:57:51 +00:00
B.concat [ header, content ]
2010-09-09 21:47:19 +00:00
encodeHandshakes :: [Handshake] -> ByteString
encodeHandshakes hss = B.concat $ map encodeHandshake hss
2010-09-09 21:47:19 +00:00
encodeHandshakeHeader :: HandshakeType -> Int -> Put
encodeHandshakeHeader ty len = putWord8 (valOfType ty) >> putWord24 len
encodeHandshakeContent :: Handshake -> Put
encodeHandshakeContent (ClientHello _ _ _ _ _ _ (Just deprecated)) = do
putBytes deprecated
encodeHandshakeContent (ClientHello version random session cipherIDs compressionIDs exts Nothing) = do
2012-03-27 07:57:51 +00:00
putVersion version
putClientRandom32 random
putSession session
putWords16 cipherIDs
putWords8 compressionIDs
putExtensions exts
return ()
2010-09-09 21:47:19 +00:00
encodeHandshakeContent (ServerHello version random session cipherID compressionID exts) =
2012-03-27 07:57:51 +00:00
putVersion version >> putServerRandom32 random >> putSession session
>> putWord16 cipherID >> putWord8 compressionID
>> putExtensions exts >> return ()
2010-09-09 21:47:19 +00:00
2013-05-19 07:05:46 +00:00
encodeHandshakeContent (Certificates cc) = putOpaque24 (runPut $ mapM_ putOpaque24 certs)
where (CertificateChainRaw certs) = encodeCertificateChain cc
2010-09-09 21:47:19 +00:00
encodeHandshakeContent (ClientKeyXchg content) = do
2012-03-27 07:57:51 +00:00
putBytes content
2010-09-09 21:47:19 +00:00
encodeHandshakeContent (ServerKeyXchg _) = do
2012-03-27 07:57:51 +00:00
-- FIXME
return ()
2010-09-09 21:47:19 +00:00
encodeHandshakeContent (HelloRequest) = return ()
encodeHandshakeContent (ServerHelloDone) = return ()
encodeHandshakeContent (CertRequest certTypes sigAlgs certAuthorities) = do
2012-03-27 07:57:51 +00:00
putWords8 (map valOfType certTypes)
case sigAlgs of
Nothing -> return ()
Just l -> putWords16 $ map (\(x,y) -> (fromIntegral $ valOfType x) * 256 + (fromIntegral $ valOfType y)) l
encodeCertAuthorities certAuthorities
where
-- Convert a distinguished name to its DER encoding.
2013-05-19 07:05:46 +00:00
encodeCA dn = return $ encodeASN1' DER (toASN1 dn []) --B.concat $ L.toChunks $ encodeDN dn
-- Encode a list of distinguished names.
encodeCertAuthorities certAuths = do
enc <- mapM encodeCA certAuths
let totLength = sum $ map (((+) 2) . B.length) enc
putWord16 (fromIntegral totLength)
mapM_ (\ b -> putWord16 (fromIntegral (B.length b)) >> putBytes b) enc
2012-07-28 12:40:11 +00:00
encodeHandshakeContent (CertVerify mbHashSig (CertVerifyData c)) = do
-- TLS 1.2 prepends the hash and signature algorithms to the
-- signature.
case mbHashSig of
Nothing -> return ()
Just (h, s) -> putWord16 $ (fromIntegral $ valOfType h) * 256 + (fromIntegral $ valOfType s)
putWord16 (fromIntegral $ B.length c)
putBytes c
2010-09-09 21:47:19 +00:00
encodeHandshakeContent (Finished opaque) = putBytes opaque
2010-09-09 21:47:19 +00:00
encodeHandshakeContent (HsNextProtocolNegotiation protocol) = do
2012-03-27 07:57:51 +00:00
putOpaque8 protocol
putOpaque8 $ B.replicate paddingLen 0
where paddingLen = 32 - ((B.length protocol + 2) `mod` 32)
2012-02-07 21:24:30 +00:00
2010-09-09 21:47:19 +00:00
{- FIXME make sure it return error if not 32 available -}
getRandom32 :: Get Bytes
getRandom32 = getBytes 32
2010-09-09 21:47:19 +00:00
getServerRandom32 :: Get ServerRandom
2010-09-19 09:49:42 +00:00
getServerRandom32 = ServerRandom <$> getRandom32
2010-09-09 21:47:19 +00:00
getClientRandom32 :: Get ClientRandom
2010-09-19 09:49:42 +00:00
getClientRandom32 = ClientRandom <$> getRandom32
2010-09-09 21:47:19 +00:00
putRandom32 :: Bytes -> Put
putRandom32 = putBytes
2010-09-09 21:47:19 +00:00
putClientRandom32 :: ClientRandom -> Put
putClientRandom32 (ClientRandom r) = putRandom32 r
putServerRandom32 :: ServerRandom -> Put
putServerRandom32 (ServerRandom r) = putRandom32 r
getSession :: Get Session
getSession = do
2012-03-27 07:57:51 +00:00
len8 <- getWord8
case fromIntegral len8 of
0 -> return $ Session Nothing
len -> Session . Just <$> getBytes len
2010-09-09 21:47:19 +00:00
putSession :: Session -> Put
2011-08-12 19:59:14 +00:00
putSession (Session Nothing) = putWord8 0
putSession (Session (Just s)) = putOpaque8 s
2010-09-09 21:47:19 +00:00
2012-05-14 03:41:50 +00:00
getExtensions :: Int -> Get [ExtensionRaw]
2010-09-09 21:47:19 +00:00
getExtensions 0 = return []
getExtensions len = do
2012-03-27 07:57:51 +00:00
extty <- getWord16
extdatalen <- getWord16
extdata <- getBytes $ fromIntegral extdatalen
extxs <- getExtensions (len - fromIntegral extdatalen - 4)
return $ (extty, extdata) : extxs
2010-09-09 21:47:19 +00:00
2012-05-14 03:41:50 +00:00
putExtension :: ExtensionRaw -> Put
putExtension (ty, l) = putWord16 ty >> putOpaque16 l
2010-09-09 21:47:19 +00:00
2012-05-14 03:41:50 +00:00
putExtensions :: [ExtensionRaw] -> Put
putExtensions [] = return ()
putExtensions es = putOpaque16 (runPut $ mapM_ putExtension es)
2010-09-09 21:47:19 +00:00
{-
- decode and encode ALERT
-}
decodeChangeCipherSpec :: ByteString -> Either TLSError ()
2011-06-12 20:38:42 +00:00
decodeChangeCipherSpec = runGetErr "changecipherspec" $ do
2012-03-27 07:57:51 +00:00
x <- getWord8
when (x /= 1) (fail "unknown change cipher spec content")
2010-09-09 21:47:19 +00:00
encodeChangeCipherSpec :: ByteString
encodeChangeCipherSpec = runPut (putWord8 1)
-- rsa pre master secret
decodePreMasterSecret :: Bytes -> Either TLSError (Version, Bytes)
decodePreMasterSecret = runGetErr "pre-master-secret" $ do
2012-03-27 07:57:51 +00:00
liftM2 (,) getVersion (getBytes 46)
encodePreMasterSecret :: Version -> Bytes -> Bytes
encodePreMasterSecret version bytes = runPut (putVersion version >> putBytes bytes)
2010-09-09 21:47:19 +00:00
{-
- generate things for packet content
-}
type PRF = Bytes -> Bytes -> Int -> Bytes
2010-09-09 21:47:19 +00:00
generateMasterSecret_SSL :: Bytes -> ClientRandom -> ServerRandom -> Bytes
generateMasterSecret_SSL premasterSecret (ClientRandom c) (ServerRandom s) =
2012-03-27 07:57:51 +00:00
B.concat $ map (computeMD5) ["A","BB","CCC"]
where
computeMD5 label = MD5.hash $ B.concat [ premasterSecret, computeSHA1 label ]
computeSHA1 label = SHA1.hash $ B.concat [ label, premasterSecret, c, s ]
generateMasterSecret_TLS :: PRF -> Bytes -> ClientRandom -> ServerRandom -> Bytes
generateMasterSecret_TLS prf premasterSecret (ClientRandom c) (ServerRandom s) =
2012-03-27 07:57:51 +00:00
prf premasterSecret seed 48
where
seed = B.concat [ "master secret", c, s ]
generateMasterSecret :: Version -> Bytes -> ClientRandom -> ServerRandom -> Bytes
generateMasterSecret SSL2 = generateMasterSecret_SSL
generateMasterSecret SSL3 = generateMasterSecret_SSL
generateMasterSecret TLS10 = generateMasterSecret_TLS prf_MD5SHA1
generateMasterSecret TLS11 = generateMasterSecret_TLS prf_MD5SHA1
generateMasterSecret TLS12 = generateMasterSecret_TLS prf_SHA256
generateKeyBlock_TLS :: PRF -> ClientRandom -> ServerRandom -> Bytes -> Int -> Bytes
2011-08-12 20:57:30 +00:00
generateKeyBlock_TLS prf (ClientRandom c) (ServerRandom s) mastersecret kbsize =
2012-03-27 07:57:51 +00:00
prf mastersecret seed kbsize where seed = B.concat [ "key expansion", s, c ]
generateKeyBlock_SSL :: ClientRandom -> ServerRandom -> Bytes -> Int -> Bytes
generateKeyBlock_SSL (ClientRandom c) (ServerRandom s) mastersecret kbsize =
2012-03-27 07:57:51 +00:00
B.concat $ map computeMD5 $ take ((kbsize `div` 16) + 1) labels
where
labels = [ uncurry BC.replicate x | x <- zip [1..] ['A'..'Z'] ]
computeMD5 label = MD5.hash $ B.concat [ mastersecret, computeSHA1 label ]
computeSHA1 label = SHA1.hash $ B.concat [ label, mastersecret, s, c ]
generateKeyBlock :: Version -> ClientRandom -> ServerRandom -> Bytes -> Int -> Bytes
2011-08-12 20:57:30 +00:00
generateKeyBlock SSL2 = generateKeyBlock_SSL
generateKeyBlock SSL3 = generateKeyBlock_SSL
generateKeyBlock TLS10 = generateKeyBlock_TLS prf_MD5SHA1
generateKeyBlock TLS11 = generateKeyBlock_TLS prf_MD5SHA1
generateKeyBlock TLS12 = generateKeyBlock_TLS prf_SHA256
2010-09-09 21:47:19 +00:00
generateFinished_TLS :: PRF -> Bytes -> Bytes -> HashCtx -> Bytes
generateFinished_TLS prf label mastersecret hashctx = prf mastersecret seed 12
2012-03-27 07:57:51 +00:00
where
seed = B.concat [ label, hashFinal hashctx ]
2010-09-09 21:47:19 +00:00
generateFinished_SSL :: Bytes -> Bytes -> HashCtx -> Bytes
generateFinished_SSL sender mastersecret hashctx = B.concat [md5hash, sha1hash]
2012-03-27 07:57:51 +00:00
where
md5hash = MD5.hash $ B.concat [ mastersecret, pad2, md5left ]
sha1hash = SHA1.hash $ B.concat [ mastersecret, B.take 40 pad2, sha1left ]
2012-03-27 07:57:51 +00:00
lefthash = hashFinal $ flip hashUpdateSSL (pad1, B.take 40 pad1)
$ foldl hashUpdate hashctx [sender,mastersecret]
(md5left,sha1left) = B.splitAt 16 lefthash
pad2 = B.replicate 48 0x5c
pad1 = B.replicate 48 0x36
generateClientFinished :: Version -> Bytes -> HashCtx -> Bytes
2011-08-12 20:57:30 +00:00
generateClientFinished ver
2012-03-27 07:57:51 +00:00
| ver < TLS10 = generateFinished_SSL "CLNT"
| ver < TLS12 = generateFinished_TLS prf_MD5SHA1 "client finished"
| otherwise = generateFinished_TLS prf_SHA256 "client finished"
generateServerFinished :: Version -> Bytes -> HashCtx -> Bytes
2011-08-12 20:57:30 +00:00
generateServerFinished ver
2012-03-27 07:57:51 +00:00
| ver < TLS10 = generateFinished_SSL "SRVR"
| ver < TLS12 = generateFinished_TLS prf_MD5SHA1 "server finished"
| otherwise = generateFinished_TLS prf_SHA256 "server finished"
2012-07-28 12:22:16 +00:00
generateCertificateVerify_SSL :: Bytes -> HashCtx -> Bytes
generateCertificateVerify_SSL = generateFinished_SSL ""