Browse Source

!!!TlsSettings changed!!!
Added some tests, and fixed some bugs they found.

Marcos Dumay de Medeiros 8 years ago
parent
commit
ff97fd0f01
12 changed files with 326 additions and 74 deletions
  1. 16 13
      src/System/IO/Uniform/Targets.hs
  2. 48 16
      src/System/IO/Uniform/ds.c
  3. 1 1
      src/System/IO/Uniform/ds.h
  4. 16 0
      test/Base.hs
  5. 88 0
      test/Blocking.hs
  6. 0 42
      test/Lazyness.hs
  7. 82 0
      test/Targets.hs
  8. 22 0
      test/cert.pem
  9. 8 0
      test/dh.pem
  10. 28 0
      test/key.pem
  11. 1 0
      test/testFile
  12. 16 2
      uniform-io.cabal

+ 16 - 13
src/System/IO/Uniform/Targets.hs

@@ -2,6 +2,7 @@
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
 {-# LANGUAGE InterruptibleFFI #-}
 {-# LANGUAGE InterruptibleFFI #-}
+{-# LANGUAGE EmptyDataDecls #-}
 
 
 module System.IO.Uniform.Targets (TlsSettings(..), UniformIO(..), SocketIO, FileIO, TlsStream, BoundedPort, SomeIO(..), connectTo, connectToHost, bindPort, accept, openFile, getPeer, closePort) where
 module System.IO.Uniform.Targets (TlsSettings(..), UniformIO(..), SocketIO, FileIO, TlsStream, BoundedPort, SomeIO(..), connectTo, connectToHost, bindPort, accept, openFile, getPeer, closePort) where
 
 
@@ -24,10 +25,10 @@ import GHC.Conc (closeFdWith, threadWaitRead, threadWaitWrite)
 import System.Posix.Types (Fd(..))
 import System.Posix.Types (Fd(..))
 
 
 -- | Settings for starttls functions.
 -- | Settings for starttls functions.
-data TlsSettings = TlsSettings {tlsPrivateKeyFile :: String, tlsCertificateChainFile :: String} deriving (Read, Show)
+data TlsSettings = TlsSettings {tlsPrivateKeyFile :: String, tlsCertificateChainFile :: String, tlsDHParametersFile :: String} deriving (Read, Show)
 
 
 instance Default TlsSettings where
 instance Default TlsSettings where
-  def = TlsSettings "" ""
+  def = TlsSettings "" "" ""
 
 
 -- |
 -- |
 -- Typeclass for uniform IO targets.
 -- Typeclass for uniform IO targets.
@@ -96,11 +97,13 @@ instance UniformIO SocketIO where
     closeFdWith closeFd f
     closeFdWith closeFd f
   startTls st s = withCString (tlsCertificateChainFile st) (
   startTls st s = withCString (tlsCertificateChainFile st) (
     \cert -> withCString (tlsPrivateKeyFile st) (
     \cert -> withCString (tlsPrivateKeyFile st) (
-      \key -> do
-        r <- c_startSockTls (sock s) cert key
-        if r == nullPtr
-          then throwErrno "could not start TLS"
-          else return . TlsStream $ r
+      \key -> withCString (tlsDHParametersFile st) (
+        \para -> do
+          r <- c_startSockTls (sock s) cert key para
+          if r == nullPtr
+            then throwErrno "could not start TLS"
+            else return . TlsStream $ r
+        )
       )
       )
     )
     )
   isSecure _ = False
   isSecure _ = False
@@ -259,13 +262,13 @@ closeFd (Fd f) = c_closeFd f
 closePort :: BoundedPort -> IO ()
 closePort :: BoundedPort -> IO ()
 closePort p = c_closePort (lis p)
 closePort p = c_closePort (lis p)
 
 
-foreign import ccall safe "getPort" c_getPort :: CInt -> IO (Ptr Nethandler)
-foreign import ccall safe "createFromHandler" c_accept :: Ptr Nethandler -> IO (Ptr Ds)
+foreign import ccall interruptible "getPort" c_getPort :: CInt -> IO (Ptr Nethandler)
+foreign import ccall interruptible "createFromHandler" c_accept :: Ptr Nethandler -> IO (Ptr Ds)
 foreign import ccall safe "createFromFileName" c_createFile :: CString -> IO (Ptr Ds)
 foreign import ccall safe "createFromFileName" c_createFile :: CString -> IO (Ptr Ds)
-foreign import ccall safe "createToIPv4Host" c_connect4 :: CUInt -> CInt -> IO (Ptr Ds)
-foreign import ccall safe "createToIPv6Host" c_connect6 :: Ptr CUChar -> CInt -> IO (Ptr Ds)
+foreign import ccall interruptible "createToIPv4Host" c_connect4 :: CUInt -> CInt -> IO (Ptr Ds)
+foreign import ccall interruptible "createToIPv6Host" c_connect6 :: Ptr CUChar -> CInt -> IO (Ptr Ds)
 
 
-foreign import ccall safe "startSockTls" c_startSockTls :: Ptr Ds -> CString -> CString -> IO (Ptr TlsDs)
+foreign import ccall interruptible "startSockTls" c_startSockTls :: Ptr Ds -> CString -> CString -> CString -> IO (Ptr TlsDs)
 foreign import ccall safe "getPeer" c_getPeer :: Ptr Ds -> Ptr CUInt -> Ptr CUChar -> Ptr CInt -> IO (CInt)
 foreign import ccall safe "getPeer" c_getPeer :: Ptr Ds -> Ptr CUInt -> Ptr CUChar -> Ptr CInt -> IO (CInt)
 
 
 foreign import ccall safe "getFd" c_getFd :: Ptr Ds -> CInt
 foreign import ccall safe "getFd" c_getFd :: Ptr Ds -> CInt
@@ -273,7 +276,7 @@ foreign import ccall safe "closeFd" c_closeFd :: CInt -> IO ()
 
 
 foreign import ccall safe "prepareToClose" c_prepareToClose :: Ptr Ds -> IO CInt
 foreign import ccall safe "prepareToClose" c_prepareToClose :: Ptr Ds -> IO CInt
 foreign import ccall safe "closeHandler" c_closePort :: Ptr Nethandler -> IO ()
 foreign import ccall safe "closeHandler" c_closePort :: Ptr Nethandler -> IO ()
-foreign import ccall safe "closeTlsDs" c_closeTls :: Ptr TlsDs -> IO (Ptr Ds)
+foreign import ccall safe "closeTls" c_closeTls :: Ptr TlsDs -> IO (Ptr Ds)
 
 
 foreign import ccall interruptible "sendDs" c_send :: Ptr Ds -> Ptr CChar -> CInt -> IO CInt
 foreign import ccall interruptible "sendDs" c_send :: Ptr Ds -> Ptr CChar -> CInt -> IO CInt
 foreign import ccall interruptible "stdDsSend" c_sendStd :: Ptr CChar -> CInt -> IO CInt
 foreign import ccall interruptible "stdDsSend" c_sendStd :: Ptr CChar -> CInt -> IO CInt

+ 48 - 16
src/System/IO/Uniform/ds.c

@@ -25,14 +25,14 @@ void *clear(void *ptr){
   return NULL;
   return NULL;
 }
 }
 
 
-void loadOpenSSL(){
+void loadOpenSSL(const char *dh){
   if(!openSslLoaded){
   if(!openSslLoaded){
-    openSslLoaded = 1;
     SSL_load_error_strings();
     SSL_load_error_strings();
     ERR_load_BIO_strings();
     ERR_load_BIO_strings();
     ERR_load_crypto_strings();
     ERR_load_crypto_strings();
     SSL_library_init();
     SSL_library_init();
-    OpenSSL_add_all_algorithms();
+    OpenSSL_add_all_algorithms();    
+    openSslLoaded = 1;    
   }
   }
 }
 }
 
 
@@ -96,7 +96,7 @@ ds createFromFile(int f){
 }
 }
 
 
 ds createFromFileName(const char *f){
 ds createFromFileName(const char *f){
-  int fd = open(f, O_CREAT | O_RDWR);
+  int fd = open(f, O_CREAT | O_RDWR, 0666);
   if(fd == -1){
   if(fd == -1){
     return NULL;
     return NULL;
   }
   }
@@ -201,10 +201,11 @@ int prepareToClose(ds d){
   return fd;
   return fd;
 }
 }
 
 
-ds closeTlsDs(tlsDs d){
+ds closeTls(tlsDs d){
   ds original = d->original;
   ds original = d->original;
   SSL_shutdown(d->s);
   SSL_shutdown(d->s);
-  SSL_shutdown(d->s);
+  //No bidirectional shutdown supported
+  //SSL_shutdown(d->s);
   SSL_free(d->s);
   SSL_free(d->s);
   free(d);
   free(d);
   return original;
   return original;
@@ -215,8 +216,10 @@ void closeHandler(nethandler h){
   free(h);
   free(h);
 }
 }
 
 
-tlsDs startSockTls(ds d, const char *cert, const char *key){
-  loadOpenSSL();
+tlsDs startSockTls(ds d, const char *cert, const char *key, const char *dh){
+  fprintf(stderr, "Starting TLS\n");
+  loadOpenSSL(dh);
+  fprintf(stderr, "OpenSSL loaded\n");
   SSL_CTX * ctx = NULL;
   SSL_CTX * ctx = NULL;
   if(d->server)
   if(d->server)
     ctx = SSL_CTX_new(TLSv1_server_method());
     ctx = SSL_CTX_new(TLSv1_server_method());
@@ -224,19 +227,39 @@ tlsDs startSockTls(ds d, const char *cert, const char *key){
     ctx = SSL_CTX_new(TLSv1_client_method());
     ctx = SSL_CTX_new(TLSv1_client_method());
   if(!ctx)
   if(!ctx)
     return NULL;
     return NULL;
+  fprintf(stderr, "Got CTX\n");
+  if(d->server){
+    FILE *dhfile = fopen(dh, "r");
+    fprintf(stderr, "dh is %s\n", dh);
+    fprintf(stderr, "dhfile is %x\n", dhfile);
+    DH *dhdt = PEM_read_DHparams(dhfile, NULL, NULL, NULL);
+    fprintf(stderr, "dhdt is %x\n", dhdt);
+    fclose(dhfile);
+    if(SSL_CTX_set_tmp_dh(ctx, dhdt) <= 0){
+      int f = prepareToClose(d);
+      closeFd(f);
+      clear(dhdt);
+      return clear(ctx);    
+    }
+    fprintf(stderr, "Set DH parameters\n");
+  }
   SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
   SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
+  fprintf(stderr, "Set CTX options\n");
+  fprintf(stderr, "Set options\n");
   if(cert)
   if(cert)
     if(SSL_CTX_use_certificate_chain_file(ctx, cert) != 1){
     if(SSL_CTX_use_certificate_chain_file(ctx, cert) != 1){
       int f = prepareToClose(d);
       int f = prepareToClose(d);
       closeFd(f);
       closeFd(f);
       return clear(ctx);
       return clear(ctx);
     }
     }
+  fprintf(stderr, "Set cert\n");
   if(key)
   if(key)
     if(SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) != 1){
     if(SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) != 1){
       int f = prepareToClose(d);
       int f = prepareToClose(d);
       closeFd(f);
       closeFd(f);
       return clear(ctx);
       return clear(ctx);
     }
     }
+  fprintf(stderr, "Set key\n");
   tlsDs t = (tlsDs)malloc(sizeof(s_tlsDs));
   tlsDs t = (tlsDs)malloc(sizeof(s_tlsDs));
   t->original = d;
   t->original = d;
   if(!(t->s = SSL_new(ctx))){
   if(!(t->s = SSL_new(ctx))){
@@ -245,30 +268,39 @@ tlsDs startSockTls(ds d, const char *cert, const char *key){
     clear(ctx);
     clear(ctx);
     return clear(t);
     return clear(t);
   }
   }
+  fprintf(stderr, "Got SSL\n");
   if(!SSL_set_fd(t->s, d->fd)){
   if(!SSL_set_fd(t->s, d->fd)){
-    closeTlsDs(t);
+    closeTls(t);
     return NULL;
     return NULL;
   }
   }
+  fprintf(stderr, "Set fd\n");
   int retry = 1;
   int retry = 1;
   int e;
   int e;
   while(retry){
   while(retry){
     retry = 0;
     retry = 0;
-    if(d->server)
+    if(d->server){
+      SSL_set_accept_state(t->s);
       e = SSL_accept(t->s);
       e = SSL_accept(t->s);
-    else
+    }else{
+      SSL_set_connect_state(t->s);
       e = SSL_connect(t->s);
       e = SSL_connect(t->s);
+    }
     if(e <= 0){
     if(e <= 0){
-      retry = 1;
-      int erval = SSL_get_error(t->s, e);
+      unsigned long erval = SSL_get_error(t->s, e);
+      char ertxt[300];
+      ERR_error_string(erval, ertxt);
+      fprintf(stderr, "SSL Error: %s\n", ertxt);
+      ERR_print_errors(t->s->bbio);
       if((erval == SSL_ERROR_WANT_READ) || (erval == SSL_ERROR_WANT_WRITE)){
       if((erval == SSL_ERROR_WANT_READ) || (erval == SSL_ERROR_WANT_WRITE)){
-	
+	//Here goes support to non-blocking IO, once it's supported
+	//retry = 1;
       }else{
       }else{
-	//ERR_print_errors(t->s->bbio);
-	closeTlsDs(t);
+	closeTls(t);
 	return NULL;
 	return NULL;
       }
       }
     }
     }
   }
   }
+  fprintf(stderr, "TLS started\n");
   return t;
   return t;
 }
 }
 
 

+ 1 - 1
src/System/IO/Uniform/ds.h

@@ -36,7 +36,7 @@ ds createFromHandler(nethandler);
 ds createToIPv4Host(const unsigned long, const int);
 ds createToIPv4Host(const unsigned long, const int);
 ds createToIPv6Host(const unsigned char[16], const int);
 ds createToIPv6Host(const unsigned char[16], const int);
 
 
-tlsDs startSockTls(ds, const char*, const char*);
+tlsDs startSockTls(ds, const char*, const char*, const char*);
 
 
 int getPeer(ds, unsigned long*, unsigned char[16], int*);
 int getPeer(ds, unsigned long*, unsigned char[16], int*);
 
 

+ 16 - 0
test/Base.hs

@@ -0,0 +1,16 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Base (simpleTest) where
+
+import Distribution.TestSuite
+
+simpleTest :: String -> IO Progress -> Test
+simpleTest n t = 
+  let test = TestInstance
+        {run = t,
+         name = n,
+         tags = [],
+         options = [],
+         setOption = \_ _ -> Right test
+        }
+  in Test test

+ 88 - 0
test/Blocking.hs

@@ -0,0 +1,88 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Blocking (tests) where
+
+import Distribution.TestSuite
+import Base (simpleTest)
+import Control.Concurrent(forkIO) 
+import qualified System.IO.Uniform as U
+import qualified System.IO.Uniform.Streamline as S
+import System.Timeout (timeout)
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Char8 as C8
+import qualified Data.Attoparsec.ByteString as A
+--import Control.Monad.IO.Class (liftIO)
+
+tests :: IO [Test]
+tests = return [
+  simpleTest "recieveLine"
+  (successTimeout "A test\n" (restoreLine S.receiveLine)),
+  simpleTest "runAttoparsec with successful parser"
+  (successTimeout "abcde" (parseBS (A.string "abcde"))),
+  simpleTest "runAttoparsec with failed parser"
+  (failTimeout "abcde" (parseBS (A.string "c"))),
+  simpleTest "lazyRecieveLine"
+  (successTimeout "Another test\n" (concatLine S.lazyRecieveLine)),
+  simpleTest "lazyReceiveN"
+  (failTimeout "abcde" (concatLine (S.lazyReceiveN 5)))
+  ]
+
+parseBS :: A.Parser ByteString -> S.Streamline IO ByteString
+parseBS p = do
+  t <- S.runAttoparsec p
+  case t of
+    Left e -> return . C8.pack $ e
+    Right s -> return s
+
+restoreLine :: S.Streamline IO ByteString -> S.Streamline IO ByteString
+restoreLine f = do
+  l <- f
+  return $ BS.concat [l, "\n"]
+  
+concatLine :: S.Streamline IO [ByteString] -> S.Streamline IO ByteString
+concatLine f = do
+  l <- f
+  return . BS.concat $ l
+
+-- | Tests the given command, by sending a string to an echo and running the command.
+--   the command must not block.
+successTimeout :: ByteString -> S.Streamline IO ByteString -> IO Progress
+successTimeout txt f = do
+  recv <- U.bindPort 8888
+  forkIO $ S.withClient (\_ _ -> do
+                            l <- f
+                            S.send l
+                            return ()
+                        ) recv
+  r' <- timeout 1000000 $ S.withServer (do
+                                     S.send txt
+                                     t <- f
+                                     if t == txt
+                                       then return . Finished $ Pass
+                                       else return . Finished . Fail . C8.unpack $ t
+                                 ) "127.0.0.1" 8888
+  U.closePort recv
+  case r' of
+    Just r -> return r
+    Nothing -> return . Finished . Fail $ "Execution blocked"
+
+-- | Tests the given command, by sending text trough the network and running it.
+--   Does not care about the result of the command, just wether it blocks.
+failTimeout :: ByteString -> S.Streamline IO ByteString -> IO Progress
+failTimeout txt f = do
+  recv <- U.bindPort 8888
+  forkIO $ S.withClient (\_ _ -> do
+                            f
+                            S.send "\n"
+                            return ()
+                        ) recv
+  r' <- timeout 1000000 $ S.withServer (do
+                                     S.send txt
+                                     S.receiveLine
+                                     return . Finished $ Pass
+                                 ) "127.0.0.1" 8888
+  U.closePort recv
+  case r' of
+    Just r -> return r
+    Nothing -> return . Finished . Fail $ "Execution blocked"

+ 0 - 42
test/Lazyness.hs

@@ -1,42 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module Lazyness (tests) where
-
-import Distribution.TestSuite
-import Control.Concurrent(forkIO) 
-import qualified System.IO.Uniform as U
-import qualified System.IO.Uniform.Streamline as S
-import System.Timeout (timeout)  
-
-tests :: IO [Test]
-tests = return [Test readLine]
-  where
-    readLine = TestInstance
-      {run = testReadLine,
-       name = "Lazyness of readLine",
-       tags = [],
-       options = [],
-       setOption = \_ _ -> Right readLine
-      }
-      
-testReadLine :: IO Progress
-testReadLine = do
-  recv <- U.bindPort 8888
-  forkIO $ S.withClient (\_ _ -> do
-                            l <- S.receiveLine
-                            S.send l
-                            S.send "\n"
-                            return ()
-                        ) recv
-  r <- timeout 1000000 $ S.withServer (do
-                                     S.send "A test\n"
-                                     S.receiveLine
-                                     return ()
-                                 ) "127.0.0.1" 8888
-  case r of
-    Just _ -> return . Finished $ Pass
-    Nothing -> return . Finished . Fail $ "Timeout on Streamline.readLine"
-
-
-
-

+ 82 - 0
test/Targets.hs

@@ -0,0 +1,82 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Targets (tests) where
+
+import Distribution.TestSuite
+import Base (simpleTest)
+import Control.Concurrent(forkIO) 
+import qualified System.IO.Uniform as U
+import System.Timeout (timeout)
+import qualified Data.ByteString.Char8 as C8
+
+tests :: IO [Test]
+tests = return [
+  simpleTest "network" testNetwork,
+  simpleTest "file" testFile
+  --Test framework fails on this test
+  --actual script works as expected
+  --simpleTest "network TLS" testTls
+  ]
+
+testNetwork :: IO Progress
+testNetwork = do
+  recv <- U.bindPort 8888
+  forkIO $ do
+    s <- U.accept recv
+    l <- U.uRead s 100
+    U.uPut s l
+    U.uClose s
+    return ()
+  r' <- timeout 1000000 $ do
+        s <- U.connectToHost "127.0.0.1" 8888
+        let l = "abcdef\n"
+        U.uPut s l
+        l' <- U.uRead s 100
+        U.uClose s
+        if l == l'
+          then return . Finished $ Pass
+          else return . Finished . Fail . C8.unpack $ l'
+  U.closePort recv
+  case r' of
+    Just r -> return r
+    Nothing -> return . Finished . Fail $ "Execution blocked"
+
+testFile :: IO Progress
+testFile = do
+  let file = "test/testFile"
+  s <- U.openFile file
+  let l = "abcde\n"
+  U.uPut s l
+  U.uClose s
+  s' <- U.openFile file
+  l' <- U.uRead s' 100
+  U.uClose s'
+  if l == l'
+    then return . Finished $ Pass
+    else return . Finished . Fail . C8.unpack $ l'
+
+testTls :: IO Progress
+testTls = do
+  recv <- U.bindPort 8888
+  let set = U.TlsSettings "test/key.pem" "test/cert.pem" "test/dh.pem"
+  forkIO $ do
+    s' <- U.accept recv
+    s <- U.startTls set s'
+    l <- U.uRead s 100
+    U.uPut s l
+    U.uClose s
+    return ()
+  r' <- timeout 1000000 $ do
+    s' <- U.connectToHost "127.0.0.1" 8888
+    s <- U.startTls set s'
+    let l = "abcdef\n"
+    U.uPut s l
+    l' <- U.uRead s 100
+    U.uClose s
+    if l == l'
+      then return . Finished $ Pass
+      else return . Finished . Fail . C8.unpack $ l'
+  U.closePort recv
+  case r' of
+    Just r -> return r
+    Nothing -> return . Finished . Fail $ "Execution blocked"

+ 22 - 0
test/cert.pem

@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDoTCCAomgAwIBAgIJAM0NsBud2MA8MA0GCSqGSIb3DQEBCwUAMGcxCzAJBgNV
+BAYTAkJSMREwDwYDVQQIDAhCcmFzaWxpYTERMA8GA1UEBwwIQnJhc2lsaWExDjAM
+BgNVBAoMBVRlc3RlMQ4wDAYDVQQLDAVUZXN0ZTESMBAGA1UEAwwJbG9jYWxob3N0
+MB4XDTE1MDYyODAwNTQzNFoXDTE2MDYyNzAwNTQzNFowZzELMAkGA1UEBhMCQlIx
+ETAPBgNVBAgMCEJyYXNpbGlhMREwDwYDVQQHDAhCcmFzaWxpYTEOMAwGA1UECgwF
+VGVzdGUxDjAMBgNVBAsMBVRlc3RlMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIp7iRgRg9iTsI3nym2yZ6AlNZyZ/O
+lslcBCcZfOhMPKQXpipTMnV2cnSLlPQrrb0Oc4SjbIHfmIAQRF2UbihDV/ox6Osd
+V5Pim61o4IK4IeUlQnIg+zo/AyE9BC2eHq87YkYr8t0hmEywMk5yfvRgBdl6R7lc
+/kQ63TjBED0LINggKPkFlsvmgFlv5JVDGAJRgEbnfrV4k1AsIfArvCynSpuEpeSV
+dOaDf1lJoO7Dab+gln/aOq7QeI4BYR+R2X1bDgIRIa4HJnN5n10yMotVF5Q27O6d
+2hW13V8Wo/qpPYCOqiGoy//iCmb7JWPc2h7tR2wES6I9vl8ic5lDn1yTAgMBAAGj
+UDBOMB0GA1UdDgQWBBSpO3vqoG9vRq78kBDFEsUEvZA4wjAfBgNVHSMEGDAWgBSp
+O3vqoG9vRq78kBDFEsUEvZA4wjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA
+A4IBAQDG2mBc3A0lZ3iM0oK5FiJN46LeJbicFPGgh2iiYsG+GOSXRfDEY/DMeEfL
+ukZCEcAUBygFxisCPR9rs5ReJIuNl7apH687OgiuSqC5OKPxcAMDgY4ECbqcBWp7
+sPfJfG9RZskwhn+yZpnyBOGGarpzpBTa8sahAppGCugSvy+Dpo4xOqiDRwByEa93
+Vzfb6pWBBeqw4i2z4XqctkqPh1pqnjdRpg0vgjwJLxFxsMXzpQq6vNkmSBSnAgnC
+L5lZ4ZcHV2hMyupToHaNEaJYw6O7SPNZr4+ODcPFHg3QwRyXtXypqh8y02Z6Fia+
+OMBZ5rFnNokcXiRSKhFJnWVivg1u
+-----END CERTIFICATE-----

+ 8 - 0
test/dh.pem

@@ -0,0 +1,8 @@
+-----BEGIN DH PARAMETERS-----
+MIIBCAKCAQEAkMksyk6ldPy+OqcR5Zo3L5dQUEgKmx6TkZaKxNnRnuisZ/f4fezh
+ArxDMmamAtOQeJ4oqLUjJUM3l/oFSmx60BgBo68oGRlN987Wudt1RJOMPnmbPZml
+mPzzP2jzh3phOYU3aWpuRHhi5sQPfQlfqrZ68kt40eBU8lZFGv28IQU6ZOLK344c
+RWuONPBTNi1NhbKQ9dPDw6yEE55mmSVKuS1rtGPX/ZX450vH0YrUlN5Aio9sRH49
+OM+kXliaCnpRFnWNcTqHSyKS+YCUahbsERuH9wW6mJU5oUtrzVApBIrAdqOy/Jsp
+oNEuIPXPdKxoNmaCQz7kuLotUhEF9lwPiwIBAg==
+-----END DH PARAMETERS-----

+ 28 - 0
test/key.pem

@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIp7iRgRg9iTsI
+3nym2yZ6AlNZyZ/OlslcBCcZfOhMPKQXpipTMnV2cnSLlPQrrb0Oc4SjbIHfmIAQ
+RF2UbihDV/ox6OsdV5Pim61o4IK4IeUlQnIg+zo/AyE9BC2eHq87YkYr8t0hmEyw
+Mk5yfvRgBdl6R7lc/kQ63TjBED0LINggKPkFlsvmgFlv5JVDGAJRgEbnfrV4k1As
+IfArvCynSpuEpeSVdOaDf1lJoO7Dab+gln/aOq7QeI4BYR+R2X1bDgIRIa4HJnN5
+n10yMotVF5Q27O6d2hW13V8Wo/qpPYCOqiGoy//iCmb7JWPc2h7tR2wES6I9vl8i
+c5lDn1yTAgMBAAECggEAGrqM0YUaz4eqP4IzpJ5ov7PzmnBLQ1++ru02sCR9ZTpm
+uWe/F5oPH5obgER1SiQ4nOYycvqPSlOsK36P4KfT4TSk9WULfLsfzf3i2aeeghyx
+w4bYYSBWH/KwyMn3sapwuT5cDpqpbkI1ZPsui/3xW6Er2SgYvxR3zkeNudoJ56NZ
+2pi4EhD9lF+jM6IfBmZ6UWi8vdtppLBP0Yfi3+CNE57//C1ozWPRlsuP7DeGpxWe
+voY4z4xZHnIULfK9JCfw5mTRI3gPn4/3z3eW9tqXE/ZkR1mkYrZ2UbJxe1MiR9jb
+P0YG6pX+SX1hlFXggs/IrKayKHMMD4B8tgPvyhlMgQKBgQD0ESobv4Z84+aNJpVW
+Ke3J229wim0Hn6bu88Aa3oEj4wJf7vgUiX4UxTCKa1mdpLszpgWHZTY60TxxE6Tw
+Ouc2eiXp1zUIMlzd5nTPNIeANQWt8HrAL5JWDaxXM0IPV9c+Wlpc4tTm3gdW6isr
+0mT5B12pnhRQLIwlqeErIPvMswKBgQDSdzJljKUrItJY8kuXSkSmXxpzhg9KBmCM
+GMeEfb/nRgKR8Gz6QAaRJ1Ax0IMr3Dmqabw2v5WHj/GcfO1q5m1ZSMf4FB6kjU6d
++menUGAXxvCjinr8grlC90koy/a4u/0g8mmCe5KMgmirQhT/ErfnqNHsprGlY+7U
+0NGZpr3goQKBgEOMRJUtarFB+dry5L3WGOOXAb6p8Qb9Hpxfhblp/1/JQiz+3FYC
+v4xMDuUgVMsWfmEK/9i7IEkjA5FgGHQMOVWQdNHFJ/4+wgj/8TAvn5jSE+JR/gcW
+o2+BlUMFArFwZDfzlbLDbJ0AshNR9+TG8/8gFMIO6BxQV/FMlO70z/uVAoGBAKQY
+n8ihol5BpjQHpnxtQZ1eZWdRTTZwRnK1F0rsKOYPpg1XogB0Typ5toNAiiV2bde6
+3S7qrZGm38Edfpds1jFZF+EK/uFZ88Qk6xB/EI05ZYJ9hGrBGeVmnTob3WAn4rL/
+jthXtOms/CMbQPeoBo+vBw424ieMBTkVH3dnlIBBAoGAe0HX47WU0T1jJY+UvCCJ
+1r88gBunrtD3ckFBX2Hk6hXXfTQd7Bsk5S/Cm3+zi2it5xS16KVdgQaTX1H9UASv
+hoJ6+pOfJYPGtMW+VWvMbqwJqSa6QKk7F0r5uyU8J51mlEQrKmhMY3xlNv3OGAaS
+ZM1G/mlQJFNv1WfLgc77Tes=
+-----END PRIVATE KEY-----

+ 1 - 0
test/testFile

@@ -0,0 +1 @@
+abcde

+ 16 - 2
uniform-io.cabal

@@ -113,13 +113,27 @@ library
   C-Sources: src/System/IO/Uniform/ds.c
   C-Sources: src/System/IO/Uniform/ds.c
   extra-libraries: ssl
   extra-libraries: ssl
 
 
-Test-suite lazyness
+Test-suite targets
   type: detailed-0.9
   type: detailed-0.9
-  test-module: Lazyness
+  test-module: Targets
   hs-source-dirs:
   hs-source-dirs:
     test
     test
   build-depends:
   build-depends:
     base >=4.7 && <5.0,
     base >=4.7 && <5.0,
     Cabal >= 1.9.2,
     Cabal >= 1.9.2,
+    bytestring >=0.10 && <1.0,
+    uniform-io == 0.1.1.0
+  ghc-options: -Wall -fno-warn-unused-do-bind -fwarn-incomplete-patterns -threaded
+
+Test-suite blocking
+  type: detailed-0.9
+  test-module: Blocking
+  hs-source-dirs:
+    test
+  build-depends:
+    base >=4.7 && <5.0,
+    Cabal >= 1.9.2,
+    bytestring >=0.10 && <1.0,
+    attoparsec >=0.10 && <1.0,
     uniform-io == 0.1.1.0
     uniform-io == 0.1.1.0
   ghc-options: -Wall -fno-warn-unused-do-bind -fwarn-incomplete-patterns -threaded
   ghc-options: -Wall -fno-warn-unused-do-bind -fwarn-incomplete-patterns -threaded