diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,5 @@
+# Revision history for tcp-streams-openssl
+
+## 0.1.0.0  -- YYYY-mm-dd
+
+* First version. Released on an unsuspecting world.
diff --git a/Data/OpenSSLSetting.hs b/Data/OpenSSLSetting.hs
new file mode 100644
--- /dev/null
+++ b/Data/OpenSSLSetting.hs
@@ -0,0 +1,88 @@
+-- | Helpers for setting up a tls connection with @HsOpenSSL@ package,
+-- for further customization, please refer to @HsOpenSSL@ package.
+--
+-- Note, functions in this module will throw error if can't load certificates or CA store.
+--
+module Data.OpenSSLSetting
+    ( -- * choose a CAStore
+      TrustedCAStore(..)
+      -- * make TLS settings
+    , makeClientSSLContext
+    , makeClientSSLContext'
+    , makeServerSSLContext
+    , makeServerSSLContext'
+    ) where
+
+import qualified OpenSSL.X509.SystemStore as X509
+import qualified OpenSSL.Session          as SSL
+import           OpenSSL                    (withOpenSSL)
+import           Data.TLSSetting            (TrustedCAStore(..), mozillaCAStorePath)
+
+
+makeCAStore :: TrustedCAStore -> SSL.SSLContext -> IO ()
+makeCAStore SystemCAStore  ctx  = X509.contextLoadSystemCerts ctx
+makeCAStore MozillaCAStore ctx  = SSL.contextSetCAFile ctx =<< mozillaCAStorePath
+makeCAStore (CustomCAStore fp) ctx = SSL.contextSetCAFile ctx fp
+
+-- | make a simple 'SSL.SSLContext' that will validate server and use tls connection
+-- without providing client's own certificate. suitable for connecting server which don't
+-- validate clients.
+--
+makeClientSSLContext :: TrustedCAStore          -- ^ trusted certificates.
+                     -> IO SSL.SSLContext
+makeClientSSLContext tca = withOpenSSL $ do
+    let caStore = makeCAStore tca
+    ctx <- SSL.context
+    caStore ctx
+    SSL.contextSetDefaultCiphers ctx
+    SSL.contextSetVerificationMode ctx (SSL.VerifyPeer True True Nothing)
+    return ctx
+
+-- | make a simple 'SSL.SSLContext' that will validate server and use tls connection
+-- while providing client's own certificate. suitable for connecting server which
+-- validate clients.
+--
+-- The chain certificate must be in PEM format and must be sorted starting with the subject's certificate
+-- (actual client or server certificate), followed by intermediate CA certificates if applicable,
+-- and ending at the highest level (root) CA.
+--
+makeClientSSLContext' :: FilePath       -- ^ public certificate (X.509 format).
+                      -> [FilePath]     -- ^ chain certificate (X.509 format).
+                      -> FilePath       -- ^ private key associated.
+                      -> TrustedCAStore -- ^ server will use these certificates to validate clients.
+                      -> IO SSL.SSLContext
+makeClientSSLContext' pub certs priv tca = withOpenSSL $ do
+    let caStore = makeCAStore tca
+    ctx <- SSL.context
+    caStore ctx
+    SSL.contextSetDefaultCiphers ctx
+    SSL.contextSetCertificateFile ctx pub
+    SSL.contextSetPrivateKeyFile ctx priv
+    mapM_ (SSL.contextSetCertificateChainFile ctx) certs
+    SSL.contextSetVerificationMode ctx (SSL.VerifyPeer True True Nothing)
+    return ctx
+
+-- | make a simple 'SSL.SSLContext' for server without validating client's certificate.
+--
+makeServerSSLContext :: FilePath       -- ^ public certificate (X.509 format).
+                     -> [FilePath]     -- ^ chain certificate (X.509 format).
+                     -> FilePath       -- ^ private key associated.
+                     -> IO SSL.SSLContext
+makeServerSSLContext pub certs priv = withOpenSSL $ do
+    ctx <- SSL.context
+    SSL.contextSetDefaultCiphers ctx
+    SSL.contextSetCertificateFile ctx pub
+    SSL.contextSetPrivateKeyFile ctx priv
+    mapM_ (SSL.contextSetCertificateChainFile ctx) certs
+    return ctx
+
+-- | make a 'SSL.SSLConext' that also validating client's certificate.
+--
+-- This's an alias to 'makeClientSSLContext''.
+--
+makeServerSSLContext' :: FilePath       -- ^ public certificate (X.509 format).
+                      -> [FilePath]     -- ^ chain certificates (X.509 format).
+                      -> FilePath       -- ^ private key associated.
+                      -> TrustedCAStore -- ^ server will use these certificates to validate clients.
+                      -> IO SSL.SSLContext
+makeServerSSLContext' = makeClientSSLContext'
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2016, winterland1989
+
+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 winterland1989 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.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,47 @@
+tcp-streams-openssl
+===================
+
+[![Hackage](https://img.shields.io/hackage/v/tcp-streams-openssl.svg?style=flat)](http://hackage.haskell.org/package/tcp-streams-openssl)
+[![Build Status](https://travis-ci.org/winterland1989/tcp-streams.svg)](https://travis-ci.org/winterland1989/tcp-streams)
+
+This package provides TLS support based on [tcp-streams](http://hackage.haskell.org/package/tcp-streams) using [HsOpenSSL](http://hackage.haskell.org/package/HsOpenSSL). By default `tcp-streams` use `tls` package which is much easier to install but slightly slower.
+
+This package is split from `tcp-streams` due to the difficulties of setting up openssl on many platform. You may need manually passing openssl library path if linker can't find them:
+
+```
+cabal install --extra-include-dirs=/usr/local/opt/openssl/include --extra-lib-dirs=/usr/local/opt/openssl/lib tcp-streams
+```
+
+License
+-------
+
+Copyright (c) 2016, Winterland
+
+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 winterland1989 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.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/System/IO/Streams/OpenSSL.hs b/System/IO/Streams/OpenSSL.hs
new file mode 100644
--- /dev/null
+++ b/System/IO/Streams/OpenSSL.hs
@@ -0,0 +1,186 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+
+-- | This module provides convenience functions for interfacing @io-streams@
+-- with @HsOpenSSL@. @ssl/SSL@ here stand for @HsOpenSSL@ library, not the
+-- deprecated SSL 2.0/3.0 protocol. the receive buffer size is 32752.
+-- sending is unbuffered, anything write into 'OutputStream' will be immediately
+-- send to underlying socket.
+--
+-- The same exceptions rule which applied to TCP apply here, with addtional
+-- 'SSL.SomeSSLException` to be watched out.
+--
+-- This module is intended to be imported @qualified@, e.g.:
+--
+-- @
+-- import qualified "System.IO.Streams.OpenSSL" as SSL
+-- @
+--
+module System.IO.Streams.OpenSSL
+  ( -- * client
+    connect
+  , connectWithVerifier
+  , withConnection
+    -- * server
+  , accept
+    -- * helpers
+  , sslToStreams
+  , close
+    -- * re-export helpers
+  , module Data.OpenSSLSetting
+  ) where
+
+import qualified Control.Exception     as E
+import           Control.Monad         (unless, void)
+import           Data.ByteString.Char8 (ByteString)
+import qualified Data.ByteString.Char8 as S
+import           Data.OpenSSLSetting
+import           Network.Socket        (HostName, PortNumber, Socket)
+import qualified Network.Socket        as N
+import           OpenSSL               (withOpenSSL)
+import           OpenSSL.Session       (SSL, SSLContext)
+import qualified OpenSSL.Session       as SSL
+import qualified OpenSSL.X509          as X509
+import           System.IO.Streams     (InputStream, OutputStream)
+import qualified System.IO.Streams     as Streams
+import qualified System.IO.Streams.TCP as TCP
+
+bUFSIZ :: Int
+bUFSIZ = 32752
+
+-- | Given an existing HsOpenSSL 'SSL' connection, produces an 'InputStream' \/
+-- 'OutputStream' pair.
+--
+sslToStreams :: SSL             -- ^ SSL connection object
+             -> IO (InputStream ByteString, OutputStream ByteString)
+sslToStreams ssl = do
+    is <- Streams.makeInputStream input
+    os <- Streams.makeOutputStream output
+    return (is, os)
+
+  where
+    input = ( do
+        s <- SSL.read ssl bUFSIZ
+        return $! if S.null s then Nothing else Just s
+        ) `E.catch` (\(_::E.SomeException) -> return Nothing)
+
+    output Nothing  = return ()
+    output (Just s) = SSL.write ssl s
+{-# INLINABLE sslToStreams #-}
+
+close :: SSL.SSL -> IO ()
+close ssl = withOpenSSL $ do
+    SSL.shutdown ssl SSL.Unidirectional
+    maybe (return ()) N.close (SSL.sslSocket ssl)
+
+-- | Convenience function for initiating an SSL connection to the given
+-- @('HostName', 'PortNumber')@ combination.
+--
+-- This function will try to verify server's identity using a very simple algorithm,
+-- which may not suit your need:
+--
+-- @
+--   matchDomain :: String -> String -> Bool
+--   matchDomain n1 n2 =
+--       let n1' = reverse (splitDot n1)
+--           n2' = reverse (splitDot n2)
+--           cmp src target = src == "*" || target == "*" || src == target
+--       in and (zipWith cmp n1' n2')
+-- @
+--
+-- If the certificate or hostname is not verified, a 'SSL.ProtocolError' will be thrown.
+--
+connect :: SSLContext           -- ^ SSL context. See the @HsOpenSSL@
+                                -- documentation for information on creating
+                                -- this.
+        -> Maybe String         -- ^ Optional certificate subject name, if set to 'Nothing'
+                                -- then we will try to verify 'HostName' as subject name.
+        -> HostName             -- ^ hostname to connect to
+        -> PortNumber           -- ^ port number to connect to
+        -> IO (InputStream ByteString, OutputStream ByteString, SSL)
+connect ctx vhost host port = withOpenSSL $ do
+    connectWithVerifier ctx verify host port
+  where
+    verify trusted cnname = trusted
+                          && maybe False (matchDomain verifyHost) cnname
+    verifyHost = maybe host id vhost
+    matchDomain :: String -> String -> Bool
+    matchDomain n1 n2 =
+        let n1' = reverse (splitDot n1)
+            n2' = reverse (splitDot n2)
+            cmp src target = src == "*" || target == "*" || src == target
+        in and (zipWith cmp n1' n2')
+    splitDot :: String -> [String]
+    splitDot "" = [""]
+    splitDot x  =
+        let (y, z) = break (== '.') x in
+        y : (if z == "" then [] else splitDot $ drop 1 z)
+
+-- | Connecting with a custom verification callback.
+--
+-- @since 0.6.0.0@
+--
+connectWithVerifier :: SSLContext       -- ^ SSL context. See the @HsOpenSSL@
+                                        -- documentation for information on creating
+                                        -- this.
+                    -> (Bool -> Maybe String -> Bool) -- ^ A verify callback, the first param is
+                                                -- the result of certificate verification, the
+                                                -- second param is the certificate's subject name.
+                    -> HostName             -- ^ hostname to connect to
+                    -> PortNumber           -- ^ port number to connect to
+                    -> IO (InputStream ByteString, OutputStream ByteString, SSL)
+connectWithVerifier ctx f host port = withOpenSSL $ do
+    sock <- TCP.connectSocket host port
+    E.bracketOnError (SSL.connection ctx sock) close $ \ ssl -> do
+        SSL.connect ssl
+        trusted <- SSL.getVerifyResult ssl
+        cert <- SSL.getPeerCertificate ssl
+        subnames <- maybe (return []) (`X509.getSubjectName` False) cert
+        let cnname = lookup "CN" subnames
+            verified = f trusted cnname
+        unless verified (E.throwIO $ SSL.ProtocolError "fail to verify certificate")
+        (is, os) <- sslToStreams ssl
+        return (is, os, ssl)
+
+
+-- | Convenience function for initiating an SSL connection to the given
+-- @('HostName', 'PortNumber')@ combination. The socket and SSL connection are
+-- closed and deleted after the user handler runs.
+--
+withConnection :: SSLContext
+
+
+               -> Maybe String
+               -> HostName
+               -> PortNumber
+               -> (InputStream ByteString -> OutputStream ByteString -> SSL -> IO a)
+                       -- ^ Action to run with the new connection
+               -> IO a
+withConnection ctx subname host port action =
+    E.bracket (connect ctx subname host port) cleanup go
+
+  where
+    go (is, os, ssl) = action is os ssl
+
+    cleanup (_, os, ssl) = E.mask_ $
+        eatException $! Streams.write Nothing os >> close ssl
+
+    eatException m = void m `E.catch` (\(_::E.SomeException) -> return ())
+
+
+-- | Accept a new connection from remote client, return a 'InputStream' / 'OutputStream'
+-- pair and remote 'N.SockAddr', you should call 'TCP.bindAndListen' first.
+--
+-- this operation will throw 'SSL.SomeSSLException' on failure.
+--
+accept :: SSL.SSLContext            -- ^ check "Data.OpenSSLSetting".
+       -> Socket                    -- ^ the listening 'Socket'.
+       -> IO (InputStream ByteString, OutputStream ByteString, SSL.SSL, N.SockAddr)
+accept ctx sock = withOpenSSL $ do
+    (sock', sockAddr) <- N.accept sock
+    E.bracketOnError (SSL.connection ctx sock') close $ \ ssl -> do
+        SSL.accept ssl
+        trusted <- SSL.getVerifyResult ssl
+        unless trusted (E.throwIO $ SSL.ProtocolError "fail to verify certificate")
+        (is, os) <- sslToStreams ssl
+        return (is, os, ssl, sockAddr)
+
diff --git a/tcp-streams-openssl.cabal b/tcp-streams-openssl.cabal
new file mode 100644
--- /dev/null
+++ b/tcp-streams-openssl.cabal
@@ -0,0 +1,58 @@
+name:                tcp-streams-openssl
+version:             0.6.0.0
+synopsis:            Tcp streams using openssl for tls support.
+description:         Tcp streams using openssl for tls support.
+license:             BSD3
+license-file:        LICENSE
+author:              winterland1989
+maintainer:          winterland1989@gmail.com
+homepage:            https://github.com/winterland1989/tcp-streams
+copyright:           (c) Winterland 2016 
+category:            Network
+build-type:          Simple
+extra-source-files:     ChangeLog.md
+                    ,   README.md
+                    ,   test/cert/*.pem
+                    ,   test/cert/*.crt
+                    ,   test/cert/*.key
+cabal-version:       >=1.10
+
+source-repository head
+  type:     git
+  location: git://github.com/winterland1989/tcp-streams.git
+
+library
+  exposed-modules:    Data.OpenSSLSetting
+                  ,   System.IO.Streams.OpenSSL
+
+  -- other-extensions:    
+  build-depends:        base           >=4.7  && < 5.0
+                    ,   network        >=2.3  && < 3.0
+                    ,   bytestring     >= 0.10.2.0
+                    ,   io-streams     >= 1.2 && < 2.0
+                    ,   tcp-streams    >= 0.6 && < 0.7
+                    ,   HsOpenSSL      >=0.10.3 && <0.12
+                    ,   HsOpenSSL-x509-system == 0.1.*
+
+  ghc-options:    -Wall
+  -- hs-source-dirs:      
+  default-language:    Haskell2010
+
+test-suite testsuite
+  type:              exitcode-stdio-1.0
+  Hs-source-dirs:    src test
+  main-is:           Main.hs
+  default-language:  Haskell2010
+  ghc-options:    -Wall -threaded
+  build-depends:        base
+                    ,   io-streams
+                    ,   tcp-streams
+                    ,   tcp-streams-openssl
+                    ,   network
+                    ,   bytestring
+                    ,   HUnit                      >= 1.2      && <2
+                    ,   QuickCheck                 >= 2.3.0.2  && <3
+                    ,   test-framework             >= 0.6      && <0.9
+                    ,   test-framework-hunit       >= 0.2.7    && <0.4
+                    ,   test-framework-quickcheck2 >= 0.2.12.1 && <0.4
+                    ,   directory      == 1.*
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,116 @@
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module Main (main) where
+
+------------------------------------------------------------------------------
+import           Control.Concurrent             (forkIO, newEmptyMVar, putMVar,
+                                                 takeMVar)
+import qualified Control.Exception              as E
+import qualified Network.Socket                 as N
+import           System.Timeout                 (timeout)
+import           Test.Framework
+import           Test.Framework.Providers.HUnit
+import           Test.HUnit                     hiding (Test)
+import qualified Data.ByteString                as B
+import           System.Directory               (removeFile)
+------------------------------------------------------------------------------
+import qualified Data.OpenSSLSetting            as SSL
+import qualified System.IO.Streams              as Stream
+import qualified System.IO.Streams.TCP          as Raw
+import qualified System.IO.Streams.OpenSSL      as SSL
+------------------------------------------------------------------------------
+
+main :: IO ()
+main = defaultMain tests
+  where
+    tests = [ testGroup "TCP" rawTests
+            , testGroup "OpenSSL" sslTests
+            ]
+
+------------------------------------------------------------------------------
+
+rawTests :: [Test]
+rawTests = [ testRawSocket ]
+
+testRawSocket :: Test
+testRawSocket = testCase "network/socket" $
+    N.withSocketsDo $ do
+    x <- timeout (10 * 10^(6::Int)) go
+    assertEqual "ok" (Just ()) x
+
+  where
+    go = do
+        portMVar   <- newEmptyMVar
+        resultMVar <- newEmptyMVar
+        forkIO $ client portMVar resultMVar
+        server portMVar
+        l <- takeMVar resultMVar
+        assertEqual "testSocket" l ["ok"]
+
+    client mvar resultMVar = do
+        _ <- takeMVar mvar
+        (is, os, sock) <- Raw.connect "127.0.0.1" 8888
+        Stream.fromList ["", "ok"] >>= Stream.connectTo os
+        N.shutdown sock N.ShutdownSend
+        Stream.toList is >>= putMVar resultMVar
+        N.close sock
+
+    server mvar = do
+        sock <- Raw.bindAndListen 8888 1024
+        putMVar mvar ()
+        (is, os, csock, _) <- Raw.accept sock
+        os' <- Stream.atEndOfOutput (N.close csock) os
+        os' `Stream.connectTo` is
+
+------------------------------------------------------------------------------
+
+sslTests :: [Test]
+sslTests = [ testSSLSocket, testHTTPS' ]
+
+testSSLSocket :: Test
+testSSLSocket = testCase "network/socket" $
+    N.withSocketsDo $ do
+    x <- timeout (10 * 10^(6::Int)) go
+    assertEqual "ok" (Just ()) x
+
+  where
+    go = do
+        portMVar   <- newEmptyMVar
+        resultMVar <- newEmptyMVar
+        forkIO $ client portMVar resultMVar
+        server portMVar
+        l <- takeMVar resultMVar
+        assertEqual "testSocket" l (Just "ok")
+
+    client mvar resultMVar = do
+        _ <- takeMVar mvar
+        cp <- SSL.makeClientSSLContext (SSL.CustomCAStore "./test/cert/ca.pem")
+        (is, os, ctx) <- SSL.connect cp (Just "Winter") "127.0.0.1" 8890
+        Stream.fromList ["", "ok"] >>= Stream.connectTo os
+        Stream.read is >>= putMVar resultMVar  -- There's no shutdown in tls, so we won't get a 'Nothing'
+        SSL.close ctx
+
+    server mvar = do
+        sp <- SSL.makeServerSSLContext "./test/cert/server.crt" [] "./test/cert/server.key"
+        sock <- Raw.bindAndListen 8890 1024
+        putMVar mvar ()
+        (is, os, ssl, _) <- SSL.accept sp sock
+        os' <- Stream.atEndOfOutput (SSL.close ssl) os
+        os' `Stream.connectTo` is
+
+testHTTPS' :: Test
+testHTTPS' = testCase "network/https" $
+    N.withSocketsDo $ do
+    x <- timeout (10 * 10^(6::Int)) go
+    assertEqual "ok" (Just 1024) x
+  where
+    go = do
+        cp <- SSL.makeClientSSLContext SSL.SystemCAStore
+        (is, os, ctx) <- SSL.connect cp (Just "*.google.com") "www.google.com" 443
+        Stream.write (Just "GET / HTTP/1.1\r\n") os
+        Stream.write (Just "Host: www.google.com\r\n") os
+        Stream.write (Just "\r\n") os
+        bs <- Stream.readExactly 1024 is
+        SSL.close ctx
+        return (B.length bs)
diff --git a/test/cert/ca.key b/test/cert/ca.key
new file mode 100644
--- /dev/null
+++ b/test/cert/ca.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMprzly4sBhDqgmd
+zwuXs7rlPZvRiZ3ySYmgGpTb9QZIPPTVTQ69GUC0WmeLtW/zni0YPUgowDUTf16X
+LDjC3wT0kUvk6ek/rQgs/AToJcWBfYxCSElPRSGb5eiXQX8N+HPNXdViJEUvhoDv
+3LgltliFZiY3BxDJ3tkWJOL7lshtAgMBAAECgYBnM4GZyluVc2IM1xVJXsW2gsvf
+VnxoN7AAZ81FmcMZudjCJsHLwuNOFuWEpzkQ488ARLxxvr0IEnG8wyw7oDbdQWGd
+AKjdTZgdkfAR9MIQCE4L3C5ZFfw4Slq6JvmucIsw7ERiulShcWrVMvseVAEYMNTm
+40OWTiWfA1qwc+ANrQJBAP4UpSgD3FY8rJSznUXJCXwougrWwZQYuaYx4MmR2QGV
+GIq8HF6QVVr9XzFAD/WIjtVm7nM+3pIS1ST9HPnQOncCQQDL80JMeNdMrXNqJZsy
+3oR0mAFXhXi2MObBnnOHce44QwNO6TqyqPhLx7M55MwNNyA9/YTi1MmhWkLWRdTt
+dek7AkEA9JoDdUZiNFMtAer4mVo022aJ1C1zJpO3Bhw2f1b9Rty2R7lYxmDFC1eo
+8MzvkDzq5N626BO6SX3/3CAgaQ7heQJAHHyz6/6NBBbOIityjB5sneSFe3YXMEuQ
+T8cUF/0f6xfhJGqLWl0joWIZdKKypb3ncQEySIS0TSdQYqGKZkir9QJAbW1uPEy4
+7g0yXwG3YtJNE2UD9JIb+qzejeAAKcdglqrEZpJNdGpjG6hlp3XWqM6YXexrEfTs
+CCskhGwSQe/RdA==
+-----END PRIVATE KEY-----
diff --git a/test/cert/ca.pem b/test/cert/ca.pem
new file mode 100644
--- /dev/null
+++ b/test/cert/ca.pem
@@ -0,0 +1,15 @@
+-----BEGIN TRUSTED CERTIFICATE-----
+MIICTTCCAbYCCQCy3IPKsROAWjANBgkqhkiG9w0BAQsFADBrMQswCQYDVQQGEwJD
+TjETMBEGA1UECgwKV2ludGVybGFuZDENMAsGA1UECwwEVGVzdDEPMA0GA1UEAwwG
+V2ludGVyMScwJQYJKoZIhvcNAQkBFhh3aW50ZXJsYW5kMTk4OUBnbWFpbC5jb20w
+HhcNMTYwNzE5MDYzNjA5WhcNMTcwNzE5MDYzNjA5WjBrMQswCQYDVQQGEwJDTjET
+MBEGA1UECgwKV2ludGVybGFuZDENMAsGA1UECwwEVGVzdDEPMA0GA1UEAwwGV2lu
+dGVyMScwJQYJKoZIhvcNAQkBFhh3aW50ZXJsYW5kMTk4OUBnbWFpbC5jb20wgZ8w
+DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMprzly4sBhDqgmdzwuXs7rlPZvRiZ3y
+SYmgGpTb9QZIPPTVTQ69GUC0WmeLtW/zni0YPUgowDUTf16XLDjC3wT0kUvk6ek/
+rQgs/AToJcWBfYxCSElPRSGb5eiXQX8N+HPNXdViJEUvhoDv3LgltliFZiY3BxDJ
+3tkWJOL7lshtAgMBAAEwDQYJKoZIhvcNAQELBQADgYEATPckjNo9SmFuSQWI74ec
+xvghpo/wG/dR7JHBcPMCftRmK5eKPkqrrtHhQz5LA61jhW+uL0q2+W6/oE+GvZnv
+QWaMtuN0YKdPM4yVQR51AMZwwQd7OXo8qgaCAoI7Be8JMzOlS3pERLlupFpn8D9e
+Te0iF3xlZX1kDbWUnS++oGM=
+-----END TRUSTED CERTIFICATE-----
diff --git a/test/cert/client.crt b/test/cert/client.crt
new file mode 100644
--- /dev/null
+++ b/test/cert/client.crt
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICJTCCAY4CAQEwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCQ04xEzARBgNV
+BAoMCldpbnRlcmxhbmQxDTALBgNVBAsMBFRlc3QxDzANBgNVBAMMBldpbnRlcjEn
+MCUGCSqGSIb3DQEJARYYd2ludGVybGFuZDE5ODlAZ21haWwuY29tMB4XDTE2MDcx
+ODA5NDYwNloXDTE3MDcxODA5NDYwNlowSzELMAkGA1UEBhMCQ04xEzARBgNVBAMM
+CldpbnRlcmxhbmQxJzAlBgkqhkiG9w0BCQEWGHdpbnRlcmxhbmQxOTg5QGdtYWls
+LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3fb1pYRCExJFpKc2ai2i
+B3CRsosZS4aCWAghVovCdmq8GOPcfH+IMxhX0hdUluKWOltj4Kl4Chi7iiZUyGNq
+kV8CkKJ62WTwqgXUqJ4ku1eHKYXb0WSBj17Y4vCtMMAF/mmB9E/cxY08KOH3/Smp
+RqmwDNoPymxmU7VCir256N0CAwEAATANBgkqhkiG9w0BAQsFAAOBgQDAQB1VMXZd
+nK/4gW5/vnoq/UOb+kmvoUi9ZPmGSopW2BHop3YEL5IkPn2UaHZH+edU8dkj79LV
+xpg0yI3CpTJE+purqNBk799mpLii2pkoDwbnIn1hf7XmPInBNJJvRjqTMlfpaWb4
+fGI6U0A27XtWi+6zy5s94arB4uoCrdvUTA==
+-----END CERTIFICATE-----
diff --git a/test/cert/client.key b/test/cert/client.key
new file mode 100644
--- /dev/null
+++ b/test/cert/client.key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQDd9vWlhEITEkWkpzZqLaIHcJGyixlLhoJYCCFWi8J2arwY49x8
+f4gzGFfSF1SW4pY6W2PgqXgKGLuKJlTIY2qRXwKQonrZZPCqBdSoniS7V4cphdvR
+ZIGPXtji8K0wwAX+aYH0T9zFjTwo4ff9KalGqbAM2g/KbGZTtUKKvbno3QIDAQAB
+AoGAevoWw2txiEt5Vm5mUZGS0fhmYLt8ekG9+bQXdHHefelI6allQX0PIu/7yCSw
+8x/7B74WqiR6o21sinAOTS/3nCcRKoaass20VIOI0DJLwOXJNliuN9DEr02uoifs
+hRUD7MTYAETCEQ58HFldgGxU98uEPcCi1HFEhrymK9EUjYECQQDyFLJ+qK+vu/m5
+ydtE+NKu5n8MyFWuMgHeE3FEhGlbQvUOeMwj82XAQN7g8XXiSkpIrHevA7iOJ3jO
+0NcXS+wxAkEA6ropuMmJk4oKDLEqTpxBbS2ILjmfVoGjZiKjKZEo9dZ/RnFz4zEB
+8SC4h55hpRp0gBBOh/QFNHcPko1WBq3YbQJAPlNX1UZG3T7PP6cZvfs1+vO7GCZn
+8M5NLsjgq5xPp8BoaU5ueH8M3l+VQmLIT/eCgo1szvFtTaQZ9V1NU2EnsQJAQJGt
+YHOwMLHMSemCZdV9+faIe47GUhmfRT1J/Ok9h0LWCB61bk3Q5u/FUykyWySH36Kc
+t7FcrS4DTqEqhPPVkQJBAPFKvcd9z+AuUlnB9/VQbaJGSJ3VDqInJkRu6GVXMvH/
+6VP3gdjAf4Jdu2sdTwQv/rSuvZg/6ngWcj6CXfbb0kw=
+-----END RSA PRIVATE KEY-----
diff --git a/test/cert/server.crt b/test/cert/server.crt
new file mode 100644
--- /dev/null
+++ b/test/cert/server.crt
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIIChDCCAe2gAwIBAgIJAMddlD79DkOBMA0GCSqGSIb3DQEBCwUAMGsxCzAJBgNV
+BAYTAkNOMRMwEQYDVQQKDApXaW50ZXJsYW5kMQ0wCwYDVQQLDARUZXN0MQ8wDQYD
+VQQDDAZXaW50ZXIxJzAlBgkqhkiG9w0BCQEWGHdpbnRlcmxhbmQxOTg5QGdtYWls
+LmNvbTAeFw0xNjA3MTkwNzQwMjJaFw0xNzA3MTkwNzQwMjJaMIGAMQswCQYDVQQG
+EwJDTjETMBEGA1UECAwKU29tZS1TdGF0ZTETMBEGA1UECgwKV2ludGVybGFuZDEN
+MAsGA1UECwwEVGVzdDEPMA0GA1UEAwwGV2ludGVyMScwJQYJKoZIhvcNAQkBFhh3
+aW50ZXJsYW5kMTk4OUBnbWFpbC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ
+AoGBALVw5Aspmpujd76UGQf6mjutf6DWlmnXCfhiLDOMj+QGonBvbxrbRpIfjpWa
+PfGDS/9mwYgDNAaU7cfUqEziwSgjTSVPF5PR721fxYFmG/269qGIuJ6i5ds9t7nQ
+JcaBZAxN22Kw3mydZAJlGdG75pO5tTQRQYsG73XcX0n1wfBXAgMBAAGjGjAYMAkG
+A1UdEwQCMAAwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBCwUAA4GBAGAcC0nVZYb5
+XnS6VXF/HO9mLGb8B67GHDROND0JdS80s2sS063P4Lfks1Sg8KddybYfX+NPGliR
+bo9VWBKe8gpegyyCrEb9F60+/SqTAlg3tO4q0AMkjFiyeOalvPz4cp464eatJ9s2
+vNCJSOqZ6nYIoDl0K9vmVckYaQxS+2p4
+-----END CERTIFICATE-----
diff --git a/test/cert/server.key b/test/cert/server.key
new file mode 100644
--- /dev/null
+++ b/test/cert/server.key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQC1cOQLKZqbo3e+lBkH+po7rX+g1pZp1wn4YiwzjI/kBqJwb28a
+20aSH46Vmj3xg0v/ZsGIAzQGlO3H1KhM4sEoI00lTxeT0e9tX8WBZhv9uvahiLie
+ouXbPbe50CXGgWQMTdtisN5snWQCZRnRu+aTubU0EUGLBu913F9J9cHwVwIDAQAB
+AoGAOr7RZvfSch/sLk0/CYFPHJFhKE8yJhSUytHmY85X7ElloKfDvltOrxL+lFt7
+QM309j1r3cDDwHnJvxCQaUxlozB0JMDqWRVtTx//0NXNW8495H8Rn1Xwwyd1LY+e
+2+jGTSKNhvSDXHPHJS93FgbbYoCXvGkVGx2mpDNksDrWDpECQQDkuV7U4KqtapU9
+73u2GKnIpJDx3Hjm8N7DDfaA5SS/3kfIABZBfWJMCIbsSRTSvN9s3XsVUEvXpjX1
+4uhW4Ck/AkEAyxQIPbuuqv+6bN3qHMLxjVGiNc92anWCifsy+4THWpWV5Q0F4WX5
+pIxL3pbuIqJMXQfTCLBAifR5GTT/0XQa6QJBAImWFLyblTASQEpsiA+HEIL4s5Q6
+GqRZWrcc7B6nOI8OaEGgA8NLaFjyfC8g2xzVrtTu+j5c+fJ0MluCLl8sIsMCQAVk
+RsO80+peV8jEK48P7fHelPvwwigZbpnTPYtH/zL8fbpTGjDd0D76KpmCUFhDDtv5
+dTTp2QzQnNZ6fcBF4OECQCkeFGnhs/YLyev2WsFx0rI8AlrjCeGq+t2HSv+/vc8M
+Zv4P6QLK46sX0wy7xkCdtSzhd6tD/HCl/KT0y45q+DY=
+-----END RSA PRIVATE KEY-----
