packages feed

network-conduit-tls (empty) → 0.5.0

raw patch · 4 files changed

+173/−0 lines, 4 filesdep +basedep +bytestringdep +certificatesetup-changed

Dependencies added: base, bytestring, certificate, conduit, crypto-api, network, network-conduit, pem, system-fileio, system-filepath, tls, tls-extra, transformers, yaml

Files

+ Data/Conduit/Network/TLS.hs view
@@ -0,0 +1,112 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+module Data.Conduit.Network.TLS+    ( TLSConfig (..)+    , runTCPServerTLS+    ) where++import Prelude hiding (FilePath, readFile)+import Data.Yaml (FromJSON (parseJSON), (.:), (.:?), (.!=), Value (Object))+import Control.Applicative ((<$>), (<*>))+import Control.Monad (mzero, forever)+import Data.String (fromString)+import Filesystem.Path.CurrentOS ((</>), FilePath)+import Filesystem (readFile)+import qualified Data.ByteString.Lazy as L+import qualified Data.Certificate.KeyRSA as KeyRSA+import qualified Data.PEM as PEM+import qualified Network.TLS as TLS+import qualified Data.Certificate.X509 as X509+import Data.Conduit.Network (HostPreference, Application, bindPort, sinkSocket, acceptSafe)+import Data.Conduit.Network.Internal (AppData (..))+import Data.Conduit (($$), yield)+import qualified Data.Conduit.List as CL+import Data.Either (rights)+import Network.Socket (sClose)+import Network.Socket.ByteString (recv)+import Control.Exception (bracket, finally)+import Control.Concurrent (forkIO)+import Control.Monad.Trans.Class (lift)+import qualified Network.TLS.Extra as TLSExtra+import Crypto.Random (newGenIO, SystemRandom)++data TLSConfig = TLSConfig+    { tlsHost :: HostPreference+    , tlsPort :: Int+    , tlsCertificate :: FilePath+    , tlsKey :: FilePath+    }++runTCPServerTLS :: TLSConfig -> Application IO -> IO ()+runTCPServerTLS TLSConfig{..} app = do+    certs <- readCertificates tlsCertificate+    key <- readPrivateKey tlsKey+    bracket+        (bindPort tlsPort tlsHost)+        sClose+        (forever . serve certs key)+  where+    serve certs key lsocket = do+        (socket, addr) <- acceptSafe lsocket+        _ <- forkIO $ handle socket addr+        return ()+      where+        handle socket addr = do+            gen <- newGenIO+            ctx <- TLS.serverWith+                params+                (gen :: SystemRandom)+                socket+                (return ()) -- flush+                (\bs -> yield bs $$ sinkSocket socket)+                (recv socket)++            TLS.handshake ctx++            let ad = AppData+                    { appSource =+                        let src = lift (TLS.recvData ctx) >>= yield >> src+                         in src+                    , appSink = CL.mapM_ $ TLS.sendData ctx . L.fromChunks . return+                    , appSockAddr = addr+                    }+++            app ad `finally` sClose socket++        params = TLS.defaultParams+            { TLS.pWantClientCert = False+            , TLS.pAllowedVersions = [TLS.SSL3,TLS.TLS10,TLS.TLS11,TLS.TLS12]+            , TLS.pCiphers         = ciphers+            , TLS.pCertificates    = zip certs $ Just key : repeat Nothing+            }++-- taken from stunnel example in tls-extra+ciphers :: [TLS.Cipher]+ciphers =+    [ TLSExtra.cipher_AES128_SHA1+    , TLSExtra.cipher_AES256_SHA1+    , TLSExtra.cipher_RC4_128_MD5+    , TLSExtra.cipher_RC4_128_SHA1+    ]++readCertificates :: FilePath -> IO [X509.X509]+readCertificates filepath = do+    certs <- rights . parseCerts . PEM.pemParseBS <$> readFile filepath+    case certs of+        []    -> error "no valid certificate found"+        (_:_) -> return certs+    where parseCerts (Right pems) = map (X509.decodeCertificate . L.fromChunks . (:[]) . PEM.pemContent)+                                  $ filter (flip elem ["CERTIFICATE", "TRUSTED CERTIFICATE"] . PEM.pemName) pems+          parseCerts (Left err) = error $ "cannot parse PEM file: " ++ err++readPrivateKey :: FilePath -> IO TLS.PrivateKey+readPrivateKey filepath = do+    pk <- rights . parseKey . PEM.pemParseBS <$> readFile filepath+    case pk of+        []    -> error "no valid RSA key found"+        (x:_) -> return x++    where parseKey (Right pems) = map (fmap (TLS.PrivRSA . snd) . KeyRSA.decodePrivate . L.fromChunks . (:[]) . PEM.pemContent)+                                $ filter ((== "RSA PRIVATE KEY") . PEM.pemName) pems+          parseKey (Left err) = error $ "Cannot parse PEM file: " ++ err
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2011, Michael Snoyman++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Michael Snoyman nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ network-conduit-tls.cabal view
@@ -0,0 +1,29 @@+name:                network-conduit-tls+version:             0.5.0+synopsis:            Create TLS-aware network code with conduits+description:         Uses the tls package for a pure-Haskell implementation.+homepage:            https://github.com/snoyberg/conduit+license:             MIT+license-file:        LICENSE+author:              Michael Snoyman+maintainer:          michael@snoyman.com+category:            Network+build-type:          Simple+cabal-version:       >=1.8++library+  exposed-modules:    Data.Conduit.Network.TLS+  build-depends:      base            >= 4        && < 5+                    , yaml            >= 0.8+                    , system-filepath >= 0.4+                    , system-fileio   >= 0.3+                    , bytestring      >= 0.9+                    , certificate     >= 1.2+                    , pem             >= 0.1+                    , tls             >= 0.9+                    , network-conduit >= 0.6+                    , conduit         >= 0.5+                    , network+                    , transformers+                    , tls-extra       >= 0.4+                    , crypto-api      >= 0.10