packages feed

HsOpenSSL 0.6 → 0.6.1

raw patch · 5 files changed

+136/−38 lines, 5 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ OpenSSL.Session: contextGetCAStore :: SSLContext -> IO X509Store
+ OpenSSL.Session: contextSetCertificate :: SSLContext -> X509 -> IO ()
+ OpenSSL.Session: contextSetPrivateKey :: (KeyPair k) => SSLContext -> k -> IO ()
+ OpenSSL.Session: lazyRead :: SSL -> IO ByteString
+ OpenSSL.Session: lazyWrite :: SSL -> ByteString -> IO ()

Files

HsOpenSSL.cabal view
@@ -5,7 +5,7 @@         can generate RSA and DSA keys, read and write PEM files,         generate message digests, sign and verify messages, encrypt         and decrypt messages.-Version: 0.6+Version: 0.6.1 License: PublicDomain License-File: COPYING Author: Adam Langley <agl at imperialviolet.org>, PHO <pho at cielonegro.org>
NEWS view
@@ -1,5 +1,15 @@ -*- Coding: utf-8 -*- +Changes from 0.6 to 0.6.1+-------------------------+* OpenSSL.Session:+    - New functions:+      # lazyRead+      # lazyWrite+      # contextGetCAStore+      # contextSetPrivateKey+      # contextSetCertificate+ Changes from 0.5.2 to 0.6 ------------------------- * INCOMPATIBLE CHANGES:
OpenSSL/BIO.hsc view
@@ -74,11 +74,12 @@ import           Control.Monad import           Data.ByteString.Internal (createAndTrim, toForeignPtr) import           Data.ByteString.Unsafe (unsafeUseAsCStringLen)-import qualified Data.ByteString.Char8      as B8-import qualified Data.ByteString.Lazy.Char8 as L8-import           Foreign                    hiding (new)+import qualified Data.ByteString.Char8         as B+import qualified Data.ByteString.Lazy.Char8    as L+import qualified Data.ByteString.Lazy.Internal as L+import           Foreign                       hiding (new) import           Foreign.C-import qualified GHC.ForeignPtr             as GF+import qualified GHC.ForeignPtr                as GF import           OpenSSL.Utils import           System.IO.Unsafe @@ -229,12 +230,12 @@ -- |@'bioRead' bio@ lazily reads all data in @bio@. bioRead :: BIO -> IO String bioRead bio-    = liftM L8.unpack $ bioReadLBS bio+    = liftM L.unpack $ bioReadLBS bio  -- |@'bioReadBS' bio len@ attempts to read @len@ bytes from @bio@, -- then return a ByteString. The actual length of result may be less -- than @len@.-bioReadBS :: BIO -> Int -> IO B8.ByteString+bioReadBS :: BIO -> Int -> IO B.ByteString bioReadBS bio maxLen     = withBioPtr bio       $ \ bioPtr ->       createAndTrim maxLen $ \ bufPtr ->@@ -249,15 +250,15 @@  -- |@'bioReadLBS' bio@ lazily reads all data in @bio@, then return a -- LazyByteString.-bioReadLBS :: BIO -> IO L8.ByteString-bioReadLBS bio = lazyRead >>= return . L8.fromChunks+bioReadLBS :: BIO -> IO L.ByteString+bioReadLBS bio = lazyRead >>= return . L.fromChunks     where-      chunkSize = 32 * 1024+      chunkSize = L.defaultChunkSize              lazyRead = unsafeInterleaveIO loop        loop = do bs <- bioReadBS bio chunkSize-                if B8.null bs then+                if B.null bs then                     do isEOF <- bioEOF bio                        if isEOF then                            return []@@ -277,10 +278,10 @@ -- return the digest and other BIOs may not support 'bioGets' at all. bioGets :: BIO -> Int -> IO String bioGets bio maxLen-    = liftM B8.unpack (bioGetsBS bio maxLen)+    = liftM B.unpack (bioGetsBS bio maxLen)  -- |'bioGetsBS' does the same as 'bioGets' but returns ByteString.-bioGetsBS :: BIO -> Int -> IO B8.ByteString+bioGetsBS :: BIO -> Int -> IO B.ByteString bioGetsBS bio maxLen     = withBioPtr bio       $ \ bioPtr ->       createAndTrim maxLen $ \ bufPtr ->@@ -295,18 +296,18 @@  -- |'bioGetsLBS' does the same as 'bioGets' but returns -- LazyByteString.-bioGetsLBS :: BIO -> Int -> IO L8.ByteString+bioGetsLBS :: BIO -> Int -> IO L.ByteString bioGetsLBS bio maxLen-    = bioGetsBS bio maxLen >>= \ bs -> (return . L8.fromChunks) [bs]+    = bioGetsBS bio maxLen >>= \ bs -> (return . L.fromChunks) [bs]  -- |@'bioWrite' bio str@ lazily writes entire @str@ to @bio@. The -- string doesn't necessarily have to be finite. bioWrite :: BIO -> String -> IO () bioWrite bio str-    = (return . L8.pack) str >>= bioWriteLBS bio+    = (return . L.pack) str >>= bioWriteLBS bio  -- |@'bioWriteBS' bio bs@ writes @bs@ to @bio@.-bioWriteBS :: BIO -> B8.ByteString -> IO ()+bioWriteBS :: BIO -> B.ByteString -> IO () bioWriteBS bio bs     = withBioPtr bio           $ \ bioPtr ->       unsafeUseAsCStringLen bs $ \ (buf, len) ->@@ -314,17 +315,17 @@     where       interpret :: CInt -> IO ()       interpret n-          | n == fromIntegral (B8.length bs)+          | n == fromIntegral (B.length bs)                       = return ()           | n == -1   = bioWriteBS bio bs -- full retry           | n <  -1   = raiseOpenSSLError-          | otherwise = bioWriteBS bio (B8.drop (fromIntegral n) bs) -- partial retry+          | otherwise = bioWriteBS bio (B.drop (fromIntegral n) bs) -- partial retry  -- |@'bioWriteLBS' bio lbs@ lazily writes entire @lbs@ to @bio@. The -- string doesn't necessarily have to be finite.-bioWriteLBS :: BIO -> L8.ByteString -> IO ()+bioWriteLBS :: BIO -> L.ByteString -> IO () bioWriteLBS bio lbs-    = mapM_ (bioWriteBS bio) $ L8.toChunks lbs+    = mapM_ (bioWriteBS bio) $ L.toChunks lbs   {- base64 ------------------------------------------------------------------- -}@@ -435,10 +436,10 @@ -- |@'newConstMem' str@ creates a read-only memory BIO source. newConstMem :: String -> IO BIO newConstMem str-    = (return . B8.pack) str >>= newConstMemBS+    = (return . B.pack) str >>= newConstMemBS  -- |@'newConstMemBS' bs@ is like 'newConstMem' but takes a ByteString.-newConstMemBS :: B8.ByteString -> IO BIO+newConstMemBS :: B.ByteString -> IO BIO newConstMemBS bs     = let (foreignBuf, off, len) = toForeignPtr bs       in@@ -454,9 +455,9 @@  -- |@'newConstMemLBS' lbs@ is like 'newConstMem' but takes a -- LazyByteString.-newConstMemLBS :: L8.ByteString -> IO BIO+newConstMemLBS :: L.ByteString -> IO BIO newConstMemLBS lbs-    = (return . B8.concat . L8.toChunks) lbs >>= newConstMemBS+    = (return . B.concat . L.toChunks) lbs >>= newConstMemBS  {- null --------------------------------------------------------------------- -} 
OpenSSL/Session.hsc view
@@ -6,6 +6,8 @@   ( -- * Contexts     SSLContext   , context+  , contextSetPrivateKey+  , contextSetCertificate   , contextSetPrivateKeyFile   , contextSetCertificateFile   , contextSetCiphers@@ -15,6 +17,7 @@   , contextSetVerificationMode   , contextSetCAFile   , contextSetCADirectory+  , contextGetCAStore      -- * SSL connections   , SSL@@ -23,6 +26,8 @@   , connect   , read   , write+  , lazyRead+  , lazyWrite   , shutdown   , ShutdownType(..)   , getPeerCertificate@@ -38,14 +43,20 @@ import Control.Exception (finally) import Foreign import Foreign.C+import qualified Data.ByteString as B import qualified Data.ByteString.Internal as B import qualified Data.ByteString.Unsafe as B-import System.IO.Error (mkIOError, ioError, eofErrorType)+import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString.Lazy.Internal as L+import System.IO.Error (mkIOError, ioError, eofErrorType, catch, isEOFError)+import System.IO.Unsafe import System.Posix.Types (Fd(..)) import Network.Socket (Socket(..)) +import OpenSSL.EVP.PKey import OpenSSL.Utils (failIfNull, failIf)-import OpenSSL.X509 (X509, X509_, wrapX509)+import OpenSSL.X509 (X509, X509_, wrapX509, withX509Ptr)+import OpenSSL.X509.Store  data SSLContext_ -- | An SSL context. Contexts carry configuration such as a server's private@@ -80,6 +91,10 @@   waitQSem sem   finally (withForeignPtr ctxfp action) $ signalQSem sem +touchContext :: SSLContext -> IO ()+touchContext (SSLContext (_, fp))+    = touchForeignPtr fp+ contextLoadFile :: (Ptr SSLContext_ -> CString -> CInt -> IO CInt)                 -> SSLContext -> String -> IO () contextLoadFile f context path =@@ -90,6 +105,29 @@          then return ()          else f ctx cpath (#const SSL_FILETYPE_ASN1) >>= failIf (/= 1) >> return () +foreign import ccall unsafe "SSL_CTX_use_PrivateKey"+    _ssl_ctx_use_privatekey :: Ptr SSLContext_ -> Ptr EVP_PKEY -> IO CInt+foreign import ccall unsafe "SSL_CTX_use_certificate"+    _ssl_ctx_use_certificate :: Ptr SSLContext_ -> Ptr X509_ -> IO CInt++-- | Install a private key into a context.+contextSetPrivateKey :: KeyPair k => SSLContext -> k -> IO ()+contextSetPrivateKey context key+    = withContext context $ \ ctx    ->+      withPKeyPtr' key    $ \ keyPtr ->+          _ssl_ctx_use_privatekey ctx keyPtr+               >>= failIf (/= 1)+               >>  return ()++-- | Install a certificate (public key) into a context.+contextSetCertificate :: SSLContext -> X509 -> IO ()+contextSetCertificate context cert+    = withContext context $ \ ctx     ->+      withX509Ptr cert    $ \ certPtr ->+          _ssl_ctx_use_certificate ctx certPtr+               >>= failIf (/= 1)+               >>  return ()+ foreign import ccall unsafe "SSL_CTX_use_PrivateKey_file"    _ssl_ctx_use_privatekey_file :: Ptr SSLContext_ -> CString -> CInt -> IO CInt foreign import ccall unsafe "SSL_CTX_use_certificate_file"@@ -180,8 +218,18 @@       _ssl_load_verify_locations ctx nullPtr cpath >>= failIf (/= 1)       return () +foreign import ccall unsafe "SSL_CTX_get_cert_store"+  _ssl_get_cert_store :: Ptr SSLContext_ -> IO (Ptr X509_STORE) +-- | Get a reference to, not a copy of, the X.509 certificate storage+--   in the SSL context.+contextGetCAStore :: SSLContext -> IO X509Store+contextGetCAStore context+    = withContext context $ \ ctx ->+      _ssl_get_cert_store ctx+           >>= wrapX509Store (touchContext context) + data SSL_ -- | This is the type of an SSL connection --@@ -309,13 +357,20 @@ --   empty ByteString is returned. If the connection dies without a graceful --   SSL shutdown, an exception is raised. read :: SSL -> Int -> IO B.ByteString-read ssl@(SSL (_, _, fd, _)) nbytes = B.createAndTrim nbytes $ f ssl where-  f ssl ptr = do-    result <- withSSL ssl $ sslIOInner _ssl_read (castPtr ptr) nbytes-    case result of-         Done n -> return $ fromIntegral n-         WantRead -> threadWaitRead fd >> f ssl ptr-         WantWrite -> threadWaitWrite fd >> f ssl ptr+read ssl@(SSL (_, _, fd, _)) nbytes = B.createAndTrim nbytes $ f ssl+    where+      f ssl ptr+          = do result <- withSSL ssl $ sslIOInner _ssl_read (castPtr ptr) nbytes+               case result of+                 Done n -> return $ fromIntegral n+                 WantRead -> threadWaitRead fd >> f ssl ptr+                 WantWrite -> threadWaitWrite fd >> f ssl ptr+            `catch`+            \ ioe ->+                if isEOFError ioe then+                    return 0+                else+                    ioError ioe -- rethrow  foreign import ccall "SSL_write" _ssl_write :: Ptr SSL_ -> Ptr Word8 -> CInt -> IO CInt @@ -329,6 +384,31 @@          Done _ -> return ()          WantRead -> threadWaitRead fd >> f ssl (ptr, len)          WantWrite -> threadWaitWrite fd >> f ssl (ptr, len)++-- | Lazily read all data until reaching EOF. If the connection dies+--   without a graceful SSL shutdown, an exception is raised.+lazyRead :: SSL -> IO L.ByteString+lazyRead ssl = lazyRead' >>= return . L.fromChunks+    where+      chunkSize = L.defaultChunkSize++      lazyRead' = unsafeInterleaveIO loop++      loop = do bs <- read ssl chunkSize+                if B.null bs then+                    -- got EOF+                    return []+                  else+                    do bss <- lazyRead'+                       return (bs:bss)++-- | Write a lazy ByteString to the SSL connection. In contrast to+--   'write', there is a chance that the string is written partway and+--   then an exception is raised for an error. The string doesn't+--   necessarily have to be finite.+lazyWrite :: SSL -> L.ByteString -> IO ()+lazyWrite ssl lbs+    = mapM_ (write ssl) $ L.toChunks lbs  foreign import ccall "SSL_shutdown" _ssl_shutdown :: Ptr SSL_ -> IO CInt 
OpenSSL/X509/Store.hsc view
@@ -9,6 +9,8 @@     , X509_STORE -- private      , newX509Store++    , wrapX509Store -- private     , withX509StorePtr -- private      , addCertToStore@@ -18,6 +20,7 @@  import           Foreign import           Foreign.C+import           Foreign.Concurrent as FC import           OpenSSL.X509 import           OpenSSL.X509.Revocation import           OpenSSL.Utils@@ -32,8 +35,8 @@ foreign import ccall unsafe "X509_STORE_new"         _new :: IO (Ptr X509_STORE) -foreign import ccall unsafe "&X509_STORE_free"-        _free :: FunPtr (Ptr X509_STORE -> IO ())+foreign import ccall unsafe "X509_STORE_free"+        _free :: Ptr X509_STORE -> IO ()  foreign import ccall unsafe "X509_STORE_add_cert"         _add_cert :: Ptr X509_STORE -> Ptr X509_ -> IO CInt@@ -45,9 +48,13 @@ newX509Store :: IO X509Store newX509Store = _new                >>= failIfNull-               >>= newForeignPtr _free-               >>= return . X509Store+               >>= \ ptr -> wrapX509Store (_free ptr) ptr +wrapX509Store :: IO () -> Ptr X509_STORE -> IO X509Store+wrapX509Store finaliser ptr+    = do fp <- newForeignPtr_ ptr+         FC.addForeignPtrFinalizer fp finaliser+         return $ X509Store fp  withX509StorePtr :: X509Store -> (Ptr X509_STORE -> IO a) -> IO a withX509StorePtr (X509Store store)