Permalink
Browse files

Implemented OpenSSL.EVP.Base64 / Buried OpenSSL.BIO

darcs-hash:20070619085206-62b54-932c3fc26e207a12ac1e126ede36287674fc2868.gz
  • Loading branch information...
1 parent addcae0 commit df2722486567537d1547dc30f58dbfe524b259ea @phonohawk committed Jun 19, 2007
View
1 .boring
@@ -58,6 +58,7 @@ _stub\.(c|h)$
^OpenSSL/BIO\.hs$
^OpenSSL/BN\.hs$
^OpenSSL/ERR\.hs$
+^OpenSSL/EVP/Base64\.hs$
^OpenSSL/EVP/Cipher\.hs$
^OpenSSL/EVP/Digest\.hs$
^OpenSSL/EVP/Open\.hs$
View
14 HsOpenSSL.cabal
@@ -1,11 +1,14 @@
Name: HsOpenSSL
-Synopsis: Wrapper of (part of) the OpenSSL
+Synopsis: (Part of) OpenSSL binding for Haskell
Description:
- FIXME: write this
+ HsOpenSSL is a (part of) OpenSSL binding for Haskell. It can
+ generate RSA keys, read and write PEM files, generate message
+ digests, sign and verify messages, encrypt and decrypt
+ messages.
Version: 0.1
License: PublicDomain
-Author: PHO <phonohawk at ps dot sakura dot ne dot jp>
-Maintainer: PHO <phonohawk at ps dot sakura dot ne dot jp>
+Author: PHO <phonohawk TA ps TOD sakura TOD ne TOD jp>
+Maintainer: PHO <phonohawk TA ps TOD sakura TOD ne TOD jp>
Stability: experimental
Homepage: http://ccm.sherry.jp/hs-openssl/
Category: Cryptography
@@ -17,6 +20,7 @@ Exposed-Modules:
OpenSSL.BIO
OpenSSL.BN
OpenSSL.ERR
+ OpenSSL.EVP.Base64
OpenSSL.EVP.Cipher
OpenSSL.EVP.Digest
OpenSSL.EVP.Open
@@ -31,7 +35,7 @@ Exposed-Modules:
Extensions:
ForeignFunctionInterface
ghc-options:
- -fglasgow-exts
+ -fglasgow-exts -O3
C-Sources:
cbits/HsOpenSSL.c
Include-Dirs:
View
2 Makefile
@@ -9,7 +9,7 @@ run: build
$(MAKE) -C examples run
.setup-config: $(CABAL_FILE) configure Setup
- ./Setup configure
+ ./Setup configure -p
configure: aclocal.m4 configure.ac
autoconf
View
98 OpenSSL.hsc
@@ -1,13 +1,109 @@
{- -*- haskell -*- -}
+
+-- |HsOpenSSL is a (part of) OpenSSL binding for Haskell. It can
+-- generate RSA keys, read and write PEM files, generate message
+-- digests, sign and verify messages, encrypt and decrypt messages.
+-- But since OpenSSL is a very large library, it is uneasy to cover
+-- everything in it.
+--
+-- Features that aren't (yet) supported:
+--
+-- [/TLS\/SSL network connection/] ssl(3) functionalities are
+-- totally uncovered. They should be covered someday.
+--
+-- [/Low-level API to symmetric ciphers/] Only high-level APIs (EVP
+-- and BIO) are available. But I believe no one will be lost without
+-- functions like @DES_set_odd_parity@.
+--
+-- [/Low-level API to asymmetric ciphers/] Only a high-level API
+-- (EVP) is available. But I believe no one will complain about the
+-- absence of functions like @RSA_public_encrypt@.
+--
+-- [/Key generation of DSA and Diffie-Hellman algorithms/] Only RSA
+-- keys can currently be generated.
+--
+-- [/X.509 certificate handling/] No operations related to X.509 are
+-- currently supported. They should be supported in the future.
+--
+-- [/HMAC message authentication/]
+--
+-- [/Low-level API to message digest functions/] Just use EVP or BIO
+-- instead of something like @MD5_Update@.
+--
+-- [/pseudo-random number generator/] rand(3) functionalities are
+-- uncovered, but OpenSSL works very well by default.
+--
+-- [/API to ASN.1, PKCS\#7 and PKCS\#12 functionalities/] They
+-- should be covered someday, but there seems no documents for those
+-- APIs.
+--
+-- [/BIO/] BIO isn't needed because we are Haskell hackers.
+--
+-- [/ENGINE cryptographic module/] The default implementations work
+-- very well, don't they?
+--
+-- [/bn(3), buffer(3), lhash(3), objects(3), stack(3) and txt_db(3)/]
+-- These internal functions are rarely used by application
+-- programmers.
+--
+-- So if you find out some features you want aren't supported, you
+-- must write your own patch. Happy hacking.
+
+#include "HsOpenSSL.h"
+
module OpenSSL
- ( withOpenSSL
+ ( -- * Initialization
+ withOpenSSL
+
+ -- * High-level cryptographic functions
+ , module OpenSSL.EVP.Cipher
+ , module OpenSSL.EVP.Digest
+ , module OpenSSL.EVP.Open
+ , module OpenSSL.EVP.PKey
+ , module OpenSSL.EVP.Seal
+ , module OpenSSL.EVP.Sign
+ , module OpenSSL.EVP.Verify
+
+ -- * PEM routines
+ , module OpenSSL.PEM
+
+ -- * RSA public key cryptosystem
+ , module OpenSSL.RSA
)
where
+
+import OpenSSL.EVP.Cipher hiding (EVP_CIPHER, EVP_CIPHER_CTX, newCtx, cryptoModeToInt)
+import OpenSSL.EVP.Digest hiding (EVP_MD, newCtx, EVP_MD_CTX)
+import OpenSSL.EVP.Open
+import OpenSSL.EVP.PKey hiding (EVP_PKEY, wrapPKey, pkeySize)
+import OpenSSL.EVP.Seal
+import OpenSSL.EVP.Sign
+import OpenSSL.EVP.Verify
+import OpenSSL.PEM
+import OpenSSL.RSA hiding (RSA_)
import OpenSSL.SSL
+
+foreign import ccall "HsOpenSSL_setupMutex"
+ setupMutex :: IO ()
+
+
+-- |Computation of @'withOpenSSL' action@ initializes the OpenSSL
+-- library and computes @action@. Every applications that use OpenSSL
+-- must wrap any other operations related to OpenSSL or they will
+-- crash.
+--
+-- > module Main where
+-- > import OpenSSL
+-- >
+-- > main :: IO ()
+-- > main = withOpenSSL $
+-- > do ...
+--
withOpenSSL :: IO a -> IO a
withOpenSSL act
= do loadErrorStrings
addAllAlgorithms
+ setupMutex
act
View
402 OpenSSL/BIO.hsc
@@ -1,43 +1,82 @@
{- -*- haskell -*- -}
+
+-- #hide
+
+{- --------------------------------------------------------------------------- -}
+{- -}
+{- FOR INTERNAL USE ONLY -}
+{- -}
+{- When I firstly saw the manpage of bio(3), it looked like a great API. I ac- -}
+{- tually wrote a wrapper and even wrote a document. What a pain! -}
+{- -}
+{- Now I realized that BIOs aren't necessary to we Haskell hackers. Their fun- -}
+{- ctionalities overlaps with Haskell's own I/O system. The only thing which -}
+{- wasn't available without bio(3) -- at least I thought so -- was the -}
+{- BIO_f_base64(3), but I found an undocumented API for the Base64 codec. So I -}
+{- decided to bury all the OpenSSL.BIO module. The game is over. -}
+{- --------------------------------------------------------------------------- -}
+
+
+#include "HsOpenSSL.h"
+
+-- |A BIO is an I\/O abstraction, it hides many of the underlying I\/O
+-- details from an application, if you are writing a pure C
+-- application...
+--
+-- I know, we are hacking on Haskell so BIO components like BIO_s_file
+-- are hardly needed. But for filter BIOs, such as BIO_f_base64 and
+-- BIO_f_cipher, they should be useful too to us.
+
module OpenSSL.BIO
- ( BIO
+ ( -- * Type
+ BIO
, BIO_
- , push
+ -- * BIO chaning
+ , bioPush
, (==>)
, (<==)
- , joinAll
-
- , flush
- , eof
-
- , read
- , readBS
- , readLBS
- , gets
- , getsBS
- , getsLBS
- , write
- , writeBS
- , writeLBS
-
+ , bioJoin
+
+ -- * BIO control operations
+ , bioFlush
+ , bioReset
+ , bioEOF
+
+ -- * BIO I\/O functions
+ , bioRead
+ , bioReadBS
+ , bioReadLBS
+ , bioGets
+ , bioGetsBS
+ , bioGetsLBS
+ , bioWrite
+ , bioWriteBS
+ , bioWriteLBS
+
+ -- * Base64 BIO filter
, newBase64
+ -- * Buffering BIO filter
+ , newBuffer
+
+ -- * Symmetric cipher BIO filter
, newCipher
+ -- * Message digest BIO filter
, newMD
- , newMemBuf
- , newConstMemBuf
- , newConstMemBufBS
- , newConstMemBufLBS
+ -- * Memory BIO sink\/source
+ , newMem
+ , newConstMem
+ , newConstMemBS
+ , newConstMemLBS
+ -- * Null data BIO sink\/source
, newNullBIO
)
where
-#include "HsOpenSSL.h"
-
import Control.Monad
import qualified Data.ByteString as B
import Data.ByteString.Base
@@ -49,14 +88,14 @@ import qualified GHC.ForeignPtr as GF
import OpenSSL.EVP.Cipher
import OpenSSL.EVP.Digest
import OpenSSL.Utils
-import Prelude hiding (read)
import System.IO.Unsafe
{- bio ---------------------------------------------------------------------- -}
type BioMethod = Ptr BIO_METHOD
data BIO_METHOD = BIO_METHOD
+-- |@BIO@ is a @ForeignPtr@ to an opaque BIO object. They are created by newXXX actions.
type BIO = ForeignPtr BIO_
data BIO_ = BIO_
@@ -72,6 +111,9 @@ foreign import ccall unsafe "BIO_push"
foreign import ccall unsafe "HsOpenSSL_BIO_set_flags"
_set_flags :: Ptr BIO_ -> Int -> IO ()
+foreign import ccall unsafe "HsOpenSSL_BIO_should_retry"
+ _should_retry :: Ptr BIO_ -> IO Int
+
new :: BioMethod -> IO BIO
new method
@@ -83,49 +125,89 @@ new method
-- 參照だけ保持してそこから讀み出す事も、兩方考へられるので、双方の
-- ForeignPtr が双方を touch する。參照カウント方式ではないから循環參照
-- しても問題無い。
-push :: BIO -> BIO -> IO ()
-push a b
+
+-- |Computation of @'bioPush' a b@ connects @b@ behind @a@.
+--
+-- Example:
+--
+-- > do b64 <- newBase64 True
+-- > mem <- newMem
+-- > bioPush b64 mem
+-- >
+-- > -- Encode some text in Base64 and write the result to the
+-- > -- memory buffer.
+-- > bioWrite b64 "Hello, world!"
+-- > bioFlush b64
+-- >
+-- > -- Then dump the memory buffer.
+-- > bioRead mem >>= putStrLn
+--
+bioPush :: BIO -> BIO -> IO ()
+bioPush a b
= withForeignPtr a $ \ aPtr ->
withForeignPtr b $ \ bPtr ->
do _push aPtr bPtr
GF.addForeignPtrConcFinalizer a $ touchForeignPtr b
GF.addForeignPtrConcFinalizer b $ touchForeignPtr a
return ()
+-- |@a '==>' b@ is an alias to @'bioPush' a b@.
+(==>) :: BIO -> BIO -> IO ()
+(==>) = bioPush
-(==>) = push
-(<==) = flip push
+-- |@a '<==' b@ is an alias to @'bioPush' b a@.
+(<==) :: BIO -> BIO -> IO ()
+(<==) = flip bioPush
-joinAll :: [BIO] -> IO ()
-joinAll [] = return ()
-joinAll (_:[]) = return ()
-joinAll (a:b:xs) = push a b >> joinAll (b:xs)
+-- |@'bioJoin' [bio1, bio2, ..]@ connects many BIOs at once.
+bioJoin :: [BIO] -> IO ()
+bioJoin [] = return ()
+bioJoin (_:[]) = return ()
+bioJoin (a:b:xs) = bioPush a b >> bioJoin (b:xs)
setFlags :: BIO -> Int -> IO ()
setFlags bio flags
= withForeignPtr bio $ \ bioPtr ->
_set_flags bioPtr flags
+bioShouldRetry :: BIO -> IO Bool
+bioShouldRetry bio
+ = withForeignPtr bio $ \ bioPtr ->
+ _should_retry bioPtr >>= return . (/= 0)
+
{- ctrl --------------------------------------------------------------------- -}
foreign import ccall unsafe "HsOpenSSL_BIO_flush"
_flush :: Ptr BIO_ -> IO Int
+foreign import ccall unsafe "HsOpenSSL_BIO_reset"
+ _reset :: Ptr BIO_ -> IO Int
+
foreign import ccall unsafe "HsOpenSSL_BIO_eof"
_eof :: Ptr BIO_ -> IO Int
-
-flush :: BIO -> IO ()
-flush bio
+-- |@'bioFlush' bio@ normally writes out any internally buffered data,
+-- in some cases it is used to signal EOF and that no more data will
+-- be written.
+bioFlush :: BIO -> IO ()
+bioFlush bio
= withForeignPtr bio $ \ bioPtr ->
_flush bioPtr >>= failIf (/= 1) >> return ()
+-- |@'bioReset' bio@ typically resets a BIO to some initial state.
+bioReset :: BIO -> IO ()
+bioReset bio
+ = withForeignPtr bio $ \ bioPtr ->
+ _reset bioPtr >> return () -- BIO_reset の戻り値は全 BIO で共通で
+ -- ないのでエラーチェックが出來ない。
-eof :: BIO -> IO Bool
-eof bio
+-- |@'bioEOF' bio@ returns 1 if @bio@ has read EOF, the precise
+-- meaning of EOF varies according to the BIO type.
+bioEOF :: BIO -> IO Bool
+bioEOF bio
= withForeignPtr bio $ \ bioPtr ->
_eof bioPtr >>= return . (== 1)
@@ -141,14 +223,16 @@ foreign import ccall unsafe "BIO_gets"
foreign import ccall unsafe "BIO_write"
_write :: Ptr BIO_ -> Ptr CChar -> Int -> IO Int
+-- |@'bioRead' bio@ lazily reads all data in @bio@.
+bioRead :: BIO -> IO String
+bioRead bio
+ = liftM L8.unpack $ bioReadLBS bio
-read :: BIO -> IO String
-read bio
- = liftM L8.unpack $ readLBS bio
-
-
-readBS :: BIO -> Int -> IO ByteString
-readBS bio maxLen
+-- |@'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 ByteString
+bioReadBS bio maxLen
= withForeignPtr bio $ \ bioPtr ->
createAndTrim maxLen $ \ buf ->
_read bioPtr (unsafeCoercePtr buf) maxLen >>= interpret
@@ -160,33 +244,41 @@ readBS bio maxLen
| n < -1 = raiseOpenSSLError
| otherwise = return n
-
-readLBS :: BIO -> IO LazyByteString
-readLBS bio = lazyRead >>= return . LPS
+-- |@'bioReadLBS' bio@ lazily reads all data in @bio@, then return a
+-- LazyByteString.
+bioReadLBS :: BIO -> IO LazyByteString
+bioReadLBS bio = lazyRead >>= return . LPS
where
chunkSize = 32 * 1024
lazyRead = unsafeInterleaveIO loop
- loop = do bs <- readBS bio chunkSize
+ loop = do bs <- bioReadBS bio chunkSize
if B.null bs then
- do isEOF <- eof bio
+ do isEOF <- bioEOF bio
if isEOF then
return []
else
- loop
+ do shouldRetry <- bioShouldRetry bio
+ if shouldRetry then
+ loop
+ else
+ fail "bioReadLBS: got null but isEOF=False, shouldRetry=False"
else
do bss <- lazyRead
return (bs:bss)
-
-gets :: BIO -> Int -> IO String
-gets bio maxLen
- = liftM B8.unpack (getsBS bio maxLen)
-
-
-getsBS :: BIO -> Int -> IO ByteString
-getsBS bio maxLen
+-- |@'bioGets' bio len@ normally attempts to read one line of data
+-- from @bio@ of maximum length @len@. There are exceptions to this
+-- however, for example 'bioGets' on a digest BIO will calculate and
+-- 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)
+
+-- |'bioGetsBS' does the same as 'bioGets' but returns ByteString.
+bioGetsBS :: BIO -> Int -> IO ByteString
+bioGetsBS bio maxLen
= withForeignPtr bio $ \ bioPtr ->
createAndTrim maxLen $ \ buf ->
_gets bioPtr (unsafeCoercePtr buf) maxLen >>= interpret
@@ -198,35 +290,38 @@ getsBS bio maxLen
| n < -1 = raiseOpenSSLError
| otherwise = return n
-
-getsLBS :: BIO -> Int -> IO LazyByteString
-getsLBS bio maxLen
- = getsBS bio maxLen >>= \ bs -> (return . LPS) [bs]
-
-
-write :: BIO -> String -> IO ()
-write bio str
- = (return . L8.pack) str >>= writeLBS bio
-
-
-writeBS :: BIO -> ByteString -> IO ()
-writeBS bio bs
+-- |'bioGetsLBS' does the same as 'bioGets' but returns
+-- LazyByteString.
+bioGetsLBS :: BIO -> Int -> IO LazyByteString
+bioGetsLBS bio maxLen
+ = bioGetsBS bio maxLen >>= \ bs -> (return . LPS) [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
+
+-- |@'bioWriteBS' bio bs@ writes @bs@ to @bio@.
+bioWriteBS :: BIO -> ByteString -> IO ()
+bioWriteBS bio bs
= withForeignPtr bio $ \ bioPtr ->
unsafeUseAsCStringLen bs $ \ (buf, len) ->
_write bioPtr buf len >>= interpret
where
interpret :: Int -> IO ()
interpret n
| n == B.length bs = return ()
- | n == -1 = writeBS bio bs -- full retry
+ | n == -1 = bioWriteBS bio bs -- full retry
| n < -1 = raiseOpenSSLError
- | otherwise = writeBS bio (B.drop n bs) -- partial retry
+ | otherwise = bioWriteBS bio (B.drop n bs) -- partial retry
+-- |@'bioWriteLBS' bio lbs@ lazily writes entire @lbs@ to @bio@. The
+-- string doesn't necessarily have to be finite.
+bioWriteLBS :: BIO -> LazyByteString -> IO ()
+bioWriteLBS bio (LPS chunks)
+ = mapM_ (bioWriteBS bio) chunks
-writeLBS :: BIO -> LazyByteString -> IO ()
-writeLBS bio (LPS chunks)
- = mapM_ (writeBS bio) chunks
-
{- base64 ------------------------------------------------------------------- -}
@@ -236,30 +331,101 @@ foreign import ccall unsafe "BIO_f_base64"
foreign import ccall unsafe "HsOpenSSL_BIO_FLAGS_BASE64_NO_NL"
_FLAGS_BASE64_NO_NL :: Int
-
+-- |@'newBase64' noNL@ creates a Base64 BIO filter. This is a filter
+-- bio that base64 encodes any data written through it and decodes any
+-- data read through it.
+--
+-- If @noNL@ flag is True, the filter encodes the data all on one line
+-- or expects the data to be all on one line.
+--
+-- Base64 BIOs do not support 'bioGets'.
+--
+-- 'bioFlush' on a Base64 BIO that is being written through is used to
+-- signal that no more data is to be encoded: this is used to flush
+-- the final block through the BIO.
newBase64 :: Bool -> IO BIO
newBase64 noNL
= do bio <- new =<< f_base64
when noNL $ setFlags bio _FLAGS_BASE64_NO_NL
return bio
+{- buffer ------------------------------------------------------------------- -}
+
+foreign import ccall unsafe "BIO_f_buffer"
+ f_buffer :: IO BioMethod
+
+foreign import ccall unsafe "HsOpenSSL_BIO_set_buffer_size"
+ _set_buffer_size :: Ptr BIO_ -> Int -> IO Int
+
+
+-- |@'newBuffer' mBufSize@ creates a buffering BIO filter. Data
+-- written to a buffering BIO is buffered and periodically written to
+-- the next BIO in the chain. Data read from a buffering BIO comes
+-- from the next BIO in the chain.
+--
+-- Buffering BIOs support 'bioGets'.
+--
+-- Calling 'bioReset' on a buffering BIO clears any buffered data.
+--
+-- Question: When I created a BIO chain like this and attempted to
+-- read from the buf, the buffering BIO weirdly behaved: BIO_read()
+-- returned nothing, but both BIO_eof() and BIO_should_retry()
+-- returned zero. I tried to examine the source code of
+-- crypto\/bio\/bf_buff.c but it was too complicated to
+-- understand. Does anyone know why this happens? The version of
+-- OpenSSL was 0.9.7l.
+--
+-- > main = withOpenSSL $
+-- > do mem <- newConstMem "Hello, world!"
+-- > buf <- newBuffer Nothing
+-- > mem ==> buf
+-- >
+-- > bioRead buf >>= putStrLn -- This fails, but why?
+--
+-- I am being depressed for this unaccountable failure.
+--
+newBuffer :: Maybe Int -- ^ Explicit buffer size (@Just n@) or the
+ -- default size (@Nothing@).
+ -> IO BIO
+newBuffer bufSize
+ = do bio <- new =<< f_buffer
+ case bufSize of
+ Just n -> withForeignPtr bio $ \ bioPtr ->
+ _set_buffer_size bioPtr n
+ >>= failIf (/= 1) >> return ()
+ Nothing -> return ()
+ return bio
+
{- cipher ------------------------------------------------------------------- -}
foreign import ccall unsafe "BIO_f_cipher"
f_cipher :: IO BioMethod
foreign import ccall unsafe "BIO_set_cipher"
- _set_cipher :: Ptr BIO_ -> EvpCipher -> Ptr CUChar -> Ptr CUChar -> Int -> IO ()
-
-
+ _set_cipher :: Ptr BIO_ -> EvpCipher -> CString -> CString -> Int -> IO ()
+
+-- |@'newCipher' cipher key iv mode@ creates a symmetric cipher BIO
+-- filter. If @mode@ is 'OpenSSL.EVP.Cipher.Encrypt', this filter
+-- encrypts any data written through it and encrypts any data read
+-- through it. If @mode@ is 'OpenSSL.EVP.Cipher.Decrypt', it does the
+-- opposite to 'OpenSSL.EVP.Cipher.Encrypt'.
+--
+-- Cipher BIOs do not support 'bioGets'.
+--
+-- 'bioFlush' on an encryption BIO that is being written through is
+-- used to signal that no more data is to be encrypted: this is used
+-- to flush and possibly pad the final block through the BIO.
+--
+-- When reading from an decryption BIO the final block is
+-- automatically decrypted and checked when EOF is detected.
newCipher :: EvpCipher -> String -> String -> CryptoMode -> IO BIO
newCipher cipher key iv mode
= do bio <- new =<< f_cipher
withForeignPtr bio $ \ bioPtr ->
withCString key $ \ keyPtr ->
withCString iv $ \ ivPtr ->
- _set_cipher bioPtr cipher (unsafeCoercePtr keyPtr) (unsafeCoercePtr ivPtr) (cryptoModeToInt mode)
+ _set_cipher bioPtr cipher keyPtr ivPtr (cryptoModeToInt mode)
return bio
@@ -271,7 +437,17 @@ foreign import ccall unsafe "BIO_f_md"
foreign import ccall unsafe "HsOpenSSL_BIO_set_md"
_set_md :: Ptr BIO_ -> Ptr EVP_MD -> IO Int
-
+-- |@'newMD' md@ creates a message digest BIO filter. This is a filter
+-- BIO that digests any data passed through it.
+--
+-- Any data written or read through a digest BIO using 'bioRead' and
+-- 'bioWrite' is digested.
+--
+-- 'bioGets', if its size parameter is large enough finishes the
+-- digest calculation and returns the digest value. The length of
+-- digest value can be retrieved using 'OpenSSL.EVP.Digest.mdSize'.
+--
+-- 'bioReset' reinitializes a digest BIO.
newMD :: EvpMD -> IO BIO
newMD md
= do bio <- new =<< f_md
@@ -289,20 +465,38 @@ foreign import ccall unsafe "BIO_new_mem_buf"
_new_mem_buf :: Ptr CChar -> Int -> IO (Ptr BIO_)
-newMemBuf :: IO BIO
-newMemBuf = s_mem >>= new
-
-
-newConstMemBuf :: String -> IO BIO
-newConstMemBuf str
- = (return . B8.pack) str >>= newConstMemBufBS
-
-
--- ByteString への參照を BIO の finalizer に持たせる。
-newConstMemBufBS :: ByteString -> IO BIO
-newConstMemBufBS bs
+-- |@'newMem'@ creates a memory BIO sink\/source. Any data written to
+-- a memory BIO can be recalled by reading from it. Unless the memory
+-- BIO is read only any data read from it is deleted from the BIO.
+--
+-- Memory BIOs support 'bioGets'.
+--
+-- Calling 'bioReset' on a erad write memory BIO clears any data in
+-- it. On a read only BIO it restores the BIO to its original state
+-- and the read only data can be read again.
+--
+-- 'bioEOF' is true if no data is in the BIO.
+--
+-- Every read from a read write memory BIO will remove the data just
+-- read with an internal copy operation, if a BIO contains a lots of
+-- data and it is read in small chunks the operation can be very
+-- slow. The use of a read only memory BIO avoids this problem. If the
+-- BIO must be read write then adding a buffering BIO ('newBuffer') to
+-- the chain will speed up the process.
+newMem :: IO BIO
+newMem = s_mem >>= new
+
+-- |@'newConstMem' str@ creates a read-only memory BIO source.
+newConstMem :: String -> IO BIO
+newConstMem str
+ = (return . B8.pack) str >>= newConstMemBS
+
+-- |@'newConstMemBS' bs@ is like 'newConstMem' but takes a ByteString.
+newConstMemBS :: ByteString -> IO BIO
+newConstMemBS bs
= let (foreignBuf, off, len) = toForeignPtr bs
in
+ -- ByteString への參照を BIO の finalizer に持たせる。
withForeignPtr foreignBuf $ \ buf ->
do bioPtr <- _new_mem_buf (unsafeCoercePtr $ buf `plusPtr` off) len
>>= failIfNull
@@ -312,16 +506,24 @@ newConstMemBufBS bs
return bio
-
-newConstMemBufLBS :: LazyByteString -> IO BIO
-newConstMemBufLBS (LPS bss)
- = (return . B.concat) bss >>= newConstMemBufBS
+-- |@'newConstMemLBS' lbs@ is like 'newConstMem' but takes a
+-- LazyByteString.
+newConstMemLBS :: LazyByteString -> IO BIO
+newConstMemLBS (LPS bss)
+ = (return . B.concat) bss >>= newConstMemBS
{- null --------------------------------------------------------------------- -}
foreign import ccall unsafe "BIO_s_null"
s_null :: IO BioMethod
-
+-- |@'newNullBIO'@ creates a null BIO sink\/source. Data written to
+-- the null sink is discarded, reads return EOF.
+--
+-- A null sink is useful if, for example, an application wishes to
+-- digest some data by writing through a digest bio but not send the
+-- digested data anywhere. Since a BIO chain must normally include a
+-- source\/sink BIO this can be achieved by adding a null sink BIO to
+-- the end of the chain.
newNullBIO :: IO BIO
newNullBIO = s_null >>= new
View
6 OpenSSL/ERR.hsc
@@ -1,4 +1,9 @@
{- -*- haskell -*- -}
+
+-- #hide
+
+#include "HsOpenSSL.h"
+
module OpenSSL.ERR
( getError
, peekError
@@ -7,7 +12,6 @@ module OpenSSL.ERR
)
where
-
import Foreign
import Foreign.C
View
127 OpenSSL/EVP/Base64.hsc
@@ -0,0 +1,127 @@
+{- -*- haskell -*- -}
+#include "HsOpenSSL.h"
+module OpenSSL.EVP.Base64
+ ( encodeBase64
+ , encodeBase64BS
+ , encodeBase64LBS
+
+ , decodeBase64
+ , decodeBase64BS
+ , decodeBase64LBS
+ )
+ where
+
+import Control.Exception
+import qualified Data.ByteString as B
+import Data.ByteString.Base
+import qualified Data.ByteString.Char8 as B8
+import qualified Data.ByteString.Lazy.Char8 as L8
+import Data.List
+import Foreign
+import Foreign.C
+import OpenSSL.Utils
+
+
+-- エンコード時: 最低 3 バイト以上になるまで次のブロックを取り出し續け
+-- る。返された[ByteString] は B.concat してから、その文字列長より小さ
+-- な最大の 3 の倍數の位置で分割し、殘りは次のブロックの一部と見做す。
+--
+-- デコード時: 分割のアルゴリズムは同じだが最低バイト数が 4。
+nextBlock :: Int -> ([ByteString], LazyByteString) -> ([ByteString], LazyByteString)
+nextBlock _ (xs, LPS [] ) = (xs, LPS [])
+nextBlock minLen (xs, LPS src) = if foldl' (+) 0 (map B.length xs) >= minLen then
+ (xs, LPS src)
+ else
+ case src of
+ (y:ys) -> nextBlock minLen (xs ++ [y], LPS ys)
+
+
+{- encode -------------------------------------------------------------------- -}
+
+foreign import ccall unsafe "EVP_EncodeBlock"
+ _EncodeBlock :: Ptr CChar -> Ptr CChar -> Int -> IO Int
+
+
+encodeBlock :: ByteString -> ByteString
+encodeBlock inBS
+ = unsafePerformIO $
+ unsafeUseAsCStringLen inBS $ \ (inBuf, inLen) ->
+ createAndTrim maxOutLen $ \ outBuf ->
+ _EncodeBlock (unsafeCoercePtr outBuf) inBuf inLen
+ where
+ maxOutLen = (inputLen `div` 3 + 1) * 4 + 1 -- +1: '\0'
+ inputLen = B.length inBS
+
+
+encodeBase64 :: String -> String
+encodeBase64 = L8.unpack . encodeBase64LBS . L8.pack
+
+
+encodeBase64BS :: ByteString -> ByteString
+encodeBase64BS = encodeBlock
+
+
+encodeBase64LBS :: LazyByteString -> LazyByteString
+encodeBase64LBS inLBS
+ | L8.null inLBS = L8.empty
+ | otherwise
+ = let (blockParts', remain' ) = nextBlock 3 ([], inLBS)
+ block' = B.concat blockParts'
+ blockLen' = B.length block'
+ (block , leftover) = if blockLen' < 3 then
+ -- 最後の半端
+ (block', B.empty)
+ else
+ B.splitAt (blockLen' - blockLen' `mod` 3) block'
+ remain = if B.null leftover then
+ remain'
+ else
+ case remain' of
+ LPS xs -> LPS (leftover:xs)
+ encodedBlock = encodeBlock block
+ LPS encodedRemain = encodeBase64LBS remain
+ in
+ LPS ([encodedBlock] ++ encodedRemain)
+
+
+{- decode -------------------------------------------------------------------- -}
+
+foreign import ccall unsafe "EVP_DecodeBlock"
+ _DecodeBlock :: Ptr CChar -> Ptr CChar -> Int -> IO Int
+
+
+decodeBlock :: ByteString -> ByteString
+decodeBlock inBS
+ = assert (B.length inBS `mod` 4 == 0) $
+ unsafePerformIO $
+ unsafeUseAsCStringLen inBS $ \ (inBuf, inLen) ->
+ createAndTrim (B.length inBS) $ \ outBuf ->
+ _DecodeBlock (unsafeCoercePtr outBuf) inBuf inLen
+
+
+decodeBase64 :: String -> String
+decodeBase64 = L8.unpack . decodeBase64LBS . L8.pack
+
+
+decodeBase64BS :: ByteString -> ByteString
+decodeBase64BS = decodeBlock
+
+
+decodeBase64LBS :: LazyByteString -> LazyByteString
+decodeBase64LBS inLBS
+ | L8.null inLBS = L8.empty
+ | otherwise
+ = let (blockParts', remain' ) = nextBlock 4 ([], inLBS)
+ block' = B.concat blockParts'
+ blockLen' = B.length block'
+ (block , leftover) = assert (blockLen' >= 4) $
+ B.splitAt (blockLen' - blockLen' `mod` 4) block'
+ remain = if B.null leftover then
+ remain'
+ else
+ case remain' of
+ LPS xs -> LPS (leftover:xs)
+ decodedBlock = decodeBlock block
+ LPS decodedRemain = decodeBase64LBS remain
+ in
+ LPS ([decodedBlock] ++ decodedRemain)
View
10 OpenSSL/EVP/Cipher.hsc
@@ -87,13 +87,13 @@ data CryptoMode = Encrypt
foreign import ccall unsafe "EVP_CipherInit"
- _CipherInit :: Ptr EVP_CIPHER_CTX -> EvpCipher -> Ptr CUChar -> Ptr CUChar -> Int -> IO Int
+ _CipherInit :: Ptr EVP_CIPHER_CTX -> EvpCipher -> CString -> CString -> Int -> IO Int
foreign import ccall unsafe "EVP_CipherUpdate"
- _CipherUpdate :: Ptr EVP_CIPHER_CTX -> Ptr CUChar -> Ptr Int -> Ptr CUChar -> Int -> IO Int
+ _CipherUpdate :: Ptr EVP_CIPHER_CTX -> Ptr CChar -> Ptr Int -> Ptr CChar -> Int -> IO Int
foreign import ccall unsafe "EVP_CipherFinal"
- _CipherFinal :: Ptr EVP_CIPHER_CTX -> Ptr CUChar -> Ptr Int -> IO Int
+ _CipherFinal :: Ptr EVP_CIPHER_CTX -> Ptr CChar -> Ptr Int -> IO Int
cryptoModeToInt :: CryptoMode -> Int
@@ -107,7 +107,7 @@ cipherInit cipher key iv mode
withForeignPtr ctx $ \ ctxPtr ->
withCString key $ \ keyPtr ->
withCString iv $ \ ivPtr ->
- _CipherInit ctxPtr cipher (unsafeCoercePtr keyPtr) (unsafeCoercePtr ivPtr) (cryptoModeToInt mode)
+ _CipherInit ctxPtr cipher keyPtr ivPtr (cryptoModeToInt mode)
>>= failIf (/= 1)
return ctx
@@ -123,7 +123,7 @@ cipherUpdateBS ctx inBS
unsafeUseAsCStringLen inBS $ \ (inBuf, inLen) ->
createAndTrim (inLen + _ctx_block_size ctxPtr - 1) $ \ outBuf ->
alloca $ \ outLenPtr ->
- _CipherUpdate ctxPtr (unsafeCoercePtr outBuf) outLenPtr (unsafeCoercePtr inBuf) inLen
+ _CipherUpdate ctxPtr (unsafeCoercePtr outBuf) outLenPtr inBuf inLen
>>= failIf (/= 1)
>> peek outLenPtr
View
3 OpenSSL/EVP/PKey.hsc
@@ -5,8 +5,7 @@ module OpenSSL.EVP.PKey
, EVP_PKEY
, wrapPKey -- private
-
- , pkeySize
+ , pkeySize -- private
-- FIXME: newPKeyDSA, newPKeyDH and newPKeyECKey may be needed
#ifndef OPENSSL_NO_RSA
View
4 OpenSSL/EVP/Seal.hsc
@@ -44,8 +44,8 @@ sealInit cipher pubKeys
-- は最大で pkeySize の長さになる。
encKeyBufs <- mapM mallocEncKeyBuf pubKeys
- -- encKeys は [Ptr a] なので、これを Ptr (Ptr CUChar) に
- -- しなければならない
+ -- encKeys は [Ptr a] なので、これを Ptr (Ptr CChar) にしなけ
+ -- ればならない
encKeyBufsPtr <- newArray encKeyBufs
-- 暗号化された共通鍵の各々の長さが書き込まれる場所を作る。
View
5 OpenSSL/EVP/Sign.hsc
@@ -23,7 +23,7 @@ import OpenSSL.Utils
foreign import ccall unsafe "EVP_SignFinal"
- _SignFinal :: Ptr EVP_MD_CTX -> Ptr CUChar -> Ptr CUInt -> Ptr EVP_PKEY -> IO Int
+ _SignFinal :: Ptr EVP_MD_CTX -> Ptr CChar -> Ptr CUInt -> Ptr EVP_PKEY -> IO Int
signInit :: EvpMD -> IO EvpMDCtx
@@ -51,7 +51,8 @@ signFinalBS ctx pkey
withForeignPtr pkey $ \ pkeyPtr ->
createAndTrim maxLen $ \ buf ->
alloca $ \ bufLen ->
- do _SignFinal ctxPtr (unsafeCoercePtr buf) bufLen pkeyPtr >>= failIf (/= 1)
+ do _SignFinal ctxPtr (unsafeCoercePtr buf) bufLen pkeyPtr
+ >>= failIf (/= 1)
liftM fromIntegral $ peek bufLen
View
5 OpenSSL/EVP/Verify.hsc
@@ -1,4 +1,5 @@
{- -*- haskell -*- -}
+#include "HsOpenSSL.h"
module OpenSSL.EVP.Verify
( verifyInit
, verifyUpdate
@@ -27,7 +28,7 @@ data VerifyStatus = VerifySuccess
foreign import ccall unsafe "EVP_VerifyFinal"
- _VerifyFinal :: Ptr EVP_MD_CTX -> Ptr CUChar -> CUInt -> Ptr EVP_PKEY -> IO Int
+ _VerifyFinal :: Ptr EVP_MD_CTX -> Ptr CChar -> CUInt -> Ptr EVP_PKEY -> IO Int
verifyInit :: EvpMD -> IO EvpMDCtx
@@ -56,7 +57,7 @@ verifyFinalBS ctx bs pkey
= withForeignPtr ctx $ \ ctxPtr ->
unsafeUseAsCStringLen bs $ \ (buf, len) ->
withForeignPtr pkey $ \ pkeyPtr ->
- _VerifyFinal ctxPtr (unsafeCoercePtr buf) (fromIntegral len) pkeyPtr >>= interpret
+ _VerifyFinal ctxPtr buf (fromIntegral len) pkeyPtr >>= interpret
where
interpret :: Int -> IO VerifyStatus
interpret 1 = return VerifySuccess
View
70 OpenSSL/PEM.hsc
@@ -4,14 +4,10 @@ module OpenSSL.PEM
, PemPasswordSupply(..)
, writePKCS8PrivateKey
- , writePKCS8PrivateKeyToString
, readPrivateKey
- , readPrivateKeyFromString
, writePublicKey
- , writePublicKeyToString
, readPublicKey
- , readPublicKeyFromString
)
where
@@ -21,7 +17,7 @@ import Control.Exception
import Control.Monad
import Foreign
import Foreign.C
-import OpenSSL.BIO as BIO
+import OpenSSL.BIO
import OpenSSL.EVP.Cipher
import OpenSSL.EVP.PKey
import OpenSSL.Utils
@@ -78,17 +74,17 @@ foreign import ccall safe "PEM_write_bio_PKCS8PrivateKey"
_write_bio_PKCS8PrivateKey :: Ptr BIO_
-> Ptr EVP_PKEY
-> Ptr EVP_CIPHER
- -> Ptr CUChar
+ -> Ptr CChar
-> Int
-> FunPtr PemPasswordCallback
-> Ptr a
-> IO Int
-writePKCS8PrivateKey :: BIO
- -> EvpPKey
- -> Maybe (EvpCipher, PemPasswordSupply)
- -> IO ()
-writePKCS8PrivateKey bio pkey encryption
+writePKCS8PrivateKey' :: BIO
+ -> EvpPKey
+ -> Maybe (EvpCipher, PemPasswordSupply)
+ -> IO ()
+writePKCS8PrivateKey' bio pkey encryption
= withForeignPtr bio $ \ bioPtr ->
withForeignPtr pkey $ \ pkeyPtr ->
do ret <- case encryption of
@@ -100,7 +96,7 @@ writePKCS8PrivateKey bio pkey encryption
Just (cipher, PwStr passStr)
-> withCStringLen passStr $ \ (passPtr, passLen) ->
- _write_bio_PKCS8PrivateKey bioPtr pkeyPtr cipher (unsafeCoercePtr passPtr) passLen nullFunPtr nullPtr
+ _write_bio_PKCS8PrivateKey bioPtr pkeyPtr cipher passPtr passLen nullFunPtr nullPtr
Just (cipher, PwCallback cb)
-> do cbPtr <- mkPemPasswordCallback $ callPasswordCB cb
@@ -114,11 +110,11 @@ writePKCS8PrivateKey bio pkey encryption
return ()
-writePKCS8PrivateKeyToString :: EvpPKey -> Maybe (EvpCipher, PemPasswordSupply) -> IO String
-writePKCS8PrivateKeyToString pkey encryption
- = do mem <- newMemBuf
- writePKCS8PrivateKey mem pkey encryption
- BIO.read mem
+writePKCS8PrivateKey :: EvpPKey -> Maybe (EvpCipher, PemPasswordSupply) -> IO String
+writePKCS8PrivateKey pkey encryption
+ = do mem <- newMem
+ writePKCS8PrivateKey' mem pkey encryption
+ bioRead mem
foreign import ccall safe "PEM_read_bio_PrivateKey"
@@ -128,8 +124,8 @@ foreign import ccall safe "PEM_read_bio_PrivateKey"
-> Ptr ()
-> IO (Ptr EVP_PKEY)
-readPrivateKey :: BIO -> PemPasswordSupply -> IO EvpPKey
-readPrivateKey bio supply
+readPrivateKey' :: BIO -> PemPasswordSupply -> IO EvpPKey
+readPrivateKey' bio supply
= withForeignPtr bio $ \ bioPtr ->
do pkeyPtr <- case supply of
PwNone
@@ -154,10 +150,10 @@ readPrivateKey bio supply
wrapPKey pkeyPtr
-readPrivateKeyFromString :: String -> PemPasswordSupply -> IO EvpPKey
-readPrivateKeyFromString pemStr supply
- = do mem <- newConstMemBuf pemStr
- readPrivateKey mem supply
+readPrivateKey :: String -> PemPasswordSupply -> IO EvpPKey
+readPrivateKey pemStr supply
+ = do mem <- newConstMem pemStr
+ readPrivateKey' mem supply
{- Public Key ---------------------------------------------------------------- -}
@@ -166,18 +162,18 @@ foreign import ccall unsafe "PEM_write_bio_PUBKEY"
_write_bio_PUBKEY :: Ptr BIO_ -> Ptr EVP_PKEY -> IO Int
-writePublicKey :: BIO -> EvpPKey -> IO ()
-writePublicKey bio pkey
+writePublicKey' :: BIO -> EvpPKey -> IO ()
+writePublicKey' bio pkey
= withForeignPtr bio $ \ bioPtr ->
withForeignPtr pkey $ \ pkeyPtr ->
_write_bio_PUBKEY bioPtr pkeyPtr >>= failIf (/= 1) >> return ()
-writePublicKeyToString :: EvpPKey -> IO String
-writePublicKeyToString pkey
- = do mem <- newMemBuf
- writePublicKey mem pkey
- BIO.read mem
+writePublicKey :: EvpPKey -> IO String
+writePublicKey pkey
+ = do mem <- newMem
+ writePublicKey' mem pkey
+ bioRead mem
foreign import ccall unsafe "PEM_read_bio_PUBKEY"
@@ -188,9 +184,9 @@ foreign import ccall unsafe "PEM_read_bio_PUBKEY"
-> IO (Ptr EVP_PKEY)
-- Why the heck PEM_read_bio_PUBKEY takes pem_password_cb? Is there
--- any form of encrypted public key!?
-readPublicKey :: BIO -> IO EvpPKey
-readPublicKey bio
+-- any form of encrypted public key?
+readPublicKey' :: BIO -> IO EvpPKey
+readPublicKey' bio
= withForeignPtr bio $ \ bioPtr ->
do cbPtr <- mkPemPasswordCallback $
callPasswordCB $ \ _ _ ->
@@ -202,7 +198,7 @@ readPublicKey bio
wrapPKey pkeyPtr
-readPublicKeyFromString :: String -> IO EvpPKey
-readPublicKeyFromString pemStr
- = do mem <- newConstMemBuf pemStr
- readPublicKey mem
+readPublicKey :: String -> IO EvpPKey
+readPublicKey pemStr
+ = do mem <- newConstMem pemStr
+ readPublicKey' mem
View
3 OpenSSL/Utils.hs
@@ -1,4 +1,7 @@
{- -*- haskell -*- -}
+
+-- #hide
+
module OpenSSL.Utils
( failIfNull
, failIf
View
74 cbits/HsOpenSSL.c
@@ -1,3 +1,4 @@
+#include <pthread.h>
#include "HsOpenSSL.h"
/* OpenSSL ********************************************************************/
@@ -18,6 +19,10 @@ int HsOpenSSL_BIO_flush(BIO* bio) {
return BIO_flush(bio);
}
+int HsOpenSSL_BIO_reset(BIO* bio) {
+ return BIO_reset(bio);
+}
+
int HsOpenSSL_BIO_eof(BIO* bio) {
return BIO_eof(bio);
}
@@ -26,6 +31,14 @@ int HsOpenSSL_BIO_set_md(BIO* bio, EVP_MD* md) {
return BIO_set_md(bio, md);
}
+int HsOpenSSL_BIO_set_buffer_size(BIO* bio, int bufSize) {
+ return BIO_set_buffer_size(bio, bufSize);
+}
+
+int HsOpenSSL_BIO_should_retry(BIO* bio) {
+ return BIO_should_retry(bio);
+}
+
int HsOpenSSL_BIO_FLAGS_BASE64_NO_NL() {
return BIO_FLAGS_BASE64_NO_NL;
}
@@ -42,3 +55,64 @@ int HsOpenSSL_EVP_CIPHER_CTX_block_size(EVP_CIPHER_CTX* ctx) {
int HsOpenSSL_EVP_CIPHER_iv_length(EVP_CIPHER* cipher) {
return EVP_CIPHER_iv_length(cipher);
}
+
+/* Threads ********************************************************************/
+static pthread_mutex_t* mutex_at;
+
+struct CRYPTO_dynlock_value {
+ pthread_mutex_t mutex;
+};
+
+static void HsOpenSSL_lockingCallback(int mode, int n, const char* file, int line) {
+ if (mode & CRYPTO_LOCK) {
+ pthread_mutex_lock(&mutex_at[n]);
+ }
+ else {
+ pthread_mutex_unlock(&mutex_at[n]);
+ }
+}
+
+static unsigned long HsOpenSSL_idCallback() {
+ return (unsigned long)pthread_self();
+}
+
+static struct CRYPTO_dynlock_value* HsOpenSSL_dynlockCreateCallback(const char* file, int line) {
+ struct CRYPTO_dynlock_value* val;
+
+ val = OPENSSL_malloc(sizeof(struct CRYPTO_dynlock_value));
+ pthread_mutex_init(&val->mutex, NULL);
+
+ return val;
+}
+
+static void HsOpenSSL_dynlockLockCallback(int mode, struct CRYPTO_dynlock_value* val, const char* file, int line) {
+ if (mode & CRYPTO_LOCK) {
+ pthread_mutex_lock(&val->mutex);
+ }
+ else {
+ pthread_mutex_unlock(&val->mutex);
+ }
+}
+
+static void HsOpenSSL_dynlockDestroyCallback(struct CRYPTO_dynlock_value* val, const char* file, int line) {
+ pthread_mutex_destroy(&val->mutex);
+ OPENSSL_free(val);
+}
+
+void HsOpenSSL_setupMutex() {
+ int i;
+
+ mutex_at = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
+
+ for (i = 0; i < CRYPTO_num_locks(); i++) {
+ pthread_mutex_init(&mutex_at[i], NULL);
+ }
+
+ CRYPTO_set_locking_callback(HsOpenSSL_lockingCallback);
+ CRYPTO_set_id_callback(HsOpenSSL_idCallback);
+
+ CRYPTO_set_dynlock_create_callback(HsOpenSSL_dynlockCreateCallback);
+ CRYPTO_set_dynlock_lock_callback(HsOpenSSL_dynlockLockCallback);
+ CRYPTO_set_dynlock_destroy_callback(HsOpenSSL_dynlockDestroyCallback);
+}
+
View
8 cbits/HsOpenSSL.h
@@ -3,6 +3,8 @@
#include <openssl/opensslconf.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
/* OpenSSL ********************************************************************/
void HsOpenSSL_OpenSSL_add_all_algorithms();
@@ -11,13 +13,19 @@ void HsOpenSSL_OPENSSL_free(void* ptr);
/* BIO ************************************************************************/
void HsOpenSSL_BIO_set_flags(BIO* bio, int flags);
int HsOpenSSL_BIO_flush(BIO* bio);
+int HsOpenSSL_BIO_reset(BIO* bio);
int HsOpenSSL_BIO_eof(BIO* bio);
int HsOpenSSL_BIO_set_md(BIO* bio, EVP_MD* md);
+int HsOpenSSL_BIO_set_buffer_size(BIO* bio, int bufSize);
+int HsOpenSSL_BIO_should_retry(BIO* bio);
int HsOpenSSL_BIO_FLAGS_BASE64_NO_NL();
/* EVP ************************************************************************/
int HsOpenSSL_EVP_MD_size(EVP_MD* md);
int HsOpenSSL_EVP_CIPHER_CTX_block_size(EVP_CIPHER_CTX* ctx);
int HsOpenSSL_EVP_CIPHER_iv_length(EVP_CIPHER* cipher);
+/* Threads ********************************************************************/
+void HsOpenSSL_setupMutex();
+
#endif
View
2 examples/HelloWorld.hs
@@ -4,6 +4,7 @@ import Data.Maybe
import OpenSSL
import OpenSSL.BN
import OpenSSL.BIO as BIO
+import OpenSSL.EVP.Base64
import OpenSSL.EVP.Cipher
import OpenSSL.EVP.Digest
import OpenSSL.EVP.Open
@@ -16,6 +17,7 @@ import OpenSSL.RSA
import System.IO
import Text.Printf
+
main = withOpenSSL $
do putStrLn "cipher: DES-CBC"
des <- liftM fromJust $ getCipherByName "DES-CBC"

0 comments on commit df27224

Please sign in to comment.