packages feed

http-enumerator 0.1.1 → 0.2.0

raw patch · 19 files changed

+172/−2552 lines, 19 filesdep +tlsdep +zlib-bindingsdep −AESdep −RSAdep −binarydep ~enumeratorsetup-changedPVP ok

version bump matches the API change (PVP)

Dependencies added: tls, zlib-bindings

Dependencies removed: AES, RSA, binary, certificate, cryptocipher, cryptohash, random, spoon, vector

Dependency ranges changed: enumerator

API changes (from Hackage documentation)

- Network.HTTP.Enumerator: HttpException :: Int -> ByteString -> HttpException
- Network.HTTP.Enumerator: data InvalidUrlException
- Network.HTTP.Enumerator: instance Exception InvalidUrlException
- Network.HTTP.Enumerator: instance Show InvalidUrlException
- Network.HTTP.Enumerator: instance Typeable InvalidUrlException
+ Network.HTTP.Enumerator: HttpParserException :: String -> HttpException
+ Network.HTTP.Enumerator: StatusCodeException :: Int -> ByteString -> HttpException
+ Network.HTTP.Enumerator: TooManyRedirects :: HttpException
- Network.HTTP.Enumerator: InvalidUrlException :: String -> String -> InvalidUrlException
+ Network.HTTP.Enumerator: InvalidUrlException :: String -> String -> HttpException
- Network.HTTP.Enumerator: httpLbsRedirect :: (MonadIO m, Failure InvalidUrlException m, Failure HttpException m) => Request -> m Response
+ Network.HTTP.Enumerator: httpLbsRedirect :: (MonadIO m, Failure HttpException m) => Request -> m Response
- Network.HTTP.Enumerator: httpRedirect :: (MonadIO m, Failure InvalidUrlException m) => (Int -> Headers -> Iteratee ByteString m a) -> Request -> m a
+ Network.HTTP.Enumerator: httpRedirect :: (MonadIO m, Failure HttpException m) => (Int -> Headers -> Iteratee ByteString m a) -> Request -> m a
- Network.HTTP.Enumerator: parseUrl :: (Failure InvalidUrlException m) => String -> m Request
+ Network.HTTP.Enumerator: parseUrl :: (Failure HttpException m) => String -> m Request
- Network.HTTP.Enumerator: simpleHttp :: (MonadIO m, Failure HttpException m, Failure InvalidUrlException m) => String -> m ByteString
+ Network.HTTP.Enumerator: simpleHttp :: (MonadIO m, Failure HttpException m) => String -> m ByteString

Files

