use strict bytestring instead of lazy bytestring.

the API stays mostly similar except for clientkeyxchg that need a bytes instead of [word8].
remove lots of unnessary packing/unpacking when setting up ciphers.
This commit is contained in:
Vincent Hanquez 2010-09-26 10:34:47 +01:00
parent c70736cf19
commit 8f91009884
13 changed files with 251 additions and 218 deletions

View file

@ -37,11 +37,11 @@ type IV = B.ByteString
data CipherTypeFunctions =
CipherNoneF -- special value for 0
| CipherBlockF (Key -> IV -> L.ByteString -> L.ByteString)
(Key -> IV -> L.ByteString -> L.ByteString)
| CipherBlockF (Key -> IV -> B.ByteString -> B.ByteString)
(Key -> IV -> B.ByteString -> B.ByteString)
| CipherStreamF (Key -> IV)
(IV -> L.ByteString -> (L.ByteString, IV))
(IV -> L.ByteString -> (L.ByteString, IV))
(IV -> B.ByteString -> (B.ByteString, IV))
(IV -> B.ByteString -> (B.ByteString, IV))
data CipherKeyExchangeType =
CipherKeyExchangeRSA
@ -63,7 +63,7 @@ data Cipher = Cipher
, cipherKeyBlockSize :: Word8
, cipherPaddingSize :: Word8
, cipherKeyExchange :: CipherKeyExchangeType
, cipherHMAC :: L.ByteString -> L.ByteString -> L.ByteString
, cipherHMAC :: B.ByteString -> B.ByteString -> B.ByteString
, cipherF :: CipherTypeFunctions
, cipherMinVer :: Maybe Version
}
@ -82,29 +82,32 @@ cipherExchangeNeedMoreData CipherKeyExchangeECDH_ECDSA = True
cipherExchangeNeedMoreData CipherKeyExchangeECDH_RSA = True
cipherExchangeNeedMoreData CipherKeyExchangeECDHE_ECDSA = True
repack :: Int -> L.ByteString -> [B.ByteString]
repack :: Int -> B.ByteString -> [B.ByteString]
repack bs x =
if L.length x > fromIntegral bs
if B.length x > bs
then
let (c1, c2) = L.splitAt (fromIntegral bs) x in
B.pack (L.unpack c1) : repack 16 c2
let (c1, c2) = B.splitAt bs x in
B.pack (B.unpack c1) : repack 16 c2
else
[ B.pack (L.unpack x) ]
[ x ]
aes128_cbc_encrypt :: Key -> IV -> L.ByteString -> L.ByteString
aes128_cbc_encrypt key iv d = AES.crypt AES.CBC key iv AES.Encrypt d16
lazyToStrict :: L.ByteString -> B.ByteString
lazyToStrict = B.concat . L.toChunks
aes128_cbc_encrypt :: Key -> IV -> B.ByteString -> B.ByteString
aes128_cbc_encrypt key iv d = lazyToStrict $ AES.crypt AES.CBC key iv AES.Encrypt d16
where d16 = L.fromChunks $ repack 16 d
aes128_cbc_decrypt :: Key -> IV -> L.ByteString -> L.ByteString
aes128_cbc_decrypt key iv d = AES.crypt AES.CBC key iv AES.Decrypt d16
aes128_cbc_decrypt :: Key -> IV -> B.ByteString -> B.ByteString
aes128_cbc_decrypt key iv d = lazyToStrict $ AES.crypt AES.CBC key iv AES.Decrypt d16
where d16 = L.fromChunks $ repack 16 d
aes256_cbc_encrypt :: Key -> IV -> L.ByteString -> L.ByteString
aes256_cbc_encrypt key iv d = AES.crypt AES.CBC key iv AES.Encrypt d16
aes256_cbc_encrypt :: Key -> IV -> B.ByteString -> B.ByteString
aes256_cbc_encrypt key iv d = lazyToStrict $ AES.crypt AES.CBC key iv AES.Encrypt d16
where d16 = L.fromChunks $ repack 16 d
aes256_cbc_decrypt :: Key -> IV -> L.ByteString -> L.ByteString
aes256_cbc_decrypt key iv d = AES.crypt AES.CBC key iv AES.Decrypt d16
aes256_cbc_decrypt :: Key -> IV -> B.ByteString -> B.ByteString
aes256_cbc_decrypt key iv d = lazyToStrict $ AES.crypt AES.CBC key iv AES.Decrypt d16
where d16 = L.fromChunks $ repack 32 d
toIV :: RC4.Ctx -> IV
@ -119,11 +122,11 @@ toCtx iv =
initF_rc4 :: Key -> IV
initF_rc4 key = toIV $ RC4.initCtx (B.unpack key)
encryptF_rc4 :: IV -> L.ByteString -> (L.ByteString, IV)
encryptF_rc4 iv d = (\(ctx, e) -> (e, toIV ctx)) $ RC4.encryptlazy (toCtx iv) d
encryptF_rc4 :: IV -> B.ByteString -> (B.ByteString, IV)
encryptF_rc4 iv d = (\(ctx, e) -> (e, toIV ctx)) $ RC4.encrypt (toCtx iv) d
decryptF_rc4 :: IV -> L.ByteString -> (L.ByteString, IV)
decryptF_rc4 iv e = (\(ctx, d) -> (d, toIV ctx)) $ RC4.decryptlazy (toCtx iv) e
decryptF_rc4 :: IV -> B.ByteString -> (B.ByteString, IV)
decryptF_rc4 iv e = (\(ctx, d) -> (d, toIV ctx)) $ RC4.decrypt (toCtx iv) e
{-
TLS 1.0 ciphers definition
@ -171,7 +174,7 @@ cipher_null_null = Cipher
, cipherIVSize = 0
, cipherKeyBlockSize = 0
, cipherPaddingSize = 0
, cipherHMAC = (\_ _ -> L.empty)
, cipherHMAC = (\_ _ -> B.empty)
, cipherKeyExchange = CipherKeyExchangeRSA
, cipherF = CipherNoneF
, cipherMinVer = Nothing

View file

@ -39,6 +39,7 @@ import Network.TLS.State
import Network.TLS.Sending
import Network.TLS.Receiving
import Network.TLS.SRandom
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import System.IO (Handle, hFlush)
import Data.List (find)
@ -88,18 +89,18 @@ runTLSClient f params rng = runTLSClientST f (TLSStateClient { scParams = params
{- | receive a single TLS packet or on error a TLSError -}
recvPacket :: Handle -> TLSClient IO (Either TLSError Packet)
recvPacket handle = do
hdr <- lift $ L.hGet handle 5 >>= return . decodeHeader
hdr <- lift $ B.hGet handle 5 >>= return . decodeHeader
case hdr of
Left err -> return $ Left err
Right header@(Header _ _ readlen) -> do
content <- lift $ L.hGet handle (fromIntegral readlen)
content <- lift $ B.hGet handle (fromIntegral readlen)
readPacket header (EncryptedData content)
{- | send a single TLS packet -}
sendPacket :: Handle -> Packet -> TLSClient IO ()
sendPacket handle pkt = do
dataToSend <- writePacket pkt
lift $ L.hPut handle dataToSend
lift $ B.hPut handle dataToSend
recvServerHello :: Handle -> TLSClient IO ()
recvServerHello handle = do
@ -150,7 +151,7 @@ connectSendClientKeyXchg handle prerand = do
connectSendFinish :: Handle -> TLSClient IO ()
connectSendFinish handle = do
cf <- getHandshakeDigest True
sendPacket handle (Handshake $ Finished $ L.unpack cf)
sendPacket handle (Handshake $ Finished $ B.unpack cf)
{- | connect through a handle as a new TLS connection. -}
connect :: Handle -> ClientRandom -> ClientKeyData -> TLSClient IO ()
@ -184,24 +185,27 @@ connect handle crand premasterRandom = do
return ()
{- | sendData sends a bunch of data -}
sendData :: Handle -> L.ByteString -> TLSClient IO ()
sendData handle d = do
if L.length d > 16384
sendDataChunk :: Handle -> B.ByteString -> TLSClient IO ()
sendDataChunk handle d =
if B.length d > 16384
then do
let (sending, remain) = L.splitAt 16384 d
let (sending, remain) = B.splitAt 16384 d
sendPacket handle $ AppData sending
sendData handle remain
sendDataChunk handle remain
else
sendPacket handle $ AppData d
{- | sendData sends a bunch of data -}
sendData :: Handle -> L.ByteString -> TLSClient IO ()
sendData handle d = mapM_ (sendDataChunk handle) (L.toChunks d)
{- | recvData get data out of Data packet, and automatically try to renegociate if
- a Handshake HelloRequest is received -}
recvData :: Handle -> TLSClient IO L.ByteString
recvData handle = do
pkt <- recvPacket handle
case pkt of
Right (AppData x) -> return x
Right (AppData x) -> return $ L.fromChunks [x]
Right (Handshake HelloRequest) -> do
-- SECURITY FIXME audit the rng here..
st <- getTLSState
@ -209,7 +213,7 @@ recvData handle = do
let (premaster, rng'') = getRandomBytes rng' 46
putTLSState $ st { stRandomGen = rng'' }
let crand = fromJust $ clientRandom bytes
connect handle crand (ClientKeyData premaster)
connect handle crand (ClientKeyData $ B.pack premaster)
recvData handle
Left err -> error ("error received: " ++ show err)
_ -> error "unexpected item"

View file

@ -28,10 +28,12 @@ module Network.TLS.Crypto
import qualified Data.CryptoHash.SHA1 as SHA1
import qualified Data.CryptoHash.MD5 as MD5
import qualified Data.ByteString as B
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as L
import Data.ByteString (ByteString)
import Codec.Crypto.RSA (PublicKey(..), PrivateKey(..))
import qualified Codec.Crypto.RSA as RSA
import Control.Spoon
import Control.Arrow (first)
import System.Random
data HashCtx =
@ -49,28 +51,28 @@ data HashType = HashTypeSHA1 | HashTypeMD5
initMD5 :: MD5.Ctx
initMD5 = MD5.init
updateMD5 :: MD5.Ctx -> B.ByteString -> MD5.Ctx
updateMD5 :: MD5.Ctx -> ByteString -> MD5.Ctx
updateMD5 = MD5.update
finalizeMD5 :: MD5.Ctx -> B.ByteString
finalizeMD5 :: MD5.Ctx -> ByteString
finalizeMD5 = MD5.finalize
hashMD5 :: ByteString -> B.ByteString
hashMD5 = MD5.hashlazy
hashMD5 :: ByteString -> ByteString
hashMD5 = MD5.hash
{- SHA1 -}
initSHA1 :: SHA1.Ctx
initSHA1 = SHA1.init
updateSHA1 :: SHA1.Ctx -> B.ByteString -> SHA1.Ctx
updateSHA1 :: SHA1.Ctx -> ByteString -> SHA1.Ctx
updateSHA1 = SHA1.update
finalizeSHA1 :: SHA1.Ctx -> B.ByteString
finalizeSHA1 :: SHA1.Ctx -> ByteString
finalizeSHA1 = SHA1.finalize
hashSHA1 :: ByteString -> B.ByteString
hashSHA1 = SHA1.hashlazy
hashSHA1 :: ByteString -> ByteString
hashSHA1 = SHA1.hash
{- generic Hashing -}
@ -94,8 +96,14 @@ finalizeHash (MD5 ctx) = finalizeMD5 ctx
need to fix the RSA package to return "Either String X".
-}
rsaEncrypt :: RandomGen g => g -> PublicKey -> ByteString -> Maybe (ByteString, g)
rsaEncrypt g pk b = teaspoon (RSA.rsaes_pkcs1_v1_5_encrypt g pk b)
lazyToStrict = B.concat . L.toChunks
rsaDecrypt :: PrivateKey -> ByteString -> Maybe ByteString
rsaDecrypt pk b = teaspoon (RSA.rsaes_pkcs1_v1_5_decrypt pk b)
rsaEncrypt :: RandomGen g => g -> PublicKey -> B.ByteString -> Maybe (B.ByteString, g)
rsaEncrypt g pk b = maybe Nothing (Just . first lazyToStrict) $ teaspoon (RSA.rsaes_pkcs1_v1_5_encrypt g pk blazy)
where
blazy = L.fromChunks [ b ]
rsaDecrypt :: PrivateKey -> B.ByteString -> Maybe B.ByteString
rsaDecrypt pk b = maybe Nothing (Just . lazyToStrict) $ teaspoon (RSA.rsaes_pkcs1_v1_5_decrypt pk blazy)
where
blazy = L.fromChunks [ b ]

View file

@ -10,54 +10,50 @@ module Network.TLS.MAC
import qualified Data.CryptoHash.MD5 as MD5
import qualified Data.CryptoHash.SHA1 as SHA1
import qualified Data.CryptoHash.SHA256 as SHA256
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString as B
import Data.ByteString.Lazy (ByteString)
import Data.ByteString (ByteString)
import Data.Bits (xor)
lazyOfStrict :: B.ByteString -> ByteString
lazyOfStrict b = L.fromChunks [ b ]
hmac :: (ByteString -> ByteString) -> Int -> ByteString -> ByteString -> ByteString
hmac f bl secret msg =
f $! L.append opad (f $! L.append ipad msg)
f $! B.append opad (f $! B.append ipad msg)
where
opad = L.map (xor 0x5c) k'
ipad = L.map (xor 0x36) k'
opad = B.map (xor 0x5c) k'
ipad = B.map (xor 0x36) k'
k' = L.append kt pad
k' = B.append kt pad
where
kt = if L.length secret > fromIntegral bl then f secret else secret
pad = L.replicate (fromIntegral bl - L.length kt) 0
kt = if B.length secret > fromIntegral bl then f secret else secret
pad = B.replicate (fromIntegral bl - B.length kt) 0
hmacMD5 :: ByteString -> ByteString -> ByteString
hmacMD5 secret msg = hmac (lazyOfStrict . MD5.hashlazy) 64 secret msg
hmacMD5 secret msg = hmac MD5.hash 64 secret msg
hmacSHA1 :: ByteString -> ByteString -> ByteString
hmacSHA1 secret msg = hmac (lazyOfStrict . SHA1.hashlazy) 64 secret msg
hmacSHA1 secret msg = hmac SHA1.hash 64 secret msg
hmacSHA256 :: ByteString -> ByteString -> ByteString
hmacSHA256 secret msg = hmac (lazyOfStrict . SHA256.hashlazy) 64 secret msg
hmacSHA256 secret msg = hmac SHA256.hash 64 secret msg
hmacIter :: (ByteString -> ByteString -> ByteString) -> ByteString -> ByteString -> ByteString -> Int -> [ByteString]
hmacIter f secret seed aprev len =
let an = f secret aprev in
let out = f secret (L.concat [an, seed]) in
let digestsize = fromIntegral $ L.length out in
let out = f secret (B.concat [an, seed]) in
let digestsize = fromIntegral $ B.length out in
if digestsize >= len
then [ L.take (fromIntegral len) out ]
then [ B.take (fromIntegral len) out ]
else out : hmacIter f secret seed an (len - digestsize)
prf_SHA1 :: ByteString -> ByteString -> Int -> ByteString
prf_SHA1 secret seed len = L.concat $ hmacIter hmacSHA1 secret seed seed len
prf_SHA1 secret seed len = B.concat $ hmacIter hmacSHA1 secret seed seed len
prf_MD5 :: ByteString -> ByteString -> Int -> ByteString
prf_MD5 secret seed len = L.concat $ hmacIter hmacMD5 secret seed seed len
prf_MD5 secret seed len = B.concat $ hmacIter hmacMD5 secret seed seed len
prf_MD5SHA1 :: ByteString -> ByteString -> Int -> ByteString
prf_MD5SHA1 secret seed len =
L.pack $ L.zipWith xor (prf_MD5 s1 seed len) (prf_SHA1 s2 seed len)
B.pack $ B.zipWith xor (prf_MD5 s1 seed len) (prf_SHA1 s2 seed len)
where
slen = L.length secret
s1 = L.take (slen `div` 2 + slen `mod` 2) secret
s2 = L.drop (slen `div` 2) secret
slen = B.length secret
s1 = B.take (slen `div` 2 + slen `mod` 2) secret
s2 = B.drop (slen `div` 2) secret

View file

@ -1,3 +1,4 @@
{-# LANGUAGE OverloadedStrings #-}
-- |
-- Module : Network.TLS.Packet
-- License : BSD-style
@ -48,9 +49,10 @@ import Control.Monad.Error
import Data.Certificate.X509
import Network.TLS.Crypto
import Network.TLS.MAC
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as L (pack, length, concat, fromChunks)
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as BC
import qualified Data.ByteString.Lazy as L
{-
- decode and encode headers
@ -90,7 +92,7 @@ encodeAlert (al, ad) = runPut (putWord8 (valOfType al) >> putWord8 (valOfType ad
{- decode and encode HANDSHAKE -}
decodeHandshakeHeader :: ByteString -> Either TLSError (HandshakeType, ByteString)
decodeHandshakeHeader :: ByteString -> Either TLSError (HandshakeType, Bytes)
decodeHandshakeHeader = runGet $ do
tyopt <- getWord8 >>= return . valToType
ty <- if isNothing tyopt
@ -100,7 +102,7 @@ decodeHandshakeHeader = runGet $ do
content <- getBytes len
empty <- isEmpty
unless empty (throwError (Error_Internal_Packet_Remaining 1))
return (ty, L.fromChunks [content])
return (ty, content)
decodeHandshake :: Version -> HandshakeType -> ByteString -> Either TLSError Handshake
decodeHandshake ver ty = runGet $ case ty of
@ -231,9 +233,9 @@ decodeServerKeyXchg ver = do
encodeHandshake :: Handshake -> ByteString
encodeHandshake o =
let content = runPut $ encodeHandshakeContent o in
let len = fromIntegral $ L.length content in
let len = fromIntegral $ B.length content in
let header = runPut $ encodeHandshakeHeader (typeOfHandshake o) len in
L.concat [ header, content ]
B.concat [ header, content ]
encodeHandshakeHeader :: HandshakeType -> Int -> Put
encodeHandshakeHeader ty len = putWord8 (valOfType ty) >> putWord24 len
@ -255,10 +257,10 @@ encodeHandshakeContent (ServerHello version random session cipherID compressionI
>> putExtensions exts >> return ()
encodeHandshakeContent (Certificates certs) =
putWord24 len >> putLazyByteString certbs
putWord24 len >> putBytes certbs
where
certbs = runPut $ mapM_ putCert certs
len = fromIntegral $ L.length certbs
len = fromIntegral $ B.length certbs
encodeHandshakeContent (ClientKeyXchg version random) = do
putVersion version
@ -276,7 +278,7 @@ encodeHandshakeContent (CertRequest certTypes sigAlgs certAuthorities) = do
case sigAlgs of
Nothing -> return ()
Just l -> putWords16 $ map (\(x,y) -> (fromIntegral $ valOfType x) * 256 + (fromIntegral $ valOfType y)) l
putByteString $ B.pack certAuthorities
putBytes $ B.pack certAuthorities
encodeHandshakeContent (CertVerify _) = undefined
@ -296,8 +298,8 @@ putVersion ver = putWord8 major >> putWord8 minor
where (major, minor) = numericalVer ver
{- FIXME make sure it return error if not 32 available -}
getRandom32 :: Get [Word8]
getRandom32 = B.unpack <$> getBytes 32
getRandom32 :: Get Bytes
getRandom32 = getBytes 32
getServerRandom32 :: Get ServerRandom
getServerRandom32 = ServerRandom <$> getRandom32
@ -305,8 +307,8 @@ getServerRandom32 = ServerRandom <$> getRandom32
getClientRandom32 :: Get ClientRandom
getClientRandom32 = ClientRandom <$> getRandom32
putRandom32 :: [Word8] -> Put
putRandom32 = mapM_ putWord8
putRandom32 :: Bytes -> Put
putRandom32 = putBytes
putClientRandom32 :: ClientRandom -> Put
putClientRandom32 (ClientRandom r) = putRandom32 r
@ -315,25 +317,25 @@ putServerRandom32 :: ServerRandom -> Put
putServerRandom32 (ServerRandom r) = putRandom32 r
getClientKeyData46 :: Get ClientKeyData
getClientKeyData46 = ClientKeyData . B.unpack <$> getBytes 46
getClientKeyData46 = ClientKeyData <$> getBytes 46
putClientKeyData46 :: ClientKeyData -> Put
putClientKeyData46 (ClientKeyData d) = mapM_ putWord8 d
putClientKeyData46 (ClientKeyData d) = putBytes d
getSession :: Get Session
getSession = do
len8 <- getWord8
case fromIntegral len8 of
0 -> return $ Session Nothing
len -> Session . Just . B.unpack <$> getBytes len
len -> Session . Just <$> getBytes len
putSession :: Session -> Put
putSession (Session session) =
case session of
Nothing -> putWord8 0
Just s -> putWord8 (fromIntegral $ length s) >> mapM_ putWord8 s
Just s -> putWord8 (fromIntegral $ B.length s) >> putBytes s
getCerts :: Int -> Get [B.ByteString]
getCerts :: Int -> Get [Bytes]
getCerts 0 = return []
getCerts len = do
certlen <- getWord24
@ -342,8 +344,8 @@ getCerts len = do
return (cert : certxs)
putCert :: Certificate -> Put
putCert cert = putWord24 (fromIntegral $ L.length content) >> putLazyByteString content
where content = encodeCertificate cert
putCert cert = putWord24 (fromIntegral $ B.length content) >> putBytes content
where content = B.concat $ L.toChunks $ encodeCertificate cert
getExtensions :: Int -> Get [Extension]
getExtensions 0 = return []
@ -358,12 +360,12 @@ putExtension :: Extension -> Put
putExtension (ty, l) = do
putWord16 ty
putWord16 (fromIntegral $ length l)
putByteString (B.pack l)
putBytes (B.pack l)
putExtensions :: Maybe [Extension] -> Put
putExtensions Nothing = return ()
putExtensions (Just es) =
putWord16 (fromIntegral $ L.length extbs) >> putLazyByteString extbs
putWord16 (fromIntegral $ B.length extbs) >> putBytes extbs
where
extbs = runPut $ mapM_ putExtension es
@ -382,29 +384,26 @@ encodeChangeCipherSpec = runPut (putWord8 1)
{-
- generate things for packet content
-}
generateMasterSecret :: ByteString -> ClientRandom -> ServerRandom -> ByteString
generateMasterSecret :: Bytes -> ClientRandom -> ServerRandom -> Bytes
generateMasterSecret premasterSecret (ClientRandom c) (ServerRandom s) =
prf_MD5SHA1 premasterSecret seed 48
where
label = map (toEnum . fromEnum) "master secret"
seed = L.concat $ map L.pack [ label, c, s]
seed = B.concat [ BC.pack "master secret", c, s ]
generateKeyBlock :: ClientRandom -> ServerRandom -> ByteString -> Int -> ByteString
generateKeyBlock :: ClientRandom -> ServerRandom -> Bytes -> Int -> Bytes
generateKeyBlock (ClientRandom c) (ServerRandom s) mastersecret kbsize =
prf_MD5SHA1 mastersecret seed kbsize
where
label = map (toEnum . fromEnum) "key expansion"
seed = L.concat $ map L.pack [ label, s, c ]
seed = B.concat [ BC.pack "key expansion", s, c ]
generateFinished :: String -> ByteString -> HashCtx -> HashCtx -> ByteString
generateFinished :: Bytes -> Bytes -> HashCtx -> HashCtx -> Bytes
generateFinished label mastersecret md5ctx sha1ctx =
prf_MD5SHA1 mastersecret seed 12
where
plabel = B.pack $ map (toEnum . fromEnum) label
seed = L.fromChunks [ plabel, finalizeHash md5ctx, finalizeHash sha1ctx ]
seed = B.concat [ label, finalizeHash md5ctx, finalizeHash sha1ctx ]
generateClientFinished :: ByteString -> HashCtx -> HashCtx -> ByteString
generateClientFinished = generateFinished "client finished"
generateClientFinished :: Bytes -> HashCtx -> HashCtx -> Bytes
generateClientFinished = generateFinished (BC.pack "client finished")
generateServerFinished :: ByteString -> HashCtx -> HashCtx -> ByteString
generateServerFinished = generateFinished "server finished"
generateServerFinished :: Bytes -> HashCtx -> HashCtx -> Bytes
generateServerFinished = generateFinished (BC.pack "server finished")

View file

@ -19,7 +19,7 @@ import Control.Monad.State
import Control.Monad.Error
import Data.Maybe
import Data.ByteString.Lazy (ByteString)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString as B
@ -72,14 +72,14 @@ readPacket hdr@(Header ProtocolType_Handshake ver _) content =
decryptRSA :: MonadTLSState m => ByteString -> m (Maybe ByteString)
decryptRSA econtent = do
rsapriv <- getTLSState >>= return . fromJust . hstRSAPrivateKey . fromJust . stHandshake
return $ rsaDecrypt rsapriv (L.drop 2 econtent)
return $ rsaDecrypt rsapriv (B.drop 2 econtent)
setMasterSecretRandom :: ByteString -> TLSRead ()
setMasterSecretRandom content = do
st <- getTLSState
let (bytes, g') = getRandomBytes (stRandomGen st) (fromIntegral $ L.length content)
let (bytes, g') = getRandomBytes (stRandomGen st) (fromIntegral $ B.length content)
putTLSState $ st { stRandomGen = g' }
setMasterSecret (L.pack bytes)
setMasterSecret (B.pack bytes)
processClientKeyXchg :: Version -> ByteString -> TLSRead ()
processClientKeyXchg ver content = do
@ -93,7 +93,7 @@ processClientFinished :: FinishedData -> TLSRead ()
processClientFinished fdata = do
cc <- getTLSState >>= return . stClientContext
expected <- getHandshakeDigest (not cc)
when (expected /= L.pack fdata) $ do
when (expected /= B.pack fdata) $ do
-- FIXME don't fail, but report the error so that the code can send a BadMac Alert.
fail ("client mac failure: expecting " ++ show expected ++ " received " ++ (show $L.pack fdata))
return ()
@ -110,7 +110,7 @@ processHsPacket ver dcontent = do
return econtent
hs <- case (ty, decodeHandshake ver ty content) of
(_, Right x) -> return x
(HandshakeType_ClientKeyXchg, Left _) -> return $ ClientKeyXchg SSL2 (ClientKeyData $ replicate 0xff 46)
(HandshakeType_ClientKeyXchg, Left _) -> return $ ClientKeyXchg SSL2 (ClientKeyData $ B.replicate 46 0xff)
(_, Left err) -> throwError err
clientmode <- isClientContext
case hs of
@ -132,14 +132,14 @@ decryptContentReally hdr e = do
st <- getTLSState
unencrypted_content <- decryptData e
let digestSize = cipherDigestSize $ fromJust $ stCipher st
let (unencrypted_msg, digest) = L.splitAt (L.length unencrypted_content - fromIntegral digestSize) unencrypted_content
let (unencrypted_msg, digest) = B.splitAt (B.length unencrypted_content - fromIntegral digestSize) unencrypted_content
let (Header pt ver _) = hdr
let new_hdr = Header pt ver (fromIntegral $ L.length unencrypted_msg)
let new_hdr = Header pt ver (fromIntegral $ B.length unencrypted_msg)
expected_digest <- makeDigest False new_hdr unencrypted_msg
if expected_digest == digest
then return $ unencrypted_msg
else throwError $ Error_Digest (L.unpack expected_digest, L.unpack digest)
else throwError $ Error_Digest (B.unpack expected_digest, B.unpack digest)
decryptContent :: Header -> EncryptedData -> TLSRead ByteString
decryptContent hdr e@(EncryptedData b) = do
@ -163,26 +163,26 @@ decryptData (EncryptedData econtent) = do
let cst = fromJust $ stRxCryptState st
let padding_size = fromIntegral $ cipherPaddingSize cipher
let writekey = B.pack $ cstKey cst
let iv = B.pack $ cstIV cst
let writekey = cstKey cst
let iv = cstIV cst
contentpadded <- case cipherF cipher of
CipherNoneF -> fail "none decrypt"
CipherBlockF _ decryptF -> do
{- update IV -}
let newiv = takelast padding_size $ L.unpack econtent
let newiv = B.pack $ takelast padding_size $ B.unpack econtent
putTLSState $ st { stRxCryptState = Just $ cst { cstIV = newiv } }
return $ decryptF writekey iv econtent
CipherStreamF initF _ decryptF -> do
let (content, newiv) = decryptF (if iv /= B.empty then iv else initF writekey) econtent
{- update Ctx -}
putTLSState $ st { stRxCryptState = Just $ cst { cstIV = B.unpack newiv } }
putTLSState $ st { stRxCryptState = Just $ cst { cstIV = newiv } }
return $ content
let content =
if cipherPaddingSize cipher > 0
then
let pb = L.last contentpadded + 1 in
fst $ L.splitAt ((L.length contentpadded) - fromIntegral pb) contentpadded
let pb = B.last contentpadded + 1 in
fst $ B.splitAt ((B.length contentpadded) - fromIntegral pb) contentpadded
else contentpadded
return content

View file

@ -15,13 +15,14 @@ module Network.TLS.Sending (
) where
import Control.Monad.State
import Data.Binary.Put (runPut, putWord16be)
--import Data.Binary.Put (runPut, putWord16be)
import Data.Maybe
import Data.ByteString.Lazy (ByteString)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString as B
import Network.TLS.Wire
import Network.TLS.Struct
import Network.TLS.Packet
import Network.TLS.State
@ -36,7 +37,7 @@ makePacketData :: MonadTLSState m => Packet -> m (Header, ByteString)
makePacketData pkt = do
ver <- getTLSState >>= return . stVersion
content <- writePacketContent pkt
let hdr = Header (packetType pkt) ver (fromIntegral $ L.length content)
let hdr = Header (packetType pkt) ver (fromIntegral $ B.length content)
return (hdr, content)
{-
@ -73,7 +74,7 @@ postprocessPacketData dat = return dat
- marshall packet data
-}
encodePacket :: MonadTLSState m => (Header, ByteString) -> m ByteString
encodePacket (hdr, content) = return $ L.concat [ encodeHeader hdr, content ]
encodePacket (hdr, content) = return $ B.concat [ encodeHeader hdr, content ]
{-
@ -105,8 +106,8 @@ encryptRSA content = do
encryptContent :: MonadTLSState m => (Header, ByteString) -> m (Header, ByteString)
encryptContent (hdr@(Header pt ver _), content) = do
digest <- makeDigest True hdr content
encrypted_msg <- encryptData $ L.concat [content, digest]
let hdrnew = Header pt ver (fromIntegral $ L.length encrypted_msg)
encrypted_msg <- encryptData $ B.concat [content, digest]
let hdrnew = Header pt ver (fromIntegral $ B.length encrypted_msg)
return (hdrnew, encrypted_msg)
takelast :: Int -> [a] -> [a]
@ -124,27 +125,27 @@ encryptData content = do
let cst = fromJust $ stTxCryptState st
let padding_size = fromIntegral $ cipherPaddingSize cipher
let msg_len = L.length content
let msg_len = B.length content
let padding = if padding_size > 0
then
let padbyte = padding_size - (msg_len `mod` padding_size) in
let padbyte' = if padbyte == 0 then padding_size else padbyte in
L.replicate padbyte' (fromIntegral (padbyte' - 1))
B.replicate padbyte' (fromIntegral (padbyte' - 1))
else
L.empty
let writekey = B.pack $ cstKey cst
let iv = B.pack $ cstIV cst
B.empty
let writekey = cstKey cst
let iv = cstIV cst
econtent <- case cipherF cipher of
CipherNoneF -> fail "none encrypt"
CipherBlockF encrypt _ -> do
let e = encrypt writekey iv (L.concat [ content, padding ])
let newiv = takelast (fromIntegral padding_size) $ L.unpack e
let e = encrypt writekey iv (B.concat [ content, padding ])
let newiv = B.pack $ takelast (fromIntegral padding_size) $ B.unpack e
putTLSState $ st { stTxCryptState = Just $ cst { cstIV = newiv } }
return e
CipherStreamF initF encryptF _ -> do
let (e, newiv) = encryptF (if iv /= B.empty then iv else initF writekey) content
putTLSState $ st { stTxCryptState = Just $ cst { cstIV = B.unpack newiv } }
putTLSState $ st { stTxCryptState = Just $ cst { cstIV = newiv } }
return e
return econtent
@ -159,9 +160,9 @@ writePacketContent (Handshake ckx@(ClientKeyXchg _ _)) = do
let premastersecret = runPut $ encodeHandshakeContent ckx
setMasterSecret premastersecret
econtent <- encryptRSA premastersecret
let extralength = runPut $ putWord16be $ fromIntegral $ L.length econtent
let hdr = runPut $ encodeHandshakeHeader (typeOfHandshake ckx) (fromIntegral (L.length econtent + 2))
return $ L.concat [hdr, extralength, econtent]
let extralength = runPut $ putWord16 $ fromIntegral $ B.length econtent
let hdr = runPut $ encodeHandshakeHeader (typeOfHandshake ckx) (fromIntegral (B.length econtent + 2))
return $ B.concat [hdr, extralength, econtent]
writePacketContent pkt@(Handshake (ClientHello ver crand _ _ _ _)) = do
cc <- isClientContext

View file

@ -40,10 +40,11 @@ import Network.TLS.State
import Network.TLS.Sending
import Network.TLS.Receiving
import Network.TLS.SRandom
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import System.IO (Handle, hFlush)
type TLSServerCert = (L.ByteString, Certificate, CertificateKey.PrivateKey)
type TLSServerCert = (B.ByteString, Certificate, CertificateKey.PrivateKey)
data TLSServerCallbacks = TLSServerCallbacks
{ cbCertificates :: Maybe ([Certificate] -> IO Bool) -- ^ optional callback to verify certificates
@ -89,18 +90,18 @@ runTLSServer f params rng = runTLSServerST f (TLSStateServer { scParams = params
{- | receive a single TLS packet or on error a TLSError -}
recvPacket :: Handle -> TLSServer IO (Either TLSError Packet)
recvPacket handle = do
hdr <- lift $ L.hGet handle 5 >>= return . decodeHeader
hdr <- lift $ B.hGet handle 5 >>= return . decodeHeader
case hdr of
Left err -> return $ Left err
Right header@(Header _ _ readlen) -> do
content <- lift $ L.hGet handle (fromIntegral readlen)
content <- lift $ B.hGet handle (fromIntegral readlen)
readPacket header (EncryptedData content)
{- | send a single TLS packet -}
sendPacket :: Handle -> Packet -> TLSServer IO ()
sendPacket handle pkt = do
dataToSend <- writePacket pkt
lift $ L.hPut handle dataToSend
lift $ B.hPut handle dataToSend
handleClientHello :: Handshake -> TLSServer IO ()
handleClientHello (ClientHello ver _ _ ciphers compressionID _) = do
@ -183,7 +184,7 @@ handshakeSendServerData handle srand = do
handshakeSendFinish :: Handle -> TLSServer IO ()
handshakeSendFinish handle = do
cf <- getHandshakeDigest False
sendPacket handle (Handshake $ Finished $ L.unpack cf)
sendPacket handle (Handshake $ Finished $ B.unpack cf)
{- after receiving a client hello, we need to redo a handshake -}
handshake :: Handle -> ServerRandom -> TLSServer IO ()
@ -213,17 +214,20 @@ listen handle srand = do
return ()
{- | sendData sends a bunch of data -}
sendData :: Handle -> L.ByteString -> TLSServer IO ()
sendData handle d =
if L.length d > 16384
sendDataChunk :: Handle -> B.ByteString -> TLSServer IO ()
sendDataChunk handle d =
if B.length d > 16384
then do
let (sending, remain) = L.splitAt 16384 d
let (sending, remain) = B.splitAt 16384 d
sendPacket handle $ AppData sending
sendData handle remain
sendDataChunk handle remain
else
sendPacket handle $ AppData d
{- | sendData sends a bunch of data -}
sendData :: Handle -> L.ByteString -> TLSServer IO ()
sendData handle d = mapM_ (sendDataChunk handle) (L.toChunks d)
{- | recvData get data out of Data packet, and automatically renegociate if
- a Handshake ClientHello is received -}
recvData :: Handle -> TLSServer IO L.ByteString
@ -238,7 +242,7 @@ recvData handle = do
let srand = fromJust $ serverRandom bytes
handshake handle srand
recvData handle
Right (AppData x) -> return x
Right (AppData x) -> return $ L.fromChunks [x]
Left err -> error ("error received: " ++ show err)
_ -> error "unexpected item"

View file

@ -43,8 +43,7 @@ import Network.TLS.Wire
import Network.TLS.Packet
import Network.TLS.Crypto
import Network.TLS.Cipher
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString as B
import Control.Monad
assert :: Monad m => String -> [(String,Bool)] -> m ()
@ -52,9 +51,9 @@ assert fctname list = forM_ list $ \ (name, assumption) -> do
when assumption $ fail (fctname ++ ": assumption about " ++ name ++ " failed")
data TLSCryptState = TLSCryptState
{ cstKey :: ![Word8]
, cstIV :: ![Word8]
, cstMacSecret :: L.ByteString
{ cstKey :: !Bytes
, cstIV :: !Bytes
, cstMacSecret :: !Bytes
} deriving (Show)
data TLSMacState = TLSMacState
@ -65,7 +64,7 @@ data TLSHandshakeState = TLSHandshakeState
{ hstClientVersion :: !(Version)
, hstClientRandom :: !ClientRandom
, hstServerRandom :: !(Maybe ServerRandom)
, hstMasterSecret :: !(Maybe [Word8])
, hstMasterSecret :: !(Maybe Bytes)
, hstRSAPublicKey :: !(Maybe PublicKey)
, hstRSAPrivateKey :: !(Maybe PrivateKey)
, hstHandshakeDigest :: Maybe (HashCtx, HashCtx) -- FIXME could be only 1 hash in tls12
@ -109,7 +108,7 @@ newTLSState rng = TLSState
modifyTLSState :: (MonadTLSState m) => (TLSState -> TLSState) -> m ()
modifyTLSState f = getTLSState >>= \st -> putTLSState (f st)
makeDigest :: (MonadTLSState m) => Bool -> Header -> ByteString -> m ByteString
makeDigest :: (MonadTLSState m) => Bool -> Header -> Bytes -> m Bytes
makeDigest w hdr content = do
st <- getTLSState
assert "make digest"
@ -120,7 +119,7 @@ makeDigest w hdr content = do
let ms = fromJust $ if w then stTxMacState st else stRxMacState st
let cipher = fromJust $ stCipher st
let hmac_msg = L.concat [ encodeWord64 $ msSequence ms, encodeHeader hdr, content ]
let hmac_msg = B.concat [ encodeWord64 $ msSequence ms, encodeHeader hdr, content ]
let digest = (cipherHMAC cipher) (cstMacSecret cst) hmac_msg
let newms = ms { msSequence = (msSequence ms) + 1 }
@ -152,7 +151,7 @@ switchRxEncryption = getTLSState >>= putTLSState . (\st -> st { stRxEncrypted =
setServerRandom :: MonadTLSState m => ServerRandom -> m ()
setServerRandom ran = updateHandshake "srand" (\hst -> hst { hstServerRandom = Just ran })
setMasterSecret :: MonadTLSState m => ByteString -> m ()
setMasterSecret :: MonadTLSState m => Bytes -> m ()
setMasterSecret premastersecret = do
st <- getTLSState
hasValidHandshake "master secret"
@ -161,7 +160,7 @@ setMasterSecret premastersecret = do
updateHandshake "master secret" (\hst ->
let ms = generateMasterSecret premastersecret (hstClientRandom hst) (fromJust $ hstServerRandom hst) in
hst { hstMasterSecret = Just $ L.unpack ms } )
hst { hstMasterSecret = Just ms } )
return ()
setPublicKey :: MonadTLSState m => PublicKey -> m ()
@ -189,21 +188,21 @@ setKeyBlock = do
let ivSize = cipherIVSize cipher
let kb = generateKeyBlock (hstClientRandom hst)
(fromJust $ hstServerRandom hst)
(L.pack $ fromJust $ hstMasterSecret hst) keyblockSize
let (cMACSecret, r1) = L.splitAt (fromIntegral digestSize) kb
let (sMACSecret, r2) = L.splitAt (fromIntegral digestSize) r1
let (cWriteKey, r3) = L.splitAt (fromIntegral keySize) r2
let (sWriteKey, r4) = L.splitAt (fromIntegral keySize) r3
let (cWriteIV, r5) = L.splitAt (fromIntegral ivSize) r4
let (sWriteIV, _) = L.splitAt (fromIntegral ivSize) r5
(fromJust $ hstMasterSecret hst) keyblockSize
let (cMACSecret, r1) = B.splitAt (fromIntegral digestSize) kb
let (sMACSecret, r2) = B.splitAt (fromIntegral digestSize) r1
let (cWriteKey, r3) = B.splitAt (fromIntegral keySize) r2
let (sWriteKey, r4) = B.splitAt (fromIntegral keySize) r3
let (cWriteIV, r5) = B.splitAt (fromIntegral ivSize) r4
let (sWriteIV, _) = B.splitAt (fromIntegral ivSize) r5
let cstClient = TLSCryptState
{ cstKey = L.unpack cWriteKey
, cstIV = L.unpack cWriteIV
{ cstKey = cWriteKey
, cstIV = cWriteIV
, cstMacSecret = cMACSecret }
let cstServer = TLSCryptState
{ cstKey = L.unpack sWriteKey
, cstIV = L.unpack sWriteIV
{ cstKey = sWriteKey
, cstIV = sWriteIV
, cstMacSecret = sMACSecret }
let msClient = TLSMacState { msSequence = 0 }
let msServer = TLSMacState { msSequence = 0 }
@ -250,22 +249,23 @@ updateHandshake n f = do
hasValidHandshake n
modifyTLSState (\st -> st { stHandshake = maybe Nothing (Just . f) (stHandshake st) })
updateHandshakeDigest :: MonadTLSState m => ByteString -> m ()
updateHandshakeDigest :: MonadTLSState m => Bytes -> m ()
updateHandshakeDigest content = updateHandshake "update digest" (\hs ->
let ctxs = case hstHandshakeDigest hs of
let (c1, c2) = case hstHandshakeDigest hs of
Nothing -> (initHash HashTypeSHA1, initHash HashTypeMD5)
Just (sha1ctx, md5ctx) -> (sha1ctx, md5ctx) in
let (nc1, nc2) = foldl (\(c1, c2) s -> (updateHash c1 s, updateHash c2 s)) ctxs $ L.toChunks content in
let nc1 = updateHash c1 content in
let nc2 = updateHash c2 content in
hs { hstHandshakeDigest = Just (nc1, nc2) }
)
getHandshakeDigest :: MonadTLSState m => Bool -> m ByteString
getHandshakeDigest :: MonadTLSState m => Bool -> m Bytes
getHandshakeDigest client = do
st <- getTLSState
let hst = fromJust $ stHandshake st
let (sha1ctx, md5ctx) = fromJust $ hstHandshakeDigest hst
let msecret = fromJust $ hstMasterSecret hst
return $ (if client then generateClientFinished else generateServerFinished) (L.pack msecret) md5ctx sha1ctx
return $ (if client then generateClientFinished else generateServerFinished) msecret md5ctx sha1ctx
endHandshake :: MonadTLSState m => m ()
endHandshake = modifyTLSState (\st -> st { stHandshake = Nothing })

View file

@ -8,7 +8,8 @@
-- the Struct module contains all definitions and values of the TLS protocol
--
module Network.TLS.Struct
( Version(..)
( Bytes
, Version(..)
, ConnectionEnd(..)
, CipherType(..)
, Extension
@ -41,10 +42,12 @@ module Network.TLS.Struct
, typeOfHandshake
) where
import Data.ByteString.Lazy (ByteString)
import Data.ByteString (ByteString, pack)
import Data.Word
import Data.Certificate.X509
type Bytes = ByteString
data Version = SSL2 | SSL3 | TLS10 | TLS11 | TLS12 deriving (Show, Eq, Ord)
data ConnectionEnd = ConnectionServer | ConnectionClient
@ -107,17 +110,17 @@ data Packet =
data Header = Header ProtocolType Version Word16 deriving (Show, Eq)
newtype ServerRandom = ServerRandom [Word8] deriving (Show, Eq)
newtype ClientRandom = ClientRandom [Word8] deriving (Show, Eq)
newtype ClientKeyData = ClientKeyData [Word8] deriving (Show, Eq)
newtype Session = Session (Maybe [Word8]) deriving (Show, Eq)
newtype ServerRandom = ServerRandom Bytes deriving (Show, Eq)
newtype ClientRandom = ClientRandom Bytes deriving (Show, Eq)
newtype ClientKeyData = ClientKeyData Bytes deriving (Show, Eq)
newtype Session = Session (Maybe Bytes) deriving (Show, Eq)
type CipherID = Word16
type CompressionID = Word8
type FinishedData = [Word8]
type Extension = (Word16, [Word8])
constrRandom32 :: ([Word8] -> a) -> [Word8] -> Maybe a
constrRandom32 constr l = if length l == 32 then Just (constr l) else Nothing
constrRandom32 :: (Bytes -> a) -> [Word8] -> Maybe a
constrRandom32 constr l = if length l == 32 then Just (constr $ pack l) else Nothing
serverRandom :: [Word8] -> Maybe ServerRandom
serverRandom l = constrRandom32 ServerRandom l

View file

@ -30,14 +30,13 @@ module Network.TLS.Wire
, putWord16
, putWords16
, putWord24
, putByteString
, putLazyByteString
, putBytes
, encodeWord64
) where
import qualified Data.Binary.Get as Bin
import Data.Binary.Put
import Data.ByteString (ByteString)
import qualified Data.Binary.Get as G
import qualified Data.Binary.Put as P
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Control.Applicative ((<$>))
import Control.Monad.Error
@ -49,32 +48,32 @@ instance Error TLSError where
noMsg = Error_Misc ""
strMsg = Error_Misc
newtype Get a = GE { runGE :: ErrorT TLSError Bin.Get a }
newtype Get a = GE { runGE :: ErrorT TLSError G.Get a }
deriving (Monad, MonadError TLSError)
instance Functor Get where
fmap f = GE . fmap f . runGE
liftGet :: Bin.Get a -> Get a
liftGet :: G.Get a -> Get a
liftGet = GE . lift
runGet :: Get a -> L.ByteString -> Either TLSError a
runGet f b = Bin.runGet (runErrorT (runGE f)) b
runGet :: Get a -> Bytes -> Either TLSError a
runGet f b = G.runGet (runErrorT (runGE f)) (L.fromChunks [b])
remaining :: Get Int
remaining = fromIntegral <$> liftGet Bin.remaining
remaining = fromIntegral <$> liftGet G.remaining
bytesRead :: Get Int
bytesRead = fromIntegral <$> liftGet Bin.bytesRead
bytesRead = fromIntegral <$> liftGet G.bytesRead
getWord8 :: Get Word8
getWord8 = liftGet Bin.getWord8
getWord8 = liftGet G.getWord8
getWords8 :: Get [Word8]
getWords8 = getWord8 >>= \lenb -> replicateM (fromIntegral lenb) getWord8
getWord16 :: Get Word16
getWord16 = liftGet Bin.getWord16be
getWord16 = liftGet G.getWord16be
getWords16 :: Get [Word16]
getWords16 = getWord16 >>= \lenb -> replicateM (fromIntegral lenb `div` 2) getWord16
@ -86,8 +85,8 @@ getWord24 = do
c <- fromIntegral <$> getWord8
return $ (a `shiftL` 16) .|. (b `shiftL` 8) .|. c
getBytes :: Int -> Get ByteString
getBytes i = liftGet $ Bin.getBytes i
getBytes :: Int -> Get Bytes
getBytes i = liftGet $ G.getBytes i
processBytes :: Int -> Get a -> Get a
processBytes i f = do
@ -99,15 +98,20 @@ processBytes i f = do
else throwError (Error_Internal_Packet_ByteProcessed r1 r2 i)
isEmpty :: Get Bool
isEmpty = liftGet Bin.isEmpty
isEmpty = liftGet G.isEmpty
type Put = P.Put
putWord8 :: Word8 -> Put
putWord8 = P.putWord8
putWords8 :: [Word8] -> Put
putWords8 l = do
putWord8 $ fromIntegral (length l)
mapM_ putWord8 l
P.putWord8 $ fromIntegral (length l)
mapM_ P.putWord8 l
putWord16 :: Word16 -> Put
putWord16 = putWord16be
putWord16 = P.putWord16be
putWords16 :: [Word16] -> Put
putWords16 l = do
@ -119,7 +123,16 @@ putWord24 i = do
let a = fromIntegral ((i `shiftR` 16) .&. 0xff)
let b = fromIntegral ((i `shiftR` 8) .&. 0xff)
let c = fromIntegral (i .&. 0xff)
mapM_ putWord8 [a,b,c]
mapM_ P.putWord8 [a,b,c]
encodeWord64 :: Word64 -> L.ByteString
encodeWord64 = runPut . putWord64be
putBytes :: Bytes -> Put
putBytes = P.putByteString
lazyToBytes :: L.ByteString -> Bytes
lazyToBytes = B.concat . L.toChunks
runPut :: Put -> Bytes
runPut = lazyToBytes . P.runPut
encodeWord64 :: Word64 -> Bytes
encodeWord64 = runPut . P.putWord64be

View file

@ -62,7 +62,7 @@ mainClient host port = do
ranByte <- B.head <$> AESRand.randBytes 1
_ <- AESRand.randBytes (fromIntegral ranByte)
clientRandom <- fromJust . clientRandom . B.unpack <$> AESRand.randBytes 32
premasterRandom <- (ClientKeyData . B.unpack) <$> AESRand.randBytes 46
premasterRandom <- ClientKeyData <$> AESRand.randBytes 46
seqInit <- conv . B.unpack <$> AESRand.randBytes 4
handle <- connectTo host (PortNumber $ fromIntegral port)
@ -118,13 +118,13 @@ usage = do
putStrLn "usage: stunnel [client|server] <params...>"
exitFailure
readCertificate :: FilePath -> IO (L.ByteString, Certificate)
readCertificate :: FilePath -> IO (B.ByteString, Certificate)
readCertificate filepath = do
content <- B.readFile filepath
let certdata = case parsePEMCert content of
Left err -> error ("cannot read PEM certificate: " ++ err)
Right x -> L.fromChunks [x]
let cert = case decodeCertificate certdata of
Right x -> x
let cert = case decodeCertificate $ L.fromChunks [certdata] of
Left err -> error ("cannot decode certificate: " ++ err)
Right x -> x
return (certdata, cert)

View file

@ -3,18 +3,20 @@ import Data.Word
import Test.QuickCheck
import Test.QuickCheck.Test
import qualified Data.ByteString as B
import Network.TLS.Struct
import Network.TLS.Packet
import Control.Monad
import Control.Applicative ((<$>))
import System.IO
liftM6 f m1 m2 m3 m4 m5 m6 = do { x1 <- m1; x2 <- m2; x3 <- m3; x4 <- m4; x5 <- m5; x6 <- m6; return (f x1 x2 x3 x4 x5 x6) }
someWords8 :: Int -> Gen [Word8]
someWords8 i = replicateM i (fromIntegral `fmap` (choose (0,255) :: Gen Int))
someWords8 i = replicateM i (fromIntegral <$> (choose (0,255) :: Gen Int))
someWords16 :: Int -> Gen [Word16]
someWords16 i = replicateM i (fromIntegral `fmap` (choose (0,65535) :: Gen Int))
someWords16 i = replicateM i (fromIntegral <$> (choose (0,65535) :: Gen Int))
instance Arbitrary Version where
arbitrary = elements [ SSL2, SSL3, TLS10, TLS11, TLS12 ]
@ -27,10 +29,10 @@ instance Arbitrary ProtocolType where
, ProtocolType_AppData ]
instance Arbitrary Word8 where
arbitrary = fromIntegral `fmap` (choose (0,255) :: Gen Int)
arbitrary = fromIntegral <$> (choose (0,255) :: Gen Int)
instance Arbitrary Word16 where
arbitrary = fromIntegral `fmap` (choose (0,65535) :: Gen Int)
arbitrary = fromIntegral <$> (choose (0,65535) :: Gen Int)
instance Arbitrary Header where
arbitrary = do
@ -40,20 +42,20 @@ instance Arbitrary Header where
return $ Header pt ver len
instance Arbitrary ClientRandom where
arbitrary = ClientRandom `fmap` someWords8 32
arbitrary = ClientRandom . B.pack <$> someWords8 32
instance Arbitrary ServerRandom where
arbitrary = ServerRandom `fmap` someWords8 32
arbitrary = ServerRandom . B.pack <$> someWords8 32
instance Arbitrary ClientKeyData where
arbitrary = ClientKeyData `fmap` someWords8 46
arbitrary = ClientKeyData . B.pack <$> someWords8 46
instance Arbitrary Session where
arbitrary = do
i <- choose (1,2) :: Gen Int
case i of
1 -> return $ Session Nothing
2 -> (Session . Just) `fmap` someWords8 32
2 -> Session . Just . B.pack <$> someWords8 32
arbitraryCiphersIDs :: Gen [Word16]
arbitraryCiphersIDs = choose (0,200) >>= someWords16