Network/HTTP/Enumerator.hs view
@@ -52,7 +52,6 @@       -- * Request bodies     , urlEncodedBody       -- * Exceptions-    , InvalidUrlException (..)     , HttpException (..)     ) where @@ -61,7 +60,7 @@ import qualified OpenSSL.Session as SSL #else import System.IO (hClose, hSetBuffering, BufferMode (NoBuffering))-import qualified Network.TLS.Client as TLS+import qualified Network.TLS.Client.Enumerator as TLS import Network (connectTo, PortID (PortNumber)) #endif @@ -73,6 +72,7 @@ import Data.Enumerator hiding (head, map, break) import qualified Data.Enumerator as E import Network.HTTP.Enumerator.HttpParser+import Network.HTTP.Enumerator.Zlib (ungzip) import Control.Exception (throwIO, Exception) import Control.Arrow (first) import Data.Char (toLower)@@ -226,6 +226,7 @@         let headers' = ("Host", hh)                      : ("Content-Length", S8.pack $ show                                                   $ L.length requestBody)+                     : ("Accept-Encoding", "gzip")                      : requestHeaders         let request = Blaze.toLazyByteString $ mconcat                 [ Blaze.fromByteString method@@ -248,27 +249,31 @@                 ]         Right () <- run $ enumList 1 (L.toChunks request) $$ iter         run $ enum $$ do-            ((_, sc, _), hs) <- iterHeaders+            ((_, sc, _), hs) <- catchParser "HTTP headers" iterHeaders             let hs' = map (first $ S8.map toLower) hs             let mcl = lookup "content-length" hs'-            let body' =+            let body' x =                     if ("transfer-encoding", "chunked") `elem` hs'-                        then iterChunks'+                        then joinI $ chunkedEnumeratee $$ x                         else case mcl >>= readMay . S8.unpack of-                            Just len -> takeLBS len-                            Nothing -> E.map id-            joinI $ body' $$ bodyIter sc hs+                            Just len -> joinI $ takeLBS len $$ x+                            Nothing -> x+            let decompress x =+                    if ("content-encoding", "gzip") `elem` hs'+                        then joinI $ ungzip $$ x+                        else x+            body' $ decompress $ bodyIter sc hs -iterChunks' :: MonadIO m => Enumeratee S.ByteString S.ByteString m a-iterChunks' k@(Continue _) = do-    len <- iterChunkHeader+chunkedEnumeratee :: MonadIO m => Enumeratee S.ByteString S.ByteString m a+chunkedEnumeratee k@(Continue _) = do+    len <- catchParser "Chunk header" iterChunkHeader     if len == 0         then return k         else do             k' <- takeLBS len k-            iterNewline-            iterChunks' k'-iterChunks' step = return step+            catchParser "End of chunk newline" iterNewline+            chunkedEnumeratee k'+chunkedEnumeratee step = return step  takeLBS :: MonadIO m => Int -> Enumeratee S.ByteString S.ByteString m a takeLBS 0 step = return step@@ -329,14 +334,6 @@             | otherwise = error $ "Invalid argument to showHex: " ++ show x      in ['%', showHex' b, showHex' c] --- | Thrown by 'parseUrl' when a URL could not be parsed correctly.------ 'httpRedirect' also uses the 'parseUrl' function to read the location header--- from a server, so it can also throw this exception.-data InvalidUrlException = InvalidUrlException String String-    deriving (Show, Typeable)-instance Exception InvalidUrlException- -- | Convert a URL into a 'Request'. -- -- This defaults some of the values in 'Request', such as setting 'method' to@@ -344,19 +341,19 @@ -- -- Since this function uses 'Failure', the return monad can be anything that is -- an instance of 'Failure', such as 'IO' or 'Maybe'.-parseUrl :: Failure InvalidUrlException m => String -> m Request+parseUrl :: Failure HttpException m => String -> m Request parseUrl s@('h':'t':'t':'p':':':'/':'/':rest) = parseUrl1 s False rest parseUrl s@('h':'t':'t':'p':'s':':':'/':'/':rest) = parseUrl1 s True rest parseUrl x = failure $ InvalidUrlException x "Invalid scheme" -parseUrl1 :: Failure InvalidUrlException m+parseUrl1 :: Failure HttpException m           => String -> Bool -> String -> m Request parseUrl1 full sec s =     parseUrl2 full sec s'   where     s' = encodeString s -parseUrl2 :: Failure InvalidUrlException m+parseUrl2 :: Failure HttpException m           => String -> Bool -> String -> m Request parseUrl2 full sec s = do     port' <- mport@@ -466,32 +463,32 @@ -- This function will 'failure' an 'HttpException' for any response with a -- non-2xx status code. It uses 'parseUrl' to parse the input. This function -- essentially wraps 'httpLbsRedirect'.-simpleHttp :: (MonadIO m, Failure HttpException m,-               Failure InvalidUrlException m)-           => String -> m L.ByteString+simpleHttp :: (MonadIO m, Failure HttpException m) => String -> m L.ByteString simpleHttp url = do     url' <- parseUrl url     Response sc _ b <- httpLbsRedirect url'     if 200 <= sc && sc < 300         then return b-        else failure $ HttpException sc b+        else failure $ StatusCodeException sc b --- | Throw by 'simpleHttp' when a response does not have a 2xx status code.-data HttpException = HttpException Int L.ByteString+data HttpException = StatusCodeException Int L.ByteString+                   | InvalidUrlException String String+                   | TooManyRedirects+                   | HttpParserException String     deriving (Show, Typeable) instance Exception HttpException  -- | Same as 'http', but follows all 3xx redirect status codes that contain a -- location header. httpRedirect-    :: (MonadIO m, Failure InvalidUrlException m)+    :: (MonadIO m, Failure HttpException m)     => (Int -> Headers -> Iteratee S.ByteString m a)     -> Request     -> m a httpRedirect iter req =-    http iter' req+    http (iter' (10 :: Int)) req   where-    iter' code hs+    iter' redirects code hs         | 300 <= code && code < 400 =             case lookup "location" $ map (first $ S8.map toLower) hs of                 Just l'' -> lift $ do@@ -516,7 +513,9 @@                             , path = path l                             , queryString = queryString l                             }-                    httpRedirect iter req'+                    if redirects == 0+                        then failure TooManyRedirects+                        else http (iter' $ redirects - 1) req'                 Nothing -> iter code hs         | otherwise = iter code hs @@ -532,9 +531,7 @@ -- -- Please see 'lbsIter' for more information on how the 'Response' value is -- created.-httpLbsRedirect :: (MonadIO m, Failure InvalidUrlException m,-                    Failure HttpException m)-                => Request -> m Response+httpLbsRedirect :: (MonadIO m, Failure HttpException m) => Request -> m Response httpLbsRedirect = httpRedirect lbsIter  readMay :: Read a => String -> Maybe a@@ -584,3 +581,6 @@         | c < 10 = Blaze.writeByte $ c + 48         | c < 16 = Blaze.writeByte $ c + 55         | otherwise = error $ "hexChar: " ++ show c++catchParser :: Monad m => String -> Iteratee a m b -> Iteratee a m b+catchParser s i = catchError i (const $ throwError $ HttpParserException s)
+ Network/HTTP/Enumerator/Zlib.hs view
@@ -0,0 +1,34 @@+module Network.HTTP.Enumerator.Zlib+    ( ungzip+    ) where++import Prelude hiding (head)+import Data.Enumerator+import qualified Data.ByteString as S+import Control.Monad.IO.Class (MonadIO (liftIO))+import Control.Monad.Trans.Class (lift)+import Codec.Zlib++ungzip :: MonadIO m => Enumeratee S.ByteString S.ByteString m b+ungzip inner = do+    fzstr <- liftIO $ initInflate $ WindowBits 31+    ungzip' fzstr inner++ungzip' :: MonadIO m => Inflate -> Enumeratee S.ByteString S.ByteString m b+ungzip' fzstr (Continue k) = do+    x <- head+    case x of+        Nothing -> do+            chunk <- liftIO $ finishInflate fzstr+            lift $ runIteratee $ k $ Chunks [chunk]+        Just bs -> do+            chunks <- liftIO $ withInflateInput fzstr bs $ go id+            step <- lift $ runIteratee $ k $ Chunks chunks+            ungzip' fzstr step+  where+    go front pop = do+        x <- pop+        case x of+            Nothing -> return $ front []+            Just y -> go (front . (:) y) pop+ungzip' _ step = return step
− Network/TLS/Cap.hs
@@ -1,19 +0,0 @@--- |--- Module      : Network.TLS.Cap--- License     : BSD-style--- Maintainer  : Vincent Hanquez <vincent@snarc.org>--- Stability   : experimental--- Portability : unknown-----module Network.TLS.Cap-	( hasHelloExtensions-	, hasExplicitBlockIV-	) where--import Network.TLS.Struct--hasHelloExtensions, hasExplicitBlockIV :: Version -> Bool--hasHelloExtensions ver = ver >= TLS12-hasExplicitBlockIV ver = ver >= TLS11
− Network/TLS/Cipher.hs
@@ -1,271 +0,0 @@--- |--- Module      : Network.TLS.Cipher--- License     : BSD-style--- Maintainer  : Vincent Hanquez <vincent@snarc.org>--- Stability   : experimental--- Portability : unknown----module Network.TLS.Cipher-	( CipherTypeFunctions(..)-	, CipherKeyExchangeType(..)-	, Cipher(..)-	, cipherExchangeNeedMoreData--	-- * builtin ciphers for ease of use, might move later to a tls-ciphers library-	, cipher_null_null-	, cipher_RC4_128_MD5-	, cipher_RC4_128_SHA1-	, cipher_AES128_SHA1-	, cipher_AES256_SHA1-	, cipher_AES128_SHA256-	, cipher_AES256_SHA256-	) where--import Data.Word-import Network.TLS.Struct (Version(..))-import Network.TLS.MAC-import qualified Data.Vector.Unboxed as Vector (fromList, toList)-import qualified Data.ByteString.Lazy as L-import qualified Data.ByteString as B--import qualified Codec.Crypto.AES as AES-import qualified Crypto.Cipher.RC4 as RC4---- FIXME convert to newtype-type Key = B.ByteString-type IV = B.ByteString--data CipherTypeFunctions =-	  CipherNoneF -- special value for 0-	| CipherBlockF (Key -> IV -> B.ByteString -> B.ByteString)-	               (Key -> IV -> B.ByteString -> B.ByteString)-	| CipherStreamF (Key -> IV)-	                (IV -> B.ByteString -> (B.ByteString, IV))-	                (IV -> B.ByteString -> (B.ByteString, IV))--data CipherKeyExchangeType =-	  CipherKeyExchangeRSA-	| CipherKeyExchangeDHE_RSA-	| CipherKeyExchangeECDHE_RSA-	| CipherKeyExchangeDHE_DSS-	| CipherKeyExchangeDH_DSS-	| CipherKeyExchangeDH_RSA-	| CipherKeyExchangeECDH_ECDSA-	| CipherKeyExchangeECDH_RSA-	| CipherKeyExchangeECDHE_ECDSA--data Cipher = Cipher-	{ cipherID           :: Word16-	, cipherName         :: String-	, cipherDigestSize   :: Word8-	, cipherKeySize      :: Word8-	, cipherIVSize       :: Word8-	, cipherKeyBlockSize :: Word8-	, cipherPaddingSize  :: Word8-	, cipherKeyExchange  :: CipherKeyExchangeType-	, cipherHMAC         :: B.ByteString -> B.ByteString -> B.ByteString-	, cipherF            :: CipherTypeFunctions-	, cipherMinVer       :: Maybe Version-	}--instance Show Cipher where-	show c = cipherName c--cipherExchangeNeedMoreData :: CipherKeyExchangeType -> Bool-cipherExchangeNeedMoreData CipherKeyExchangeRSA         = False-cipherExchangeNeedMoreData CipherKeyExchangeDHE_RSA     = True-cipherExchangeNeedMoreData CipherKeyExchangeECDHE_RSA   = True-cipherExchangeNeedMoreData CipherKeyExchangeDHE_DSS     = True-cipherExchangeNeedMoreData CipherKeyExchangeDH_DSS      = False-cipherExchangeNeedMoreData CipherKeyExchangeDH_RSA      = False-cipherExchangeNeedMoreData CipherKeyExchangeECDH_ECDSA  = True-cipherExchangeNeedMoreData CipherKeyExchangeECDH_RSA    = True-cipherExchangeNeedMoreData CipherKeyExchangeECDHE_ECDSA = True--repack :: Int -> B.ByteString -> [B.ByteString]-repack bs x =-	if B.length x > bs-		then-			let (c1, c2) = B.splitAt bs x in-			B.pack (B.unpack c1) : repack 16 c2-		else-			[ x ]--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 -> 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 -> 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 -> 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-toIV (v, x, y) = B.pack (x : y : Vector.toList v)--toCtx :: IV -> RC4.Ctx-toCtx iv =-	case B.unpack iv of-		x:y:l -> (Vector.fromList l, x, y)-		_     -> (Vector.fromList [], 0, 0)--initF_rc4 :: Key -> IV-initF_rc4 key     = toIV $ RC4.initCtx (B.unpack key)--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 -> B.ByteString -> (B.ByteString, IV)-decryptF_rc4 iv e = (\(ctx, d) -> (d, toIV ctx)) $ RC4.decrypt (toCtx iv) e--{--TLS 1.0 ciphers definition--CipherSuite TLS_NULL_WITH_NULL_NULL               = { 0x00,0x00 };-CipherSuite TLS_RSA_WITH_NULL_MD5                 = { 0x00,0x01 };-CipherSuite TLS_RSA_WITH_NULL_SHA                 = { 0x00,0x02 };-CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5        = { 0x00,0x03 };-CipherSuite TLS_RSA_WITH_RC4_128_MD5              = { 0x00,0x04 };-CipherSuite TLS_RSA_WITH_RC4_128_SHA              = { 0x00,0x05 };-CipherSuite TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5    = { 0x00,0x06 };-CipherSuite TLS_RSA_WITH_IDEA_CBC_SHA             = { 0x00,0x07 };-CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA     = { 0x00,0x08 };-CipherSuite TLS_RSA_WITH_DES_CBC_SHA              = { 0x00,0x09 };-CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA         = { 0x00,0x0A };-CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA  = { 0x00,0x0B };-CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA           = { 0x00,0x0C };-CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA      = { 0x00,0x0D };-CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA  = { 0x00,0x0E };-CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA           = { 0x00,0x0F };-CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA      = { 0x00,0x10 };-CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x11 };-CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA          = { 0x00,0x12 };-CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA     = { 0x00,0x13 };-CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x14 };-CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA          = { 0x00,0x15 };-CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA     = { 0x00,0x16 };-CipherSuite TLS_DH_anon_EXPORT_WITH_RC4_40_MD5    = { 0x00,0x17 };-CipherSuite TLS_DH_anon_WITH_RC4_128_MD5          = { 0x00,0x18 };-CipherSuite TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x19 };-CipherSuite TLS_DH_anon_WITH_DES_CBC_SHA          = { 0x00,0x1A };-CipherSuite TLS_DH_anon_WITH_3DES_EDE_CBC_SHA     = { 0x00,0x1B };--}--{-- - some builtin ciphers description- -}--cipher_null_null :: Cipher-cipher_null_null = Cipher-	{ cipherID           = 0x0-	, cipherName         = "null-null"-	, cipherDigestSize   = 0-	, cipherKeySize      = 0-	, cipherIVSize       = 0-	, cipherKeyBlockSize = 0-	, cipherPaddingSize  = 0-	, cipherHMAC         = (\_ _ -> B.empty)-	, cipherKeyExchange  = CipherKeyExchangeRSA-	, cipherF            = CipherNoneF-	, cipherMinVer       = Nothing-	}--cipher_RC4_128_MD5 :: Cipher-cipher_RC4_128_MD5 = Cipher-	{ cipherID           = 0x04-	, cipherName         = "RSA-rc4-128-md5"-	, cipherDigestSize   = 16-	, cipherKeySize      = 16-	, cipherIVSize       = 0-	, cipherKeyBlockSize = 2 * (16 + 16 + 0)-	, cipherPaddingSize  = 0-	, cipherHMAC         = hmacMD5-	, cipherKeyExchange  = CipherKeyExchangeRSA-	, cipherF            = CipherStreamF initF_rc4 encryptF_rc4 decryptF_rc4-	, cipherMinVer       = Nothing-	}--cipher_RC4_128_SHA1 :: Cipher-cipher_RC4_128_SHA1 = Cipher-	{ cipherID           = 0x05-	, cipherName         = "RSA-rc4-128-sha1"-	, cipherDigestSize   = 20-	, cipherKeySize      = 16-	, cipherIVSize       = 0-	, cipherKeyBlockSize = 2 * (20 + 16 + 0)-	, cipherPaddingSize  = 0-	, cipherHMAC         = hmacSHA1-	, cipherKeyExchange  = CipherKeyExchangeRSA-	, cipherF            = CipherStreamF initF_rc4 encryptF_rc4 decryptF_rc4-	, cipherMinVer       = Nothing-	}--cipher_AES128_SHA1 :: Cipher-cipher_AES128_SHA1 = Cipher-	{ cipherID           = 0x2f-	, cipherName         = "RSA-aes128-sha1"-	, cipherDigestSize   = 20-	, cipherKeySize      = 16-	, cipherIVSize       = 16-	, cipherKeyBlockSize = 2 * (20 + 16 + 16)-	, cipherPaddingSize  = 16-	, cipherHMAC         = hmacSHA1-	, cipherKeyExchange  = CipherKeyExchangeRSA-	, cipherF            = CipherBlockF aes128_cbc_encrypt aes128_cbc_decrypt-	, cipherMinVer       = Just SSL3-	}--cipher_AES256_SHA1 :: Cipher-cipher_AES256_SHA1 = Cipher-	{ cipherID           = 0x35-	, cipherName         = "RSA-aes256-sha1"-	, cipherDigestSize   = 20-	, cipherKeySize      = 32-	, cipherIVSize       = 16-	, cipherKeyBlockSize = 2 * (20 + 32 + 16)-	, cipherPaddingSize  = 16-	, cipherHMAC         = hmacSHA1-	, cipherKeyExchange  = CipherKeyExchangeRSA-	, cipherF            = CipherBlockF aes256_cbc_encrypt aes256_cbc_decrypt-	, cipherMinVer       = Just SSL3-	}--cipher_AES128_SHA256 :: Cipher-cipher_AES128_SHA256 = Cipher-	{ cipherID           = 0x3c-	, cipherName         = "RSA-aes128-sha256"-	, cipherDigestSize   = 32-	, cipherKeySize      = 16-	, cipherIVSize       = 16-	, cipherKeyBlockSize = 2 * (32 + 16 + 16)-	, cipherPaddingSize  = 16-	, cipherHMAC         = hmacSHA256-	, cipherKeyExchange  = CipherKeyExchangeRSA-	, cipherF            = CipherBlockF aes128_cbc_encrypt aes128_cbc_decrypt-	, cipherMinVer       = Just TLS12-	}--cipher_AES256_SHA256 :: Cipher-cipher_AES256_SHA256 = Cipher-	{ cipherID           = 0x3d-	, cipherName         = "RSA-aes256-sha256"-	, cipherDigestSize   = 32-	, cipherKeySize      = 32-	, cipherIVSize       = 16-	, cipherKeyBlockSize = 2 * (32 + 32 + 16)-	, cipherPaddingSize  = 16-	, cipherHMAC         = hmacSHA256-	, cipherKeyExchange  = CipherKeyExchangeRSA-	, cipherF            = CipherBlockF aes256_cbc_encrypt aes256_cbc_decrypt-	, cipherMinVer       = Just TLS12-	}
− Network/TLS/Client.hs
@@ -1,308 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving, MultiParamTypeClasses #-}---- |--- Module      : Network.TLS.Client--- License     : BSD-style--- Maintainer  : Vincent Hanquez <vincent@snarc.org>--- Stability   : experimental--- Portability : unknown------ the Client module contains the necessary calls to create a connecting TLS socket--- aka. a client socket.----module Network.TLS.Client-	( TLSClientParams(..)-	, TLSClientCallbacks(..)-	, TLSStateClient-	, newIState-	-- * low level packet sending receiving.-	, recvPacket-	, sendPacket-	-- * API, warning probably subject to change-	, connect-	, sendData-	, recvData-	, close-    -- * Enumerator interface-    , clientEnum-    , clientEnumSimple-	) where--import Data.Maybe-import Data.Word-import Control.Applicative ((<$>))-import Data.Certificate.X509-import Network.TLS.Cipher-import Network.TLS.Struct-import Network.TLS.Packet-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)-import Data.IORef-import qualified Data.Enumerator as E-import qualified Control.Monad.IO.Class as Trans-import qualified Control.Monad.Trans.Class as Trans-import qualified Codec.Crypto.AES.Random as AESRand-import Data.Bits-import Control.Monad (when, unless)--data TLSClientCallbacks = TLSClientCallbacks-	{ cbCertificates :: Maybe ([Certificate] -> IO Bool) -- ^ optional callback to verify certificates-	}--instance Show TLSClientCallbacks where-	show _ = "[callbacks]"--data TLSClientParams = TLSClientParams-	{ cpConnectVersion  :: Version            -- ^ client version we're sending by default-	, cpAllowedVersions :: [Version]          -- ^ allowed versions from the server-	, cpSession         :: Maybe [Word8]      -- ^ session for this connection-	, cpCiphers         :: [Cipher]           -- ^ all ciphers for this connection-	, cpCertificate     :: Maybe Certificate  -- ^ an optional client certificate-	, cpCallbacks       :: TLSClientCallbacks -- ^ user callbacks-	} deriving (Show)--data TLSStateClient = TLSStateClient-	{ scParams   :: TLSClientParams -- ^ client params and config for this connection-	, scTLSState :: TLSState        -- ^ client TLS State for this connection-	, scCertRequested :: Bool       -- ^ mark that the server requested a certificate-	} deriving (Show)--type IState = IORef TLSStateClient--newIState :: TLSClientParams -> SRandomGen -> IO IState-newIState params rng = newIORef $ TLSStateClient-    { scParams = params-    , scTLSState = state-    , scCertRequested = False-    }-  where-    state = (newTLSState rng) { stVersion = cpConnectVersion params, stClientContext = True }--{- | receive a single TLS packet or on error a TLSError -}-recvPacket :: IState -> Handle -> IO (Either TLSError Packet)-recvPacket istate handle = do-	hdr <- B.hGet handle 5 >>= return . decodeHeader-	case hdr of-		Left err                          -> return $ Left err-		Right header@(Header _ _ readlen) -> do-			content <- B.hGet handle (fromIntegral readlen)-			runIStateWrapper (readPacket header (EncryptedData content)) istate--newtype IStateWrapper a = IStateWrapper { runIStateWrapper :: IState -> IO a }-instance Monad IStateWrapper where-	return = IStateWrapper . const . return-	(IStateWrapper f) >>= g = IStateWrapper $ \ i -> do-		x <- f i-		runIStateWrapper (g x) i-instance MonadTLSState IStateWrapper where-	getTLSState = IStateWrapper $ fmap scTLSState . readIORef-	putTLSState s = IStateWrapper $ \i -> do-		cs <- readIORef i-		writeIORef i cs { scTLSState = s }--{- | send a single TLS packet -}-sendPacket :: IState -> Handle -> Packet -> IO ()-sendPacket istate handle pkt = do-	dataToSend <- runIStateWrapper (writePacket pkt) istate-	B.hPut handle dataToSend--recvServerHello :: IState -> Handle -> IO ()-recvServerHello istate handle = do-	state' <- readIORef istate-	let ciphers = cpCiphers $ scParams state'-	let allowedvers = cpAllowedVersions $ scParams state'-	let callbacks = cpCallbacks $ scParams state'-	pkt <- recvPacket istate handle-	let hs = case pkt of-		Right (Handshake h) -> h-		Left err            -> error ("error received: " ++ show err)-		Right x             -> error ("unexpected packet received, expecting handshake " ++ show x)-	case hs of-		ServerHello ver _ _ cipher _ _ -> do-			case find ((==) ver) allowedvers of-				Nothing -> error ("received version which is not allowed: " ++ show ver)-				Just _  -> do-					state <- readIORef istate-					let st = state { scTLSState = (scTLSState state) { stVersion = ver } }-					writeIORef istate st--			case find ((==) cipher . cipherID) ciphers of-				Nothing -> error "no cipher in common with the server"-				Just c  -> do-					state <- readIORef istate-					let st = state { scTLSState = (scTLSState state) { stCipher = Just c } }-					writeIORef istate st-			recvServerHello istate handle-		CertRequest _ _ _  -> do-			sc <- readIORef istate-			writeIORef istate sc { scCertRequested = True }-			recvServerHello istate handle-		Certificates certs -> do-			valid <- maybe (return True) (\cb -> cb certs) (cbCertificates callbacks)-			unless valid $ error "certificates received deemed invalid by user"-			recvServerHello istate handle-		ServerHelloDone    -> return ()-		_                  -> error "unexpected handshake message received in server hello messages"--connectSendClientHello :: IState -> Handle -> ClientRandom -> IO ()-connectSendClientHello istate handle crand = do-	state <- readIORef istate-	let ver = cpConnectVersion $ scParams state-	let ciphers = cpCiphers $ scParams state-	sendPacket istate handle $ Handshake (ClientHello ver crand (Session Nothing) (map cipherID ciphers) [ 0 ] Nothing)--connectSendClientCertificate :: IState -> Handle -> IO ()-connectSendClientCertificate istate handle = do-	certRequested <- scCertRequested <$> readIORef istate-	when certRequested $ do-		clientCert <- cpCertificate . scParams <$> readIORef istate-		sendPacket istate handle $ Handshake (Certificates $ maybe [] (:[]) clientCert)--connectSendClientKeyXchg :: IState -> Handle -> ClientKeyData -> IO ()-connectSendClientKeyXchg istate handle prerand = do-	ver <- cpConnectVersion . scParams <$> readIORef istate-	sendPacket istate handle $ Handshake (ClientKeyXchg ver prerand)--connectSendFinish :: IState -> Handle -> IO ()-connectSendFinish istate handle = do-	cf <- runIStateWrapper (getHandshakeDigest True) istate-	sendPacket istate handle (Handshake $ Finished $ B.unpack cf)--{- | connect through a handle as a new TLS connection. -}-connect :: IState -> Handle -> ClientRandom -> ClientKeyData -> IO ()-connect istate handle crand premasterRandom = do-	connectSendClientHello istate handle crand-	recvServerHello istate handle-	connectSendClientCertificate istate handle--	connectSendClientKeyXchg istate handle premasterRandom--	{- maybe send certificateVerify -}-	{- FIXME not implemented yet -}--	sendPacket istate handle (ChangeCipherSpec)-	hFlush handle--	{- send Finished -}-	connectSendFinish istate handle-	-	{- receive changeCipherSpec -}-	pktCCS <- recvPacket istate handle-	case pktCCS of-		Right ChangeCipherSpec -> return ()-		x                      -> error ("unexpected reply. expecting change cipher spec  " ++ show x)--	{- receive Finished -}-	pktFin <- recvPacket istate handle-	case pktFin of-		Right (Handshake (Finished _)) -> return ()-		x                              -> error ("unexpected reply. expecting finished " ++ show x)--	return ()--sendDataChunk :: IState -> Handle -> B.ByteString -> IO ()-sendDataChunk istate handle d =-	if B.length d > 16384-		then do-			let (sending, remain) = B.splitAt 16384 d-			sendPacket istate handle $ AppData sending-			sendDataChunk istate handle remain-		else-			sendPacket istate handle $ AppData d--{- | sendData sends a bunch of data -}-sendData :: IState -> Handle -> L.ByteString -> IO ()-sendData istate handle d = mapM_ (sendDataChunk istate handle) (L.toChunks d)--{- | recvData get data out of Data packet, and automatically try to renegociate if- - a Handshake HelloRequest is received -}-recvData :: IState -> Handle -> IO L.ByteString-recvData istate handle = do-	pkt <- recvPacket istate handle-	case pkt of-		Right (AppData x) -> return $ L.fromChunks [x]-		Right (Handshake HelloRequest) -> do-			-- SECURITY FIXME audit the rng here..-			state <- readIORef istate-			let st = scTLSState state-			let (bytes, rng') = getRandomBytes (stRandomGen st) 32-			let (premaster, rng'') = getRandomBytes rng' 46-			writeIORef istate $ state { scTLSState = st { stRandomGen = rng'' } }-			let crand = fromJust $ clientRandom bytes-			connect istate handle crand (ClientKeyData $ B.pack premaster)-			recvData istate handle-		Left err          -> error ("error received: " ++ show err)-		_                 -> error "unexpected item"--{- | close a TLS connection.- - note that it doesn't close the handle, but just signal we're going to close- - the connection to the other side -}-close :: IState -> Handle -> IO ()-close istate handle = do-	sendPacket istate handle $ Alert (AlertLevel_Warning, CloseNotify)--clientEnumSimple-    :: Trans.MonadIO m-    => Handle-    -> (E.Iteratee B.ByteString m () -> E.Enumerator B.ByteString m a -> m b)-    -> m b-clientEnumSimple h f = do-	ranByte <- Trans.liftIO $ B.head <$> AESRand.randBytes 1-	_ <- Trans.liftIO $ AESRand.randBytes (fromIntegral ranByte)-	clientRandom' <- Trans.liftIO $ fromJust . clientRandom . B.unpack <$> AESRand.randBytes 32-	premasterRandom <- Trans.liftIO $ ClientKeyData <$> AESRand.randBytes 46-	seqInit <- Trans.liftIO $ conv . B.unpack <$> AESRand.randBytes 4-	let clientstate = TLSClientParams-		{ cpConnectVersion = TLS10-		, cpAllowedVersions = [ TLS10, TLS11 ]-		, cpSession = Nothing-		, cpCiphers = ciphers-		, cpCertificate = Nothing-		, cpCallbacks = TLSClientCallbacks-			{ cbCertificates = Nothing-			}-		}-	clientEnum clientstate (makeSRandomGen seqInit) h clientRandom' premasterRandom f-  where-    ciphers =-        [ cipher_AES128_SHA1-        , cipher_AES256_SHA1-        , cipher_RC4_128_MD5-        , cipher_RC4_128_SHA1-        ]-    conv l = (a `shiftL` 24) .|. (b `shiftL` 16) .|. (c `shiftL` 8) .|. d-        where-            [a,b,c,d] = map fromIntegral l--clientEnum :: Trans.MonadIO m-           => TLSClientParams -> SRandomGen -> Handle -> ClientRandom -> ClientKeyData-           -> (E.Iteratee B.ByteString m () -> E.Enumerator B.ByteString m a -> m b)-           -> m b-clientEnum tcp srg h cr ckd f = do-    istate <- Trans.liftIO $ newIState tcp srg-    Trans.liftIO $ connect istate h cr ckd-    b <- f (iter istate) (enum istate)-    Trans.liftIO $ close istate h-    return b-  where-    iter :: Trans.MonadIO m => IState -> E.Iteratee B.ByteString m ()-    iter istate =-        E.continue go-      where-        go E.EOF = return ()-        go (E.Chunks xs) = do-            Trans.liftIO $ sendData istate h $ L.fromChunks xs-            E.continue go-    enum :: Trans.MonadIO m => IState -> E.Enumerator B.ByteString m a-    enum istate (E.Continue k) = do-		lbs <- Trans.liftIO $ recvData istate h-		let chunks = E.Chunks $ L.toChunks lbs-		step <- Trans.lift $ E.runIteratee $ k chunks-		enum istate step-    enum _ step = E.returnI step
+ Network/TLS/Client/Enumerator.hs view
@@ -0,0 +1,86 @@+module Network.TLS.Client.Enumerator+    ( clientEnumSimple+    , clientEnum+    ) where++import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L+import qualified Data.Enumerator as E+import qualified Control.Monad.IO.Class as Trans++import Network.TLS.Client+import Network.TLS.SRandom+import Network.TLS.Struct+import Network.TLS.Cipher++import Control.Monad.State (runStateT)++import Data.IORef+import System.IO (Handle)++type IState = IORef TLSStateClient++newIState :: TLSClientParams -> SRandomGen -> IO IState+newIState params rng = do+    ((), tsc) <- runTLSClient (return ()) params rng+    newIORef tsc++clientEnumSimple+    :: Trans.MonadIO m+    => Handle+    -> (E.Iteratee B.ByteString m () -> E.Enumerator B.ByteString m a -> m b)+    -> m b+clientEnumSimple h f = do+    let clientstate = TLSClientParams+            { cpConnectVersion = TLS10+            , cpAllowedVersions = [ TLS10, TLS11 ]+            , cpSession = Nothing+            , cpCiphers = ciphers+            , cpCertificate = Nothing+            , cpCallbacks = TLSClientCallbacks+                { cbCertificates = Nothing+                }+            }+    srand <- Trans.liftIO makeSRandomGen+    clientEnum clientstate srand h f+  where+    ciphers =+        [ cipher_AES128_SHA1+        , cipher_AES256_SHA1+        , cipher_RC4_128_MD5+        , cipher_RC4_128_SHA1+        ]++clientEnum :: Trans.MonadIO m+           => TLSClientParams -> SRandomGen -> Handle+           -> (E.Iteratee B.ByteString m () -> E.Enumerator B.ByteString m a -> m b)+           -> m b+clientEnum tcp srg h f = do+    istate <- Trans.liftIO $ newIState tcp srg+    tlsHelper istate $ connect h+    b <- f (iter istate) (enum istate)+    tlsHelper istate $ close h+    return b+  where+    iter :: Trans.MonadIO m => IState -> E.Iteratee B.ByteString m ()+    iter istate =+        E.continue go+      where+        go E.EOF = return ()+        go (E.Chunks xs) = do+            tlsHelper istate $ sendData h $ L.fromChunks xs+            E.continue go+    enum :: Trans.MonadIO m => IState -> E.Enumerator B.ByteString m a+    enum istate (E.Continue k) = E.Iteratee $ do+        lbs <- tlsHelper istate $ recvData h+        let chunks = E.Chunks $ L.toChunks lbs+        step <- E.runIteratee $ k chunks+        E.runIteratee $ enum istate step+    enum _ step = E.returnI step++tlsHelper :: Trans.MonadIO m => IState -> TLSClient IO a -> m a+tlsHelper istate (TLSClient client) = do+    state <- Trans.liftIO $ readIORef istate+    (ret, state') <- Trans.liftIO $ runStateT client state+    Trans.liftIO $ writeIORef istate state'+    return ret
− Network/TLS/Crypto.hs
@@ -1,110 +0,0 @@-module Network.TLS.Crypto-	( HashType(..)-	, HashCtx--	-- * incremental interface with algorithm type wrapping for genericity-	, initHash-	, updateHash-	, finalizeHash--	-- * single pass lazy bytestring interface for each algorithm-	, hashMD5-	, hashSHA1-	-- * incremental interface for each algorithm-	, initMD5-	, updateMD5-	, finalizeMD5-	, initSHA1-	, updateSHA1-	, finalizeSHA1--	-- * RSA stuff-	, PublicKey(..)-	, PrivateKey(..)-	, rsaEncrypt-	, rsaDecrypt-	) where--import qualified Data.CryptoHash.SHA1 as SHA1-import qualified Data.CryptoHash.MD5 as MD5-import qualified Data.ByteString as B-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 =-	  SHA1 !SHA1.Ctx-	| MD5 !MD5.Ctx--instance Show HashCtx where-	show (SHA1 _) = "sha1"-	show (MD5 _) = "md5"--data HashType = HashTypeSHA1 | HashTypeMD5--{- MD5 -}--initMD5 :: MD5.Ctx-initMD5 = MD5.init--updateMD5 :: MD5.Ctx -> ByteString -> MD5.Ctx-updateMD5 = MD5.update--finalizeMD5 :: MD5.Ctx -> ByteString-finalizeMD5 = MD5.finalize--hashMD5 :: ByteString -> ByteString-hashMD5 = MD5.hash--{- SHA1 -}--initSHA1 :: SHA1.Ctx-initSHA1 = SHA1.init--updateSHA1 :: SHA1.Ctx -> ByteString -> SHA1.Ctx-updateSHA1 = SHA1.update--finalizeSHA1 :: SHA1.Ctx -> ByteString-finalizeSHA1 = SHA1.finalize--hashSHA1 :: ByteString -> ByteString-hashSHA1 = SHA1.hash--{- generic Hashing -}--initHash :: HashType -> HashCtx-initHash HashTypeSHA1 = SHA1 (initSHA1)-initHash HashTypeMD5  = MD5 (initMD5)--updateHash :: HashCtx -> B.ByteString -> HashCtx-updateHash (SHA1 ctx) = SHA1 . updateSHA1 ctx-updateHash (MD5 ctx)  = MD5 . updateMD5 ctx--finalizeHash :: HashCtx -> B.ByteString-finalizeHash (SHA1 ctx) = finalizeSHA1 ctx-finalizeHash (MD5 ctx)  = finalizeMD5 ctx--{- RSA reexport and maybification -}--{- on using spoon:- because we use rsa Encrypt/Decrypt in a pure context, catching the exception- when the key is not correctly set or the data isn't correct.- need to fix the RSA package to return "Either String X".--}--lazyToStrict :: L.ByteString -> B.ByteString-lazyToStrict = B.concat . L.toChunks--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 ]
− Network/TLS/MAC.hs
@@ -1,59 +0,0 @@-module Network.TLS.MAC-	( hmacMD5-	, hmacSHA1-	, hmacSHA256-	, prf_MD5-	, prf_SHA1-	, prf_MD5SHA1-	) where--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 as B-import Data.ByteString (ByteString)-import Data.Bits (xor)--hmac :: (ByteString -> ByteString) -> Int -> ByteString -> ByteString -> ByteString-hmac f bl secret msg =-	f $! B.append opad (f $! B.append ipad msg)-	where-		opad = B.map (xor 0x5c) k'-		ipad = B.map (xor 0x36) k'--		k' = B.append kt pad-			where-			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 MD5.hash 64 secret msg--hmacSHA1 :: ByteString -> ByteString -> ByteString-hmacSHA1 secret msg = hmac SHA1.hash 64 secret msg--hmacSHA256 :: ByteString -> ByteString -> ByteString-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 (B.concat [an, seed]) in-	let digestsize = fromIntegral $ B.length out in-	if digestsize >= len-		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 = B.concat $ hmacIter hmacSHA1 secret seed seed len--prf_MD5 :: ByteString -> ByteString -> Int -> ByteString-prf_MD5 secret seed len = B.concat $ hmacIter hmacMD5 secret seed seed len--prf_MD5SHA1 :: ByteString -> ByteString -> Int -> ByteString-prf_MD5SHA1 secret seed len =-	B.pack $ B.zipWith xor (prf_MD5 s1 seed len) (prf_SHA1 s2 seed len)-	where-		slen  = B.length secret-		s1    = B.take (slen `div` 2 + slen `mod` 2) secret-		s2    = B.drop (slen `div` 2) secret
− Network/TLS/Packet.hs
@@ -1,435 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--- |--- 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-	(-	-- * marshall functions for header messages-	  decodeHeader-	, encodeHeader--	-- * marshall functions for alert messages-	, decodeAlert-	, encodeAlert--	-- * marshall functions for handshake messages-	, decodeHandshakeHeader-	, decodeHandshake-	, encodeHandshake-	, encodeHandshakeHeader-	, encodeHandshakeContent--	-- * marshall functions for change cipher spec message-	, decodeChangeCipherSpec-	, encodeChangeCipherSpec--	-- * generate things for packet content-	, generateMasterSecret-	, generateKeyBlock-	, generateClientFinished-	, generateServerFinished-	) where--import Network.TLS.Struct-import Network.TLS.Cap-import Network.TLS.Wire-import Data.Either (partitionEithers)-import Data.Maybe (fromJust, isNothing)-import Control.Applicative ((<$>))-import Control.Monad-import Control.Monad.Error-import Data.Certificate.X509-import Network.TLS.Crypto-import Network.TLS.MAC-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- -}-decodeHeader :: ByteString -> Either TLSError Header-decodeHeader = runGet $ do-	ty <- getWord8-	major <- getWord8-	minor <- getWord8-	len <- getWord16-	case (valToType ty, verOfNum (major, minor)) of-		(Just y, Just v) -> return $ Header y v len-		(Nothing, _)     -> throwError (Error_Packet "invalid type")-		(_, Nothing)     -> throwError (Error_Packet "invalid version")--encodeHeader :: Header -> ByteString-encodeHeader (Header pt ver len) =-	{- FIXME check len <= 2^14 -}-	runPut (putWord8 (valOfType pt) >> putWord8 major >> putWord8 minor >> putWord16 len)-	where (major, minor) = numericalVer ver--{-- - decode and encode ALERT- -}--decodeAlert :: ByteString -> Either TLSError (AlertLevel, AlertDescription)-decodeAlert = runGet $ do-	al <- getWord8-	ad <- getWord8-	case (valToType al, valToType ad) of-		(Just a, Just d) -> return (a, d)-		(Nothing, _)     -> throwError (Error_Packet "missing alert level")-		(_, Nothing)     -> throwError (Error_Packet "missing alert description")--encodeAlert :: (AlertLevel, AlertDescription) -> ByteString-encodeAlert (al, ad) = runPut (putWord8 (valOfType al) >> putWord8 (valOfType ad))--{- decode and encode HANDSHAKE -}--decodeHandshakeHeader :: ByteString -> Either TLSError (HandshakeType, Bytes)-decodeHandshakeHeader = runGet $ do-	tyopt <- getWord8 >>= return . valToType-	ty <- if isNothing tyopt-		then throwError (Error_Unknown_Type "handshake type")-		else return $ fromJust tyopt-	len <- getWord24-	content <- getBytes len-	empty <- isEmpty-	unless empty (throwError (Error_Internal_Packet_Remaining 1))-	return (ty, content)--decodeHandshake :: Version -> HandshakeType -> ByteString -> Either TLSError Handshake-decodeHandshake ver ty = runGet $ case ty of-	HandshakeType_HelloRequest    -> decodeHelloRequest-	HandshakeType_ClientHello     -> decodeClientHello-	HandshakeType_ServerHello     -> decodeServerHello-	HandshakeType_Certificate     -> decodeCertificates-	HandshakeType_ServerKeyXchg   -> decodeServerKeyXchg ver-	HandshakeType_CertRequest     -> decodeCertRequest ver-	HandshakeType_ServerHelloDone -> decodeServerHelloDone-	HandshakeType_CertVerify      -> decodeCertVerify-	HandshakeType_ClientKeyXchg   -> decodeClientKeyXchg-	HandshakeType_Finished        -> decodeFinished ver--decodeHelloRequest :: Get Handshake-decodeHelloRequest = return HelloRequest--decodeClientHello :: Get Handshake-decodeClientHello = do-	ver          <- getVersion-	random       <- getClientRandom32-	session      <- getSession-	ciphers      <- getWords16-	compressions <- getWords8-	r            <- remaining-	exts <- if hasHelloExtensions ver && r > 0-		then fmap fromIntegral getWord16 >>= getExtensions >>= return . Just-		else return Nothing-	return $ ClientHello ver random session ciphers compressions exts--decodeServerHello :: Get Handshake-decodeServerHello = do-	ver           <- getVersion-	random        <- getServerRandom32-	session       <- getSession-	cipherid      <- getWord16-	compressionid <- getWord8-	r             <- remaining-	exts <- if hasHelloExtensions ver && r > 0-		then fmap fromIntegral getWord16 >>= getExtensions >>= return . Just-		else return Nothing-	return $ ServerHello ver random session cipherid compressionid exts--decodeServerHelloDone :: Get Handshake-decodeServerHelloDone = return ServerHelloDone--decodeCertificates :: Get Handshake-decodeCertificates = do-	certslen <- getWord24-	certs <- getCerts certslen >>= return . map (decodeCertificate . L.fromChunks . (:[]))-	let (l, r) = partitionEithers certs-	if length l > 0-		then throwError $ Error_Certificate $ show l-		else return $ Certificates r--decodeFinished :: Version -> Get Handshake-decodeFinished ver = do-	-- unfortunately passing the verify_data_size here would be tedious for >=TLS12,-	-- so just return the remaining string.-	len <- if ver >= TLS12-		then remaining-		else if ver == SSL3 then return 36-			else return 12-	opaque <- getBytes (fromIntegral len)-	return $ Finished $ B.unpack opaque--getSignatureHashAlgorithm :: Int -> Get [ (HashAlgorithm, SignatureAlgorithm) ]-getSignatureHashAlgorithm 0   = return []-getSignatureHashAlgorithm len = do-	h <- fromJust . valToType <$> getWord8-	s <- fromJust . valToType <$> getWord8-	xs <- getSignatureHashAlgorithm (len - 2)-	return ((h, s) : xs)--decodeCertRequest :: Version -> Get Handshake-decodeCertRequest ver = do-	certTypes <- map (fromJust . valToType . fromIntegral) <$> getWords8--	sigHashAlgs <- if ver >= TLS12-		then do-			sighashlen <- getWord16-			Just <$> getSignatureHashAlgorithm (fromIntegral sighashlen)-		else return Nothing-	dNameLen <- getWord16-	when (ver < TLS12 && dNameLen < 3) $ throwError (Error_Misc "certrequest distinguishname not of the correct size")-	dName <- getBytes $ fromIntegral dNameLen-	return $ CertRequest certTypes sigHashAlgs (B.unpack dName)--decodeCertVerify :: Get Handshake-decodeCertVerify =-	{- FIXME -}-	return $ CertVerify []--decodeClientKeyXchg :: Get Handshake-decodeClientKeyXchg = do-	ver <- getVersion-	ran <- getClientKeyData46-	return $ ClientKeyXchg ver ran---- FIXME need to work out how we marshall an opaque number---numberise :: ByteString -> Integer-numberise _ = 0--decodeServerKeyXchg_DH :: Get ServerDHParams-decodeServerKeyXchg_DH = do-	p <- getWord16 >>= getBytes . fromIntegral-	g <- getWord16 >>= getBytes . fromIntegral-	y <- getWord16 >>= getBytes . fromIntegral-	return $ ServerDHParams { dh_p = numberise p, dh_g = numberise g, dh_Ys = numberise y }--decodeServerKeyXchg_RSA :: Get ServerRSAParams-decodeServerKeyXchg_RSA = do-	modulus <- getWord16 >>= getBytes . fromIntegral-	expo <- getWord16 >>= getBytes . fromIntegral-	return $ ServerRSAParams { rsa_modulus = numberise modulus, rsa_exponent = numberise expo }--decodeServerKeyXchg :: Version -> Get Handshake-decodeServerKeyXchg ver = do-	-- mostly unimplemented-	skxAlg <- case ver of-		TLS12 -> return $ SKX_RSA Nothing-		TLS10 -> do-			rsaparams <- decodeServerKeyXchg_RSA-			return $ SKX_RSA $ Just rsaparams-		_ -> do-			return $ SKX_RSA Nothing-	return (ServerKeyXchg skxAlg)--encodeHandshake :: Handshake -> ByteString-encodeHandshake o =-	let content = runPut $ encodeHandshakeContent o in-	let len = fromIntegral $ B.length content in-	let header = runPut $ encodeHandshakeHeader (typeOfHandshake o) len in-	B.concat [ header, content ]--encodeHandshakeHeader :: HandshakeType -> Int -> Put-encodeHandshakeHeader ty len = putWord8 (valOfType ty) >> putWord24 len--encodeHandshakeContent :: Handshake -> Put--encodeHandshakeContent (ClientHello version random session cipherIDs compressionIDs exts) = do-	putVersion version-	putClientRandom32 random-	putSession session-	putWords16 cipherIDs-	putWords8 compressionIDs-	putExtensions exts-	return ()--encodeHandshakeContent (ServerHello version random session cipherID compressionID exts) =-	putVersion version >> putServerRandom32 random >> putSession session-	                   >> putWord16 cipherID >> putWord8 compressionID-	                   >> putExtensions exts >> return ()--encodeHandshakeContent (Certificates certs) =-	putWord24 len >> putBytes certbs-	where-		certbs = runPut $ mapM_ putCert certs-		len    = fromIntegral $ B.length certbs--encodeHandshakeContent (ClientKeyXchg version random) = do-	putVersion version-	putClientKeyData46 random--encodeHandshakeContent (ServerKeyXchg _) = do-	-- FIXME-	return ()--encodeHandshakeContent (HelloRequest) = return ()-encodeHandshakeContent (ServerHelloDone) = return ()--encodeHandshakeContent (CertRequest certTypes sigAlgs certAuthorities) = do-	putWords8 (map valOfType certTypes)-	case sigAlgs of-		Nothing -> return ()-		Just l  -> putWords16 $ map (\(x,y) -> (fromIntegral $ valOfType x) * 256 + (fromIntegral $ valOfType y)) l-	putBytes $ B.pack certAuthorities--encodeHandshakeContent (CertVerify _) = undefined--encodeHandshakeContent (Finished opaque) = mapM_ putWord8 opaque--{- marshall helpers -}-getVersion :: Get Version-getVersion = do-	major <- getWord8-	minor <- getWord8-	case verOfNum (major, minor) of-		Just v   -> return v-		Nothing  -> throwError (Error_Unknown_Version major minor)--putVersion :: Version -> Put-putVersion ver = putWord8 major >> putWord8 minor-	where (major, minor) = numericalVer ver--{- FIXME make sure it return error if not 32 available -}-getRandom32 :: Get Bytes-getRandom32 = getBytes 32--getServerRandom32 :: Get ServerRandom-getServerRandom32 = ServerRandom <$> getRandom32--getClientRandom32 :: Get ClientRandom-getClientRandom32 = ClientRandom <$> getRandom32--putRandom32 :: Bytes -> Put-putRandom32 = putBytes--putClientRandom32 :: ClientRandom -> Put-putClientRandom32 (ClientRandom r) = putRandom32 r--putServerRandom32 :: ServerRandom -> Put-putServerRandom32 (ServerRandom r) = putRandom32 r--getClientKeyData46 :: Get ClientKeyData-getClientKeyData46 = ClientKeyData <$> getBytes 46--putClientKeyData46 :: ClientKeyData -> Put-putClientKeyData46 (ClientKeyData d) = putBytes d--getSession :: Get Session-getSession = do-	len8 <- getWord8-	case fromIntegral len8 of-		0   -> return $ Session Nothing-		len -> Session . Just <$> getBytes len--putSession :: Session -> Put-putSession (Session session) =-	case session of-		Nothing -> putWord8 0-		Just s  -> putWord8 (fromIntegral $ B.length s) >> putBytes s--getCerts :: Int -> Get [Bytes]-getCerts 0   = return []-getCerts len = do-	certlen <- getWord24-	cert <- getBytes certlen-	certxs <- getCerts (len - certlen - 3)-	return (cert : certxs)--putCert :: Certificate -> Put-putCert cert = putWord24 (fromIntegral $ B.length content) >> putBytes content-	where content = B.concat $ L.toChunks $ encodeCertificate cert--getExtensions :: Int -> Get [Extension]-getExtensions 0   = return []-getExtensions len = do-	extty <- getWord16-	extdatalen <- getWord16-	extdata <- getBytes $ fromIntegral extdatalen-	extxs <- getExtensions (len - fromIntegral extdatalen - 4)-	return $ (extty, B.unpack extdata) : extxs--putExtension :: Extension -> Put-putExtension (ty, l) = do-	putWord16 ty-	putWord16 (fromIntegral $ length l)-	putBytes (B.pack l)--putExtensions :: Maybe [Extension] -> Put-putExtensions Nothing   = return ()-putExtensions (Just es) =-	putWord16 (fromIntegral $ B.length extbs) >> putBytes extbs-	where-		extbs = runPut $ mapM_ putExtension es--{-- - decode and encode ALERT- -}--decodeChangeCipherSpec :: ByteString -> Either TLSError ()-decodeChangeCipherSpec b = do-	case runGet getWord8 b of-		Left e -> Left e-		Right x ->-			if x == 1-				then Right ()-				else Left $ Error_Misc "unknown change cipher spec content"--encodeChangeCipherSpec :: ByteString-encodeChangeCipherSpec = runPut (putWord8 1)--{-- - generate things for packet content- -}-generateMasterSecret_TLS, generateMasterSecret_SSL :: Bytes -> ClientRandom -> ServerRandom -> Bytes-generateMasterSecret_TLS premasterSecret (ClientRandom c) (ServerRandom s) =-	prf_MD5SHA1 premasterSecret seed 48-	where-		seed = B.concat [ BC.pack "master secret", c, s ]--generateMasterSecret_SSL premasterSecret (ClientRandom c) (ServerRandom s) =-	B.concat $ map (computeMD5 . BC.pack) [ "A", "BB", "CCC" ]-	where-		computeMD5  label = hashMD5 $ B.concat [ premasterSecret, computeSHA1 label ]-		computeSHA1 label = hashSHA1 $ B.concat [ label, premasterSecret, c, s ]--generateMasterSecret :: Version -> Bytes -> ClientRandom -> ServerRandom -> Bytes-generateMasterSecret ver =-	if ver < TLS10 then generateMasterSecret_SSL else generateMasterSecret_TLS--generateKeyBlock :: ClientRandom -> ServerRandom -> Bytes -> Int -> Bytes-generateKeyBlock (ClientRandom c) (ServerRandom s) mastersecret kbsize =-	prf_MD5SHA1 mastersecret seed kbsize-	where-		seed = B.concat [ BC.pack "key expansion", s, c ]--generateFinished_TLS :: Bytes -> Bytes -> HashCtx -> HashCtx -> Bytes-generateFinished_TLS label mastersecret md5ctx sha1ctx =-	prf_MD5SHA1 mastersecret seed 12-	where-		seed = B.concat [ label, finalizeHash md5ctx, finalizeHash sha1ctx ]--generateFinished_SSL :: Bytes -> Bytes -> HashCtx -> HashCtx -> Bytes-generateFinished_SSL sender mastersecret md5ctx sha1ctx =-	B.concat [md5hash, sha1hash]-	where-		md5hash = hashMD5 $ B.concat [ mastersecret, pad2, md5left ]-		sha1hash = hashSHA1 $ B.concat [ mastersecret, pad2, sha1left ]-		pad2 = B.empty -- FIXME-		md5left = hashMD5 B.empty-		sha1left = hashSHA1 B.empty--generateClientFinished :: Version -> Bytes -> HashCtx -> HashCtx -> Bytes-generateClientFinished ver =-	if ver < TLS10 then generateFinished_SSL "CLNT" else generateFinished_TLS (BC.pack "client finished")--generateServerFinished :: Version -> Bytes -> HashCtx -> HashCtx -> Bytes-generateServerFinished ver =-	if ver < TLS10 then generateFinished_SSL "SRVR" else generateFinished_TLS (BC.pack "server finished")
− Network/TLS/Receiving.hs
@@ -1,218 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleContexts #-}---- |--- Module      : Network.TLS.Receiving--- License     : BSD-style--- Maintainer  : Vincent Hanquez <vincent@snarc.org>--- Stability   : experimental--- Portability : unknown------ the Receiving module contains calls related to unmarshalling packets according--- to the TLS state----module Network.TLS.Receiving (-	readPacket-	) where--import Control.Applicative ((<$>))-import Control.Monad.State-import Control.Monad.Error-import Data.Maybe--import Data.ByteString (ByteString)-import qualified Data.ByteString.Lazy as L-import qualified Data.ByteString as B--import Network.TLS.Util-import Network.TLS.Cap-import Network.TLS.Struct-import Network.TLS.Packet-import Network.TLS.State-import Network.TLS.Cipher-import Network.TLS.Crypto-import Network.TLS.SRandom-import Data.Certificate.X509--newtype TLSRead a = TLSR { runTLSR :: ErrorT TLSError (State TLSState) a }-	deriving (Monad, MonadError TLSError)--instance Functor TLSRead where-	fmap f = TLSR . fmap f . runTLSR--instance MonadTLSState TLSRead where-	putTLSState x = TLSR (lift $ put x)-	getTLSState   = TLSR (lift get)--runTLSRead :: MonadTLSState m => TLSRead a -> m (Either TLSError a)-runTLSRead f = do-	st <- getTLSState-	let (a, newst) = runState (runErrorT (runTLSR f)) st-	putTLSState newst-	return a--returnEither :: Either TLSError a -> TLSRead a-returnEither (Left err) = throwError err-returnEither (Right a)  = return a--readPacket :: MonadTLSState m => Header -> EncryptedData -> m (Either TLSError Packet)-readPacket hdr@(Header ProtocolType_AppData _ _) content =-	runTLSRead (AppData <$> decryptContent hdr content)--readPacket hdr@(Header ProtocolType_Alert _ _)   content =-	runTLSRead (decryptContent hdr content >>= returnEither . decodeAlert >>= return . Alert)--readPacket hdr@(Header ProtocolType_ChangeCipherSpec _ _) content = runTLSRead $ do-	dcontent <- decryptContent hdr content-	returnEither $ decodeChangeCipherSpec dcontent-	switchRxEncryption-	isClientContext >>= \cc -> when (not cc) setKeyBlock-	return ChangeCipherSpec--readPacket hdr@(Header ProtocolType_Handshake ver _) content =-	runTLSRead (decryptContent hdr content >>= processHsPacket ver)--decryptRSA :: MonadTLSState m => ByteString -> m (Maybe ByteString)-decryptRSA econtent = do-	rsapriv <- getTLSState >>= return . fromJust . hstRSAPrivateKey . fromJust . stHandshake-	return $ rsaDecrypt rsapriv (B.drop 2 econtent)--setMasterSecretRandom :: ByteString -> TLSRead ()-setMasterSecretRandom content = do-	st <- getTLSState-	let (bytes, g') = getRandomBytes (stRandomGen st) (fromIntegral $ B.length content)-	putTLSState $ st { stRandomGen = g' }-	setMasterSecret (B.pack bytes)--processClientKeyXchg :: Version -> ByteString -> TLSRead ()-processClientKeyXchg ver content = do-	{- the TLS protocol expect the initial client version received in the ClientHello, not the negociated version -}-	expectedVer <- getTLSState >>= return . hstClientVersion . fromJust . stHandshake-	if expectedVer /= ver-		then setMasterSecretRandom content-		else setMasterSecret content--processClientFinished :: FinishedData -> TLSRead ()-processClientFinished fdata = do-	cc <- getTLSState >>= return . stClientContext-	expected <- getHandshakeDigest (not cc)-	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 ()--processHsPacket :: Version -> ByteString -> TLSRead Packet-processHsPacket ver dcontent = do-	(ty, econtent) <- returnEither $ decodeHandshakeHeader dcontent-	-- SECURITY FIXME if RSA fail, we need to generate a random master secret and not fail.-	content <- case ty of-		HandshakeType_ClientKeyXchg -> do-			copt <- decryptRSA econtent-			return $ maybe econtent id copt-		_                           ->-			return econtent-	hs <- case (ty, decodeHandshake ver ty content) of-		(_, Right x)                            -> return x-		(HandshakeType_ClientKeyXchg, Left _)   -> return $ ClientKeyXchg SSL2 (ClientKeyData $ B.replicate 46 0xff)-		(_, Left err)                           -> throwError err-	clientmode <- isClientContext-	case hs of-		ClientHello cver ran _ _ _ _ -> unless clientmode $ do-			startHandshakeClient cver ran-		ServerHello sver ran _ _ _ _ -> when clientmode $ do-			setServerRandom ran-			setVersion sver-		Certificates certs           -> when clientmode $ do processCertificates certs-		ClientKeyXchg cver _         -> unless clientmode $ do-			processClientKeyXchg cver content-		Finished fdata               -> processClientFinished fdata-		_                            -> return ()-	when (finishHandshakeTypeMaterial ty) (updateHandshakeDigest dcontent)-	return $ Handshake hs---decryptContent :: Header -> EncryptedData -> TLSRead ByteString-decryptContent hdr e@(EncryptedData b) = do-	st <- getTLSState-	if stRxEncrypted st-		then decryptData e >>= getCipherData hdr-		else return b--getCipherData :: Header -> CipherData -> TLSRead ByteString-getCipherData hdr cdata = do-	-- check if the MAC is valid.-	macValid <- case cipherDataMAC cdata of-		Nothing     -> return True-		Just digest -> do-			let (Header pt ver _) = hdr-			let new_hdr = Header pt ver (fromIntegral $ B.length $ cipherDataContent cdata)-			expected_digest <- makeDigest False new_hdr $ cipherDataContent cdata-			if expected_digest == digest-				then return True-				else return False--	-- check if the padding is filled with the correct pattern if it exists-	paddingValid <- case cipherDataPadding cdata of-		Nothing  -> return True-		Just pad -> do-			let b = B.length pad - 1-			return $ maybe True (const False) $ B.find (/= fromIntegral b) pad--	unless (and $! [ macValid, paddingValid ]) $ do-		throwError $ Error_Digest ([], [])--	return $ cipherDataContent cdata--decryptData :: EncryptedData -> TLSRead CipherData-decryptData (EncryptedData econtent) = do-	st <- getTLSState--	assert "decrypt data"-		[ ("cipher", isNothing $ stCipher st)-		, ("crypt state", isNothing $ stRxCryptState st) ]--	let cipher       = fromJust $ stCipher st-	let cst          = fromJust $ stRxCryptState st-	let padding_size = fromIntegral $ cipherPaddingSize cipher-	let digestSize   = fromIntegral $ cipherDigestSize cipher-	let writekey     = cstKey cst--	case cipherF cipher of-		CipherNoneF -> fail "none decrypt"-		CipherBlockF _ decryptF -> do-			{- update IV -}-			let (iv, econtent') =-				if hasExplicitBlockIV $ stVersion st-					then B.splitAt (fromIntegral $ cipherIVSize cipher) econtent-					else (cstIV cst, econtent)-			let newiv = fromJust $ takelast padding_size econtent'-			putTLSState $ st { stRxCryptState = Just $ cst { cstIV = newiv } }--			let content' = decryptF writekey iv econtent'-			let paddinglength = fromIntegral (B.last content') + 1-			let contentlen = B.length content' - paddinglength - digestSize-			let (content, mac, padding) = fromJust $ partition3 content' (contentlen, digestSize, paddinglength)-			return $ CipherData-				{ cipherDataContent = content-				, cipherDataMAC     = Just mac-				, cipherDataPadding = Just padding-				}-		CipherStreamF initF _ decryptF -> do-			let iv = cstIV cst-			let (content', newiv) = decryptF (if iv /= B.empty then iv else initF writekey) econtent-			{- update Ctx -}-			let contentlen        = B.length content' - digestSize-			let (content, mac, _) = fromJust $ partition3 content' (contentlen, digestSize, 0)-			putTLSState $ st { stRxCryptState = Just $ cst { cstIV = newiv } }-			return $ CipherData-				{ cipherDataContent = content-				, cipherDataMAC     = Just mac-				, cipherDataPadding = Nothing-				}--processCertificates :: [Certificate] -> TLSRead ()-processCertificates certs = do-	case certPubKey $ head certs of-		PubKey _ (PubKeyRSA (lm, m, e)) -> do-			let pk = PublicKey { public_size = fromIntegral lm, public_n = m, public_e = e }-			setPublicKey pk-		_                    -> return ()
− Network/TLS/SRandom.hs
@@ -1,30 +0,0 @@--- this is probably not a very good random interface, nor it has any good randomness capability.--- the module is just here until a really good CPRNG implementation come up..-module Network.TLS.SRandom-	( SRandomGen-	, makeSRandomGen-	, getRandomByte-	, getRandomBytes-	) where--import System.Random-import Control.Arrow (first)-import Data.Word--type SRandomGen = StdGen--makeSRandomGen :: Int -> SRandomGen-makeSRandomGen i = mkStdGen i--getRandomByte :: SRandomGen -> (Word8, SRandomGen)-getRandomByte rng = first fromIntegral $ next rng--getRandomBytes :: SRandomGen -> Int -> ([Word8], SRandomGen)-getRandomBytes rng n =-	let list = helper rng n in-	(map fst list, snd $ last list)-	where-		helper _ 0 = []-		helper g i =-			let (b, g') = getRandomByte g in-			(b, g') : helper g' (i-1)
− Network/TLS/Sending.hs
@@ -1,179 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}---- |--- Module      : Network.TLS.Sending--- License     : BSD-style--- Maintainer  : Vincent Hanquez <vincent@snarc.org>--- Stability   : experimental--- Portability : unknown------ the Sending module contains calls related to marshalling packets according--- to the TLS state ----module Network.TLS.Sending (-	writePacket-	) where--import Control.Monad.State-import Data.Maybe--import Data.ByteString (ByteString)-import qualified Data.ByteString as B--import Network.TLS.Util-import Network.TLS.Cap-import Network.TLS.Wire-import Network.TLS.Struct-import Network.TLS.Packet-import Network.TLS.State-import Network.TLS.Cipher-import Network.TLS.Crypto--{-- - 'makePacketData' create a Header and a content bytestring related to a packet- - this doesn't change any state- -}-makePacketData :: MonadTLSState m => Packet -> m (Header, ByteString)-makePacketData pkt = do-	ver <- getTLSState >>= return . stVersion-	content <- writePacketContent pkt-	let hdr = Header (packetType pkt) ver (fromIntegral $ B.length content)-	return (hdr, content)--{-- - Handshake data need to update a digest- -}-processPacketData :: MonadTLSState m => (Header, ByteString) -> m (Header, ByteString)-processPacketData dat@(Header ty _ _, content) = do-	when (ty == ProtocolType_Handshake) (updateHandshakeDigest content)-	return dat--{-- - when Tx Encrypted is set, we pass the data through encryptContent, otherwise- - we just return the packet- -}-encryptPacketData :: MonadTLSState m => (Header, ByteString) -> m (Header, ByteString)-encryptPacketData dat = do-	st <- getTLSState-	if stTxEncrypted st-		then encryptContent dat-		else return dat--{-- - ChangeCipherSpec state change need to be handled after encryption otherwise- - its own packet would be encrypted with the new context, instead of beeing sent- - under the current context- -}-postprocessPacketData :: MonadTLSState m => (Header, ByteString) -> m (Header, ByteString)-postprocessPacketData dat@(Header ProtocolType_ChangeCipherSpec _ _, _) =-	switchTxEncryption >> isClientContext >>= \cc -> when cc setKeyBlock >> return dat--postprocessPacketData dat = return dat--{-- - marshall packet data- -}-encodePacket :: MonadTLSState m => (Header, ByteString) -> m ByteString-encodePacket (hdr, content) = return $ B.concat [ encodeHeader hdr, content ]---{-- - writePacket transform a packet into marshalled data related to current state- - and updating state on the go- -}-writePacket :: MonadTLSState m => Packet -> m ByteString-writePacket pkt = makePacketData pkt >>= processPacketData >>=-                  encryptPacketData >>= postprocessPacketData >>= encodePacket--{------------------------------------------------------------------------------}-{- SENDING Helpers                                                            -}-{------------------------------------------------------------------------------}--{- if the RSA encryption fails we just return an empty bytestring, and let the protocol- - fail by itself; however it would be probably better to just report it since it's an internal problem.- -}-encryptRSA :: MonadTLSState m => ByteString -> m ByteString-encryptRSA content = do-	st <- getTLSState-	let g = stRandomGen st-	let rsakey = fromJust $ hstRSAPublicKey $ fromJust $ stHandshake st-	case rsaEncrypt g rsakey content of-		Nothing             -> fail "no RSA key selected"-		Just (econtent, g') -> do-			putTLSState (st { stRandomGen = g' })-			return econtent--encryptContent :: MonadTLSState m => (Header, ByteString) -> m (Header, ByteString)-encryptContent (hdr@(Header pt ver _), content) = do-	digest <- makeDigest True hdr content-	encrypted_msg <- encryptData $ B.concat [content, digest]-	let hdrnew = Header pt ver (fromIntegral $ B.length encrypted_msg)-	return (hdrnew, encrypted_msg)--encryptData :: MonadTLSState m => ByteString -> m ByteString-encryptData content = do-	st <- getTLSState--	assert "encrypt data"-		[ ("cipher", isNothing $ stCipher st)-		, ("crypt state", isNothing $ stTxCryptState st) ]--	let cipher = fromJust $ stCipher st-	let cst = fromJust $ stTxCryptState st-	let padding_size = fromIntegral $ cipherPaddingSize cipher--	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-			B.replicate padbyte' (fromIntegral (padbyte' - 1))-		else-			B.empty-	let writekey = cstKey cst--	econtent <- case cipherF cipher of-		CipherNoneF -> fail "none encrypt"-		CipherBlockF encrypt _ -> do-			let iv = cstIV cst-			let e = encrypt writekey iv (B.concat [ content, padding ])-			let newiv = fromJust $ takelast (fromIntegral $ cipherIVSize cipher) e-			putTLSState $ st { stTxCryptState = Just $ cst { cstIV = newiv } }-			return $ if hasExplicitBlockIV $ stVersion st-				then B.concat [iv,e]-				else e-		CipherStreamF initF encryptF _ -> do-			let iv = cstIV cst-			let (e, newiv) = encryptF (if iv /= B.empty then iv else initF writekey) content-			putTLSState $ st { stTxCryptState = Just $ cst { cstIV = newiv } }-			return e-	return econtent--encodePacketContent :: Packet -> ByteString-encodePacketContent (Handshake h)      = encodeHandshake h-encodePacketContent (Alert a)          = encodeAlert a-encodePacketContent (ChangeCipherSpec) = encodeChangeCipherSpec-encodePacketContent (AppData x)        = x--writePacketContent :: MonadTLSState m => Packet -> m ByteString-writePacketContent (Handshake ckx@(ClientKeyXchg _ _)) = do-	let premastersecret = runPut $ encodeHandshakeContent ckx-	setMasterSecret premastersecret-	econtent <- encryptRSA premastersecret-	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-	when cc (startHandshakeClient ver crand)-	return $ encodePacketContent pkt--writePacketContent pkt@(Handshake (ServerHello ver srand _ _ _ _)) = do-	cc <- isClientContext-	unless cc $ do-		setVersion ver-		setServerRandom srand-	return $ encodePacketContent pkt--writePacketContent pkt = return $ encodePacketContent pkt
− Network/TLS/State.hs
@@ -1,267 +0,0 @@--- |--- Module      : Network.TLS.State--- License     : BSD-style--- Maintainer  : Vincent Hanquez <vincent@snarc.org>--- Stability   : experimental--- Portability : unknown------ the State module contains calls related to state initialization/manipulation--- which is use by the Receiving module and the Sending module.----module Network.TLS.State-	( TLSState(..)-	, TLSHandshakeState(..)-	, TLSCryptState(..)-	, TLSMacState(..)-	, MonadTLSState, getTLSState, putTLSState, modifyTLSState-	, newTLSState-	, assert -- FIXME move somewhere else (Internal.hs ?)-	, finishHandshakeTypeMaterial-	, finishHandshakeMaterial-	, makeDigest-	, setMasterSecret-	, setPublicKey-	, setPrivateKey-	, setKeyBlock-	, setVersion-	, setCipher-	, setServerRandom-	, switchTxEncryption-	, switchRxEncryption-	, isClientContext-	, startHandshakeClient-	, updateHandshakeDigest-	, getHandshakeDigest-	, endHandshake-	) where--import Data.Word-import Data.Maybe (fromJust, isNothing)-import Network.TLS.Util-import Network.TLS.Struct-import Network.TLS.SRandom-import Network.TLS.Wire-import Network.TLS.Packet-import Network.TLS.Crypto-import Network.TLS.Cipher-import qualified Data.ByteString as B-import Control.Monad--assert :: Monad m => String -> [(String,Bool)] -> m ()-assert fctname list = forM_ list $ \ (name, assumption) -> do-	when assumption $ fail (fctname ++ ": assumption about " ++ name ++ " failed")--data TLSCryptState = TLSCryptState-	{ cstKey        :: !Bytes-	, cstIV         :: !Bytes-	, cstMacSecret  :: !Bytes-	} deriving (Show)--data TLSMacState = TLSMacState-	{ msSequence :: Word64-	} deriving (Show)--data TLSHandshakeState = TLSHandshakeState-	{ hstClientVersion   :: !(Version)-	, hstClientRandom    :: !ClientRandom-	, hstServerRandom    :: !(Maybe ServerRandom)-	, hstMasterSecret    :: !(Maybe Bytes)-	, hstRSAPublicKey    :: !(Maybe PublicKey)-	, hstRSAPrivateKey   :: !(Maybe PrivateKey)-	, hstHandshakeDigest :: Maybe (HashCtx, HashCtx) -- FIXME could be only 1 hash in tls12-	} deriving (Show)--data TLSState = TLSState-	{ stClientContext :: Bool-	, stVersion       :: !Version-	, stHandshake     :: !(Maybe TLSHandshakeState)-	, stTxEncrypted   :: Bool-	, stRxEncrypted   :: Bool-	, stTxCryptState  :: !(Maybe TLSCryptState)-	, stRxCryptState  :: !(Maybe TLSCryptState)-	, stTxMacState    :: !(Maybe TLSMacState)-	, stRxMacState    :: !(Maybe TLSMacState)-	, stCipher        :: Maybe Cipher-	, stRandomGen     :: SRandomGen-	} deriving (Show)--class (Monad m) => MonadTLSState m where-	getTLSState :: m TLSState-	putTLSState :: TLSState -> m ()--newTLSState :: SRandomGen -> TLSState-newTLSState rng = TLSState-	{ stClientContext = False-	, stVersion       = TLS10-	, stHandshake     = Nothing-	, stTxEncrypted   = False-	, stRxEncrypted   = False-	, stTxCryptState  = Nothing-	, stRxCryptState  = Nothing-	, stTxMacState    = Nothing-	, stRxMacState    = Nothing-	, stCipher        = Nothing-	, stRandomGen     = rng-	}--modifyTLSState :: (MonadTLSState m) => (TLSState -> TLSState) -> m ()-modifyTLSState f = getTLSState >>= \st -> putTLSState (f st)--makeDigest :: (MonadTLSState m) => Bool -> Header -> Bytes -> m Bytes-makeDigest w hdr content = do-	st <- getTLSState-	assert "make digest"-		[ ("cipher", isNothing $ stCipher st)-		, ("crypt state", isNothing $ if w then stTxCryptState st else stRxCryptState st)-		, ("mac state", isNothing $ if w then stTxMacState st else stRxMacState st) ]-	let cst = fromJust $ if w then stTxCryptState st else stRxCryptState st-	let ms = fromJust $ if w then stTxMacState st else stRxMacState st-	let cipher = fromJust $ stCipher st--	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 }--	modifyTLSState (\_ -> if w then st { stTxMacState = Just newms } else st { stRxMacState = Just newms })-	return digest--finishHandshakeTypeMaterial :: HandshakeType -> Bool-finishHandshakeTypeMaterial HandshakeType_ClientHello     = True-finishHandshakeTypeMaterial HandshakeType_ServerHello     = True-finishHandshakeTypeMaterial HandshakeType_Certificate     = True-finishHandshakeTypeMaterial HandshakeType_HelloRequest    = False-finishHandshakeTypeMaterial HandshakeType_ServerHelloDone = True-finishHandshakeTypeMaterial HandshakeType_ClientKeyXchg   = True-finishHandshakeTypeMaterial HandshakeType_ServerKeyXchg   = True-finishHandshakeTypeMaterial HandshakeType_CertRequest     = True-finishHandshakeTypeMaterial HandshakeType_CertVerify      = False-finishHandshakeTypeMaterial HandshakeType_Finished        = True--finishHandshakeMaterial :: Handshake -> Bool-finishHandshakeMaterial = finishHandshakeTypeMaterial . typeOfHandshake--switchTxEncryption :: MonadTLSState m => m ()-switchTxEncryption = getTLSState >>= putTLSState . (\st -> st { stTxEncrypted = True })--switchRxEncryption :: MonadTLSState m => m ()-switchRxEncryption = getTLSState >>= putTLSState . (\st -> st { stRxEncrypted = True })--setServerRandom :: MonadTLSState m => ServerRandom -> m ()-setServerRandom ran = updateHandshake "srand" (\hst -> hst { hstServerRandom = Just ran })--setMasterSecret :: MonadTLSState m => Bytes -> m ()-setMasterSecret premastersecret = do-	st <- getTLSState-	hasValidHandshake "master secret"-	assert "set master secret"-		[ ("server random", (isNothing $ hstServerRandom $ fromJust $ stHandshake st)) ]--	updateHandshake "master secret" (\hst ->-		let ms = generateMasterSecret (stVersion st) premastersecret (hstClientRandom hst) (fromJust $ hstServerRandom hst) in-		hst { hstMasterSecret = Just ms } )-	return ()--setPublicKey :: MonadTLSState m => PublicKey -> m ()-setPublicKey pk = updateHandshake "publickey" (\hst -> hst { hstRSAPublicKey = Just pk })--setPrivateKey :: MonadTLSState m => PrivateKey -> m ()-setPrivateKey pk = updateHandshake "privatekey" (\hst -> hst { hstRSAPrivateKey = Just pk })--setKeyBlock :: MonadTLSState m => m ()-setKeyBlock = do-	st <- getTLSState--	let hst = fromJust $ stHandshake st-	assert "set key block"-		[ ("cipher", (isNothing $ stCipher st))-		, ("server random", (isNothing $ hstServerRandom hst))-		, ("master secret", (isNothing $ hstMasterSecret hst))-		]--	let cc = stClientContext st-	let cipher = fromJust $ stCipher st-	let keyblockSize = fromIntegral $ cipherKeyBlockSize cipher-	let digestSize = fromIntegral $ cipherDigestSize cipher-	let keySize = fromIntegral $ cipherKeySize cipher-	let ivSize = fromIntegral $ cipherIVSize cipher-	let kb = generateKeyBlock (hstClientRandom hst)-	                          (fromJust $ hstServerRandom hst)-	                          (fromJust $ hstMasterSecret hst) keyblockSize--	let (cMACSecret, sMACSecret, cWriteKey, sWriteKey, cWriteIV, sWriteIV) =-		fromJust $ partition6 kb (digestSize, digestSize, keySize, keySize, ivSize, ivSize)--	let cstClient = TLSCryptState-		{ cstKey        = cWriteKey-		, cstIV         = cWriteIV-		, cstMacSecret  = cMACSecret }-	let cstServer = TLSCryptState-		{ cstKey        = sWriteKey-		, cstIV         = sWriteIV-		, cstMacSecret  = sMACSecret }-	let msClient = TLSMacState { msSequence = 0 }-	let msServer = TLSMacState { msSequence = 0 }-	putTLSState $ st-		{ stTxCryptState = Just $ if cc then cstClient else cstServer-		, stRxCryptState = Just $ if cc then cstServer else cstClient-		, stTxMacState   = Just $ if cc then msClient else msServer-		, stRxMacState   = Just $ if cc then msServer else msClient-		}--setCipher :: MonadTLSState m => Cipher -> m ()-setCipher cipher = getTLSState >>= putTLSState . (\st -> st { stCipher = Just cipher })--setVersion :: MonadTLSState m => Version -> m ()-setVersion ver = getTLSState >>= putTLSState . (\st -> st { stVersion = ver })--isClientContext :: MonadTLSState m => m Bool-isClientContext = getTLSState >>= return . stClientContext---- create a new empty handshake state-newEmptyHandshake :: Version -> ClientRandom -> TLSHandshakeState-newEmptyHandshake ver crand = TLSHandshakeState-	{ hstClientVersion   = ver-	, hstClientRandom    = crand-	, hstServerRandom    = Nothing-	, hstMasterSecret    = Nothing-	, hstRSAPublicKey    = Nothing-	, hstRSAPrivateKey   = Nothing-	, hstHandshakeDigest = Nothing-	}--startHandshakeClient :: MonadTLSState m => Version -> ClientRandom -> m ()-startHandshakeClient ver crand = do-	-- FIXME check if handshake is already not null-	chs <- getTLSState >>= return . stHandshake-	when (isNothing chs) $-		modifyTLSState (\st -> st { stHandshake = Just $ newEmptyHandshake ver crand })--hasValidHandshake :: MonadTLSState m => String -> m ()-hasValidHandshake name = getTLSState >>= \st -> assert name [ ("valid handshake", isNothing $ stHandshake st) ]--updateHandshake :: MonadTLSState m => String -> (TLSHandshakeState -> TLSHandshakeState) -> m ()-updateHandshake n f = do-	hasValidHandshake n-	modifyTLSState (\st -> st { stHandshake = maybe Nothing (Just . f) (stHandshake st) })--updateHandshakeDigest :: MonadTLSState m => Bytes -> m ()-updateHandshakeDigest content = updateHandshake "update digest" (\hs ->-	let (c1, c2) = case hstHandshakeDigest hs of-		Nothing                -> (initHash HashTypeSHA1, initHash HashTypeMD5)-		Just (sha1ctx, md5ctx) -> (sha1ctx, md5ctx) in-	let nc1 = updateHash c1 content in-	let nc2 = updateHash c2 content in-	hs { hstHandshakeDigest = Just (nc1, nc2) }-	)--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) (stVersion st) msecret md5ctx sha1ctx--endHandshake :: MonadTLSState m => m ()-endHandshake = modifyTLSState (\st -> st { stHandshake = Nothing })
− Network/TLS/Struct.hs
@@ -1,417 +0,0 @@--- |--- Module      : Network.TLS.Struct--- License     : BSD-style--- Maintainer  : Vincent Hanquez <vincent@snarc.org>--- Stability   : experimental--- Portability : unknown------ the Struct module contains all definitions and values of the TLS protocol----module Network.TLS.Struct-	( Bytes-	, Version(..)-	, ConnectionEnd(..)-	, CipherType(..)-	, CipherData(..)-	, Extension-	, EncryptedData(..)-	, CertificateType(..)-	, HashAlgorithm(..)-	, SignatureAlgorithm(..)-	, ProtocolType(..)-	, TLSError(..)-	, ServerDHParams(..)-	, ServerRSAParams(..)-	, ServerKeyXchgAlgorithmData(..)-	, Packet(..)-	, Header(..)-	, ServerRandom(..)-	, ClientRandom(..)-	, ClientKeyData(..)-	, serverRandom-	, clientRandom-	, FinishedData-	, Session(..)-	, AlertLevel(..)-	, AlertDescription(..)-	, HandshakeType(..)-	, Handshake(..)-	, numericalVer-	, verOfNum-	, TypeValuable, valOfType, valToType-	, packetType-	, typeOfHandshake-	) where--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-data CipherType = CipherStream | CipherBlock | CipherAEAD--data CipherData = CipherData-	{ cipherDataContent :: Bytes-	, cipherDataMAC     :: Maybe Bytes-	, cipherDataPadding :: Maybe Bytes-	} deriving (Show,Eq)--data CertificateType =-	  CertificateType_RSA_Sign         -- TLS10-	| CertificateType_DSS_Sign         -- TLS10-	| CertificateType_RSA_Fixed_DH     -- TLS10-	| CertificateType_DSS_Fixed_DH     -- TLS10-	| CertificateType_RSA_Ephemeral_dh -- TLS12-	| CertificateType_DSS_Ephemeral_dh -- TLS12-	| CertificateType_fortezza_dms     -- TLS12-	| CertificateType_Unknown Word8-	deriving (Show,Eq)--data HashAlgorithm =-	  HashNone-	| HashMD5-	| HashSHA1-	| HashSHA224-	| HashSHA256-	| HashSHA384-	| HashSHA512-	| HashOther Word8-	deriving (Show,Eq)--data SignatureAlgorithm =-	  SignatureAnonymous-	| SignatureRSA-	| SignatureDSS-	| SignatureECDSA-	| SignatureOther Word8-	deriving (Show,Eq)--data ProtocolType =-	  ProtocolType_ChangeCipherSpec-	| ProtocolType_Alert-	| ProtocolType_Handshake-	| ProtocolType_AppData-	deriving (Eq, Show)--data TLSError =-	  Error_Misc String-	| Error_Certificate String-	| Error_Digest ([Word8], [Word8])-	| Error_Packet String-	| Error_Packet_Size_Mismatch (Int, Int)-	| Error_Internal_Packet_Remaining Int-	| Error_Internal_Packet_ByteProcessed Int Int Int-	| Error_Unknown_Version Word8 Word8-	| Error_Unknown_Type String-	deriving (Eq, Show)--data Packet =-	  Handshake Handshake-	| Alert (AlertLevel, AlertDescription)-	| ChangeCipherSpec-	| AppData ByteString-	deriving (Show,Eq)--data Header = Header ProtocolType Version Word16 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 :: (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--clientRandom :: [Word8] -> Maybe ClientRandom-clientRandom l = constrRandom32 ClientRandom l--newtype EncryptedData = EncryptedData ByteString-	deriving (Show)--data AlertLevel =-	  AlertLevel_Warning-	| AlertLevel_Fatal-	deriving (Show,Eq)--data AlertDescription =-	  CloseNotify-	| UnexpectedMessage-	| BadRecordMac-	| DecryptionFailed-	| RecordOverflow-	| DecompressionFailure-	| HandshakeFailure-	| BadCertificate-	| UnsupportedCertificate-	| CertificateRevoked-	| CertificateExpired-	| CertificateUnknown-	| IllegalParameter-	| UnknownCa-	| AccessDenied-	| DecodeError-	| DecryptError-	| ExportRestriction-	| ProtocolVersion-	| InsufficientSecurity-	| InternalError-	| UserCanceled-	| NoRenegotiation-	deriving (Show,Eq)--data HandshakeType =-	  HandshakeType_HelloRequest-	| HandshakeType_ClientHello-	| HandshakeType_ServerHello-	| HandshakeType_Certificate-	| HandshakeType_ServerKeyXchg-	| HandshakeType_CertRequest-	| HandshakeType_ServerHelloDone-	| HandshakeType_CertVerify-	| HandshakeType_ClientKeyXchg-	| HandshakeType_Finished-	deriving (Show,Eq)--data ServerDHParams = ServerDHParams-	{ dh_p  :: Integer -- ^ prime modulus-	, dh_g  :: Integer -- ^ generator-	, dh_Ys :: Integer -- ^ public value (g^X mod p)-	} deriving (Show,Eq)--data ServerRSAParams = ServerRSAParams-	{ rsa_modulus  :: Integer-	, rsa_exponent :: Integer-	} deriving (Show,Eq)--data ServerKeyXchgAlgorithmData =-	  SKX_DH_Anon ServerDHParams-	| SKX_DHE_DSS ServerDHParams [Word8]-	| SKX_DHE_RSA ServerDHParams [Word8]-	| SKX_RSA (Maybe ServerRSAParams)-	| SKX_DH_DSS (Maybe ServerRSAParams)-	| SKX_DH_RSA (Maybe ServerRSAParams)-	deriving (Show,Eq)--data Handshake =-	  ClientHello !Version !ClientRandom !Session ![CipherID] ![CompressionID] (Maybe [Extension])-	| ServerHello !Version !ServerRandom !Session !CipherID !CompressionID (Maybe [Extension])-	| Certificates [Certificate]-	| HelloRequest-	| ServerHelloDone-	| ClientKeyXchg Version ClientKeyData-	| ServerKeyXchg ServerKeyXchgAlgorithmData-	| CertRequest [CertificateType] (Maybe [ (HashAlgorithm, SignatureAlgorithm) ]) [Word8]-	| CertVerify [Word8]-	| Finished FinishedData-	deriving (Show,Eq)--packetType :: Packet -> ProtocolType-packetType (Handshake _)    = ProtocolType_Handshake-packetType (Alert _)        = ProtocolType_Alert-packetType ChangeCipherSpec = ProtocolType_ChangeCipherSpec-packetType (AppData _)      = ProtocolType_AppData--typeOfHandshake :: Handshake -> HandshakeType-typeOfHandshake (ClientHello _ _ _ _ _ _) = HandshakeType_ClientHello-typeOfHandshake (ServerHello _ _ _ _ _ _) = HandshakeType_ServerHello-typeOfHandshake (Certificates _)          = HandshakeType_Certificate-typeOfHandshake (HelloRequest)            = HandshakeType_HelloRequest-typeOfHandshake (ServerHelloDone)         = HandshakeType_ServerHelloDone-typeOfHandshake (ClientKeyXchg _ _)       = HandshakeType_ClientKeyXchg-typeOfHandshake (ServerKeyXchg _)         = HandshakeType_ServerKeyXchg-typeOfHandshake (CertRequest _ _ _)       = HandshakeType_CertRequest-typeOfHandshake (CertVerify _)            = HandshakeType_CertVerify-typeOfHandshake (Finished _)              = HandshakeType_Finished--numericalVer :: Version -> (Word8, Word8)-numericalVer SSL2  = (2, 0)-numericalVer SSL3  = (3, 0)-numericalVer TLS10 = (3, 1)-numericalVer TLS11 = (3, 2)-numericalVer TLS12 = (3, 3)--verOfNum :: (Word8, Word8) -> Maybe Version-verOfNum (2, 0) = Just SSL2-verOfNum (3, 0) = Just SSL3-verOfNum (3, 1) = Just TLS10-verOfNum (3, 2) = Just TLS11-verOfNum (3, 3) = Just TLS12-verOfNum _      = Nothing--class TypeValuable a where-	valOfType :: a -> Word8-	valToType :: Word8 -> Maybe a--instance TypeValuable ConnectionEnd where-	valOfType ConnectionServer = 0-	valOfType ConnectionClient = 1--	valToType 0 = Just ConnectionServer-	valToType 1 = Just ConnectionClient-	valToType _ = Nothing--instance TypeValuable CipherType where-	valOfType CipherStream = 0-	valOfType CipherBlock  = 1-	valOfType CipherAEAD   = 2--	valToType 0 = Just CipherStream-	valToType 1 = Just CipherBlock-	valToType 2 = Just CipherAEAD-	valToType _ = Nothing--instance TypeValuable ProtocolType where-	valOfType ProtocolType_ChangeCipherSpec = 20-	valOfType ProtocolType_Alert            = 21-	valOfType ProtocolType_Handshake        = 22-	valOfType ProtocolType_AppData          = 23--	valToType 20 = Just ProtocolType_ChangeCipherSpec-	valToType 21 = Just ProtocolType_Alert-	valToType 22 = Just ProtocolType_Handshake-	valToType 23 = Just ProtocolType_AppData-	valToType _  = Nothing--instance TypeValuable HandshakeType where-	valOfType HandshakeType_HelloRequest    = 0-	valOfType HandshakeType_ClientHello     = 1-	valOfType HandshakeType_ServerHello     = 2-	valOfType HandshakeType_Certificate     = 11-	valOfType HandshakeType_ServerKeyXchg   = 12-	valOfType HandshakeType_CertRequest     = 13-	valOfType HandshakeType_ServerHelloDone = 14-	valOfType HandshakeType_CertVerify      = 15-	valOfType HandshakeType_ClientKeyXchg   = 16-	valOfType HandshakeType_Finished        = 20--	valToType 0  = Just HandshakeType_HelloRequest-	valToType 1  = Just HandshakeType_ClientHello-	valToType 2  = Just HandshakeType_ServerHello-	valToType 11 = Just HandshakeType_Certificate-	valToType 12 = Just HandshakeType_ServerKeyXchg-	valToType 13 = Just HandshakeType_CertRequest-	valToType 14 = Just HandshakeType_ServerHelloDone-	valToType 15 = Just HandshakeType_CertVerify-	valToType 16 = Just HandshakeType_ClientKeyXchg-	valToType 20 = Just HandshakeType_Finished-	valToType _  = Nothing--instance TypeValuable AlertLevel where-	valOfType AlertLevel_Warning = 1-	valOfType AlertLevel_Fatal   = 2--	valToType 1 = Just AlertLevel_Warning-	valToType 2 = Just AlertLevel_Fatal-	valToType _ = Nothing--instance TypeValuable AlertDescription where-	valOfType CloseNotify            = 0-	valOfType UnexpectedMessage      = 10-	valOfType BadRecordMac           = 20-	valOfType DecryptionFailed       = 21-	valOfType RecordOverflow         = 22-	valOfType DecompressionFailure   = 30-	valOfType HandshakeFailure       = 40-	valOfType BadCertificate         = 42-	valOfType UnsupportedCertificate = 43-	valOfType CertificateRevoked     = 44-	valOfType CertificateExpired     = 45-	valOfType CertificateUnknown     = 46-	valOfType IllegalParameter       = 47-	valOfType UnknownCa              = 48-	valOfType AccessDenied           = 49-	valOfType DecodeError            = 50-	valOfType DecryptError           = 51-	valOfType ExportRestriction      = 60-	valOfType ProtocolVersion        = 70-	valOfType InsufficientSecurity   = 71-	valOfType InternalError          = 80-	valOfType UserCanceled           = 90-	valOfType NoRenegotiation        = 100--	valToType 0   = Just CloseNotify-	valToType 10  = Just UnexpectedMessage-	valToType 20  = Just BadRecordMac-	valToType 21  = Just DecryptionFailed-	valToType 22  = Just RecordOverflow-	valToType 30  = Just DecompressionFailure-	valToType 40  = Just HandshakeFailure-	valToType 42  = Just BadCertificate-	valToType 43  = Just UnsupportedCertificate-	valToType 44  = Just CertificateRevoked-	valToType 45  = Just CertificateExpired-	valToType 46  = Just CertificateUnknown-	valToType 47  = Just IllegalParameter-	valToType 48  = Just UnknownCa-	valToType 49  = Just AccessDenied-	valToType 50  = Just DecodeError-	valToType 51  = Just DecryptError-	valToType 60  = Just ExportRestriction-	valToType 70  = Just ProtocolVersion-	valToType 71  = Just InsufficientSecurity-	valToType 80  = Just InternalError-	valToType 90  = Just UserCanceled-	valToType 100 = Just NoRenegotiation-	valToType _   = Nothing--instance TypeValuable CertificateType where-	valOfType CertificateType_RSA_Sign         = 1-	valOfType CertificateType_DSS_Sign         = 2-	valOfType CertificateType_RSA_Fixed_DH     = 3-	valOfType CertificateType_DSS_Fixed_DH     = 4-	valOfType CertificateType_RSA_Ephemeral_dh = 5-	valOfType CertificateType_DSS_Ephemeral_dh = 6-	valOfType CertificateType_fortezza_dms     = 20-	valOfType (CertificateType_Unknown i)      = i--	valToType 1  = Just CertificateType_RSA_Sign-	valToType 2  = Just CertificateType_DSS_Sign-	valToType 3  = Just CertificateType_RSA_Fixed_DH-	valToType 4  = Just CertificateType_DSS_Fixed_DH-	valToType 5  = Just CertificateType_RSA_Ephemeral_dh-	valToType 6  = Just CertificateType_DSS_Ephemeral_dh-	valToType 20 = Just CertificateType_fortezza_dms-	valToType i  = Just (CertificateType_Unknown i)--instance TypeValuable HashAlgorithm where-	valOfType HashNone      = 0-	valOfType HashMD5       = 1-	valOfType HashSHA1      = 2-	valOfType HashSHA224    = 3-	valOfType HashSHA256    = 4-	valOfType HashSHA384    = 5-	valOfType HashSHA512    = 6-	valOfType (HashOther i) = i--	valToType 0 = Just HashNone-	valToType 1 = Just HashMD5-	valToType 2 = Just HashSHA1-	valToType 3 = Just HashSHA224-	valToType 4 = Just HashSHA256-	valToType 5 = Just HashSHA384-	valToType 6 = Just HashSHA512-	valToType i = Just (HashOther i)--instance TypeValuable SignatureAlgorithm where-	valOfType SignatureAnonymous = 0-	valOfType SignatureRSA       = 1-	valOfType SignatureDSS       = 2-	valOfType SignatureECDSA     = 3-	valOfType (SignatureOther i) = i--	valToType 0 = Just SignatureAnonymous-	valToType 1 = Just SignatureRSA-	valToType 2 = Just SignatureDSS-	valToType 3 = Just SignatureECDSA-	valToType i = Just (SignatureOther i)
− Network/TLS/Util.hs
@@ -1,37 +0,0 @@-module Network.TLS.Util-	( sub-	, takelast-	, partition3-	, partition6-	) where--import Network.TLS.Struct (Bytes)-import Network.TLS.Wire-import qualified Data.ByteString as B--sub :: Bytes -> Int -> Int -> Maybe Bytes-sub b offset len-	| B.length b < offset + len = Nothing-	| otherwise                 = Just $ B.take len $ snd $ B.splitAt offset b--takelast :: Int -> Bytes -> Maybe Bytes-takelast i b-	| B.length b >= i = sub b (B.length b - i) i-	| otherwise       = Nothing--partition3 :: Bytes -> (Int,Int,Int) -> Maybe (Bytes, Bytes, Bytes)-partition3 bytes (d1,d2,d3) = either (const Nothing) Just $ (flip runGet) bytes $ do-	p1 <- getBytes d1-	p2 <- getBytes d2-	p3 <- getBytes d3-	return (p1,p2,p3)--partition6 :: Bytes -> (Int,Int,Int,Int,Int,Int) -> Maybe (Bytes, Bytes, Bytes, Bytes, Bytes, Bytes)-partition6 bytes (d1,d2,d3,d4,d5,d6) = either (const Nothing) Just $ (flip runGet) bytes $ do-	p1 <- getBytes d1-	p2 <- getBytes d2-	p3 <- getBytes d3-	p4 <- getBytes d4-	p5 <- getBytes d5-	p6 <- getBytes d6-	return (p1,p2,p3,p4,p5,p6)
− Network/TLS/Wire.hs
@@ -1,138 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving,FlexibleInstances #-}---- |--- Module      : Network.TLS.Wire--- License     : BSD-style--- Maintainer  : Vincent Hanquez <vincent@snarc.org>--- Stability   : experimental--- Portability : unknown------ the Wire module is a specialized Binary package related to the TLS protocol.--- all multibytes values are written as big endian.----module Network.TLS.Wire-	( Get-	, runGet-	, remaining-	, bytesRead-	, getWord8-	, getWords8-	, getWord16-	, getWords16-	, getWord24-	, getBytes-	, processBytes-	, isEmpty-	, Put-	, runPut-	, putWord8-	, putWords8-	, putWord16-	, putWords16-	, putWord24-	, putBytes-	, encodeWord64-	) where--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-import Data.Word-import Data.Bits-import Network.TLS.Struct--instance Error TLSError where-	noMsg = Error_Misc ""-	strMsg = Error_Misc--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 :: G.Get a -> Get a-liftGet = GE . lift--runGet :: Get a -> Bytes -> Either TLSError a-runGet f b = G.runGet (runErrorT (runGE f)) (L.fromChunks [b])--remaining :: Get Int-remaining = fromIntegral <$> liftGet G.remaining--bytesRead :: Get Int-bytesRead = fromIntegral <$> liftGet G.bytesRead--getWord8 :: Get Word8-getWord8 = liftGet G.getWord8--getWords8 :: Get [Word8]-getWords8 = getWord8 >>= \lenb -> replicateM (fromIntegral lenb) getWord8--getWord16 :: Get Word16-getWord16 = liftGet G.getWord16be--getWords16 :: Get [Word16]-getWords16 = getWord16 >>= \lenb -> replicateM (fromIntegral lenb `div` 2) getWord16--getWord24 :: Get Int-getWord24 = do-	a <- fromIntegral <$> getWord8-	b <- fromIntegral <$> getWord8-	c <- fromIntegral <$> getWord8-	return $ (a `shiftL` 16) .|. (b `shiftL` 8) .|. c--getBytes :: Int -> Get Bytes-getBytes i = liftGet $ G.getBytes i--processBytes :: Int -> Get a -> Get a-processBytes i f = do-	r1 <- bytesRead-	ret <- f-	r2 <- bytesRead-	if r2 == (r1 + i)-		then return ret-		else throwError (Error_Internal_Packet_ByteProcessed r1 r2 i)-	-isEmpty :: Get Bool-isEmpty = liftGet G.isEmpty--type Put = P.Put--putWord8 :: Word8 -> Put-putWord8 = P.putWord8--putWords8 :: [Word8] -> Put-putWords8 l = do-	P.putWord8 $ fromIntegral (length l)-	mapM_ P.putWord8 l--putWord16 :: Word16 -> Put-putWord16 = P.putWord16be--putWords16 :: [Word16] -> Put-putWords16 l = do-	putWord16 $ 2 * (fromIntegral $ length l)-	mapM_ putWord16 l--putWord24 :: Int -> Put-putWord24 i = do-	let a = fromIntegral ((i `shiftR` 16) .&. 0xff)-	let b = fromIntegral ((i `shiftR` 8) .&. 0xff)-	let c = fromIntegral (i .&. 0xff)-	mapM_ P.putWord8 [a,b,c]--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
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
+ Setup.lhs view
@@ -0,0 +1,8 @@+#!/usr/bin/env runhaskell++> module Main where+> import Distribution.Simple+> import System.Cmd (system)++> main :: IO ()+> main = defaultMain
http-enumerator.cabal view
@@ -1,5 +1,5 @@ name:            http-enumerator-version:         0.1.1+version:         0.2.0 license:         BSD3 license-file:    LICENSE author:          Michael Snoyman <michael@snoyman.com>@@ -25,43 +25,25 @@                  , bytestring            >= 0.9.1.4 && < 0.10                  , transformers          >= 0.2     && < 0.3                  , failure               >= 0.1     && < 0.2-                 , enumerator            >= 0.4     && < 0.5+                 , enumerator            >= 0.4.1   && < 0.5                  , network               >= 2.2.1   && < 2.3                  , network-bytestring    >= 0.1.3   && < 0.2                  , attoparsec            >= 0.8.0.2 && < 0.9                  , attoparsec-enumerator >= 0.2     && < 0.3                  , utf8-string           >= 0.3.4   && < 0.4                  , blaze-builder         >= 0.1     && < 0.2+                 , zlib-bindings         >= 0.0.0   && < 0.1     if flag(openssl)         build-depends: HsOpenSSL         >= 0.8     && < 0.9         cpp-options:   -DOPENSSL     else-        build-depends: AES               >= 0.2.7   && < 0.3-                     , RSA               >= 1.0.5   && < 1.1-                     , certificate       >= 0.2.1   && < 0.3-                     , cryptocipher      >= 0.1     && < 0.2-                     , cryptohash        >= 0.5.2   && < 0.6-                     , random            >= 1.0     && < 1.1-                     , vector            >= 0.6     && < 0.7-                     , spoon             >= 0.3     && < 0.4+        build-depends: tls               >= 0.2     && < 0.3                      , mtl               >= 1.1     && < 1.2-                     , binary            >= 0.5.0.2 && < 0.6     exposed-modules: Network.HTTP.Enumerator     other-modules:   Network.HTTP.Enumerator.HttpParser+                     Network.HTTP.Enumerator.Zlib     if ! flag(openssl)-        other-modules: Network.TLS.Client-                       Network.TLS.SRandom-                       Network.TLS.Cipher-                       Network.TLS.Struct-                       Network.TLS.Receiving-                       Network.TLS.Sending-                       Network.TLS.State-                       Network.TLS.Packet-                       Network.TLS.MAC-                       Network.TLS.Crypto-                       Network.TLS.Cap-                       Network.TLS.Util-                       Network.TLS.Wire+        other-modules: Network.TLS.Client.Enumerator     ghc-options:     -Wall  executable http-enumerator