diff --git a/COPYING b/COPYING
new file mode 100644
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,29 @@
+<!-- -*- xml -*-
+
+HsOpenSSL はパブリックドメインに在ります。
+HsOpenSSL is in the public domain.
+
+See http://creativecommons.org/licenses/publicdomain/
+
+-->
+
+<rdf:RDF xmlns="http://web.resource.org/cc/"
+	     xmlns:dc="http://purl.org/dc/elements/1.1/"
+	     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+  <Work rdf:about="http://ccm.sherry.jp/HsOpenSSL/">
+	<dc:title>HsOpenSSL</dc:title>
+	<dc:rights>
+      <Agent>
+	    <dc:title>phonohawk</dc:title>
+	  </Agent>
+    </dc:rights>
+	<license rdf:resource="http://web.resource.org/cc/PublicDomain" />
+  </Work>
+      
+  <License rdf:about="http://web.resource.org/cc/PublicDomain">
+	<permits rdf:resource="http://web.resource.org/cc/Reproduction" />
+	<permits rdf:resource="http://web.resource.org/cc/Distribution" />
+	<permits rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+  </License>
+
+</rdf:RDF>
diff --git a/HsOpenSSL.buildinfo.in b/HsOpenSSL.buildinfo.in
new file mode 100644
--- /dev/null
+++ b/HsOpenSSL.buildinfo.in
@@ -0,0 +1,2 @@
+cc-options: @OPENSSL_CFLAGS@
+ld-options: @OPENSSL_LIBS@
diff --git a/HsOpenSSL.cabal b/HsOpenSSL.cabal
new file mode 100644
--- /dev/null
+++ b/HsOpenSSL.cabal
@@ -0,0 +1,63 @@
+Name: HsOpenSSL
+Synopsis: (Part of) OpenSSL binding for Haskell
+Description:
+        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
+License-File: COPYING
+Author: PHO <phonohawk at ps dot sakura dot ne dot jp>
+Maintainer: PHO <phonohawk at ps dot sakura dot ne dot jp>
+Stability: experimental
+Homepage: http://ccm.sherry.jp/HsOpenSSL/
+Category: Cryptography
+Tested-With: GHC == 6.6.1
+Build-Depends:
+        base, time
+Exposed-Modules:
+        OpenSSL
+        OpenSSL.ASN1
+        OpenSSL.BIO
+        OpenSSL.BN
+        OpenSSL.ERR
+        OpenSSL.EVP.Base64
+        OpenSSL.EVP.Cipher
+        OpenSSL.EVP.Digest
+        OpenSSL.EVP.Open
+        OpenSSL.EVP.PKey
+        OpenSSL.EVP.Seal
+        OpenSSL.EVP.Sign
+        OpenSSL.EVP.Verify
+        OpenSSL.Objects
+        OpenSSL.PEM
+        OpenSSL.PKCS7
+        OpenSSL.RSA
+        OpenSSL.SSL
+        OpenSSL.Stack
+        OpenSSL.Utils
+        OpenSSL.X509
+        OpenSSL.X509.Revocation
+        OpenSSL.X509.Name
+        OpenSSL.X509.Request
+        OpenSSL.X509.Store
+Extensions:
+        ForeignFunctionInterface
+ghc-options:
+        -fglasgow-exts -O2 -fwarn-unused-imports
+C-Sources:
+        cbits/HsOpenSSL.c
+Include-Dirs:
+        cbits
+Install-Includes:
+        HsOpenSSL.h
+Extra-Source-Files:
+        HsOpenSSL.buildinfo.in
+        cbits/HsOpenSSL.h
+        configure
+        configure.ac
+        examples/Makefile
+        examples/GenRSAKey.hs
+        examples/HelloWorld.hs
+        examples/PKCS7.hs
diff --git a/OpenSSL.hsc b/OpenSSL.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL.hsc
@@ -0,0 +1,78 @@
+{- -*- 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 v3 extension handling/] It 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 PKCS\#12 functionality/] It should be covered someday.
+--
+--   [/BIO/] BIO isn't needed because we are Haskell hackers. Though
+--   HsOpenSSL itself uses BIO internally.
+--
+--   [/ENGINE cryptographic module/] The default implementations work
+--   very well, don't they?
+--
+-- 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
+    )
+    where
+
+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 might
+-- crash.
+--
+-- > module Main where
+-- > import OpenSSL
+-- >
+-- > main :: IO ()
+-- > main = withOpenSSL $
+-- >        do ...
+--
+withOpenSSL :: IO a -> IO a
+withOpenSSL act
+    = do loadErrorStrings
+         addAllAlgorithms
+         setupMutex
+         act
diff --git a/OpenSSL/ASN1.hsc b/OpenSSL/ASN1.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/ASN1.hsc
@@ -0,0 +1,166 @@
+{- -*- haskell -*- -}
+
+-- #hide
+
+#include "HsOpenSSL.h"
+
+module OpenSSL.ASN1
+    ( ASN1_OBJECT
+    , obj2nid
+    , nid2sn
+    , nid2ln
+
+    , ASN1_STRING
+    , peekASN1String
+
+    , ASN1_INTEGER
+    , peekASN1Integer
+    , withASN1Integer
+
+    , ASN1_TIME
+    , peekASN1Time
+    , withASN1Time
+    )
+    where
+
+
+import           Control.Exception
+import           Control.Monad
+import           Data.Time.Clock
+import           Data.Time.Clock.POSIX
+import           Data.Time.Format
+import           Foreign
+import           Foreign.C
+import           OpenSSL.BIO
+import           OpenSSL.BN
+import           OpenSSL.Utils
+import           System.Locale
+
+{- ASN1_OBJECT --------------------------------------------------------------- -}
+
+data ASN1_OBJECT
+
+foreign import ccall unsafe "OBJ_obj2nid"
+        obj2nid :: Ptr ASN1_OBJECT -> IO Int
+
+foreign import ccall unsafe "OBJ_nid2sn"
+        _nid2sn :: Int -> IO CString
+
+foreign import ccall unsafe "OBJ_nid2ln"
+        _nid2ln :: Int -> IO CString
+
+
+nid2sn :: Int -> IO String
+nid2sn nid = _nid2sn nid >>= peekCString
+
+
+nid2ln :: Int -> IO String
+nid2ln nid = _nid2ln nid >>= peekCString
+
+
+{- ASN1_STRING --------------------------------------------------------------- -}
+
+data ASN1_STRING
+
+peekASN1String :: Ptr ASN1_STRING -> IO String
+peekASN1String strPtr
+    = do buf <- (#peek ASN1_STRING, data  ) strPtr
+         len <- (#peek ASN1_STRING, length) strPtr
+         peekCStringLen (buf, len)
+
+
+{- ASN1_INTEGER -------------------------------------------------------------- -}
+
+data ASN1_INTEGER
+
+foreign import ccall unsafe "HsOpenSSL_M_ASN1_INTEGER_new"
+        _ASN1_INTEGER_new :: IO (Ptr ASN1_INTEGER)
+
+foreign import ccall unsafe "HsOpenSSL_M_ASN1_INTEGER_free"
+        _ASN1_INTEGER_free :: Ptr ASN1_INTEGER -> IO ()
+
+foreign import ccall unsafe "ASN1_INTEGER_to_BN"
+        _ASN1_INTEGER_to_BN :: Ptr ASN1_INTEGER -> BigNum -> IO BigNum
+
+foreign import ccall unsafe "BN_to_ASN1_INTEGER"
+        _BN_to_ASN1_INTEGER :: BigNum -> Ptr ASN1_INTEGER -> IO (Ptr ASN1_INTEGER)
+
+
+peekASN1Integer :: Ptr ASN1_INTEGER -> IO Integer
+peekASN1Integer intPtr
+    = allocaBN $ \ bn ->
+      do _ASN1_INTEGER_to_BN intPtr bn
+              >>= failIfNull
+         peekBN bn
+
+
+allocaASN1Integer :: (Ptr ASN1_INTEGER -> IO a) -> IO a
+allocaASN1Integer m
+    = bracket _ASN1_INTEGER_new _ASN1_INTEGER_free m
+
+
+withASN1Integer :: Integer -> (Ptr ASN1_INTEGER -> IO a) -> IO a
+withASN1Integer int m
+    = withBN int $ \ bn ->
+      allocaASN1Integer $ \ intPtr ->
+      do _BN_to_ASN1_INTEGER bn intPtr
+              >>= failIfNull
+         m intPtr
+
+
+{- ASN1_TIME ---------------------------------------------------------------- -}
+
+data ASN1_TIME
+
+foreign import ccall unsafe "HsOpenSSL_M_ASN1_TIME_new"
+        _ASN1_TIME_new :: IO (Ptr ASN1_TIME)
+
+foreign import ccall unsafe "HsOpenSSL_M_ASN1_TIME_free"
+        _ASN1_TIME_free :: Ptr ASN1_TIME -> IO ()
+
+foreign import ccall unsafe "ASN1_TIME_set"
+        _ASN1_TIME_set :: Ptr ASN1_TIME -> CTime -> IO (Ptr ASN1_TIME)
+
+foreign import ccall unsafe "ASN1_TIME_print"
+        _ASN1_TIME_print :: Ptr BIO_ -> Ptr ASN1_TIME -> IO Int
+
+
+peekASN1Time :: Ptr ASN1_TIME -> IO UTCTime -- asn1/t_x509.c
+peekASN1Time time
+    = do bio <- newMem
+         withBioPtr bio $ \ bioPtr ->
+             _ASN1_TIME_print bioPtr time
+                  >>= failIf (/= 1)
+         timeStr <- bioRead bio
+         case parseTime locale "%b %e %H:%M:%S %Y %Z" timeStr of
+           Just utc -> return utc
+           Nothing  -> fail ("peekASN1Time: failed to parse time string: " ++ timeStr)
+    where
+      locale :: TimeLocale
+      locale = TimeLocale {
+                 wDays       = undefined
+               , months      = [ (undefined, x)
+                                     | x <- [ "Jan", "Feb", "Mar", "Apr", "May", "Jun"
+                                            , "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+                                            ]
+                               ]
+               , intervals   = undefined
+               , amPm        = undefined
+               , dateTimeFmt = undefined
+               , dateFmt     = undefined
+               , timeFmt     = undefined
+               , time12Fmt   = undefined
+               }
+
+
+allocaASN1Time :: (Ptr ASN1_TIME -> IO a) -> IO a
+allocaASN1Time m
+    = bracket _ASN1_TIME_new _ASN1_TIME_free m
+
+
+withASN1Time :: UTCTime -> (Ptr ASN1_TIME -> IO a) -> IO a
+withASN1Time utc m
+    = allocaASN1Time $ \ time ->
+      do _ASN1_TIME_set time (fromIntegral $ round $ utcTimeToPOSIXSeconds utc)
+              >>= failIfNull
+         m time
diff --git a/OpenSSL/BIO.hsc b/OpenSSL/BIO.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/BIO.hsc
@@ -0,0 +1,477 @@
+{- -*- 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.      -}
+{-          I FOUND AN UNDOCUMENTED API FOR THE VERY BASE64 CODEC.             -}
+{- So I decided to bury all the OpenSSL.BIO module. The game is over.          -}
+{-                                                                             -}
+{- --------------------------------------------------------------------------- -}
+
+
+-- |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
+    ( -- * Type
+      BIO
+    , BIO_
+
+    , wrapBioPtr  -- private
+    , withBioPtr  -- private
+    , withBioPtr' -- private
+
+      -- * BIO chaning
+    , bioPush
+    , (==>)
+    , (<==)
+    , 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
+
+      -- * Memory BIO sink\/source
+    , newMem
+    , newConstMem
+    , newConstMemBS
+    , newConstMemLBS
+
+      -- * Null data BIO sink\/source
+    , newNullBIO
+    )
+    where
+
+import           Control.Monad
+import           Data.ByteString.Base
+import qualified Data.ByteString.Char8      as B8
+import qualified Data.ByteString.Lazy.Char8 as L8
+import           Foreign                    hiding (new)
+import           Foreign.C
+import qualified GHC.ForeignPtr             as GF
+import           OpenSSL.Utils
+import           System.IO.Unsafe
+
+{- bio ---------------------------------------------------------------------- -}
+
+data    BIO_METHOD
+
+-- |@BIO@ is a @ForeignPtr@ to an opaque BIO object. They are created by newXXX actions.
+newtype BIO  = BIO (ForeignPtr BIO_)
+data    BIO_
+
+foreign import ccall unsafe "BIO_new"
+        _new :: Ptr BIO_METHOD -> IO (Ptr BIO_)
+
+foreign import ccall unsafe "&BIO_free"
+        _free :: FunPtr (Ptr BIO_ -> IO ())
+
+foreign import ccall unsafe "BIO_push"
+        _push :: Ptr BIO_ -> Ptr BIO_ -> IO (Ptr BIO_)
+
+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 :: Ptr BIO_METHOD -> IO BIO
+new method
+    = _new method >>= failIfNull >>= wrapBioPtr
+
+
+wrapBioPtr :: Ptr BIO_ -> IO BIO
+wrapBioPtr bioPtr = newForeignPtr _free bioPtr >>= return . BIO
+
+
+withBioPtr :: BIO -> (Ptr BIO_ -> IO a) -> IO a
+withBioPtr (BIO bio) = withForeignPtr bio
+
+
+withBioPtr' :: Maybe BIO -> (Ptr BIO_ -> IO a) -> IO a
+withBioPtr' Nothing    f = f nullPtr
+withBioPtr' (Just bio) f = withBioPtr bio f
+
+
+-- a の後ろに b を付ける。a の參照だけ保持してそこに書き込む事も、b の
+-- 參照だけ保持してそこから讀み出す事も、兩方考へられるので、双方の
+-- ForeignPtr が双方を touch する。參照カウント方式ではないから循環參照
+-- しても問題無い。
+
+-- |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 (BIO a) (BIO 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
+
+-- |@a '<==' b@ is an alias to @'bioPush' b a@.
+(<==) :: BIO -> BIO -> IO ()
+(<==) = flip bioPush
+
+
+-- |@'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
+    = withBioPtr bio $ \ bioPtr ->
+      _set_flags bioPtr flags
+
+bioShouldRetry :: BIO -> IO Bool
+bioShouldRetry bio
+    = withBioPtr 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
+
+-- |@'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
+    = withBioPtr bio $ \ bioPtr ->
+      _flush bioPtr >>= failIf (/= 1) >> return ()
+
+-- |@'bioReset' bio@ typically resets a BIO to some initial state.
+bioReset :: BIO -> IO ()
+bioReset bio
+    = withBioPtr bio $ \ bioPtr ->
+      _reset bioPtr >> return () -- BIO_reset の戻り値は全 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
+    = withBioPtr bio $ \ bioPtr ->
+      _eof bioPtr >>= return . (== 1)
+
+
+{- I/O ---------------------------------------------------------------------- -}
+
+foreign import ccall unsafe "BIO_read"
+        _read :: Ptr BIO_ -> Ptr CChar -> Int -> IO Int
+
+foreign import ccall unsafe "BIO_gets"
+        _gets :: Ptr BIO_ -> Ptr CChar -> Int -> IO Int
+
+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
+
+-- |@'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
+    = withBioPtr bio       $ \ bioPtr ->
+      createAndTrim maxLen $ \ bufPtr ->
+      _read bioPtr (unsafeCoercePtr bufPtr) maxLen >>= interpret
+    where
+      interpret :: Int -> IO Int
+      interpret n
+          | n ==  0   = return 0
+          | n == -1   = return 0
+          | n <  -1   = raiseOpenSSLError
+          | otherwise = return n
+
+-- |@'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 <- bioReadBS bio chunkSize
+                if B8.null bs then
+                    do isEOF <- bioEOF bio
+                       if isEOF then
+                           return []
+                         else
+                           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)
+
+-- |@'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
+    = withBioPtr bio       $ \ bioPtr ->
+      createAndTrim maxLen $ \ bufPtr ->
+      _gets bioPtr (unsafeCoercePtr bufPtr) maxLen >>= interpret
+    where
+      interpret :: Int -> IO Int
+      interpret n
+          | n ==  0   = return 0
+          | n == -1   = return 0
+          | n <  -1   = raiseOpenSSLError
+          | otherwise = return n
+
+-- |'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
+    = withBioPtr bio           $ \ bioPtr ->
+      unsafeUseAsCStringLen bs $ \ (buf, len) ->
+      _write bioPtr buf len >>= interpret
+    where
+      interpret :: Int -> IO ()
+      interpret n
+          | n == B8.length bs = return ()
+          | n == -1           = bioWriteBS bio bs -- full retry
+          | n <  -1           = raiseOpenSSLError
+          | otherwise         = bioWriteBS bio (B8.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
+
+
+{- base64 ------------------------------------------------------------------- -}
+
+foreign import ccall unsafe "BIO_f_base64"
+        f_base64 :: IO (Ptr BIO_METHOD)
+
+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 (Ptr BIO_METHOD)
+
+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  -> withBioPtr bio $ \ bioPtr ->
+                      _set_buffer_size bioPtr n
+                           >>= failIf (/= 1) >> return ()
+           Nothing -> return ()
+         return bio
+
+
+{- mem ---------------------------------------------------------------------- -}
+
+foreign import ccall unsafe "BIO_s_mem"
+        s_mem :: IO (Ptr BIO_METHOD)
+
+foreign import ccall unsafe "BIO_new_mem_buf"
+        _new_mem_buf :: Ptr CChar -> Int -> IO (Ptr BIO_)
+
+
+-- |@'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
+
+           bio <- newForeignPtr _free bioPtr
+           GF.addForeignPtrConcFinalizer bio $ touchForeignPtr foreignBuf
+           
+           return $ BIO bio
+
+-- |@'newConstMemLBS' lbs@ is like 'newConstMem' but takes a
+-- LazyByteString.
+newConstMemLBS :: LazyByteString -> IO BIO
+newConstMemLBS (LPS bss)
+    = (return . B8.concat) bss >>= newConstMemBS
+
+{- null --------------------------------------------------------------------- -}
+
+foreign import ccall unsafe "BIO_s_null"
+        s_null :: IO (Ptr BIO_METHOD)
+
+-- |@'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
diff --git a/OpenSSL/BN.hsc b/OpenSSL/BN.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/BN.hsc
@@ -0,0 +1,64 @@
+{- -*- haskell -*- -}
+
+-- #hide
+
+module OpenSSL.BN
+    ( BigNum
+    , BIGNUM
+
+    , allocaBN
+    , withBN
+    , peekBN
+    )
+    where
+
+import           Control.Exception
+import           Control.Monad
+import           Foreign
+import           Foreign.C
+import           OpenSSL.Utils
+
+
+type BigNum = Ptr BIGNUM
+data BIGNUM = BIGNUM
+
+
+foreign import ccall unsafe "BN_new"
+        _new :: IO BigNum
+
+foreign import ccall unsafe "BN_free"
+        _free :: BigNum -> IO ()
+
+foreign import ccall unsafe "BN_bn2dec"
+        _bn2dec :: BigNum -> IO CString
+
+foreign import ccall unsafe "BN_dec2bn"
+        _dec2bn :: Ptr BigNum -> CString -> IO Int
+
+foreign import ccall unsafe "HsOpenSSL_OPENSSL_free"
+        _openssl_free :: Ptr a -> IO ()
+
+
+allocaBN :: (BigNum -> IO a) -> IO a
+allocaBN m
+    = bracket _new _free m
+
+
+withBN :: Integer -> (BigNum -> IO a) -> IO a
+withBN dec m
+    = withCString (show dec) $ \ strPtr ->
+      alloca $ \ bnPtr ->
+      do _dec2bn bnPtr strPtr
+              >>= failIf (== 0)
+         bracket (peek bnPtr) _free m
+
+
+peekBN :: BigNum -> IO Integer
+peekBN bn
+    = do strPtr <- _bn2dec bn
+         when (strPtr == nullPtr) $ fail "BN_bn2dec failed"
+         
+         str <- peekCString strPtr
+         _openssl_free strPtr
+
+         return $ read str
diff --git a/OpenSSL/ERR.hsc b/OpenSSL/ERR.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/ERR.hsc
@@ -0,0 +1,37 @@
+{- -*- haskell -*- -}
+
+-- #hide
+
+module OpenSSL.ERR
+    ( getError
+    , peekError
+
+    , errorString
+    )
+    where
+
+import           Foreign
+import           Foreign.C
+
+
+foreign import ccall unsafe "ERR_get_error"
+        _get_error :: IO CULong
+
+foreign import ccall unsafe "ERR_peek_error"
+        _peek_error :: IO CULong
+
+foreign import ccall unsafe "ERR_error_string"
+        _error_string :: CULong -> CString -> IO CString
+
+
+getError :: IO Integer
+getError = _get_error >>= return . fromIntegral
+
+
+peekError :: IO Integer
+peekError = _peek_error >>= return . fromIntegral
+
+
+errorString :: Integer -> IO String
+errorString code
+    = _error_string (fromIntegral code) nullPtr >>= peekCString
diff --git a/OpenSSL/EVP/Base64.hsc b/OpenSSL/EVP/Base64.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/EVP/Base64.hsc
@@ -0,0 +1,138 @@
+{- -*- haskell -*- -}
+
+-- |An interface to Base64 codec.
+
+module OpenSSL.EVP.Base64
+    ( -- * Encoding
+      encodeBase64
+    , encodeBase64BS
+    , encodeBase64LBS
+
+      -- * Decoding
+    , decodeBase64
+    , decodeBase64BS
+    , decodeBase64LBS
+    )
+    where
+
+import           Control.Exception
+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] は B8.concat してから、その文字列長より小さ
+-- な最大の 3 の倍數の位置で分割し、殘りは次のブロックの一部と見做す。
+--
+-- デコード時: 分割のアルゴリズムは同じだが最低バイト数が 4。
+nextBlock :: Int -> ([ByteString], LazyByteString) -> ([ByteString], LazyByteString)
+nextBlock _      (xs, LPS [] ) = (xs, LPS [])
+nextBlock minLen (xs, LPS src) = if foldl' (+) 0 (map B8.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  = B8.length inBS
+
+
+-- |@'encodeBase64' str@ lazilly encodes a stream of data to
+-- Base64. The string doesn't have to be finite. Note that the string
+-- must not contain any letters which aren't in the range of U+0000 -
+-- U+00FF.
+encodeBase64 :: String -> String
+encodeBase64 = L8.unpack . encodeBase64LBS . L8.pack
+
+-- |@'encodeBase64BS' bs@ strictly encodes a chunk of data to Base64.
+encodeBase64BS :: ByteString -> ByteString
+encodeBase64BS = encodeBlock
+
+-- |@'encodeBase64LBS' lbs@ lazilly encodes a stream of data to
+-- Base64. The string doesn't have to be finite.
+encodeBase64LBS :: LazyByteString -> LazyByteString
+encodeBase64LBS inLBS
+    | L8.null inLBS = L8.empty
+    | otherwise
+        = let (blockParts', remain' ) = nextBlock 3 ([], inLBS)
+              block'                  = B8.concat blockParts'
+              blockLen'               = B8.length block'
+              (block      , leftover) = if blockLen' < 3 then
+                                            -- 最後の半端
+                                            (block', B8.empty)
+                                        else
+                                            B8.splitAt (blockLen' - blockLen' `mod` 3) block'
+              remain                  = if B8.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 (B8.length inBS `mod` 4 == 0) $
+      unsafePerformIO $
+      unsafeUseAsCStringLen inBS $ \ (inBuf, inLen) ->
+      createAndTrim (B8.length inBS) $ \ outBuf ->
+      _DecodeBlock (unsafeCoercePtr outBuf) inBuf inLen
+
+-- |@'decodeBase64' str@ lazilly decodes a stream of data from
+-- Base64. The string doesn't have to be finite.
+decodeBase64 :: String -> String
+decodeBase64 = L8.unpack . decodeBase64LBS . L8.pack
+
+-- |@'decodeBase64BS' bs@ strictly decodes a chunk of data from
+-- Base64.
+decodeBase64BS :: ByteString -> ByteString
+decodeBase64BS = decodeBlock
+
+-- |@'decodeBase64LBS' lbs@ lazilly decodes a stream of data from
+-- Base64. The string doesn't have to be finite.
+decodeBase64LBS :: LazyByteString -> LazyByteString
+decodeBase64LBS inLBS
+    | L8.null inLBS = L8.empty
+    | otherwise
+        = let (blockParts', remain' ) = nextBlock 4 ([], inLBS)
+              block'                  = B8.concat blockParts'
+              blockLen'               = B8.length block'
+              (block      , leftover) = assert (blockLen' >= 4) $
+                                        B8.splitAt (blockLen' - blockLen' `mod` 4) block'
+              remain                  = if B8.null leftover then
+                                            remain'
+                                        else
+                                            case remain' of
+                                              LPS xs -> LPS (leftover:xs)
+              decodedBlock            = decodeBlock block
+              LPS decodedRemain       = decodeBase64LBS remain
+          in
+            LPS ([decodedBlock] ++ decodedRemain)
diff --git a/OpenSSL/EVP/Cipher.hsc b/OpenSSL/EVP/Cipher.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/EVP/Cipher.hsc
@@ -0,0 +1,221 @@
+{- -*- haskell -*- -}
+
+-- #prune
+
+-- |An interface to symmetric cipher algorithms.
+
+#include "HsOpenSSL.h"
+
+module OpenSSL.EVP.Cipher
+    ( Cipher
+    , EVP_CIPHER -- private
+    , withCipherPtr -- private
+
+    , getCipherByName
+    , getCipherNames
+
+    , cipherIvLength -- private
+
+    , CipherCtx -- private
+    , EVP_CIPHER_CTX -- private
+    , newCtx -- private
+    , withCipherCtxPtr -- private
+
+    , CryptoMode(..)
+
+    , cipherStrictly -- private
+    , cipherLazily -- private
+
+    , cipher
+    , cipherBS
+    , cipherLBS
+    )
+    where
+
+import           Control.Monad
+import           Data.ByteString.Base
+import qualified Data.ByteString.Char8 as B8
+import qualified Data.ByteString.Lazy.Char8 as L8
+import           Foreign
+import           Foreign.C
+import           OpenSSL.Objects
+import           OpenSSL.Utils
+import           System.IO.Unsafe
+
+
+{- EVP_CIPHER ---------------------------------------------------------------- -}
+
+-- |@Cipher@ is an opaque object that represents an algorithm of
+-- symmetric cipher.
+newtype Cipher     = Cipher (Ptr EVP_CIPHER)
+data    EVP_CIPHER
+
+
+foreign import ccall unsafe "EVP_get_cipherbyname"
+        _get_cipherbyname :: CString -> IO (Ptr EVP_CIPHER)
+
+
+foreign import ccall unsafe "HsOpenSSL_EVP_CIPHER_iv_length"
+        _iv_length :: Ptr EVP_CIPHER -> Int
+
+
+withCipherPtr :: Cipher -> (Ptr EVP_CIPHER -> IO a) -> IO a
+withCipherPtr (Cipher cipher) f = f cipher
+
+-- |@'getCipherByName' name@ returns a symmetric cipher algorithm
+-- whose name is @name@. If no algorithms are found, the result is
+-- @Nothing@.
+getCipherByName :: String -> IO (Maybe Cipher)
+getCipherByName name
+    = withCString name $ \ namePtr ->
+      do ptr <- _get_cipherbyname namePtr
+         if ptr == nullPtr then
+             return Nothing
+           else
+             return $ Just $ Cipher ptr
+
+-- |@'getCipherNames'@ returns a list of name of symmetric cipher
+-- algorithms.
+getCipherNames :: IO [String]
+getCipherNames = getObjNames CipherMethodType True
+
+
+cipherIvLength :: Cipher -> Int
+cipherIvLength (Cipher cipher) = _iv_length cipher
+
+
+{- EVP_CIPHER_CTX ------------------------------------------------------------ -}
+
+newtype CipherCtx      = CipherCtx (ForeignPtr EVP_CIPHER_CTX)
+data    EVP_CIPHER_CTX
+
+
+foreign import ccall unsafe "EVP_CIPHER_CTX_init"
+        _ctx_init :: Ptr EVP_CIPHER_CTX -> IO ()
+
+foreign import ccall unsafe "&EVP_CIPHER_CTX_cleanup"
+        _ctx_cleanup :: FunPtr (Ptr EVP_CIPHER_CTX -> IO ())
+
+foreign import ccall unsafe "HsOpenSSL_EVP_CIPHER_CTX_block_size"
+        _ctx_block_size :: Ptr EVP_CIPHER_CTX -> Int
+
+
+newCtx :: IO CipherCtx
+newCtx = do ctx <- mallocForeignPtrBytes (#size EVP_CIPHER_CTX)
+            withForeignPtr ctx $ \ ctxPtr ->
+                _ctx_init ctxPtr
+            addForeignPtrFinalizer _ctx_cleanup ctx
+            return $ CipherCtx ctx
+
+
+withCipherCtxPtr :: CipherCtx -> (Ptr EVP_CIPHER_CTX -> IO a) -> IO a
+withCipherCtxPtr (CipherCtx ctx) = withForeignPtr ctx
+
+
+{- encrypt/decrypt ----------------------------------------------------------- -}
+
+-- |@CryptoMode@ represents instruction to 'cipher' and such like.
+data CryptoMode = Encrypt | Decrypt
+
+
+foreign import ccall unsafe "EVP_CipherInit"
+        _CipherInit :: Ptr EVP_CIPHER_CTX -> Ptr EVP_CIPHER -> CString -> CString -> Int -> IO Int
+
+foreign import ccall unsafe "EVP_CipherUpdate"
+        _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 CChar -> Ptr Int -> IO Int
+
+
+cryptoModeToInt :: CryptoMode -> Int
+cryptoModeToInt Encrypt = 1
+cryptoModeToInt Decrypt = 0
+
+
+cipherInit :: Cipher -> String -> String -> CryptoMode -> IO CipherCtx
+cipherInit (Cipher c) key iv mode
+    = do ctx <- newCtx
+         withCipherCtxPtr ctx $ \ ctxPtr ->
+             withCString key $ \ keyPtr ->
+                 withCString iv $ \ ivPtr ->
+                     _CipherInit ctxPtr c keyPtr ivPtr (cryptoModeToInt mode)
+                          >>= failIf (/= 1)
+         return ctx
+
+
+cipherUpdateBS :: CipherCtx -> ByteString -> IO ByteString
+cipherUpdateBS ctx inBS
+    = withCipherCtxPtr ctx $ \ ctxPtr ->
+      unsafeUseAsCStringLen inBS $ \ (inBuf, inLen) ->
+      createAndTrim (inLen + _ctx_block_size ctxPtr - 1) $ \ outBuf ->
+      alloca $ \ outLenPtr ->
+      _CipherUpdate ctxPtr (unsafeCoercePtr outBuf) outLenPtr inBuf inLen
+           >>= failIf (/= 1)
+           >>  peek outLenPtr
+
+
+cipherFinalBS :: CipherCtx -> IO ByteString
+cipherFinalBS ctx
+    = withCipherCtxPtr ctx $ \ ctxPtr ->
+      createAndTrim (_ctx_block_size ctxPtr) $ \ outBuf ->
+      alloca $ \ outLenPtr ->
+      _CipherFinal ctxPtr (unsafeCoercePtr outBuf) outLenPtr
+           >>= failIf (/= 1)
+           >>  peek outLenPtr
+
+-- |@'cipher'@ lazilly encrypts or decrypts a stream of data. The
+-- input string doesn't necessarily have to be finite.
+cipher :: Cipher     -- ^ algorithm to use
+       -> String     -- ^ symmetric key
+       -> String     -- ^ IV
+       -> CryptoMode -- ^ operation
+       -> String     -- ^ An input string to encrypt\/decrypt. Note
+                     --   that the string must not contain any letters
+                     --   which aren't in the range of U+0000 -
+                     --   U+00FF.
+       -> IO String  -- ^ the result string
+cipher c key iv mode input
+    = liftM L8.unpack $ cipherLBS c key iv mode $ L8.pack input
+
+-- |@'cipherBS'@ strictly encrypts or decrypts a chunk of data.
+cipherBS :: Cipher        -- ^ algorithm to use
+         -> String        -- ^ symmetric key
+         -> String        -- ^ IV
+         -> CryptoMode    -- ^ operation
+         -> ByteString    -- ^ input string to encrypt\/decrypt
+         -> IO ByteString -- ^ the result string
+cipherBS c key iv mode input
+    = do ctx <- cipherInit c key iv mode
+         cipherStrictly ctx input
+
+-- |@'cipherLBS'@ lazilly encrypts or decrypts a stream of data. The
+-- input string doesn't necessarily have to be finite.
+cipherLBS :: Cipher            -- ^ algorithm to use
+          -> String            -- ^ symmetric key
+          -> String            -- ^ IV
+          -> CryptoMode        -- ^ operation
+          -> LazyByteString    -- ^ input string to encrypt\/decrypt
+          -> IO LazyByteString -- ^ the result string
+cipherLBS c key iv mode input
+    = do ctx <- cipherInit c key iv mode
+         cipherLazily ctx input
+
+
+cipherStrictly :: CipherCtx -> ByteString -> IO ByteString
+cipherStrictly ctx input
+    = do output'  <- cipherUpdateBS ctx input
+         output'' <- cipherFinalBS ctx
+         return $ B8.append output' output''
+
+
+cipherLazily :: CipherCtx -> LazyByteString -> IO LazyByteString
+
+cipherLazily ctx (LPS [])
+    = cipherFinalBS ctx >>= \ bs -> (return . LPS) [bs]
+
+cipherLazily ctx (LPS (x:xs))
+    = do y      <- cipherUpdateBS ctx x
+         LPS ys <- unsafeInterleaveIO $
+                   cipherLazily ctx (LPS xs)
+         return $ LPS (y:ys)
diff --git a/OpenSSL/EVP/Digest.hsc b/OpenSSL/EVP/Digest.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/EVP/Digest.hsc
@@ -0,0 +1,175 @@
+{- -*- haskell -*- -}
+
+-- #prune
+
+-- |An interface to message digest algorithms.
+
+#include "HsOpenSSL.h"
+
+module OpenSSL.EVP.Digest
+    ( Digest
+    , EVP_MD -- private
+    , withMDPtr -- private
+
+    , getDigestByName
+    , getDigestNames
+
+    , DigestCtx -- private
+    , EVP_MD_CTX -- private
+    , withDigestCtxPtr -- private
+
+    , digestStrictly -- private
+    , digestLazily   -- private
+
+    , digest
+    , digestBS
+    , digestLBS
+    )
+    where
+
+import           Control.Monad
+import           Data.ByteString.Base
+import qualified Data.ByteString.Char8 as B8
+import qualified Data.ByteString.Lazy.Char8 as L8
+import           Foreign
+import           Foreign.C
+import           OpenSSL.Objects
+import           OpenSSL.Utils
+
+
+{- EVP_MD -------------------------------------------------------------------- -}
+
+-- |@Digest@ is an opaque object that represents an algorithm of
+-- message digest.
+newtype Digest  = Digest (Ptr EVP_MD)
+data    EVP_MD
+
+
+foreign import ccall unsafe "EVP_get_digestbyname"
+        _get_digestbyname :: CString -> IO (Ptr EVP_MD)
+
+foreign import ccall unsafe "HsOpenSSL_EVP_MD_size"
+        mdSize :: Ptr EVP_MD -> Int
+
+
+withMDPtr :: Digest -> (Ptr EVP_MD -> IO a) -> IO a
+withMDPtr (Digest mdPtr) f = f mdPtr
+
+-- |@'getDigestByName' name@ returns a message digest algorithm whose
+-- name is @name@. If no algorithms are found, the result is
+-- @Nothing@.
+getDigestByName :: String -> IO (Maybe Digest)
+getDigestByName name
+    = withCString name $ \ namePtr ->
+      do ptr <- _get_digestbyname namePtr
+         if ptr == nullPtr then
+             return Nothing
+           else
+             return $ Just $ Digest ptr
+
+-- |@'getDigestNames'@ returns a list of name of message digest
+-- algorithms.
+getDigestNames :: IO [String]
+getDigestNames = getObjNames MDMethodType True
+
+
+{- EVP_MD_CTX ---------------------------------------------------------------- -}
+
+newtype DigestCtx  = DigestCtx (ForeignPtr EVP_MD_CTX)
+data    EVP_MD_CTX
+
+
+foreign import ccall unsafe "EVP_MD_CTX_init"
+        _ctx_init :: Ptr EVP_MD_CTX -> IO ()
+
+foreign import ccall unsafe "&EVP_MD_CTX_cleanup"
+        _ctx_cleanup :: FunPtr (Ptr EVP_MD_CTX -> IO ())
+
+
+newCtx :: IO DigestCtx
+newCtx = do ctx <- mallocForeignPtrBytes (#size EVP_MD_CTX)
+            withForeignPtr ctx $ \ ctxPtr ->
+                _ctx_init ctxPtr
+            addForeignPtrFinalizer _ctx_cleanup ctx
+            return $ DigestCtx ctx
+
+
+withDigestCtxPtr :: DigestCtx -> (Ptr EVP_MD_CTX -> IO a) -> IO a
+withDigestCtxPtr (DigestCtx ctx) = withForeignPtr ctx
+
+
+{- digest -------------------------------------------------------------------- -}
+
+foreign import ccall unsafe "EVP_DigestInit"
+        _DigestInit :: Ptr EVP_MD_CTX -> Ptr EVP_MD -> IO Int
+
+foreign import ccall unsafe "EVP_DigestUpdate"
+        _DigestUpdate :: Ptr EVP_MD_CTX -> Ptr CChar -> CSize -> IO Int
+
+foreign import ccall unsafe "EVP_DigestFinal"
+        _DigestFinal :: Ptr EVP_MD_CTX -> Ptr CChar -> Ptr CUInt -> IO Int
+
+
+digestInit :: Digest -> IO DigestCtx
+digestInit (Digest md)
+    = do ctx <- newCtx
+         withDigestCtxPtr ctx $ \ ctxPtr ->
+             _DigestInit ctxPtr md >>= failIf (/= 1)
+         return ctx   
+
+
+digestUpdateBS :: DigestCtx -> ByteString -> IO ()
+digestUpdateBS ctx bs
+    = withDigestCtxPtr ctx $ \ ctxPtr ->
+      unsafeUseAsCStringLen bs $ \ (buf, len) ->
+      _DigestUpdate ctxPtr buf (fromIntegral len) >>= failIf (/= 1) >> return ()
+
+
+digestUpdateLBS :: DigestCtx -> LazyByteString -> IO ()
+digestUpdateLBS ctx (LPS chunks)
+    = mapM_ (digestUpdateBS ctx) chunks
+
+
+digestFinal :: DigestCtx -> IO String
+digestFinal ctx
+    = withDigestCtxPtr ctx $ \ ctxPtr ->
+      allocaArray (#const EVP_MAX_MD_SIZE) $ \ bufPtr ->
+      alloca $ \ bufLenPtr ->
+      do _DigestFinal ctxPtr bufPtr bufLenPtr >>= failIf (/= 1)
+         bufLen <- liftM fromIntegral $ peek bufLenPtr
+         peekCStringLen (bufPtr, bufLen)
+
+
+digestStrictly :: Digest -> ByteString -> IO DigestCtx
+digestStrictly md input
+    = do ctx <- digestInit md
+         digestUpdateBS ctx input
+         return ctx
+
+
+digestLazily :: Digest -> LazyByteString -> IO DigestCtx
+digestLazily md (LPS input)
+    = do ctx <- digestInit md
+         mapM_ (digestUpdateBS ctx) input
+         return ctx
+
+-- |@'digest'@ digests a stream of data. The string must
+-- not contain any letters which aren't in the range of U+0000 -
+-- U+00FF.
+digest :: Digest -> String -> String
+digest md input
+    = digestLBS md $ L8.pack input
+
+-- |@'digestBS'@ digests a chunk of data.
+digestBS :: Digest -> ByteString -> String
+digestBS md input
+    = unsafePerformIO $
+      do ctx <- digestStrictly md input
+         digestFinal ctx
+
+-- |@'digestLBS'@ digests a stream of data.
+digestLBS :: Digest -> LazyByteString -> String
+digestLBS md input
+    = unsafePerformIO $
+      do ctx <- digestLazily md input
+         digestFinal ctx
diff --git a/OpenSSL/EVP/Open.hsc b/OpenSSL/EVP/Open.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/EVP/Open.hsc
@@ -0,0 +1,79 @@
+{- -*- haskell -*- -}
+
+-- |Asymmetric cipher decryption using encrypted symmetric key. This
+-- is an opposite of "OpenSSL.EVP.Seal".
+
+module OpenSSL.EVP.Open
+    ( open
+    , openBS
+    , openLBS
+    )
+    where
+
+import           Control.Monad
+import           Data.ByteString.Base
+import qualified Data.ByteString.Char8 as B8
+import qualified Data.ByteString.Lazy.Char8 as L8
+import           Foreign
+import           Foreign.C
+import           OpenSSL.EVP.Cipher
+import           OpenSSL.EVP.PKey
+import           OpenSSL.Utils
+
+
+foreign import ccall unsafe "EVP_OpenInit"
+        _OpenInit :: Ptr EVP_CIPHER_CTX
+                  -> Cipher
+                  -> Ptr CChar
+                  -> Int
+                  -> CString
+                  -> Ptr EVP_PKEY
+                  -> IO Int
+
+
+openInit :: Cipher -> String -> String -> PKey -> IO CipherCtx
+openInit cipher encKey iv pkey
+    = do ctx <- newCtx
+         withCipherCtxPtr ctx $ \ ctxPtr ->
+             withCStringLen encKey $ \ (encKeyPtr, encKeyLen) ->
+                 withCString iv $ \ ivPtr ->
+                     withPKeyPtr pkey $ \ pkeyPtr ->
+                         _OpenInit ctxPtr cipher encKeyPtr encKeyLen ivPtr pkeyPtr
+                              >>= failIf (== 0)
+         return ctx
+
+-- |@'open'@ lazilly decrypts a stream of data. The input string
+-- doesn't necessarily have to be finite.
+open :: Cipher -- ^ symmetric cipher algorithm to use
+     -> String -- ^ encrypted symmetric key to decrypt the input string
+     -> String -- ^ IV
+     -> PKey   -- ^ private key to decrypt the symmetric key
+     -> String -- ^ input string to decrypt
+     -> String -- ^ decrypted string
+open cipher encKey iv pkey input
+    = L8.unpack $ openLBS cipher encKey iv pkey $ L8.pack input
+
+-- |@'openBS'@ decrypts a chunk of data.
+openBS :: Cipher     -- ^ symmetric cipher algorithm to use
+       -> String     -- ^ encrypted symmetric key to decrypt the input string
+       -> String     -- ^ IV
+       -> PKey       -- ^ private key to decrypt the symmetric key
+       -> ByteString -- ^ input string to decrypt
+       -> ByteString -- ^ decrypted string
+openBS cipher encKey iv pkey input
+    = unsafePerformIO $
+      do ctx <- openInit cipher encKey iv pkey
+         cipherStrictly ctx input
+
+-- |@'openLBS'@ lazilly decrypts a stream of data. The input string
+-- doesn't necessarily have to be finite.
+openLBS :: Cipher         -- ^ symmetric cipher algorithm to use
+        -> String         -- ^ encrypted symmetric key to decrypt the input string
+        -> String         -- ^ IV
+        -> PKey           -- ^ private key to decrypt the symmetric key
+        -> LazyByteString -- ^ input string to decrypt
+        -> LazyByteString -- ^ decrypted string
+openLBS cipher encKey iv pkey input
+    = unsafePerformIO $
+      do ctx <- openInit cipher encKey iv pkey
+         cipherLazily ctx input
diff --git a/OpenSSL/EVP/PKey.hsc b/OpenSSL/EVP/PKey.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/EVP/PKey.hsc
@@ -0,0 +1,102 @@
+{- -*- haskell -*- -}
+
+-- #prune
+
+-- |An interface to asymmetric cipher keypair.
+
+#include "HsOpenSSL.h"
+
+module OpenSSL.EVP.PKey
+    ( PKey
+    , EVP_PKEY -- private
+
+    , wrapPKeyPtr -- private
+    , withPKeyPtr -- private
+    , unsafePKeyToPtr -- private
+    , touchPKey -- private
+    , pkeySize -- private
+    , pkeyDefaultMD -- private
+
+      -- FIXME: newPKeyDSA, newPKeyDH and newPKeyECKey may be needed
+#ifndef OPENSSL_NO_RSA
+    , newPKeyRSA
+#endif
+    )
+    where
+
+import           Foreign
+import           OpenSSL.EVP.Digest
+import           OpenSSL.RSA
+import           OpenSSL.Utils
+
+-- |@PKey@ is an opaque object that represents either public key or
+-- public\/private keypair. The concrete algorithm of asymmetric
+-- cipher is hidden in the object.
+newtype PKey     = PKey (ForeignPtr EVP_PKEY)
+data    EVP_PKEY
+
+
+foreign import ccall unsafe "EVP_PKEY_new"
+        _pkey_new :: IO (Ptr EVP_PKEY)
+
+foreign import ccall unsafe "&EVP_PKEY_free"
+        _pkey_free :: FunPtr (Ptr EVP_PKEY -> IO ())
+
+foreign import ccall unsafe "EVP_PKEY_size"
+        _pkey_size :: Ptr EVP_PKEY -> IO Int
+
+
+wrapPKeyPtr :: Ptr EVP_PKEY -> IO PKey
+wrapPKeyPtr pkeyPtr
+    = newForeignPtr _pkey_free pkeyPtr >>= return . PKey
+
+
+withPKeyPtr :: PKey -> (Ptr EVP_PKEY -> IO a) -> IO a
+withPKeyPtr (PKey pkey) = withForeignPtr pkey
+
+
+unsafePKeyToPtr :: PKey -> Ptr EVP_PKEY
+unsafePKeyToPtr (PKey pkey) = unsafeForeignPtrToPtr pkey
+
+
+touchPKey :: PKey -> IO ()
+touchPKey (PKey pkey) = touchForeignPtr pkey
+
+
+pkeySize :: PKey -> IO Int
+pkeySize pkey
+    = withPKeyPtr pkey $ \ pkeyPtr ->
+      _pkey_size pkeyPtr
+
+
+pkeyDefaultMD :: PKey -> IO Digest
+pkeyDefaultMD pkey
+    = withPKeyPtr pkey $ \ pkeyPtr ->
+      do pkeyType   <- (#peek EVP_PKEY, type) pkeyPtr :: IO Int
+         digestName <- case pkeyType of
+#ifndef OPENSSL_NO_RSA
+                         (#const EVP_PKEY_RSA) -> return "sha1"
+#endif
+#ifndef OPENSSLNO_DSA
+                         (#const EVP_PKEY_DSA) -> return "dss1"
+#endif
+                         _ -> fail ("pkeyDefaultMD: unsupported pkey type: " ++ show pkeyType)
+         mDigest <- getDigestByName digestName
+         case mDigest of
+           Just digest -> return digest
+           Nothing     -> fail ("pkeyDefaultMD: digest method not found: " ++ digestName)
+
+
+#ifndef OPENSSL_NO_RSA
+foreign import ccall unsafe "EVP_PKEY_set1_RSA"
+        _set1_RSA :: Ptr EVP_PKEY -> Ptr RSA_ -> IO Int
+
+-- |@'newPKeyRSA' rsa@ encapsulates an 'RSA' key into 'PKey'.
+newPKeyRSA :: RSA -> PKey
+newPKeyRSA rsa
+    = unsafePerformIO $
+      withRSAPtr rsa $ \ rsaPtr ->
+      do pkeyPtr <- _pkey_new >>= failIfNull
+         _set1_RSA pkeyPtr rsaPtr >>= failIf (/= 1)
+         wrapPKeyPtr pkeyPtr
+#endif
diff --git a/OpenSSL/EVP/Seal.hsc b/OpenSSL/EVP/Seal.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/EVP/Seal.hsc
@@ -0,0 +1,134 @@
+{- -*- haskell -*- -}
+
+-- |Asymmetric cipher decryption using encrypted symmetric key. This
+-- is an opposite of "OpenSSL.EVP.Open".
+
+module OpenSSL.EVP.Seal
+    ( seal
+    , sealBS
+    , sealLBS
+    )
+    where
+
+import           Control.Monad
+import           Data.ByteString.Base
+import qualified Data.ByteString.Char8 as B8
+import qualified Data.ByteString.Lazy.Char8 as L8
+import           Foreign
+import           Foreign.C
+import           OpenSSL.EVP.Cipher
+import           OpenSSL.EVP.PKey
+import           OpenSSL.Utils
+
+
+foreign import ccall unsafe "EVP_SealInit"
+        _SealInit :: Ptr EVP_CIPHER_CTX
+                  -> Cipher
+                  -> Ptr (Ptr CChar)
+                  -> Ptr Int
+                  -> CString
+                  -> Ptr (Ptr EVP_PKEY)
+                  -> Int
+                  -> IO Int
+
+
+sealInit :: Cipher -> [PKey] -> IO (CipherCtx, [String], String)
+
+sealInit _ []
+    = fail "sealInit: at least one public key is required"
+
+sealInit cipher pubKeys
+    = do ctx <- newCtx
+         
+         -- 暗号化された共通鍵の配列が書き込まれる場所を作る。各共通鍵
+         -- は最大で pkeySize の長さになる。
+         encKeyBufs <- mapM mallocEncKeyBuf pubKeys
+
+         -- encKeys は [Ptr a] なので、これを Ptr (Ptr CChar) にしなけ
+         -- ればならない。
+         encKeyBufsPtr <- newArray encKeyBufs
+
+         -- 暗号化された共通鍵の各々の長さが書き込まれる場所を作る。
+         encKeyBufsLenPtr <- mallocArray nKeys
+
+         -- IV の書き込まれる場所を作る。
+         ivPtr <- mallocArray (cipherIvLength cipher)
+
+         -- [PKey] から Ptr (Ptr EVP_PKEY) を作る。後でそれぞれの
+         -- PKey を touchForeignPtr する事を忘れてはならない。
+         pubKeysPtr <- newArray $ map unsafePKeyToPtr pubKeys
+
+         -- 確保した領域を解放する IO アクションを作って置く
+         let cleanup = do mapM_ free encKeyBufs
+                          free encKeyBufsPtr
+                          free encKeyBufsLenPtr
+                          free ivPtr
+                          free pubKeysPtr
+                          mapM_ touchPKey pubKeys
+
+         -- いよいよ EVP_SealInit を呼ぶ。
+         ret <- withCipherCtxPtr ctx $ \ ctxPtr ->
+                _SealInit ctxPtr cipher encKeyBufsPtr encKeyBufsLenPtr ivPtr pubKeysPtr nKeys
+
+         if ret == 0 then
+             cleanup >> raiseOpenSSLError
+           else
+             do encKeysLen <- peekArray nKeys encKeyBufsLenPtr
+                encKeys    <- mapM peekCStringLen $ zip encKeyBufs encKeysLen
+                iv         <- peekCString ivPtr
+                cleanup
+                return (ctx, encKeys, iv)
+    where
+      nKeys :: Int
+      nKeys = length pubKeys
+
+      mallocEncKeyBuf :: Storable a => PKey -> IO (Ptr a)
+      mallocEncKeyBuf pubKey
+          = pkeySize pubKey >>= mallocArray
+
+-- |@'seal'@ lazilly encrypts a stream of data. The input string
+-- doesn't necessarily have to be finite.
+seal :: Cipher        -- ^ symmetric cipher algorithm to use
+     -> [PKey]        -- ^ A list of public keys to encrypt a
+                      --   symmetric key. At least one public key must
+                      --   be supplied. If two or more keys are given,
+                      --   the symmetric key are encrypted by each
+                      --   public keys so that any of the
+                      --   corresponding private keys can decrypt the
+                      --   message.
+     -> String        -- ^ input string to encrypt
+     -> IO (String, [String], String) -- ^ (encrypted string, list of
+                                      --   encrypted asymmetric keys,
+                                      --   IV)
+seal cipher pubKeys input
+    = do (output, encKeys, iv) <- sealLBS cipher pubKeys $ L8.pack input
+         return (L8.unpack output, encKeys, iv)
+
+-- |@'sealBS'@ strictly encrypts a chunk of data.
+sealBS :: Cipher     -- ^ symmetric cipher algorithm to use
+       -> [PKey]     -- ^ list of public keys to encrypt a symmetric
+                     --   key
+       -> ByteString -- ^ input string to encrypt
+       -> IO (ByteString, [String], String) -- ^ (encrypted string,
+                                            --   list of encrypted
+                                            --   asymmetric keys, IV)
+sealBS cipher pubKeys input
+    = do (ctx, encKeys, iv) <- sealInit cipher pubKeys
+         output             <- cipherStrictly ctx input
+         return (output, encKeys, iv)
+
+-- |@'sealLBS'@ lazilly encrypts a stream of data. The input string
+-- doesn't necessarily have to be finite.
+sealLBS :: Cipher         -- ^ symmetric cipher algorithm to use
+        -> [PKey]         -- ^ list of public keys to encrypt a
+                          --   symmetric key
+        -> LazyByteString -- ^ input string to encrypt
+        -> IO (LazyByteString, [String], String) -- ^ (encrypted
+                                                 --   string, list of
+                                                 --   encrypted
+                                                 --   asymmetric keys,
+                                                 --   IV)
+sealLBS cipher pubKeys input
+    = do (ctx, encKeys, iv) <- sealInit cipher pubKeys
+         output             <- cipherLazily ctx input
+         return (output, encKeys, iv)
diff --git a/OpenSSL/EVP/Sign.hsc b/OpenSSL/EVP/Sign.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/EVP/Sign.hsc
@@ -0,0 +1,67 @@
+{- -*- haskell -*- -}
+
+-- |Message signing using asymmetric cipher and message digest
+-- algorithm. This is an opposite of "OpenSSL.EVP.Verify".
+
+module OpenSSL.EVP.Sign
+    ( sign
+    , signBS
+    , signLBS
+    )
+    where
+
+import           Control.Monad
+import           Data.ByteString.Base
+import qualified Data.ByteString.Char8 as B8
+import qualified Data.ByteString.Lazy.Char8 as L8
+import           Foreign
+import           Foreign.C
+import           OpenSSL.EVP.Digest
+import           OpenSSL.EVP.PKey
+import           OpenSSL.Utils
+
+
+foreign import ccall unsafe "EVP_SignFinal"
+        _SignFinal :: Ptr EVP_MD_CTX -> Ptr CChar -> Ptr CUInt -> Ptr EVP_PKEY -> IO Int
+
+
+signFinal :: DigestCtx -> PKey -> IO String
+signFinal ctx pkey
+    = do maxLen <- pkeySize pkey
+         withDigestCtxPtr ctx $ \ ctxPtr ->
+             withPKeyPtr pkey $ \ pkeyPtr ->
+                 allocaArray maxLen $ \ bufPtr ->
+                     alloca $ \ bufLenPtr ->
+                         do _SignFinal ctxPtr bufPtr bufLenPtr pkeyPtr
+                                 >>= failIf (/= 1)
+                            bufLen <- liftM fromIntegral $ peek bufLenPtr
+                            peekCStringLen (bufPtr, bufLen)
+
+
+-- |@'sign'@ generates a signature from a stream of data. The string
+-- must not contain any letters which aren't in the range of U+0000 -
+-- U+00FF.
+sign :: Digest    -- ^ message digest algorithm to use
+     -> PKey      -- ^ private key to sign the message digest
+     -> String    -- ^ input string
+     -> IO String -- ^ the result signature
+sign md pkey input
+    = signLBS md pkey $ L8.pack input
+
+-- |@'signBS'@ generates a signature from a chunk of data.
+signBS :: Digest     -- ^ message digest algorithm to use
+       -> PKey       -- ^ private key to sign the message digest
+       -> ByteString -- ^ input string
+       -> IO String  -- ^ the result signature
+signBS md pkey input
+    = do ctx <- digestStrictly md input
+         signFinal ctx pkey
+
+-- |@'signLBS'@ generates a signature from a stream of data.
+signLBS :: Digest         -- ^ message digest algorithm to use
+        -> PKey           -- ^ private key to sign the message digest
+        -> LazyByteString -- ^ input string
+        -> IO String      -- ^ the result signature
+signLBS md pkey input
+    = do ctx <- digestLazily md input
+         signFinal ctx pkey
diff --git a/OpenSSL/EVP/Verify.hsc b/OpenSSL/EVP/Verify.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/EVP/Verify.hsc
@@ -0,0 +1,76 @@
+{- -*- haskell -*- -}
+
+-- |Message verification using asymmetric cipher and message digest
+-- algorithm. This is an opposite of "OpenSSL.EVP.Sign".
+
+module OpenSSL.EVP.Verify
+    ( VerifyStatus(..)
+    , verify
+    , verifyBS
+    , verifyLBS
+    )
+    where
+
+import           Control.Monad
+import           Data.ByteString.Base
+import qualified Data.ByteString.Char8 as B8
+import qualified Data.ByteString.Lazy.Char8 as L8
+import           Data.Typeable
+import           Foreign
+import           Foreign.C
+import           OpenSSL.EVP.Digest
+import           OpenSSL.EVP.PKey
+import           OpenSSL.Utils
+
+-- |@'VerifyStatus'@ represents a result of verification.
+data VerifyStatus = VerifySuccess
+                  | VerifyFailure
+                    deriving (Show, Eq, Typeable)
+
+
+foreign import ccall unsafe "EVP_VerifyFinal"
+        _VerifyFinal :: Ptr EVP_MD_CTX -> Ptr CChar -> CUInt -> Ptr EVP_PKEY -> IO Int
+
+
+verifyFinalBS :: DigestCtx -> String -> PKey -> IO VerifyStatus
+verifyFinalBS ctx sig pkey
+    = withDigestCtxPtr ctx $ \ ctxPtr ->
+      withCStringLen sig $ \ (buf, len) ->
+      withPKeyPtr pkey $ \ pkeyPtr ->
+      _VerifyFinal ctxPtr buf (fromIntegral len) pkeyPtr >>= interpret
+    where
+      interpret :: Int -> IO VerifyStatus
+      interpret 1 = return VerifySuccess
+      interpret 0 = return VerifyFailure
+      interpret _ = raiseOpenSSLError
+
+-- |@'verify'@ verifies a signature and a stream of data. The string
+-- must not contain any letters which aren't in the range of U+0000 -
+-- U+00FF.
+verify :: Digest          -- ^ message digest algorithm to use
+       -> String          -- ^ message signature
+       -> PKey            -- ^ public key to verify the signature
+       -> String          -- ^ input string to verify
+       -> IO VerifyStatus -- ^ the result of verification
+verify md sig pkey input
+    = verifyLBS md sig pkey (L8.pack input)
+
+-- |@'verifyBS'@ verifies a signature and a chunk of data.
+verifyBS :: Digest          -- ^ message digest algorithm to use
+         -> String          -- ^ message signature
+         -> PKey            -- ^ public key to verify the signature
+         -> ByteString      -- ^ input string to verify
+         -> IO VerifyStatus -- ^ the result of verification
+verifyBS md sig pkey input
+    = do ctx <- digestStrictly md input
+         verifyFinalBS ctx sig pkey
+
+-- |@'verifyLBS'@ verifies a signature of a stream of data.
+verifyLBS :: Digest          -- ^ message digest algorithm to use
+          -> String          -- ^ message signature
+          -> PKey            -- ^ public key to verify the signature
+          -> LazyByteString  -- ^ input string to verify
+          -> IO VerifyStatus -- ^ the result of verification
+verifyLBS md sig pkey input
+    = do ctx <- digestLazily md input
+         verifyFinalBS ctx sig pkey
diff --git a/OpenSSL/Objects.hsc b/OpenSSL/Objects.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/Objects.hsc
@@ -0,0 +1,69 @@
+{- -*- haskell -*- -}
+
+-- #hide
+
+#include "HsOpenSSL.h"
+
+module OpenSSL.Objects
+    ( ObjNameType(..)
+    , getObjNames
+    )
+    where
+
+import           Data.IORef
+import           Foreign
+import           Foreign.C
+
+
+type ObjName  = Ptr OBJ_NAME
+data OBJ_NAME
+
+type DoAllCallback = ObjName -> Ptr () -> IO ()
+
+
+foreign import ccall safe "OBJ_NAME_do_all"
+        _NAME_do_all :: Int -> FunPtr DoAllCallback -> Ptr () -> IO ()
+
+foreign import ccall safe "OBJ_NAME_do_all_sorted"
+        _NAME_do_all_sorted :: Int -> FunPtr DoAllCallback -> Ptr () -> IO ()
+
+foreign import ccall "wrapper"
+        mkDoAllCallback :: DoAllCallback -> IO (FunPtr DoAllCallback)
+
+
+data ObjNameType = MDMethodType
+                 | CipherMethodType
+                 | PKeyMethodType
+                 | CompMethodType
+
+objNameTypeToInt :: ObjNameType -> Int
+objNameTypeToInt MDMethodType     = #const OBJ_NAME_TYPE_MD_METH
+objNameTypeToInt CipherMethodType = #const OBJ_NAME_TYPE_CIPHER_METH
+objNameTypeToInt PKeyMethodType   = #const OBJ_NAME_TYPE_PKEY_METH
+objNameTypeToInt CompMethodType   = #const OBJ_NAME_TYPE_COMP_METH
+
+
+iterateObjNames :: ObjNameType -> Bool -> (ObjName -> IO ()) -> IO ()
+iterateObjNames nameType wantSorted cb
+    = do cbPtr <- mkDoAllCallback $ \ name _ -> cb name
+         let action = if wantSorted then
+                          _NAME_do_all_sorted
+                      else
+                          _NAME_do_all
+         action (objNameTypeToInt nameType) cbPtr nullPtr
+         freeHaskellFunPtr cbPtr
+
+
+objNameStr :: ObjName -> IO String
+objNameStr name
+    = do strPtr <- (#peek OBJ_NAME, name) name
+         peekCString strPtr
+
+
+getObjNames :: ObjNameType -> Bool -> IO [String]
+getObjNames nameType wantSorted
+    = do listRef <- newIORef []
+         iterateObjNames nameType wantSorted $ \ name ->
+             do nameStr <- objNameStr name
+                modifyIORef listRef (++ [nameStr])
+         readIORef listRef
diff --git a/OpenSSL/PEM.hsc b/OpenSSL/PEM.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/PEM.hsc
@@ -0,0 +1,459 @@
+{- -*- haskell -*- -}
+
+-- |An interface to PEM routines.
+
+module OpenSSL.PEM
+    ( -- * Password supply
+      PemPasswordCallback
+    , PemPasswordRWState(..)
+    , PemPasswordSupply(..)
+
+      -- * Private key
+    , writePKCS8PrivateKey
+    , readPrivateKey
+
+      -- * Public key
+    , writePublicKey
+    , readPublicKey
+
+      -- * X.509 certificate
+    , writeX509
+    , readX509
+
+      -- * PKCS#10 certificate request
+    , PemX509ReqFormat(..)
+    , writeX509Req
+    , readX509Req
+
+      -- * Certificate Revocation List
+    , writeCRL
+    , readCRL
+
+      -- * PKCS#7 structure
+    , writePkcs7
+    , readPkcs7
+    )
+    where
+
+import           Control.Exception
+import           Control.Monad
+import           Foreign
+import           Foreign.C
+import           OpenSSL.BIO
+import           OpenSSL.EVP.Cipher
+import           OpenSSL.EVP.PKey
+import           OpenSSL.PKCS7
+import           OpenSSL.Utils
+import           OpenSSL.X509
+import           OpenSSL.X509.Request
+import           OpenSSL.X509.Revocation
+import           Prelude hiding (catch)
+import           System.IO
+
+
+-- |@'PemPasswordCallback'@ represents a callback function to supply a
+-- password.
+type PemPasswordCallback
+    =  Int                -- ^ maximum length of the password to be
+                          --   accepted
+    -> PemPasswordRWState -- ^ context
+    -> IO String          -- ^ the result password
+
+type PemPasswordCallback' = Ptr CChar -> Int -> Int -> Ptr () -> IO Int
+
+
+-- |@'PemPasswordRWState'@ represents a context of
+-- 'PemPasswordCallback'.
+data PemPasswordRWState = PwRead  -- ^ The callback was called to get
+                                  --   a password to read something
+                                  --   encrypted.
+                        | PwWrite -- ^ The callback was called to get
+                                  --   a password to encrypt
+                                  --   something.
+
+-- |@'PemPasswordSupply'@ represents a way to supply password.
+--
+-- FIXME: using PwTTY causes an error but I don't know why:
+-- \"error:0906406D:PEM routines:DEF_CALLBACK:problems getting
+-- password\"
+data PemPasswordSupply = PwNone       -- ^ no password
+                       | PwStr String -- ^ password in a static string
+                       | PwCallback PemPasswordCallback -- ^ get a
+                                                        --   password
+                                                        --   by a
+                                                        --   callback
+                       | PwTTY        -- ^ read a password from TTY
+
+
+foreign import ccall "wrapper"
+        mkPemPasswordCallback :: PemPasswordCallback' -> IO (FunPtr PemPasswordCallback')
+
+
+rwflagToState :: Int -> PemPasswordRWState
+rwflagToState 0 = PwRead
+rwflagToState 1 = PwWrite
+
+
+callPasswordCB :: PemPasswordCallback -> PemPasswordCallback'
+callPasswordCB cb buf bufLen rwflag _
+    = let mode = rwflagToState rwflag
+          try  = do passStr <- cb bufLen mode
+                    let passLen = length passStr
+
+                    when (passLen > bufLen)
+                         $ failForTooLongPassword bufLen
+
+                    pokeArray buf $ map (toEnum . fromEnum) passStr
+                    return passLen
+      in
+        try `catch` \ exc ->
+            do hPutStrLn stderr $ show exc
+               return 0 -- zero indicates an error
+    where
+      failForTooLongPassword :: Int -> IO a
+      failForTooLongPassword len
+          = fail ("callPasswordCB: the password which the callback returned is too long: "
+                  ++ "it must be at most " ++ show len ++ " bytes.")
+
+
+{- PKCS#8 -------------------------------------------------------------------- -}
+
+foreign import ccall safe "PEM_write_bio_PKCS8PrivateKey"
+        _write_bio_PKCS8PrivateKey :: Ptr BIO_
+                                   -> Ptr EVP_PKEY
+                                   -> Ptr EVP_CIPHER
+                                   -> Ptr CChar
+                                   -> Int
+                                   -> FunPtr PemPasswordCallback'
+                                   -> Ptr a
+                                   -> IO Int
+
+writePKCS8PrivateKey' :: BIO
+                      -> PKey
+                      -> Maybe (Cipher, PemPasswordSupply)
+                      -> IO ()
+writePKCS8PrivateKey' bio pkey encryption
+    = withBioPtr bio   $ \ bioPtr  ->
+      withPKeyPtr pkey $ \ pkeyPtr ->
+      do ret <- case encryption of
+                  Nothing
+                      -> _write_bio_PKCS8PrivateKey bioPtr pkeyPtr nullPtr nullPtr 0 nullFunPtr nullPtr
+
+                  Just (_, PwNone)
+                      -> _write_bio_PKCS8PrivateKey bioPtr pkeyPtr nullPtr nullPtr 0 nullFunPtr nullPtr
+
+                  Just (cipher, PwStr passStr)
+                      -> withCStringLen passStr $ \ (passPtr, passLen) ->
+                         withCipherPtr cipher   $ \ cipherPtr          ->
+                         _write_bio_PKCS8PrivateKey bioPtr pkeyPtr cipherPtr passPtr passLen nullFunPtr nullPtr
+
+                  Just (cipher, PwCallback cb)
+                      -> withCipherPtr cipher $ \ cipherPtr ->
+                         do cbPtr <- mkPemPasswordCallback $ callPasswordCB cb
+                            ret   <- _write_bio_PKCS8PrivateKey bioPtr pkeyPtr cipherPtr nullPtr 0 cbPtr nullPtr
+                            freeHaskellFunPtr cbPtr
+                            return ret
+               
+                  Just (cipher, PwTTY)
+                      -> withCipherPtr cipher $ \ cipherPtr ->
+                         _write_bio_PKCS8PrivateKey bioPtr pkeyPtr cipherPtr nullPtr 0 nullFunPtr nullPtr
+         failIf (/= 1) ret
+         return ()
+
+-- |@'writePKCS8PrivateKey'@ writes a private key to PEM string in
+-- PKCS#8 format.
+writePKCS8PrivateKey
+    :: PKey      -- ^ private key to write
+    -> Maybe (Cipher, PemPasswordSupply) -- ^ Either (symmetric cipher
+                                         --   algorithm, password
+                                         --   supply) or @Nothing@. If
+                                         --   @Nothing@ is given the
+                                         --   private key is not
+                                         --   encrypted.
+    -> IO String -- ^ the result PEM string
+writePKCS8PrivateKey pkey encryption
+    = do mem <- newMem
+         writePKCS8PrivateKey' mem pkey encryption
+         bioRead mem
+
+
+foreign import ccall safe "PEM_read_bio_PrivateKey"
+        _read_bio_PrivateKey :: Ptr BIO_
+                             -> Ptr (Ptr EVP_PKEY)
+                             -> FunPtr PemPasswordCallback'
+                             -> Ptr ()
+                             -> IO (Ptr EVP_PKEY)
+
+readPrivateKey' :: BIO -> PemPasswordSupply -> IO PKey
+readPrivateKey' bio supply
+    = withBioPtr bio $ \ bioPtr ->
+      do pkeyPtr <- case supply of
+                      PwNone
+                          -> withCString "" $ \ strPtr ->
+                             _read_bio_PrivateKey bioPtr nullPtr nullFunPtr (unsafeCoercePtr strPtr)
+                                
+                      PwStr passStr
+                          -> do cbPtr <- mkPemPasswordCallback $
+                                         callPasswordCB $ \ _ _ ->
+                                         return passStr
+                                pkeyPtr <- _read_bio_PrivateKey bioPtr nullPtr cbPtr nullPtr 
+                                freeHaskellFunPtr cbPtr
+                                return pkeyPtr
+                      PwCallback cb
+                          -> do cbPtr <- mkPemPasswordCallback $ callPasswordCB cb
+                                pkeyPtr <- _read_bio_PrivateKey bioPtr nullPtr cbPtr nullPtr 
+                                freeHaskellFunPtr cbPtr
+                                return pkeyPtr
+                      PwTTY
+                          -> _read_bio_PrivateKey bioPtr nullPtr nullFunPtr nullPtr 
+         failIfNull pkeyPtr
+         wrapPKeyPtr pkeyPtr
+
+-- |@'readPrivateKey' pem supply@ reads a private key in PEM string.
+readPrivateKey :: String -> PemPasswordSupply -> IO PKey
+readPrivateKey pemStr supply
+    = do mem <- newConstMem pemStr
+         readPrivateKey' mem supply
+
+
+{- Public Key ---------------------------------------------------------------- -}
+
+foreign import ccall unsafe "PEM_write_bio_PUBKEY"
+        _write_bio_PUBKEY :: Ptr BIO_ -> Ptr EVP_PKEY -> IO Int
+
+foreign import ccall unsafe "PEM_read_bio_PUBKEY"
+        _read_bio_PUBKEY :: Ptr BIO_
+                         -> Ptr (Ptr EVP_PKEY)
+                         -> FunPtr PemPasswordCallback'
+                         -> Ptr ()
+                         -> IO (Ptr EVP_PKEY)
+
+
+writePublicKey' :: BIO -> PKey -> IO ()
+writePublicKey' bio pkey
+    = withBioPtr bio   $ \ bioPtr  ->
+      withPKeyPtr pkey $ \ pkeyPtr ->
+      _write_bio_PUBKEY bioPtr pkeyPtr >>= failIf (/= 1) >> return ()
+
+-- |@'writePublicKey' pubkey@ writes a public to PEM string.
+writePublicKey :: PKey -> IO String
+writePublicKey pkey
+    = do mem <- newMem
+         writePublicKey' mem pkey
+         bioRead mem
+
+-- Why the heck PEM_read_bio_PUBKEY takes pem_password_cb? Is there
+-- any form of encrypted public key?
+readPublicKey' :: BIO -> IO PKey
+readPublicKey' bio
+    = withBioPtr bio $ \ bioPtr ->
+      withCString "" $ \ passPtr ->
+      _read_bio_PUBKEY bioPtr nullPtr nullFunPtr (unsafeCoercePtr passPtr)
+           >>= failIfNull
+           >>= wrapPKeyPtr
+
+-- |@'readPublicKey' pem@ reads a public key in PEM string.
+readPublicKey :: String -> IO PKey
+readPublicKey pemStr
+    = newConstMem pemStr >>= readPublicKey'
+
+
+{- X.509 certificate --------------------------------------------------------- -}
+
+foreign import ccall unsafe "PEM_write_bio_X509_AUX"
+        _write_bio_X509_AUX :: Ptr BIO_
+                            -> Ptr X509_
+                            -> IO Int
+
+foreign import ccall safe "PEM_read_bio_X509_AUX"
+        _read_bio_X509_AUX :: Ptr BIO_
+                           -> Ptr (Ptr X509_)
+                           -> FunPtr PemPasswordCallback'
+                           -> Ptr ()
+                           -> IO (Ptr X509_)
+
+writeX509' :: BIO -> X509 -> IO ()
+writeX509' bio x509
+    = withBioPtr bio   $ \ bioPtr  ->
+      withX509Ptr x509 $ \ x509Ptr ->
+      _write_bio_X509_AUX bioPtr x509Ptr
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'writeX509' cert@ writes an X.509 certificate to PEM string.
+writeX509 :: X509 -> IO String
+writeX509 x509
+    = do mem <- newMem
+         writeX509' mem x509
+         bioRead mem
+
+
+-- I believe X.509 isn't encrypted.
+readX509' :: BIO -> IO X509
+readX509' bio
+    = withBioPtr bio $ \ bioPtr ->
+      withCString "" $ \ passPtr ->
+      _read_bio_X509_AUX bioPtr nullPtr nullFunPtr (unsafeCoercePtr passPtr)
+           >>= failIfNull
+           >>= wrapX509
+
+-- |@'readX509' pem@ reads an X.509 certificate in PEM string.
+readX509 :: String -> IO X509
+readX509 pemStr
+    = newConstMem pemStr >>= readX509'
+
+
+{- PKCS#10 certificate request ----------------------------------------------- -}
+
+foreign import ccall unsafe "PEM_write_bio_X509_REQ"
+        _write_bio_X509_REQ :: Ptr BIO_
+                            -> Ptr X509_REQ
+                            -> IO Int
+
+foreign import ccall unsafe "PEM_write_bio_X509_REQ_NEW"
+        _write_bio_X509_REQ_NEW :: Ptr BIO_
+                                -> Ptr X509_REQ
+                                -> IO Int
+
+foreign import ccall safe "PEM_read_bio_X509_REQ"
+        _read_bio_X509_REQ :: Ptr BIO_
+                           -> Ptr (Ptr X509_REQ)
+                           -> FunPtr PemPasswordCallback'
+                           -> Ptr ()
+                           -> IO (Ptr X509_REQ)
+
+-- |@'PemX509ReqFormat'@ represents format of PKCS#10 certificate
+-- request.
+data PemX509ReqFormat
+    = ReqNewFormat -- ^ The new format, whose header is \"NEW
+                   --   CERTIFICATE REQUEST\".
+    | ReqOldFormat -- ^ The old format, whose header is \"CERTIFICATE
+                   --   REQUEST\".
+
+
+writeX509Req' :: BIO -> X509Req -> PemX509ReqFormat -> IO ()
+writeX509Req' bio req format
+    = withBioPtr bio     $ \ bioPtr ->
+      withX509ReqPtr req $ \ reqPtr ->
+      writer bioPtr reqPtr
+                 >>= failIf (/= 1)
+                 >>  return ()
+    where
+      writer = case format of
+                 ReqNewFormat -> _write_bio_X509_REQ_NEW
+                 ReqOldFormat -> _write_bio_X509_REQ
+
+-- |@'writeX509Req'@ writes a PKCS#10 certificate request to PEM
+-- string.
+writeX509Req :: X509Req          -- ^ request
+             -> PemX509ReqFormat -- ^ format
+             -> IO String        -- ^ the result PEM string
+writeX509Req req format
+    = do mem <- newMem
+         writeX509Req' mem req format
+         bioRead mem
+
+
+readX509Req' :: BIO -> IO X509Req
+readX509Req' bio
+    = withBioPtr bio $ \ bioPtr ->
+      withCString "" $ \ passPtr ->
+      _read_bio_X509_REQ bioPtr nullPtr nullFunPtr (unsafeCoercePtr passPtr)
+           >>= failIfNull
+           >>= wrapX509Req
+
+-- |@'readX509Req'@ reads a PKCS#10 certificate request in PEM string.
+readX509Req :: String -> IO X509Req
+readX509Req pemStr
+    = newConstMem pemStr >>= readX509Req'
+
+
+{- Certificate Revocation List ----------------------------------------------- -}
+
+foreign import ccall unsafe "PEM_write_bio_X509_CRL"
+        _write_bio_X509_CRL :: Ptr BIO_
+                            -> Ptr X509_CRL
+                            -> IO Int
+
+foreign import ccall safe "PEM_read_bio_X509_CRL"
+        _read_bio_X509_CRL :: Ptr BIO_
+                           -> Ptr (Ptr X509_CRL)
+                           -> FunPtr PemPasswordCallback'
+                           -> Ptr ()
+                           -> IO (Ptr X509_CRL)
+
+
+writeCRL' :: BIO -> CRL -> IO ()
+writeCRL' bio crl
+    = withBioPtr bio $ \ bioPtr ->
+      withCRLPtr crl $ \ crlPtr ->
+      _write_bio_X509_CRL bioPtr crlPtr
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'writeCRL' crl@ writes a Certificate Revocation List to PEM
+-- string.
+writeCRL :: CRL -> IO String
+writeCRL crl
+    = do mem <- newMem
+         writeCRL' mem crl
+         bioRead mem
+
+
+readCRL' :: BIO -> IO CRL
+readCRL' bio
+    = withBioPtr bio $ \ bioPtr ->
+      withCString "" $ \ passPtr ->
+      _read_bio_X509_CRL bioPtr nullPtr nullFunPtr (unsafeCoercePtr passPtr)
+           >>= failIfNull
+           >>= wrapCRL
+
+-- |@'readCRL' pem@ reads a Certificate Revocation List in PEM string.
+readCRL :: String -> IO CRL
+readCRL pemStr
+    = newConstMem pemStr >>= readCRL'
+
+
+{- PKCS#7 -------------------------------------------------------------------- -}
+
+foreign import ccall unsafe "PEM_write_bio_PKCS7"
+        _write_bio_PKCS7 :: Ptr BIO_
+                         -> Ptr PKCS7
+                         -> IO Int
+
+foreign import ccall safe "PEM_read_bio_PKCS7"
+        _read_bio_PKCS7 :: Ptr BIO_
+                        -> Ptr (Ptr PKCS7)
+                        -> FunPtr PemPasswordCallback'
+                        -> Ptr ()
+                        -> IO (Ptr PKCS7)
+
+
+writePkcs7' :: BIO -> Pkcs7 -> IO ()
+writePkcs7' bio pkcs7
+    = withBioPtr bio     $ \ bioPtr ->
+      withPkcs7Ptr pkcs7 $ \ pkcs7Ptr ->
+      _write_bio_PKCS7 bioPtr pkcs7Ptr
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'writePkcs7' p7@ writes a PKCS#7 structure to PEM string.
+writePkcs7 :: Pkcs7 -> IO String
+writePkcs7 pkcs7
+    = do mem <- newMem
+         writePkcs7' mem pkcs7
+         bioRead mem
+
+
+readPkcs7' :: BIO -> IO Pkcs7
+readPkcs7' bio
+    = withBioPtr bio $ \ bioPtr ->
+      withCString "" $ \ passPtr ->
+      _read_bio_PKCS7 bioPtr nullPtr nullFunPtr (unsafeCoercePtr passPtr)
+           >>= failIfNull
+           >>= wrapPkcs7Ptr
+
+-- |@'readPkcs7' pem@ reads a PKCS#7 structure in PEM string.
+readPkcs7 :: String -> IO Pkcs7
+readPkcs7 pemStr
+    = newConstMem pemStr >>= readPkcs7'
diff --git a/OpenSSL/PKCS7.hsc b/OpenSSL/PKCS7.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/PKCS7.hsc
@@ -0,0 +1,419 @@
+{- -*- haskell -*- -}
+
+-- #prune
+
+-- |An interface to PKCS#7 structure and S\/MIME message.
+
+#include "HsOpenSSL.h"
+
+module OpenSSL.PKCS7
+    ( -- * Types
+      Pkcs7
+    , PKCS7 -- private
+    , Pkcs7Flag(..)
+    , Pkcs7VerifyStatus(..)
+    , wrapPkcs7Ptr -- private
+    , withPkcs7Ptr -- private
+
+      -- * Encryption and Signing
+    , pkcs7Sign
+    , pkcs7Verify
+    , pkcs7Encrypt
+    , pkcs7Decrypt
+
+      -- * S\/MIME
+    , writeSmime
+    , readSmime
+    )
+    where
+
+import           Data.List
+import           Data.Traversable
+import           Data.Typeable
+import           Foreign
+import           Foreign.C
+import           OpenSSL.BIO
+import           OpenSSL.EVP.Cipher
+import           OpenSSL.EVP.PKey
+import           OpenSSL.Stack
+import           OpenSSL.Utils
+import           OpenSSL.X509
+import           OpenSSL.X509.Store
+
+
+{- PKCS#7 -------------------------------------------------------------------- -}
+
+-- |@'Pkcs7'@ represents an abstract PKCS#7 structure. The concrete
+-- type of structure is hidden in the object: such polymorphism isn't
+-- very haskellish but please get it out of your mind since OpenSSL is
+-- written in C.
+newtype Pkcs7 = Pkcs7 (ForeignPtr PKCS7)
+data    PKCS7
+
+-- |@'Pkcs7Flag'@ is a set of flags that are used in many operations
+-- related to PKCS#7.
+data Pkcs7Flag = Pkcs7Text
+               | Pkcs7NoCerts
+               | Pkcs7NoSigs
+               | Pkcs7NoChain
+               | Pkcs7NoIntern
+               | Pkcs7NoVerify
+               | Pkcs7Detached
+               | Pkcs7Binary
+               | Pkcs7NoAttr
+               | Pkcs7NoSmimeCap
+               | Pkcs7NoOldMimeType
+               | Pkcs7CRLFEOL
+                 deriving (Show, Eq, Typeable)
+
+flagToInt :: Pkcs7Flag -> Int
+flagToInt Pkcs7Text          = #const PKCS7_TEXT
+flagToInt Pkcs7NoCerts       = #const PKCS7_NOCERTS
+flagToInt Pkcs7NoSigs        = #const PKCS7_NOSIGS
+flagToInt Pkcs7NoChain       = #const PKCS7_NOCHAIN
+flagToInt Pkcs7NoIntern      = #const PKCS7_NOINTERN
+flagToInt Pkcs7NoVerify      = #const PKCS7_NOVERIFY
+flagToInt Pkcs7Detached      = #const PKCS7_DETACHED
+flagToInt Pkcs7Binary        = #const PKCS7_BINARY
+flagToInt Pkcs7NoAttr        = #const PKCS7_NOATTR
+flagToInt Pkcs7NoSmimeCap    = #const PKCS7_NOSMIMECAP
+flagToInt Pkcs7NoOldMimeType = #const PKCS7_NOOLDMIMETYPE
+flagToInt Pkcs7CRLFEOL       = #const PKCS7_CRLFEOL
+
+-- |@'Pkcs7VerifyStatus'@ represents a result of PKCS#7
+-- verification. See 'pkcs7Verify'.
+data Pkcs7VerifyStatus
+    = Pkcs7VerifySuccess (Maybe String) -- ^ Nothing if the PKCS#7
+                                        --   signature was a detached
+                                        --   signature, and @Just content@
+                                        --   if it wasn't.
+    | Pkcs7VerifyFailure
+      deriving (Show, Eq, Typeable)
+
+
+flagListToInt :: [Pkcs7Flag] -> Int
+flagListToInt = foldl' (.|.) 0 . map flagToInt
+
+
+foreign import ccall "&PKCS7_free"
+        _free :: FunPtr (Ptr PKCS7 -> IO ())
+
+foreign import ccall "HsOpenSSL_PKCS7_is_detached"
+        _is_detached :: Ptr PKCS7 -> IO CLong
+
+foreign import ccall "PKCS7_sign"
+        _sign :: Ptr X509_ -> Ptr EVP_PKEY -> Ptr STACK -> Ptr BIO_ -> Int -> IO (Ptr PKCS7)
+
+foreign import ccall "PKCS7_verify"
+        _verify :: Ptr PKCS7 -> Ptr STACK -> Ptr X509_STORE -> Ptr BIO_ -> Ptr BIO_ -> Int -> IO Int
+
+foreign import ccall "PKCS7_encrypt"
+        _encrypt :: Ptr STACK -> Ptr BIO_ -> Ptr EVP_CIPHER -> Int -> IO (Ptr PKCS7)
+
+foreign import ccall "PKCS7_decrypt"
+        _decrypt :: Ptr PKCS7 -> Ptr EVP_PKEY -> Ptr X509_ -> Ptr BIO_ -> Int -> IO Int
+
+
+wrapPkcs7Ptr :: Ptr PKCS7 -> IO Pkcs7
+wrapPkcs7Ptr p7Ptr = newForeignPtr _free p7Ptr >>= return . Pkcs7
+
+
+withPkcs7Ptr :: Pkcs7 -> (Ptr PKCS7 -> IO a) -> IO a
+withPkcs7Ptr (Pkcs7 pkcs7) = withForeignPtr pkcs7
+
+
+isDetachedSignature :: Pkcs7 -> IO Bool
+isDetachedSignature pkcs7
+    = withPkcs7Ptr pkcs7 $ \ pkcs7Ptr ->
+      _is_detached pkcs7Ptr
+           >>= return . (== 1)
+
+
+pkcs7Sign' :: X509 -> PKey -> [X509] -> BIO -> [Pkcs7Flag] -> IO Pkcs7
+pkcs7Sign' signCert pkey certs input flagList
+    = withX509Ptr signCert $ \ signCertPtr ->
+      withPKeyPtr pkey     $ \ pkeyPtr     ->
+      withX509Stack certs  $ \ certStack   ->
+      withBioPtr input     $ \ inputPtr    ->
+      _sign signCertPtr pkeyPtr certStack inputPtr (flagListToInt flagList)
+           >>= failIfNull
+           >>= wrapPkcs7Ptr
+
+-- |@'pkcs7Sign'@ creates a PKCS#7 signedData structure.
+pkcs7Sign :: X509        -- ^ certificate to sign with
+          -> PKey        -- ^ corresponding private key
+          -> [X509]      -- ^ optional additional set of certificates
+                         --   to include in the PKCS#7 structure (for
+                         --   example any intermediate CAs in the
+                         --   chain)
+          -> String      -- ^ data to be signed
+          -> [Pkcs7Flag] -- ^ An optional set of flags:
+                         -- 
+                         --   ['Pkcs7Text'] Many S\/MIME clients
+                         --   expect the signed content to include
+                         --   valid MIME headers. If the 'Pkcs7Text'
+                         --   flag is set MIME headers for type
+                         --   \"text\/plain\" are prepended to the
+                         --   data.
+                         --
+                         --   ['Pkcs7NoCerts'] If 'Pkcs7NoCerts' is
+                         --   set the signer's certificate will not be
+                         --   included in the PKCS#7 structure, the
+                         --   signer's certificate must still be
+                         --   supplied in the parameter though. This
+                         --   can reduce the size of the signature if
+                         --   the signer's certificate can be obtained
+                         --   by other means: for example a previously
+                         --   signed message.
+                         --
+                         --   ['Pkcs7Detached'] The data being signed
+                         --   is included in the PKCS#7 structure,
+                         --   unless 'Pkcs7Detached' is set in which
+                         --   case it is ommited. This is used for
+                         --   PKCS#7 detached signatures which are
+                         --   used in S\/MIME plaintext signed message
+                         --   for example.
+                         --
+                         --   ['Pkcs7Binary'] Normally the supplied
+                         --   content is translated into MIME
+                         --   canonical format (as required by the
+                         --   S\/MIME specifications) but if
+                         --   'Pkcs7Binary' is set no translation
+                         --   occurs. This option should be uesd if
+                         --   the supplied data is in binary format
+                         --   otherwise the translation will corrupt
+                         --   it.
+                         --
+                         --   ['Pkcs7NoAttr']
+                         --
+                         --   ['Pkcs7NoSmimeCap'] The signedData
+                         --   structure includes several PKCS#7
+                         --   authenticatedAttributes including the
+                         --   signing time, the PKCS#7 content type
+                         --   and the supported list of ciphers in an
+                         --   SMIMECapabilities attribute. If
+                         --   'Pkcs7NoAttr' is set then no
+                         --   authenticatedAttributes will be used. If
+                         --   Pkcs7NoSmimeCap is set then just the
+                         --   SMIMECapabilities are omitted.
+          -> IO Pkcs7
+pkcs7Sign signCert pkey certs input flagList
+    = do mem <- newConstMem input
+         pkcs7Sign' signCert pkey certs mem flagList
+
+
+pkcs7Verify' :: Pkcs7 -> [X509] -> X509Store -> Maybe BIO -> [Pkcs7Flag] -> IO (Maybe BIO, Bool)
+pkcs7Verify' pkcs7 certs store inData flagList
+    = withPkcs7Ptr pkcs7     $ \ pkcs7Ptr  ->
+      withX509Stack certs    $ \ certStack ->
+      withX509StorePtr store $ \ storePtr  ->
+      withBioPtr' inData     $ \ inDataPtr ->
+      do isDetached <- isDetachedSignature pkcs7
+         outData    <- if isDetached then
+                           return Nothing
+                       else
+                           newMem >>= return . Just
+         withBioPtr' outData $ \ outDataPtr ->
+             _verify pkcs7Ptr certStack storePtr inDataPtr outDataPtr (flagListToInt flagList)
+                  >>= interpret outData
+    where
+      interpret :: Maybe BIO -> Int -> IO (Maybe BIO, Bool)
+      interpret bio 1 = return (bio    , True )
+      interpret _   _ = return (Nothing, False)
+
+-- |@'pkcs7Verify'@ verifies a PKCS#7 signedData structure.
+pkcs7Verify :: Pkcs7           -- ^ A PKCS#7 structure to verify.
+            -> [X509]          -- ^ Set of certificates in which to
+                               --   search for the signer's
+                               --   certificate.
+            -> X509Store       -- ^ Trusted certificate store (used
+                               --   for chain verification).
+            -> Maybe String    -- ^ Signed data if the content is not
+                               --   present in the PKCS#7 structure
+                               --   (that is it is detached).
+            -> [Pkcs7Flag]     -- ^ An optional set of flags:
+                               -- 
+                               --   ['Pkcs7NoIntern'] If
+                               --   'Pkcs7NoIntern' is set the
+                               --   certificates in the message itself
+                               --   are not searched when locating the
+                               --   signer's certificate. This means
+                               --   that all the signers certificates
+                               --   must be in the second argument
+                               --   (['X509']).
+                               --
+                               --   ['Pkcs7Text'] If the 'Pkcs7Text'
+                               --   flag is set MIME headers for type
+                               --   \"text\/plain\" are deleted from
+                               --   the content. If the content is not
+                               --   of type \"text\/plain\" then an
+                               --   error is returned.
+                               --
+                               --   ['Pkcs7NoVerify'] If
+                               --   'Pkcs7NoVerify' is set the
+                               --   signer's certificates are not
+                               --   chain verified.
+                               --
+                               --   ['Pkcs7NoChain'] If 'Pkcs7NoChain'
+                               --   is set then the certificates
+                               --   contained in the message are not
+                               --   used as untrusted CAs. This means
+                               --   that the whole verify chain (apart
+                               --   from the signer's certificate)
+                               --   must be contained in the trusted
+                               --   store.
+                               --
+                               --   ['Pkcs7NoSigs'] If 'Pkcs7NoSigs'
+                               --   is set then the signatures on the
+                               --   data are not checked.
+            -> IO Pkcs7VerifyStatus
+pkcs7Verify pkcs7 certs store inData flagList
+    = do inDataBio               <- forM inData newConstMem
+         (outDataBio, isSuccess) <- pkcs7Verify' pkcs7 certs store inDataBio flagList
+         if isSuccess then
+             do outData <- forM outDataBio bioRead
+                return $ Pkcs7VerifySuccess outData
+           else
+             return Pkcs7VerifyFailure
+
+
+pkcs7Encrypt' :: [X509] -> BIO -> Cipher -> [Pkcs7Flag] -> IO Pkcs7
+pkcs7Encrypt' certs input cipher flagList
+    = withX509Stack certs  $ \ certsPtr  ->
+      withBioPtr    input  $ \ inputPtr  ->
+      withCipherPtr cipher $ \ cipherPtr ->
+      _encrypt certsPtr inputPtr cipherPtr (flagListToInt flagList)
+           >>= failIfNull
+           >>= wrapPkcs7Ptr
+
+-- |@'pkcs7Encrypt'@ creates a PKCS#7 envelopedData structure.
+pkcs7Encrypt :: [X509]      -- ^ A list of recipient certificates.
+             -> String      -- ^ The content to be encrypted.
+             -> Cipher      -- ^ The symmetric cipher to use.
+             -> [Pkcs7Flag] -- ^ An optional set of flags:
+                            --
+                            --   ['Pkcs7Text'] If the 'Pkcs7Text' flag
+                            --   is set MIME headers for type
+                            --   \"text\/plain\" are prepended to the
+                            --   data.
+                            --
+                            --   ['Pkcs7Binary'] Normally the supplied
+                            --   content is translated into MIME
+                            --   canonical format (as required by the
+                            --   S\/MIME specifications) if
+                            --   'Pkcs7Binary' is set no translation
+                            --   occurs. This option should be used if
+                            --   the supplied data is in binary format
+                            --   otherwise the translation will
+                            --   corrupt it. If 'Pkcs7Binary' is set
+                            --   then 'Pkcs7Text' is ignored.
+             -> IO Pkcs7
+pkcs7Encrypt certs input cipher flagList
+    = do mem <- newConstMem input
+         pkcs7Encrypt' certs mem cipher flagList
+
+
+pkcs7Decrypt' :: Pkcs7 -> PKey -> X509 -> BIO -> [Pkcs7Flag] -> IO ()
+pkcs7Decrypt' pkcs7 pkey cert output flagList
+    = withPkcs7Ptr pkcs7  $ \ pkcs7Ptr  ->
+      withPKeyPtr  pkey   $ \ pkeyPtr   ->
+      withX509Ptr  cert   $ \ certPtr   ->
+      withBioPtr   output $ \ outputPtr ->
+      _decrypt pkcs7Ptr pkeyPtr certPtr outputPtr (flagListToInt flagList)
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'pkcs7Decrypt'@ decrypts content from PKCS#7 envelopedData
+-- structure.
+pkcs7Decrypt :: Pkcs7       -- ^ The PKCS#7 structure to decrypt.
+             -> PKey        -- ^ The private key of the recipient.
+             -> X509        -- ^ The recipient's certificate.
+             -> [Pkcs7Flag] -- ^ An optional set of flags:
+                            --
+                            --   ['Pkcs7Text'] If the 'Pkcs7Text' flag
+                            --   is set MIME headers for type
+                            --   \"text\/plain\" are deleted from the
+                            --   content. If the content is not of
+                            --   type \"text\/plain\" then an error is
+                            --   thrown.
+             -> IO String   -- ^ The decrypted content.
+pkcs7Decrypt pkcs7 pkey cert flagList
+    = do mem <- newMem
+         pkcs7Decrypt' pkcs7 pkey cert mem flagList
+         bioRead mem
+
+
+{- S/MIME -------------------------------------------------------------------- -}
+
+foreign import ccall unsafe "SMIME_write_PKCS7"
+        _SMIME_write_PKCS7 :: Ptr BIO_ -> Ptr PKCS7 -> Ptr BIO_ -> Int -> IO Int
+
+foreign import ccall unsafe "SMIME_read_PKCS7"
+        _SMIME_read_PKCS7 :: Ptr BIO_ -> Ptr (Ptr BIO_) -> IO (Ptr PKCS7)
+
+-- |@'writeSmime'@ writes PKCS#7 structure to S\/MIME message.
+writeSmime :: Pkcs7        -- ^ A PKCS#7 structure to be written.
+           -> Maybe String -- ^ If cleartext signing
+                           --   (multipart\/signed) is being used then
+                           --   the signed data must be supplied here.
+           -> [Pkcs7Flag]  -- ^ An optional set of flags:
+                           --
+                           --   ['Pkcs7Detached'] If 'Pkcs7Detached'
+                           --   is set then cleartext signing will be
+                           --   used, this option only makes sense for
+                           --   signedData where 'Pkcs7Detached' is
+                           --   also set when 'pkcs7Sign' is also
+                           --   called.
+                           --
+                           --   ['Pkcs7Text'] If the 'Pkcs7Text' flag
+                           --   is set MIME headers for type
+                           --   \"text\/plain\" are added to the
+                           --   content, this only makes sense if
+                           --   'Pkcs7Detached' is also set.
+           -> IO String    -- ^ The result S\/MIME message.
+writeSmime pkcs7 dataStr flagList
+    = do outBio  <- newMem
+         dataBio <- forM dataStr newConstMem
+         writeSmime' outBio pkcs7 dataBio flagList
+         bioRead outBio
+
+
+writeSmime' :: BIO -> Pkcs7 -> Maybe BIO -> [Pkcs7Flag] -> IO ()
+writeSmime' outBio pkcs7 dataBio flagList
+    = withBioPtr   outBio  $ \ outBioPtr  ->
+      withPkcs7Ptr pkcs7   $ \ pkcs7Ptr   ->
+      withBioPtr'  dataBio $ \ dataBioPtr ->
+      _SMIME_write_PKCS7 outBioPtr pkcs7Ptr dataBioPtr (flagListToInt flagList)
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'readSmime'@ parses S\/MIME message.
+readSmime :: String -- ^ The message to be read.
+          -> IO (Pkcs7, Maybe String) -- ^ (The result PKCS#7
+                                      --   structure, @Just content@
+                                      --   if the PKCS#7 structure was
+                                      --   a cleartext signature and
+                                      --   @Nothing@ if it wasn't.)
+readSmime input
+    = do inBio           <- newConstMem input
+         (pkcs7, outBio) <- readSmime' inBio
+         output          <- forM outBio bioRead
+         return (pkcs7, output)
+
+
+readSmime' :: BIO -> IO (Pkcs7, Maybe BIO)
+readSmime' inBio
+    = withBioPtr inBio $ \ inBioPtr     ->
+      alloca           $ \ outBioPtrPtr ->
+      do poke outBioPtrPtr nullPtr
+
+         pkcs7     <- _SMIME_read_PKCS7 inBioPtr outBioPtrPtr
+                      >>= failIfNull
+                      >>= wrapPkcs7Ptr
+         outBioPtr <- peek outBioPtrPtr
+         outBio    <- if outBioPtr == nullPtr then
+                          return Nothing
+                      else
+                          wrapBioPtr outBioPtr >>= return . Just
+
+         return (pkcs7, outBio)
diff --git a/OpenSSL/RSA.hsc b/OpenSSL/RSA.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/RSA.hsc
@@ -0,0 +1,152 @@
+{- -*- haskell -*- -}
+
+-- #prune
+
+-- |An interface to RSA public key generator.
+
+#include "HsOpenSSL.h"
+
+module OpenSSL.RSA
+    ( -- * Type
+      RSA
+    , RSA_ -- private
+    , withRSAPtr -- private
+
+      -- * Generating keypair
+    , RSAGenKeyCallback
+    , generateKey
+
+      -- * Exploring keypair
+    , rsaN
+    , rsaE
+    , rsaD
+    , rsaP
+    , rsaQ
+    , rsaDMP1
+    , rsaDMQ1
+    , rsaIQMP
+    )
+    where
+
+import           Control.Monad
+import           Foreign
+import           OpenSSL.BN
+import           OpenSSL.Utils
+
+-- |@'RSA'@ is an opaque object that represents either RSA public key
+-- or public\/private keypair.
+newtype RSA  = RSA (ForeignPtr RSA_)
+data    RSA_
+
+
+foreign import ccall unsafe "&RSA_free"
+        _free :: FunPtr (Ptr RSA_ -> IO ())
+
+
+withRSAPtr :: RSA -> (Ptr RSA_ -> IO a) -> IO a
+withRSAPtr (RSA rsa) = withForeignPtr rsa
+
+
+{- generation --------------------------------------------------------------- -}
+
+-- |@'RSAGenKeyCallback'@ represents a callback function to get
+-- informed the progress of RSA key generation.
+--
+-- * @callback 0 i@ is called after generating the @i@-th potential
+--   prime number.
+--
+-- * While the number is being tested for primality, @callback 1 j@ is
+--   called after the @j@-th iteration (j = 0, 1, ...).
+--
+-- * When the @n@-th randomly generated prime is rejected as not
+--   suitable for the key, @callback 2 n@ is called.
+--
+-- * When a random @p@ has been found with @p@-1 relatively prime to
+--   @e@, it is called as @callback 3 0@.
+--
+-- * The process is then repeated for prime @q@ with @callback 3 1@.
+type RSAGenKeyCallback = Int -> Int -> IO ()
+
+type RSAGenKeyCallback' = Int -> Int -> Ptr () -> IO ()
+
+
+foreign import ccall "wrapper"
+        mkGenKeyCallback :: RSAGenKeyCallback' -> IO (FunPtr RSAGenKeyCallback')
+
+foreign import ccall safe "RSA_generate_key"
+        _generate_key :: Int -> Int -> FunPtr RSAGenKeyCallback' -> Ptr a -> IO (Ptr RSA_)
+
+-- |@'generateKey'@ generates an RSA keypair.
+generateKey :: Int    -- ^ The number of bits of the public modulus
+                      --   (i.e. key size). Key sizes with @n < 1024@
+                      --   should be considered insecure.
+            -> Int    -- ^ The public exponent. It is an odd number,
+                      --   typically 3, 17 or 65537.
+            -> Maybe RSAGenKeyCallback -- ^ A callback function.
+            -> IO RSA -- ^ The generated keypair.
+
+generateKey nbits e Nothing
+    = do ptr <- _generate_key nbits e nullFunPtr nullPtr
+         failIfNull ptr
+         newForeignPtr _free ptr >>= return . RSA
+
+generateKey nbits e (Just cb)
+    = do cbPtr <- mkGenKeyCallback
+                  $ \ arg1 arg2 _ -> cb arg1 arg2
+         ptr   <- _generate_key nbits e cbPtr nullPtr
+         freeHaskellFunPtr cbPtr
+         failIfNull ptr
+         newForeignPtr _free ptr >>= return . RSA
+
+
+{- exploration -------------------------------------------------------------- -}
+
+peekRSAPublic :: (Ptr RSA_ -> IO (Ptr BIGNUM)) -> RSA -> IO Integer
+peekRSAPublic peeker rsa
+    = withRSAPtr rsa $ \ rsaPtr ->
+      do bn <- peeker rsaPtr
+         when (bn == nullPtr) $ fail "peekRSAPublic: got a nullPtr"
+         peekBN bn
+
+
+peekRSAPrivate :: (Ptr RSA_ -> IO (Ptr BIGNUM)) -> RSA -> IO (Maybe Integer)
+peekRSAPrivate peeker rsa
+    = withRSAPtr rsa $ \ rsaPtr ->
+      do bn <- peeker rsaPtr
+         if bn == nullPtr then
+             return Nothing
+           else
+             peekBN bn >>= return . Just
+
+-- |@'rsaN' pubKey@ returns the public modulus of the key.
+rsaN :: RSA -> IO Integer
+rsaN = peekRSAPublic (#peek RSA, n)
+
+-- |@'rsaE' pubKey@ returns the public exponent of the key.
+rsaE :: RSA -> IO Integer
+rsaE = peekRSAPublic (#peek RSA, e)
+
+-- |@'rsaD' privKey@ returns the private exponent of the key. If
+-- @privKey@ is not really a private key, the result is @Nothing@.
+rsaD :: RSA -> IO (Maybe Integer)
+rsaD = peekRSAPrivate (#peek RSA, d)
+
+-- |@'rsaP' privkey@ returns the secret prime factor @p@ of the key.
+rsaP :: RSA -> IO (Maybe Integer)
+rsaP = peekRSAPrivate (#peek RSA, p)
+
+-- |@'rsaQ' privkey@ returns the secret prime factor @q@ of the key.
+rsaQ :: RSA -> IO (Maybe Integer)
+rsaQ = peekRSAPrivate (#peek RSA, q)
+
+-- |@'rsaDMP1' privkey@ returns @d mod (p-1)@ of the key.
+rsaDMP1 :: RSA -> IO (Maybe Integer)
+rsaDMP1 = peekRSAPrivate (#peek RSA, dmp1)
+
+-- |@'rsaDMQ1' privkey@ returns @d mod (q-1)@ of the key.
+rsaDMQ1 :: RSA -> IO (Maybe Integer)
+rsaDMQ1 = peekRSAPrivate (#peek RSA, dmq1)
+
+-- |@'rsaIQMP' privkey@ returns @q^-1 mod p@ of the key.
+rsaIQMP :: RSA -> IO (Maybe Integer)
+rsaIQMP = peekRSAPrivate (#peek RSA, iqmp)
diff --git a/OpenSSL/SSL.hsc b/OpenSSL/SSL.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/SSL.hsc
@@ -0,0 +1,15 @@
+{- -*- haskell -*- -}
+
+-- #hide
+
+module OpenSSL.SSL
+    ( loadErrorStrings
+    , addAllAlgorithms
+    )
+    where
+
+foreign import ccall unsafe "SSL_load_error_strings"
+        loadErrorStrings :: IO ()
+
+foreign import ccall unsafe "HsOpenSSL_OpenSSL_add_all_algorithms"
+        addAllAlgorithms :: IO ()
diff --git a/OpenSSL/Stack.hsc b/OpenSSL/Stack.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/Stack.hsc
@@ -0,0 +1,64 @@
+{- -*- haskell -*- -}
+
+-- #hide
+
+module OpenSSL.Stack
+    ( STACK
+    , mapStack
+    , withStack
+    , withForeignStack
+    )
+    where
+
+import           Control.Exception
+import           Foreign
+import           OpenSSL.Utils
+
+
+data STACK
+
+
+foreign import ccall unsafe "sk_new_null"
+        skNewNull :: IO (Ptr STACK)
+
+foreign import ccall unsafe "sk_free"
+        skFree :: Ptr STACK -> IO ()
+
+foreign import ccall unsafe "sk_push"
+        skPush :: Ptr STACK -> Ptr () -> IO ()
+
+foreign import ccall unsafe "sk_num"
+        skNum :: Ptr STACK -> IO Int
+
+foreign import ccall unsafe "sk_value"
+        skValue :: Ptr STACK -> Int -> IO (Ptr ())
+
+
+mapStack :: (Ptr a -> IO b) -> Ptr STACK -> IO [b]
+mapStack m st
+    = do num <- skNum st
+         mapM (\ i -> skValue st i >>= return . unsafeCoercePtr >>= m)
+                  $ take num [0..]
+
+
+newStack :: [Ptr a] -> IO (Ptr STACK)
+newStack values
+    = do st <- skNewNull
+         mapM_ (skPush st . unsafeCoercePtr) values
+         return st
+
+
+withStack :: [Ptr a] -> (Ptr STACK -> IO b) -> IO b
+withStack values f
+    = bracket (newStack values) skFree f
+
+
+withForeignStack :: (fp -> Ptr obj)
+                 -> (fp -> IO ())
+                 -> [fp]
+                 -> (Ptr STACK -> IO ret)
+                 -> IO ret
+withForeignStack unsafeFpToPtr touchFp fps action
+    = do ret <- withStack (map unsafeFpToPtr fps) action
+         mapM_ touchFp fps
+         return ret
diff --git a/OpenSSL/Utils.hs b/OpenSSL/Utils.hs
new file mode 100644
--- /dev/null
+++ b/OpenSSL/Utils.hs
@@ -0,0 +1,38 @@
+{- -*- haskell -*- -}
+
+-- #hide
+
+module OpenSSL.Utils
+    ( failIfNull
+    , failIf
+    , raiseOpenSSLError
+
+    , unsafeCoercePtr
+    )
+    where
+
+import           Foreign
+import           GHC.Base
+import           OpenSSL.ERR
+
+
+failIfNull :: Ptr a -> IO (Ptr a)
+failIfNull ptr
+    = if ptr == nullPtr then
+          raiseOpenSSLError
+      else
+          return ptr
+
+
+failIf :: (a -> Bool) -> a -> IO a
+failIf f a
+    | f a       = raiseOpenSSLError
+    | otherwise = return a
+
+
+raiseOpenSSLError :: IO a
+raiseOpenSSLError = getError >>= errorString >>= fail
+
+
+unsafeCoercePtr :: Ptr a -> Ptr b
+unsafeCoercePtr = unsafeCoerce#
diff --git a/OpenSSL/X509.hsc b/OpenSSL/X509.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/X509.hsc
@@ -0,0 +1,372 @@
+{- -*- haskell -*- -}
+
+-- #prune
+
+-- |An interface to X.509 certificate.
+
+module OpenSSL.X509
+    ( -- * Type
+      X509
+    , X509_
+
+      -- * Functions to manipulate certificate
+    , newX509
+    , wrapX509 -- private
+    , withX509Ptr -- private
+    , withX509Stack -- private
+    , unsafeX509ToPtr -- private
+    , touchX509 -- private
+
+    , compareX509
+
+    , signX509
+    , verifyX509
+
+    , printX509
+
+      -- * Accessors
+    , getVersion
+    , setVersion
+
+    , getSerialNumber
+    , setSerialNumber
+
+    , getIssuerName
+    , setIssuerName
+
+    , getSubjectName
+    , setSubjectName
+
+    , getNotBefore
+    , setNotBefore
+
+    , getNotAfter
+    , setNotAfter
+
+    , getPublicKey
+    , setPublicKey
+
+    , getSubjectEmail
+    )
+    where
+
+import           Control.Monad
+import           Data.Time.Clock
+import           Foreign
+import           Foreign.C
+import           OpenSSL.ASN1
+import           OpenSSL.BIO
+import           OpenSSL.EVP.Digest
+import           OpenSSL.EVP.PKey
+import           OpenSSL.EVP.Verify
+import           OpenSSL.Utils
+import           OpenSSL.Stack
+import           OpenSSL.X509.Name
+
+-- |@'X509'@ is an opaque object that represents X.509 certificate.
+newtype X509  = X509 (ForeignPtr X509_)
+data    X509_
+
+
+foreign import ccall unsafe "X509_new"
+        _new :: IO (Ptr X509_)
+
+foreign import ccall unsafe "&X509_free"
+        _free :: FunPtr (Ptr X509_ -> IO ())
+
+foreign import ccall unsafe "X509_print"
+        _print :: Ptr BIO_ -> Ptr X509_ -> IO Int
+
+foreign import ccall unsafe "X509_cmp"
+        _cmp :: Ptr X509_ -> Ptr X509_ -> IO Int
+
+foreign import ccall unsafe "HsOpenSSL_X509_get_version"
+        _get_version :: Ptr X509_ -> IO CLong
+
+foreign import ccall unsafe "X509_set_version"
+        _set_version :: Ptr X509_ -> CLong -> IO Int
+
+foreign import ccall unsafe "X509_get_serialNumber"
+        _get_serialNumber :: Ptr X509_ -> IO (Ptr ASN1_INTEGER)
+
+foreign import ccall unsafe "X509_set_serialNumber"
+        _set_serialNumber :: Ptr X509_ -> Ptr ASN1_INTEGER -> IO Int
+
+foreign import ccall unsafe "X509_get_issuer_name"
+        _get_issuer_name :: Ptr X509_ -> IO (Ptr X509_NAME)
+
+foreign import ccall unsafe "X509_set_issuer_name"
+        _set_issuer_name :: Ptr X509_ -> Ptr X509_NAME -> IO Int
+
+foreign import ccall unsafe "X509_get_subject_name"
+        _get_subject_name :: Ptr X509_ -> IO (Ptr X509_NAME)
+
+foreign import ccall unsafe "X509_set_subject_name"
+        _set_subject_name :: Ptr X509_ -> Ptr X509_NAME -> IO Int
+
+foreign import ccall unsafe "HsOpenSSL_X509_get_notBefore"
+        _get_notBefore :: Ptr X509_ -> IO (Ptr ASN1_TIME)
+
+foreign import ccall unsafe "X509_set_notBefore"
+        _set_notBefore :: Ptr X509_ -> Ptr ASN1_TIME -> IO Int
+
+foreign import ccall unsafe "HsOpenSSL_X509_get_notAfter"
+        _get_notAfter :: Ptr X509_ -> IO (Ptr ASN1_TIME)
+
+foreign import ccall unsafe "X509_set_notAfter"
+        _set_notAfter :: Ptr X509_ -> Ptr ASN1_TIME -> IO Int
+
+foreign import ccall unsafe "X509_get_pubkey"
+        _get_pubkey :: Ptr X509_ -> IO (Ptr EVP_PKEY)
+
+foreign import ccall unsafe "X509_set_pubkey"
+        _set_pubkey :: Ptr X509_ -> Ptr EVP_PKEY -> IO Int
+
+foreign import ccall unsafe "X509_get1_email"
+        _get1_email :: Ptr X509_ -> IO (Ptr STACK)
+
+foreign import ccall unsafe "X509_email_free"
+        _email_free :: Ptr STACK -> IO ()
+
+foreign import ccall unsafe "X509_sign"
+        _sign :: Ptr X509_ -> Ptr EVP_PKEY -> Ptr EVP_MD -> IO Int
+
+foreign import ccall unsafe "X509_verify"
+        _verify :: Ptr X509_ -> Ptr EVP_PKEY -> IO Int
+
+-- |@'newX509'@ creates an empty certificate. You must set the
+-- following properties to and sign it (see 'signX509') to actually
+-- use the certificate.
+--
+--   [/Version/] See 'setVersion'.
+--
+--   [/Serial number/] See 'setSerialNumber'.
+--
+--   [/Issuer name/] See 'setIssuerName'.
+--
+--   [/Subject name/] See 'setSubjectName'.
+--
+--   [/Validity/] See 'setNotBefore' and 'setNotAfter'.
+--
+--   [/Public Key/] See 'setPublicKey'.
+--
+newX509 :: IO X509
+newX509 = _new >>= failIfNull >>= wrapX509
+
+
+wrapX509 :: Ptr X509_ -> IO X509
+wrapX509 x509Ptr = newForeignPtr _free x509Ptr >>= return . X509
+
+
+withX509Ptr :: X509 -> (Ptr X509_ -> IO a) -> IO a
+withX509Ptr (X509 x509) = withForeignPtr x509
+
+
+withX509Stack :: [X509] -> (Ptr STACK -> IO a) -> IO a
+withX509Stack = withForeignStack unsafeX509ToPtr touchX509
+
+
+unsafeX509ToPtr :: X509 -> Ptr X509_
+unsafeX509ToPtr (X509 x509) = unsafeForeignPtrToPtr x509
+
+
+touchX509 :: X509 -> IO ()
+touchX509 (X509 x509) = touchForeignPtr x509
+
+-- |@'compareX509' cert1 cert2@ compares two certificates.
+compareX509 :: X509 -> X509 -> IO Ordering
+compareX509 cert1 cert2
+    = withX509Ptr cert1 $ \ cert1Ptr ->
+      withX509Ptr cert2 $ \ cert2Ptr ->
+      _cmp cert1Ptr cert2Ptr >>= return . interpret
+    where
+      interpret :: Int -> Ordering
+      interpret n
+          | n > 0     = GT
+          | n < 0     = LT
+          | otherwise = EQ
+
+-- |@'signX509'@ signs a certificate with an issuer private key.
+signX509 :: X509         -- ^ The certificate to be signed.
+         -> PKey         -- ^ The private key to sign with.
+         -> Maybe Digest -- ^ A hashing algorithm to use. If @Nothing@
+                         --   the most suitable algorithm for the key
+                         --   is automatically used.
+         -> IO ()
+signX509 x509 pkey mDigest
+    = withX509Ptr x509 $ \ x509Ptr ->
+      withPKeyPtr pkey $ \ pkeyPtr ->
+      do digest <- case mDigest of
+                     Just md -> return md
+                     Nothing -> pkeyDefaultMD pkey
+         withMDPtr digest $ \ digestPtr ->
+             _sign x509Ptr pkeyPtr digestPtr
+                  >>= failIf (== 0)
+         return ()
+
+-- |@'verifyX509'@ verifies a signature of certificate with an issuer
+-- public key.
+verifyX509 :: X509 -- ^ The certificate to be verified.
+           -> PKey -- ^ The public key to verify with.
+           -> IO VerifyStatus
+verifyX509 x509 pkey
+    = withX509Ptr x509 $ \ x509Ptr ->
+      withPKeyPtr pkey $ \ pkeyPtr ->
+      _verify x509Ptr pkeyPtr
+           >>= interpret
+    where
+      interpret :: Int -> IO VerifyStatus
+      interpret 1 = return VerifySuccess
+      interpret 0 = return VerifyFailure
+      interpret _ = raiseOpenSSLError
+
+-- |@'printX509' cert@ translates a certificate into human-readable
+-- format.
+printX509 :: X509 -> IO String
+printX509 x509
+    = do mem <- newMem
+         withX509Ptr x509 $ \ x509Ptr ->
+             withBioPtr mem $ \ memPtr ->
+                 _print memPtr x509Ptr
+                      >>= failIf (/= 1)
+         bioRead mem
+
+-- |@'getVersion' cert@ returns the version number of certificate. It
+-- seems the number is 0-origin: version 2 means X.509 v3.
+getVersion :: X509 -> IO Int
+getVersion x509
+    = withX509Ptr x509 $ \ x509Ptr ->
+      liftM fromIntegral $ _get_version x509Ptr
+
+-- |@'setVersion' cert ver@ updates the version number of certificate.
+setVersion :: X509 -> Int -> IO ()
+setVersion x509 ver
+    = withX509Ptr x509 $ \ x509Ptr ->
+      _set_version x509Ptr (fromIntegral ver)
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'getSerialNumber' cert@ returns the serial number of certificate.
+getSerialNumber :: X509 -> IO Integer
+getSerialNumber x509
+    = withX509Ptr x509 $ \ x509Ptr ->
+      _get_serialNumber x509Ptr
+           >>= peekASN1Integer
+
+-- |@'setSerialNumber' cert num@ updates the serial number of
+-- certificate.
+setSerialNumber :: X509 -> Integer -> IO ()
+setSerialNumber x509 serial
+    = withX509Ptr x509 $ \ x509Ptr ->
+      withASN1Integer serial $ \ serialPtr ->
+      _set_serialNumber x509Ptr serialPtr
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'getIssuerName'@ returns the issuer name of certificate.
+getIssuerName :: X509 -- ^ The certificate to examine.
+              -> Bool -- ^ @True@ if you want the keys of each parts
+                      --   to be of long form (e.g. \"commonName\"),
+                      --   or @False@ if you don't (e.g. \"CN\").
+              -> IO [(String, String)] -- ^ Pairs of key and value,
+                                       -- for example \[(\"C\",
+                                       -- \"JP\"), (\"ST\",
+                                       -- \"Some-State\"), ...\].
+getIssuerName x509 wantLongName
+    = withX509Ptr x509 $ \ x509Ptr ->
+      do namePtr <- _get_issuer_name x509Ptr
+         peekX509Name namePtr wantLongName
+
+-- |@'setIssuerName' cert name@ updates the issuer name of
+-- certificate. Keys of each parts may be of either long form or short
+-- form. See 'getIssuerName'.
+setIssuerName :: X509 -> [(String, String)] -> IO ()
+setIssuerName x509 issuer
+    = withX509Ptr x509 $ \ x509Ptr ->
+      withX509Name issuer $ \ namePtr ->
+      _set_issuer_name x509Ptr namePtr
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'getSubjectName' cert wantLongName@ returns the subject name of
+-- certificate. See 'getIssuerName'.
+getSubjectName :: X509 -> Bool -> IO [(String, String)]
+getSubjectName x509 wantLongName
+    = withX509Ptr x509 $ \ x509Ptr ->
+      do namePtr <- _get_subject_name x509Ptr
+         peekX509Name namePtr wantLongName
+
+-- |@'setSubjectName' cert name@ updates the subject name of
+-- certificate. See 'setIssuerName'.
+setSubjectName :: X509 -> [(String, String)] -> IO ()
+setSubjectName x509 subject
+    = withX509Ptr x509 $ \ x509Ptr ->
+      withX509Name subject $ \ namePtr ->
+      _set_subject_name x509Ptr namePtr
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'getNotBefore' cert@ returns the time when the certificate begins
+-- to be valid.
+getNotBefore :: X509 -> IO UTCTime
+getNotBefore x509
+    = withX509Ptr x509 $ \ x509Ptr ->
+      _get_notBefore x509Ptr
+           >>= peekASN1Time
+
+-- |@'setNotBefore' cert utc@ updates the time when the certificate
+-- begins to be valid.
+setNotBefore :: X509 -> UTCTime -> IO ()
+setNotBefore x509 utc
+    = withX509Ptr x509 $ \ x509Ptr ->
+      withASN1Time utc $ \ time ->
+      _set_notBefore x509Ptr time
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'getNotAfter' cert@ returns the time when the certificate
+-- expires.
+getNotAfter :: X509 -> IO UTCTime
+getNotAfter x509
+    = withX509Ptr x509 $ \ x509Ptr ->
+      _get_notAfter x509Ptr
+           >>= peekASN1Time
+
+-- |@'setNotAfter' cert utc@ updates the time when the certificate
+-- expires.
+setNotAfter :: X509 -> UTCTime -> IO ()
+setNotAfter x509 utc
+    = withX509Ptr x509 $ \ x509Ptr ->
+      withASN1Time utc $ \ time ->
+      _set_notAfter x509Ptr time
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'getPublicKey' cert@ returns the public key of the subject of
+-- certificate.
+getPublicKey :: X509 -> IO PKey
+getPublicKey x509
+    = withX509Ptr x509 $ \ x509Ptr ->
+      _get_pubkey x509Ptr
+           >>= failIfNull
+           >>= wrapPKeyPtr
+
+-- |@'setPublicKey' cert pubkey@ updates the public key of the subject
+-- of certificate.
+setPublicKey :: X509 -> PKey -> IO ()
+setPublicKey x509 pkey
+    = withX509Ptr x509 $ \ x509Ptr ->
+      withPKeyPtr pkey $ \ pkeyPtr ->
+      _set_pubkey x509Ptr pkeyPtr
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'getSubjectEmail' cert@ returns every subject email addresses in
+-- the certificate.
+getSubjectEmail :: X509 -> IO [String]
+getSubjectEmail x509
+    = withX509Ptr x509 $ \ x509Ptr ->
+      do st   <- _get1_email x509Ptr
+         list <- mapStack peekCString st
+         _email_free st
+         return list
diff --git a/OpenSSL/X509/Name.hsc b/OpenSSL/X509/Name.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/X509/Name.hsc
@@ -0,0 +1,86 @@
+{- -*- haskell -*- -}
+
+-- #hide
+
+#include "HsOpenSSL.h"
+
+module OpenSSL.X509.Name
+    ( X509_NAME
+
+    , allocaX509Name
+    , withX509Name
+    , peekX509Name
+    )
+    where
+
+import           Control.Exception
+import           Foreign
+import           Foreign.C
+import           OpenSSL.ASN1
+import           OpenSSL.Utils
+
+
+data X509_NAME
+data X509_NAME_ENTRY
+
+foreign import ccall unsafe "X509_NAME_new"
+        _new :: IO (Ptr X509_NAME)
+
+foreign import ccall unsafe "X509_NAME_free"
+        _free :: Ptr X509_NAME -> IO ()
+
+foreign import ccall unsafe "X509_NAME_add_entry_by_txt"
+        _add_entry_by_txt :: Ptr X509_NAME -> CString -> Int -> Ptr CChar -> Int -> Int -> Int -> IO Int
+
+foreign import ccall unsafe "X509_NAME_entry_count"
+        _entry_count :: Ptr X509_NAME -> IO Int
+
+foreign import ccall unsafe "X509_NAME_get_entry"
+        _get_entry :: Ptr X509_NAME -> Int -> IO (Ptr X509_NAME_ENTRY)
+
+foreign import ccall unsafe "X509_NAME_ENTRY_get_object"
+        _ENTRY_get_object :: Ptr X509_NAME_ENTRY -> IO (Ptr ASN1_OBJECT)
+
+foreign import ccall unsafe "X509_NAME_ENTRY_get_data"
+        _ENTRY_get_data :: Ptr X509_NAME_ENTRY -> IO (Ptr ASN1_STRING)
+
+
+allocaX509Name :: (Ptr X509_NAME -> IO a) -> IO a
+allocaX509Name m
+    = bracket _new _free m
+
+
+withX509Name :: [(String, String)] -> (Ptr X509_NAME -> IO a) -> IO a
+withX509Name name m
+    = allocaX509Name $ \ namePtr ->
+      do mapM_ (addEntry namePtr) name
+         m namePtr
+    where
+      addEntry :: Ptr X509_NAME -> (String, String) -> IO ()
+      addEntry namePtr (key, val)
+          = withCString    key $ \ keyPtr ->
+            withCStringLen val $ \ (valPtr, valLen) ->
+            _add_entry_by_txt namePtr keyPtr (#const MBSTRING_UTF8) valPtr valLen (-1) 0
+                 >>= failIf (/= 1)
+                 >>  return ()
+
+
+peekX509Name :: Ptr X509_NAME -> Bool -> IO [(String, String)]
+peekX509Name namePtr wantLongName
+    = do count <- _entry_count namePtr >>= failIf (< 0)
+         mapM peekEntry $ take count [0..]
+    where
+      peekEntry :: Int -> IO (String, String)
+      peekEntry n
+          = do ent <- _get_entry namePtr n  >>= failIfNull
+               obj <- _ENTRY_get_object ent >>= failIfNull
+               dat <- _ENTRY_get_data   ent >>= failIfNull
+
+               nid <- obj2nid obj
+               key <- if wantLongName then
+                          nid2ln nid
+                      else
+                          nid2sn nid
+               val <- peekASN1String dat
+
+               return (key, val)
diff --git a/OpenSSL/X509/Request.hsc b/OpenSSL/X509/Request.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/X509/Request.hsc
@@ -0,0 +1,249 @@
+{- -*- haskell -*- -}
+
+-- #prune
+
+-- |An interface to PKCS#10 certificate request.
+
+module OpenSSL.X509.Request
+    ( -- * Type
+      X509Req
+    , X509_REQ -- private
+
+      -- * Functions to manipulate request
+    , newX509Req
+    , wrapX509Req -- private
+    , withX509ReqPtr -- private
+
+    , signX509Req
+    , verifyX509Req
+
+    , printX509Req
+
+    , makeX509FromReq
+
+      -- * Accessors
+    , getVersion
+    , setVersion
+
+    , getSubjectName
+    , setSubjectName
+
+    , getPublicKey
+    , setPublicKey
+    )
+    where
+
+import           Control.Monad
+import           Foreign
+import           Foreign.C
+import           OpenSSL.BIO
+import           OpenSSL.EVP.Digest
+import           OpenSSL.EVP.PKey
+import           OpenSSL.EVP.Verify
+import           OpenSSL.Utils
+import           OpenSSL.X509 (X509)
+import qualified OpenSSL.X509 as Cert
+import           OpenSSL.X509.Name
+
+-- |@'X509Req'@ is an opaque object that represents PKCS#10
+-- certificate request.
+newtype X509Req  = X509Req (ForeignPtr X509_REQ)
+data    X509_REQ
+
+
+foreign import ccall unsafe "X509_REQ_new"
+        _new :: IO (Ptr X509_REQ)
+
+foreign import ccall unsafe "&X509_REQ_free"
+        _free :: FunPtr (Ptr X509_REQ -> IO ())
+
+foreign import ccall unsafe "X509_REQ_sign"
+        _sign :: Ptr X509_REQ -> Ptr EVP_PKEY -> Ptr EVP_MD -> IO Int
+
+foreign import ccall unsafe "X509_REQ_verify"
+        _verify :: Ptr X509_REQ -> Ptr EVP_PKEY -> IO Int
+
+foreign import ccall unsafe "X509_REQ_print"
+        _print :: Ptr BIO_ -> Ptr X509_REQ -> IO Int
+
+foreign import ccall unsafe "HsOpenSSL_X509_REQ_get_version"
+        _get_version :: Ptr X509_REQ -> IO CLong
+
+foreign import ccall unsafe "X509_REQ_set_version"
+        _set_version :: Ptr X509_REQ -> CLong -> IO Int
+
+foreign import ccall unsafe "HsOpenSSL_X509_REQ_get_subject_name"
+        _get_subject_name :: Ptr X509_REQ -> IO (Ptr X509_NAME)
+
+foreign import ccall unsafe "X509_REQ_set_subject_name"
+        _set_subject_name :: Ptr X509_REQ -> Ptr X509_NAME -> IO Int
+
+foreign import ccall unsafe "X509_REQ_get_pubkey"
+        _get_pubkey :: Ptr X509_REQ -> IO (Ptr EVP_PKEY)
+
+foreign import ccall unsafe "X509_REQ_set_pubkey"
+        _set_pubkey :: Ptr X509_REQ -> Ptr EVP_PKEY -> IO Int
+
+-- |@'newX509Req'@ creates an empty certificate request. You must set
+-- the following properties to and sign it (see 'signX509Req') to
+-- actually use the certificate request.
+--
+--  [/Version/] See 'setVersion'.
+--
+--  [/Subject Name/] See 'setSubjectName'.
+--
+--  [/Public Key/] See 'setPublicKey'.
+--
+newX509Req :: IO X509Req
+newX509Req = _new >>= wrapX509Req
+
+
+wrapX509Req :: Ptr X509_REQ -> IO X509Req
+wrapX509Req reqPtr = newForeignPtr _free reqPtr >>= return . X509Req
+
+
+withX509ReqPtr :: X509Req -> (Ptr X509_REQ -> IO a) -> IO a
+withX509ReqPtr (X509Req req) = withForeignPtr req
+
+-- |@'signX509Req'@ signs a certificate request with a subject private
+-- key.
+signX509Req :: X509Req      -- ^ The request to be signed.
+            -> PKey         -- ^ The private key to sign with.
+            -> Maybe Digest -- ^ A hashing algorithm to use. If
+                            --   @Nothing@ the most suitable algorithm
+                            --   for the key is automatically used.
+            -> IO ()
+signX509Req req pkey mDigest
+    = withX509ReqPtr req  $ \ reqPtr  ->
+      withPKeyPtr    pkey $ \ pkeyPtr ->
+      do digest <- case mDigest of
+                     Just md -> return md
+                     Nothing -> pkeyDefaultMD pkey
+         withMDPtr digest $ \ digestPtr ->
+             _sign reqPtr pkeyPtr digestPtr
+                  >>= failIf (== 0)
+         return ()
+
+-- |@'verifyX509Req'@ verifies a signature of certificate request with
+-- a subject public key.
+verifyX509Req :: X509Req -- ^ The request to be verified.
+              -> PKey    -- ^ The public key to verify with.
+              -> IO VerifyStatus
+verifyX509Req req pkey
+    = withX509ReqPtr req  $ \ reqPtr  ->
+      withPKeyPtr    pkey $ \ pkeyPtr ->
+      _verify reqPtr pkeyPtr
+           >>= interpret
+    where
+      interpret :: Int -> IO VerifyStatus
+      interpret 1 = return VerifySuccess
+      interpret 0 = return VerifyFailure
+      interpret _ = raiseOpenSSLError
+
+-- |@'printX509Req' req@ translates a certificate request into
+-- human-readable format.
+printX509Req :: X509Req -> IO String
+printX509Req req
+    = do mem <- newMem
+         withBioPtr mem $ \ memPtr ->
+             withX509ReqPtr req $ \ reqPtr ->
+                 _print memPtr reqPtr
+                      >>= failIf (/= 1)
+         bioRead mem
+
+-- |@'getVersion' req@ returns the version number of certificate
+-- request.
+getVersion :: X509Req -> IO Int
+getVersion req
+    = withX509ReqPtr req $ \ reqPtr ->
+      liftM fromIntegral $ _get_version reqPtr
+
+-- |@'setVersion' req ver@ updates the version number of certificate
+-- request.
+setVersion :: X509Req -> Int -> IO ()
+setVersion req ver
+    = withX509ReqPtr req $ \ reqPtr ->
+      _set_version reqPtr (fromIntegral ver)
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'getSubjectName' req wantLongName@ returns the subject name of
+-- certificate request. See 'OpenSSL.X509.getSubjectName' of
+-- "OpenSSL.X509".
+getSubjectName :: X509Req -> Bool -> IO [(String, String)]
+getSubjectName req wantLongName
+    = withX509ReqPtr req $ \ reqPtr ->
+      do namePtr <- _get_subject_name reqPtr
+         peekX509Name namePtr wantLongName
+
+-- |@'setSubjectName' req name@ updates the subject name of
+-- certificate request. See 'OpenSSL.X509.setSubjectName' of
+-- "OpenSSL.X509".
+setSubjectName :: X509Req -> [(String, String)] -> IO ()
+setSubjectName req subject
+    = withX509ReqPtr req $ \ reqPtr ->
+      withX509Name subject $ \ namePtr ->
+      _set_subject_name reqPtr namePtr
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'getPublicKey' req@ returns the public key of the subject of
+-- certificate request.
+getPublicKey :: X509Req -> IO PKey
+getPublicKey req
+    = withX509ReqPtr req $ \ reqPtr ->
+      _get_pubkey reqPtr
+           >>= failIfNull
+           >>= wrapPKeyPtr
+
+-- |@'setPublicKey' req@ updates the public key of the subject of
+-- certificate request.
+setPublicKey :: X509Req -> PKey -> IO ()
+setPublicKey req pkey
+    = withX509ReqPtr req  $ \ reqPtr  ->
+      withPKeyPtr    pkey $ \ pkeyPtr ->
+      _set_pubkey reqPtr pkeyPtr
+           >>= failIf (/= 1)
+           >>  return ()
+
+
+-- |@'makeX509FromReq' req cert@ creates an empty X.509 certificate
+-- and copies as much data from the request as possible. The resulting
+-- certificate doesn't have the following data and it isn't signed so
+-- you must fill them and sign it yourself.
+--
+--   * Serial number
+--
+--   * Validity (Not Before and Not After)
+--
+-- Example:
+--
+-- > import Data.Time.Clock
+-- >
+-- > genCert :: X509 -> EvpPKey -> Integer -> Int -> X509Req -> IO X509
+-- > genCert caCert caKey serial days req
+-- >     = do cert <- makeX509FromReq req caCert
+-- >          now  <- getCurrentTime
+-- >          setSerialNumber cert serial
+-- >          setNotBefore cert $ addUTCTime (-1) now
+-- >          setNotAfter  cert $ addUTCTime (days * 24 * 60 * 60) now
+-- >          signX509 cert caKey Nothing
+-- >          return cert
+--
+makeX509FromReq :: X509Req
+                -> X509
+                -> IO X509
+makeX509FromReq req caCert
+    = do reqPubKey <- getPublicKey req
+         verified  <- verifyX509Req req reqPubKey
+
+         when (verified == VerifyFailure)
+                  $ fail "makeX509FromReq: the request isn't properly signed by its own key."
+
+         cert <- Cert.newX509
+         Cert.setVersion cert 2 -- Version 2 means X509 v3. It's confusing.
+         Cert.setIssuerName  cert =<< Cert.getSubjectName caCert False
+         Cert.setSubjectName cert =<< getSubjectName req False
+         Cert.setPublicKey   cert =<< getPublicKey req
+
+         return cert
diff --git a/OpenSSL/X509/Revocation.hsc b/OpenSSL/X509/Revocation.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/X509/Revocation.hsc
@@ -0,0 +1,324 @@
+{- -*- haskell -*- -}
+
+-- #prune
+
+-- |An interface to Certificate Revocation List.
+
+#include "HsOpenSSL.h"
+
+module OpenSSL.X509.Revocation
+    ( -- * Types
+      CRL
+    , X509_CRL -- privae
+    , RevokedCertificate(..)
+
+      -- * Functions to manipulate revocation list
+    , newCRL
+    , wrapCRL -- private
+    , withCRLPtr -- private
+
+    , signCRL
+    , verifyCRL
+
+    , printCRL
+
+    , sortCRL
+
+      -- * Accessors
+    , getVersion
+    , setVersion
+
+    , getLastUpdate
+    , setLastUpdate
+
+    , getNextUpdate
+    , setNextUpdate
+
+    , getIssuerName
+    , setIssuerName
+
+    , getRevokedList
+    , addRevoked
+    )
+    where
+
+import           Control.Monad
+import           Data.Time.Clock
+import           Data.Typeable
+import           Foreign
+import           Foreign.C
+import           OpenSSL.ASN1
+import           OpenSSL.BIO
+import           OpenSSL.EVP.Digest
+import           OpenSSL.EVP.PKey
+import           OpenSSL.EVP.Verify
+import           OpenSSL.Stack
+import           OpenSSL.Utils
+import           OpenSSL.X509.Name
+
+-- |@'CRL'@ is an opaque object that represents Certificate Revocation
+-- List.
+newtype CRL          = CRL (ForeignPtr X509_CRL)
+data    X509_CRL
+data    X509_REVOKED
+
+-- |@'RevokedCertificate'@ represents a revoked certificate in a
+-- list. Each certificates are supposed to be distinguishable by
+-- issuer name and serial number, so it is sufficient to have only
+-- serial number on each entries.
+data RevokedCertificate
+    = RevokedCertificate {
+        revSerialNumber   :: Integer
+      , revRevocationDate :: UTCTime
+      }
+    deriving (Show, Eq, Typeable)
+
+
+foreign import ccall unsafe "X509_CRL_new"
+        _new :: IO (Ptr X509_CRL)
+
+foreign import ccall unsafe "&X509_CRL_free"
+        _free :: FunPtr (Ptr X509_CRL -> IO ())
+
+foreign import ccall unsafe "X509_CRL_sign"
+        _sign :: Ptr X509_CRL -> Ptr EVP_PKEY -> Ptr EVP_MD -> IO Int
+
+foreign import ccall unsafe "X509_CRL_verify"
+        _verify :: Ptr X509_CRL -> Ptr EVP_PKEY -> IO Int
+
+foreign import ccall unsafe "X509_CRL_print"
+        _print :: Ptr BIO_ -> Ptr X509_CRL -> IO Int
+
+foreign import ccall unsafe "HsOpenSSL_X509_CRL_get_version"
+        _get_version :: Ptr X509_CRL -> IO CLong
+
+foreign import ccall unsafe "X509_CRL_set_version"
+        _set_version :: Ptr X509_CRL -> CLong -> IO Int
+
+foreign import ccall unsafe "HsOpenSSL_X509_CRL_get_lastUpdate"
+        _get_lastUpdate :: Ptr X509_CRL -> IO (Ptr ASN1_TIME)
+
+foreign import ccall unsafe "X509_CRL_set_lastUpdate"
+        _set_lastUpdate :: Ptr X509_CRL -> Ptr ASN1_TIME -> IO Int
+
+foreign import ccall unsafe "HsOpenSSL_X509_CRL_get_nextUpdate"
+        _get_nextUpdate :: Ptr X509_CRL -> IO (Ptr ASN1_TIME)
+
+foreign import ccall unsafe "X509_CRL_set_nextUpdate"
+        _set_nextUpdate :: Ptr X509_CRL -> Ptr ASN1_TIME -> IO Int
+
+foreign import ccall unsafe "HsOpenSSL_X509_CRL_get_issuer"
+        _get_issuer_name :: Ptr X509_CRL -> IO (Ptr X509_NAME)
+
+foreign import ccall unsafe "X509_CRL_set_issuer_name"
+        _set_issuer_name :: Ptr X509_CRL -> Ptr X509_NAME -> IO Int
+
+foreign import ccall unsafe "HsOpenSSL_X509_CRL_get_REVOKED"
+        _get_REVOKED :: Ptr X509_CRL -> IO (Ptr STACK)
+
+foreign import ccall unsafe "X509_CRL_add0_revoked"
+        _add0_revoked :: Ptr X509_CRL -> Ptr X509_REVOKED -> IO Int
+
+foreign import ccall unsafe "X509_CRL_sort"
+        _sort :: Ptr X509_CRL -> IO Int
+
+
+
+foreign import ccall unsafe "X509_REVOKED_new"
+        _new_revoked :: IO (Ptr X509_REVOKED)
+
+foreign import ccall unsafe "X509_REVOKED_free"
+        freeRevoked :: Ptr X509_REVOKED -> IO ()
+
+foreign import ccall unsafe "X509_REVOKED_set_serialNumber"
+        _set_serialNumber :: Ptr X509_REVOKED -> Ptr ASN1_INTEGER -> IO Int
+
+foreign import ccall unsafe "X509_REVOKED_set_revocationDate"
+        _set_revocationDate :: Ptr X509_REVOKED -> Ptr ASN1_TIME -> IO Int
+
+-- |@'newCRL'@ creates an empty revocation list. You must set the
+-- following properties to and sign it (see 'signCRL') to actually use
+-- the revocation list. If you have any certificates to be listed, you
+-- must of course add them (see 'addRevoked') before signing the list.
+--
+--   [/Version/] See 'setVersion'.
+--
+--   [/Last Update/] See 'setLastUpdate'.
+--
+--   [/Next Update/] See 'setNextUpdate'.
+--
+--   [/Issuer Name/] See 'setIssuerName'.
+--
+newCRL :: IO CRL
+newCRL = _new >>= wrapCRL
+
+
+wrapCRL :: Ptr X509_CRL -> IO CRL
+wrapCRL crlPtr = newForeignPtr _free crlPtr >>= return . CRL
+
+
+withCRLPtr :: CRL -> (Ptr X509_CRL -> IO a) -> IO a
+withCRLPtr (CRL crl) = withForeignPtr crl
+
+-- |@'signCRL'@ signs a revocation list with an issuer private key.
+signCRL :: CRL          -- ^ The revocation list to be signed.
+        -> PKey         -- ^ The private key to sign with.
+        -> Maybe Digest -- ^ A hashing algorithm to use. If @Nothing@
+                        --   the most suitable algorithm for the key
+                        --   is automatically used.
+        -> IO ()
+signCRL crl pkey mDigest
+    = withCRLPtr crl   $ \ crlPtr  ->
+      withPKeyPtr pkey $ \ pkeyPtr ->
+      do digest <- case mDigest of
+                     Just md -> return md
+                     Nothing -> pkeyDefaultMD pkey
+         withMDPtr digest $ \ digestPtr ->
+             _sign crlPtr pkeyPtr digestPtr
+                  >>= failIf (== 0)
+         return ()
+
+-- |@'verifyCRL'@ verifies a signature of revocation list with an
+-- issuer public key.
+verifyCRL :: CRL -> PKey -> IO VerifyStatus
+verifyCRL crl pkey
+    = withCRLPtr crl   $ \ crlPtr ->
+      withPKeyPtr pkey $ \ pkeyPtr ->
+      _verify crlPtr pkeyPtr
+           >>= interpret
+    where
+      interpret :: Int -> IO VerifyStatus
+      interpret 1 = return VerifySuccess
+      interpret 0 = return VerifyFailure
+      interpret _ = raiseOpenSSLError
+
+-- |@'printCRL'@ translates a revocation list into human-readable
+-- format.
+printCRL :: CRL -> IO String
+printCRL crl
+    = do mem <- newMem
+         withBioPtr mem $ \ memPtr ->
+             withCRLPtr crl $ \ crlPtr ->
+                 _print memPtr crlPtr
+                      >>= failIf (/= 1)
+         bioRead mem
+
+-- |@'getVersion' crl@ returns the version number of revocation list.
+getVersion :: CRL -> IO Int
+getVersion crl
+    = withCRLPtr crl $ \ crlPtr ->
+      liftM fromIntegral $ _get_version crlPtr
+
+-- |@'setVersion' crl ver@ updates the version number of revocation
+-- list.
+setVersion :: CRL -> Int -> IO ()
+setVersion crl ver
+    = withCRLPtr crl $ \ crlPtr ->
+      _set_version crlPtr (fromIntegral ver)
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'getLastUpdate' crl@ returns the time when the revocation list
+-- has last been updated.
+getLastUpdate :: CRL -> IO UTCTime
+getLastUpdate crl
+    = withCRLPtr crl $ \ crlPtr ->
+      _get_lastUpdate crlPtr
+           >>= peekASN1Time
+
+-- |@'setLastUpdate' crl utc@ updates the time when the revocation
+-- list has last been updated.
+setLastUpdate :: CRL -> UTCTime -> IO ()
+setLastUpdate crl utc
+    = withCRLPtr crl $ \ crlPtr ->
+      withASN1Time utc $ \ time ->
+      _set_lastUpdate crlPtr time
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'getNextUpdate' crl@ returns the time when the revocation list
+-- will next be updated.
+getNextUpdate :: CRL -> IO UTCTime
+getNextUpdate crl
+    = withCRLPtr crl $ \ crlPtr ->
+      _get_nextUpdate crlPtr
+           >>= peekASN1Time
+
+-- |@'setNextUpdate' crl utc@ updates the time when the revocation
+-- list will next be updated.
+setNextUpdate :: CRL -> UTCTime -> IO ()
+setNextUpdate crl utc
+    = withCRLPtr crl $ \ crlPtr ->
+      withASN1Time utc $ \ time ->
+      _set_nextUpdate crlPtr time
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'getIssuerName' crl wantLongName@ returns the issuer name of
+-- revocation list. See 'OpenSSL.X509.getIssuerName' of
+-- "OpenSSL.X509".
+getIssuerName :: CRL -> Bool -> IO [(String, String)]
+getIssuerName crl wantLongName
+    = withCRLPtr crl $ \ crlPtr ->
+      do namePtr <- _get_issuer_name crlPtr
+         peekX509Name namePtr wantLongName
+
+-- |@'setIssuerName' crl name@ updates the issuer name of revocation
+-- list. See 'OpenSSL.X509.setIssuerName' of "OpenSSL.X509".
+setIssuerName :: CRL -> [(String, String)] -> IO ()
+setIssuerName crl issuer
+    = withCRLPtr crl  $ \ crlPtr  ->
+      withX509Name issuer $ \ namePtr ->
+      _set_issuer_name crlPtr namePtr
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'getRevokedList' crl@ returns the list of revoked certificates.
+getRevokedList :: CRL -> IO [RevokedCertificate]
+getRevokedList crl
+    = withCRLPtr crl $ \ crlPtr ->
+      do stRevoked <- _get_REVOKED crlPtr
+         mapStack peekRevoked stRevoked
+    where
+      peekRevoked :: Ptr X509_REVOKED -> IO RevokedCertificate
+      peekRevoked rev
+          = do serial <- peekASN1Integer =<< (#peek X509_REVOKED, serialNumber  ) rev
+               date   <- peekASN1Time    =<< (#peek X509_REVOKED, revocationDate) rev
+               return RevokedCertificate {
+                            revSerialNumber   = serial
+                          , revRevocationDate = date
+                          }
+
+newRevoked :: RevokedCertificate -> IO (Ptr X509_REVOKED)
+newRevoked revoked
+    = do revPtr  <- _new_revoked
+
+         seriRet <- withASN1Integer (revSerialNumber revoked) $ \ serialPtr ->
+                    _set_serialNumber revPtr serialPtr
+
+         dateRet <- withASN1Time (revRevocationDate revoked) $ \ datePtr ->
+                    _set_revocationDate revPtr datePtr
+
+         if seriRet /= 1 || dateRet /= 1 then
+             freeRevoked revPtr >> raiseOpenSSLError
+           else
+             return revPtr
+
+-- |@'addRevoked' crl revoked@ add the certificate to the revocation
+-- list.
+addRevoked :: CRL -> RevokedCertificate -> IO ()
+addRevoked crl revoked
+    = withCRLPtr crl $ \ crlPtr ->
+      do revPtr <- newRevoked revoked
+         ret    <- _add0_revoked crlPtr revPtr
+         case ret of
+           1 -> return ()
+           _ -> freeRevoked revPtr >> raiseOpenSSLError
+
+-- |@'sortCRL' crl@ sorts the certificates in the revocation list.
+sortCRL :: CRL -> IO ()
+sortCRL crl
+    = withCRLPtr crl $ \ crlPtr ->
+      _sort crlPtr
+           >>= failIf (/= 1)
+           >>  return ()
diff --git a/OpenSSL/X509/Store.hsc b/OpenSSL/X509/Store.hsc
new file mode 100644
--- /dev/null
+++ b/OpenSSL/X509/Store.hsc
@@ -0,0 +1,71 @@
+{- -*- haskell -*- -}
+
+-- #prune
+
+-- |An interface to X.509 certificate store.
+
+module OpenSSL.X509.Store
+    ( X509Store
+    , X509_STORE -- private
+
+    , newX509Store
+    , withX509StorePtr -- private
+
+    , addCertToStore
+    , addCRLToStore
+    )
+    where
+
+import           Foreign
+import           OpenSSL.X509
+import           OpenSSL.X509.Revocation
+import           OpenSSL.Utils
+
+-- |@'X509Store'@ is an opaque object that represents X.509
+-- certificate store. The certificate store is usually used for chain
+-- verification.
+newtype X509Store  = X509Store (ForeignPtr X509_STORE)
+data    X509_STORE
+
+
+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_add_cert"
+        _add_cert :: Ptr X509_STORE -> Ptr X509_ -> IO Int
+
+foreign import ccall unsafe "X509_STORE_add_crl"
+        _add_crl :: Ptr X509_STORE -> Ptr X509_CRL -> IO Int
+
+-- |@'newX509Store'@ creates an empty X.509 certificate store.
+newX509Store :: IO X509Store
+newX509Store = _new
+               >>= failIfNull
+               >>= newForeignPtr _free
+               >>= return . X509Store
+
+
+withX509StorePtr :: X509Store -> (Ptr X509_STORE -> IO a) -> IO a
+withX509StorePtr (X509Store store)
+    = withForeignPtr store
+
+-- |@'addCertToStore' store cert@ adds a certificate to store.
+addCertToStore :: X509Store -> X509 -> IO ()
+addCertToStore store cert
+    = withX509StorePtr store $ \ storePtr ->
+      withX509Ptr cert       $ \ certPtr  ->
+      _add_cert storePtr certPtr
+           >>= failIf (/= 1)
+           >>  return ()
+
+-- |@'addCRLToStore' store crl@ adds a revocation list to store.
+addCRLToStore :: X509Store -> CRL -> IO ()
+addCRLToStore store crl
+    = withX509StorePtr store $ \ storePtr ->
+      withCRLPtr crl         $ \ crlPtr   ->
+      _add_crl storePtr crlPtr
+           >>= failIf (/= 1)
+           >>  return ()
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,4 @@
+#!/usr/bin/env runghc
+
+import Distribution.Simple
+main = defaultMainWithHooks defaultUserHooks
diff --git a/cbits/HsOpenSSL.c b/cbits/HsOpenSSL.c
new file mode 100644
--- /dev/null
+++ b/cbits/HsOpenSSL.c
@@ -0,0 +1,183 @@
+#include <pthread.h>
+#include "HsOpenSSL.h"
+
+/* OpenSSL ********************************************************************/
+void HsOpenSSL_OpenSSL_add_all_algorithms() {
+    OpenSSL_add_all_algorithms();
+}
+
+void HsOpenSSL_OPENSSL_free(void* ptr) {
+    OPENSSL_free(ptr);
+}
+
+/* BIO ************************************************************************/
+void HsOpenSSL_BIO_set_flags(BIO* bio, int flags) {
+    BIO_set_flags(bio, flags);
+}
+
+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);
+}
+
+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;
+}
+
+/* EVP ************************************************************************/
+int HsOpenSSL_EVP_MD_size(EVP_MD* md) {
+    return EVP_MD_size(md);
+}
+
+int HsOpenSSL_EVP_CIPHER_CTX_block_size(EVP_CIPHER_CTX* ctx) {
+    return EVP_CIPHER_CTX_block_size(ctx);
+}
+
+int HsOpenSSL_EVP_CIPHER_iv_length(EVP_CIPHER* cipher) {
+    return EVP_CIPHER_iv_length(cipher);
+}
+
+/* X509 ***********************************************************************/
+long HsOpenSSL_X509_get_version(X509* x509) {
+    return X509_get_version(x509);
+}
+
+ASN1_TIME* HsOpenSSL_X509_get_notBefore(X509* x509) {
+    return X509_get_notBefore(x509);
+}
+
+ASN1_TIME* HsOpenSSL_X509_get_notAfter(X509* x509) {
+    return X509_get_notAfter(x509);
+}
+
+long HsOpenSSL_X509_REQ_get_version(X509_REQ* req) {
+    return X509_REQ_get_version(req);
+}
+
+X509_NAME* HsOpenSSL_X509_REQ_get_subject_name(X509_REQ* req) {
+    return X509_REQ_get_subject_name(req);
+}
+
+long HsOpenSSL_X509_CRL_get_version(X509_CRL* crl) {
+    return X509_CRL_get_version(crl);
+}
+
+ASN1_TIME* HsOpenSSL_X509_CRL_get_lastUpdate(X509_CRL* crl) {
+    return X509_CRL_get_lastUpdate(crl);
+}
+
+ASN1_TIME* HsOpenSSL_X509_CRL_get_nextUpdate(X509_CRL* crl) {
+    return X509_CRL_get_nextUpdate(crl);
+}
+
+X509_NAME* HsOpenSSL_X509_CRL_get_issuer(X509_CRL* crl) {
+    return X509_CRL_get_issuer(crl);
+}
+
+STACK_OF(X509_REVOKED)* HsOpenSSL_X509_CRL_get_REVOKED(X509_CRL* crl) {
+    return X509_CRL_get_REVOKED(crl);
+}
+
+
+/* PKCS#7 *********************************************************************/
+long HsOpenSSL_PKCS7_is_detached(PKCS7* pkcs7) {
+    return PKCS7_is_detached(pkcs7);
+}
+
+
+/* ASN1 ***********************************************************************/
+ASN1_INTEGER* HsOpenSSL_M_ASN1_INTEGER_new() {
+    return M_ASN1_INTEGER_new();
+}
+
+void HsOpenSSL_M_ASN1_INTEGER_free(ASN1_INTEGER* intPtr) {
+    M_ASN1_INTEGER_free(intPtr);
+}
+
+ASN1_INTEGER* HsOpenSSL_M_ASN1_TIME_new() {
+    return M_ASN1_TIME_new();
+}
+
+void HsOpenSSL_M_ASN1_TIME_free(ASN1_TIME* timePtr) {
+    M_ASN1_TIME_free(timePtr);
+}
+
+/* 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);
+}
+
diff --git a/cbits/HsOpenSSL.h b/cbits/HsOpenSSL.h
new file mode 100644
--- /dev/null
+++ b/cbits/HsOpenSSL.h
@@ -0,0 +1,63 @@
+#ifndef HSOPENSSL_H_INCLUDED
+#define HSOPENSSL_H_INCLUDED
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/opensslconf.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs7.h>
+#include <openssl/ssl.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/x509v3.h>
+
+/* OpenSSL ********************************************************************/
+void HsOpenSSL_OpenSSL_add_all_algorithms();
+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);
+
+/* X509 ***********************************************************************/
+long HsOpenSSL_X509_get_version(X509* x509);
+ASN1_TIME* HsOpenSSL_X509_get_notBefore(X509* x509);
+ASN1_TIME* HsOpenSSL_X509_get_notAfter(X509* x509);
+
+long HsOpenSSL_X509_REQ_get_version(X509_REQ* req);
+X509_NAME* HsOpenSSL_X509_REQ_get_subject_name(X509_REQ* req);
+
+long HsOpenSSL_X509_CRL_get_version(X509_CRL* crl);
+ASN1_TIME* HsOpenSSL_X509_CRL_get_lastUpdate(X509_CRL* crl);
+ASN1_TIME* HsOpenSSL_X509_CRL_get_nextUpdate(X509_CRL* crl);
+X509_NAME* HsOpenSSL_X509_CRL_get_issuer(X509_CRL* crl);
+STACK_OF(X509_REVOKED)* HsOpenSSL_X509_CRL_get_REVOKED(X509_CRL* crl);
+
+/* PKCS#7 *********************************************************************/
+long HsOpenSSL_PKCS7_is_detached(PKCS7* pkcs7);
+
+/* ASN1 ***********************************************************************/
+ASN1_INTEGER* HsOpenSSL_M_ASN1_INTEGER_new();
+void HsOpenSSL_M_ASN1_INTEGER_free(ASN1_INTEGER* intPtr);
+ASN1_INTEGER* HsOpenSSL_M_ASN1_TIME_new();
+void HsOpenSSL_M_ASN1_TIME_free(ASN1_TIME* timePtr);
+
+/* Threads ********************************************************************/
+void HsOpenSSL_setupMutex();
+
+#endif
diff --git a/configure b/configure
new file mode 100644
--- /dev/null
+++ b/configure
@@ -0,0 +1,2794 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.60.
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+if test "x$CONFIG_SHELL" = x; then
+  if (eval ":") 2>/dev/null; then
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+
+  if test $as_have_required = yes && 	 (eval ":
+(as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=\$LINENO
+  as_lineno_2=\$LINENO
+  test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+  test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+") 2> /dev/null; then
+  :
+else
+  as_candidate_shells=
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /usr/bin/posix$PATH_SEPARATOR/bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  case $as_dir in
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
+	   done;;
+       esac
+done
+IFS=$as_save_IFS
+
+
+      for as_shell in $as_candidate_shells $SHELL; do
+	 # Try only shells that exist, to save several forks.
+	 if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		{ ("$as_shell") 2> /dev/null <<\_ASEOF
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+:
+_ASEOF
+}; then
+  CONFIG_SHELL=$as_shell
+	       as_have_required=yes
+	       if { "$as_shell" 2> /dev/null <<\_ASEOF
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+:
+(as_func_return () {
+  (exit $1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = "$1" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test $exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+
+_ASEOF
+}; then
+  break
+fi
+
+fi
+
+      done
+
+      if test "x$CONFIG_SHELL" != x; then
+  for as_var in BASH_ENV ENV
+        do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+        done
+        export CONFIG_SHELL
+        exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+
+    if test $as_have_required = no; then
+  echo This script requires a shell more modern than all the
+      echo shells that I found on your system.  Please install a
+      echo modern shell, or manually run the script under such a
+      echo shell if you do have one.
+      { (exit 1); exit 1; }
+fi
+
+
+fi
+
+fi
+
+
+
+(eval "as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0") || {
+  echo No shell found that supports shell functions.
+  echo Please tell autoconf@gnu.org about your system,
+  echo including any error possibly output before this
+  echo message
+}
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s='ln -s'
+  # ... but there are two gotchas:
+  # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+  # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+  # In both cases, we have to default to `cp -p'.
+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+    as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+# Find out whether ``test -x'' works.  Don't use a zero-byte file, as
+# systems may use methods other than mode bits to determine executability.
+cat >conf$$.file <<_ASEOF
+#! /bin/sh
+exit 0
+_ASEOF
+chmod +x conf$$.file
+if test -x conf$$.file >/dev/null 2>&1; then
+  as_executable_p="test -x"
+else
+  as_executable_p=:
+fi
+rm -f conf$$.file
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+exec 7<&0 </dev/null 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="HsOpenSSL"
+ac_unique_file="OpenSSL/SSL.hsc"
+ac_subst_vars='SHELL
+PATH_SEPARATOR
+PACKAGE_NAME
+PACKAGE_TARNAME
+PACKAGE_VERSION
+PACKAGE_STRING
+PACKAGE_BUGREPORT
+exec_prefix
+prefix
+program_transform_name
+bindir
+sbindir
+libexecdir
+datarootdir
+datadir
+sysconfdir
+sharedstatedir
+localstatedir
+includedir
+oldincludedir
+docdir
+infodir
+htmldir
+dvidir
+pdfdir
+psdir
+libdir
+localedir
+mandir
+DEFS
+ECHO_C
+ECHO_N
+ECHO_T
+LIBS
+build_alias
+host_alias
+target_alias
+PKG_CONFIG
+OPENSSL_CFLAGS
+OPENSSL_LIBS
+LIBOBJS
+LTLIBOBJS'
+ac_subst_files=''
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+PKG_CONFIG
+OPENSSL_CFLAGS
+OPENSSL_LIBS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=*)	ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *)	ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+    eval enable_$ac_feature=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+    eval enable_$ac_feature=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval with_$ac_package=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/-/_/g'`
+    eval with_$ac_package=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; }
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  { echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute directory names.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; }
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  { echo "$as_me: error: Working directory cannot be determined" >&2
+   { (exit 1); exit 1; }; }
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  { echo "$as_me: error: pwd does not report name of working directory" >&2
+   { (exit 1); exit 1; }; }
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$0" ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$0" : 'X\(//\)[^/]' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$0" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2
+   { (exit 1); exit 1; }; }
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+			  [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+			  [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR           user executables [EPREFIX/bin]
+  --sbindir=DIR          system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR       program executables [EPREFIX/libexec]
+  --sysconfdir=DIR       read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR   modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR    modifiable single-machine data [PREFIX/var]
+  --libdir=DIR           object code libraries [EPREFIX/lib]
+  --includedir=DIR       C header files [PREFIX/include]
+  --oldincludedir=DIR    C header files for non-gcc [/usr/include]
+  --datarootdir=DIR      read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR          read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR          info documentation [DATAROOTDIR/info]
+  --localedir=DIR        locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR           man documentation [DATAROOTDIR/man]
+  --docdir=DIR           documentation root [DATAROOTDIR/doc/PACKAGE]
+  --htmldir=DIR          html documentation [DOCDIR]
+  --dvidir=DIR           dvi documentation [DOCDIR]
+  --pdfdir=DIR           pdf documentation [DOCDIR]
+  --psdir=DIR            ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Some influential environment variables:
+  PKG_CONFIG  path to pkg-config utility
+  OPENSSL_CFLAGS
+              C compiler flags for OPENSSL, overriding pkg-config
+  OPENSSL_LIBS
+              linker flags for OPENSSL, overriding pkg-config
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" || continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.60
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.60.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  echo "PATH: $as_dir"
+done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    2)
+      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      ac_configure_args="$ac_configure_args '$ac_arg'"
+      ;;
+    esac
+  done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      echo "$as_me: caught signal $ac_signal"
+    echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -n "$CONFIG_SITE"; then
+  set x "$CONFIG_SITE"
+elif test "x$prefix" != xNONE; then
+  set x "$prefix/share/config.site" "$prefix/etc/config.site"
+else
+  set x "$ac_default_prefix/share/config.site" \
+	"$ac_default_prefix/etc/config.site"
+fi
+shift
+for ac_site_file
+do
+  if test -r "$ac_site_file"; then
+    { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special
+  # files actually), so we avoid doing that.
+  if test -f "$cache_file"; then
+    { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	{ echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	{ echo "$as_me:$LINENO:   former value:  $ac_old_val" >&5
+echo "$as_me:   former value:  $ac_old_val" >&2;}
+	{ echo "$as_me:$LINENO:   current value: $ac_new_val" >&5
+echo "$as_me:   current value: $ac_new_val" >&2;}
+	ac_cache_corrupted=:
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PKG_CONFIG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5
+echo "${ECHO_T}$PKG_CONFIG" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { echo "$as_me:$LINENO: result: $ac_pt_PKG_CONFIG" >&5
+echo "${ECHO_T}$ac_pt_PKG_CONFIG" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=0.9.0
+	{ echo "$as_me:$LINENO: checking pkg-config is at least version $_pkg_min_version" >&5
+echo $ECHO_N "checking pkg-config is at least version $_pkg_min_version... $ECHO_C" >&6; }
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+	else
+		{ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+		PKG_CONFIG=""
+	fi
+
+fi
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for OPENSSL" >&5
+echo $ECHO_N "checking for OPENSSL... $ECHO_C" >&6; }
+
+if test -n "$PKG_CONFIG"; then
+    if test -n "$OPENSSL_CFLAGS"; then
+        pkg_cv_OPENSSL_CFLAGS="$OPENSSL_CFLAGS"
+    else
+        if test -n "$PKG_CONFIG" && \
+    { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"openssl >= 0.9.7l\"") >&5
+  ($PKG_CONFIG --exists --print-errors "openssl >= 0.9.7l") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  pkg_cv_OPENSSL_CFLAGS=`$PKG_CONFIG --cflags "openssl >= 0.9.7l" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+    fi
+else
+	pkg_failed=untried
+fi
+if test -n "$PKG_CONFIG"; then
+    if test -n "$OPENSSL_LIBS"; then
+        pkg_cv_OPENSSL_LIBS="$OPENSSL_LIBS"
+    else
+        if test -n "$PKG_CONFIG" && \
+    { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"openssl >= 0.9.7l\"") >&5
+  ($PKG_CONFIG --exists --print-errors "openssl >= 0.9.7l") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  pkg_cv_OPENSSL_LIBS=`$PKG_CONFIG --libs "openssl >= 0.9.7l" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+    fi
+else
+	pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        OPENSSL_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "openssl >= 0.9.7l"`
+        else
+	        OPENSSL_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "openssl >= 0.9.7l"`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$OPENSSL_PKG_ERRORS" >&5
+
+	{ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                { { echo "$as_me:$LINENO: error: openssl >= 0.9.7l is required to build this package." >&5
+echo "$as_me: error: openssl >= 0.9.7l is required to build this package." >&2;}
+   { (exit 1); exit 1; }; }
+elif test $pkg_failed = untried; then
+	{ { echo "$as_me:$LINENO: error: openssl >= 0.9.7l is required to build this package." >&5
+echo "$as_me: error: openssl >= 0.9.7l is required to build this package." >&2;}
+   { (exit 1); exit 1; }; }
+else
+	OPENSSL_CFLAGS=$pkg_cv_OPENSSL_CFLAGS
+	OPENSSL_LIBS=$pkg_cv_OPENSSL_LIBS
+        { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+	:
+fi
+
+ac_config_files="$ac_config_files HsOpenSSL.buildinfo"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes (double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \).
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    test "x$cache_file" != "x/dev/null" &&
+      { echo "$as_me:$LINENO: updating cache $cache_file" >&5
+echo "$as_me: updating cache $cache_file" >&6;}
+    cat confcache >$cache_file
+  else
+    { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section.  Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+t clear
+:clear
+s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 (][^	 (]*([^)]*)\)[	 ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 ][^	 ]*\)[	 ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[	 `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+	g
+	s/^\n//
+	s/\n/ /g
+	p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s='ln -s'
+  # ... but there are two gotchas:
+  # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+  # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+  # In both cases, we have to default to `cp -p'.
+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+    as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+# Find out whether ``test -x'' works.  Don't use a zero-byte file, as
+# systems may use methods other than mode bits to determine executability.
+cat >conf$$.file <<_ASEOF
+#! /bin/sh
+exit 0
+_ASEOF
+chmod +x conf$$.file
+if test -x conf$$.file >/dev/null 2>&1; then
+  as_executable_p="test -x"
+else
+  as_executable_p=:
+fi
+rm -f conf$$.file
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+
+# Save the log message, to keep $[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.60.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number, then exit
+  -q, --quiet      do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+  --file=FILE[:TEMPLATE]
+		   instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to <bug-autoconf@gnu.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.60,
+  with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2006 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value.  By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    echo "$ac_cs_version"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+    ac_need_defaults=false;;
+  --he | --h |  --help | --hel | -h )
+    echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) { echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; } ;;
+
+  *) ac_config_targets="$ac_config_targets $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+  echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+  CONFIG_SHELL=$SHELL
+  export CONFIG_SHELL
+  exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "HsOpenSSL.buildinfo") CONFIG_FILES="$CONFIG_FILES HsOpenSSL.buildinfo" ;;
+
+  *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp=
+  trap 'exit_status=$?
+  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+  trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} ||
+{
+   echo "$me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+#
+# Set up the sed scripts for CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "$CONFIG_FILES"; then
+
+_ACEOF
+
+
+
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  cat >conf$$subs.sed <<_ACEOF
+SHELL!$SHELL$ac_delim
+PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim
+PACKAGE_NAME!$PACKAGE_NAME$ac_delim
+PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim
+PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim
+PACKAGE_STRING!$PACKAGE_STRING$ac_delim
+PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim
+exec_prefix!$exec_prefix$ac_delim
+prefix!$prefix$ac_delim
+program_transform_name!$program_transform_name$ac_delim
+bindir!$bindir$ac_delim
+sbindir!$sbindir$ac_delim
+libexecdir!$libexecdir$ac_delim
+datarootdir!$datarootdir$ac_delim
+datadir!$datadir$ac_delim
+sysconfdir!$sysconfdir$ac_delim
+sharedstatedir!$sharedstatedir$ac_delim
+localstatedir!$localstatedir$ac_delim
+includedir!$includedir$ac_delim
+oldincludedir!$oldincludedir$ac_delim
+docdir!$docdir$ac_delim
+infodir!$infodir$ac_delim
+htmldir!$htmldir$ac_delim
+dvidir!$dvidir$ac_delim
+pdfdir!$pdfdir$ac_delim
+psdir!$psdir$ac_delim
+libdir!$libdir$ac_delim
+localedir!$localedir$ac_delim
+mandir!$mandir$ac_delim
+DEFS!$DEFS$ac_delim
+ECHO_C!$ECHO_C$ac_delim
+ECHO_N!$ECHO_N$ac_delim
+ECHO_T!$ECHO_T$ac_delim
+LIBS!$LIBS$ac_delim
+build_alias!$build_alias$ac_delim
+host_alias!$host_alias$ac_delim
+target_alias!$target_alias$ac_delim
+PKG_CONFIG!$PKG_CONFIG$ac_delim
+OPENSSL_CFLAGS!$OPENSSL_CFLAGS$ac_delim
+OPENSSL_LIBS!$OPENSSL_LIBS$ac_delim
+LIBOBJS!$LIBOBJS$ac_delim
+LTLIBOBJS!$LTLIBOBJS$ac_delim
+_ACEOF
+
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 42; then
+    break
+  elif $ac_last_try; then
+    { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`
+if test -n "$ac_eof"; then
+  ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`
+  ac_eof=`expr $ac_eof + 1`
+fi
+
+cat >>$CONFIG_STATUS <<_ACEOF
+cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end
+_ACEOF
+sed '
+s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
+s/^/s,@/; s/!/@,|#_!!_#|/
+:n
+t n
+s/'"$ac_delim"'$/,g/; t
+s/$/\\/; p
+N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n
+' >>$CONFIG_STATUS <conf$$subs.sed
+rm -f conf$$subs.sed
+cat >>$CONFIG_STATUS <<_ACEOF
+:end
+s/|#_!!_#|//g
+CEOF$ac_eof
+_ACEOF
+
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[	 ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+fi # test -n "$CONFIG_FILES"
+
+
+for ac_tag in  :F $CONFIG_FILES
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5
+echo "$as_me: error: Invalid tag $ac_tag." >&2;}
+   { (exit 1); exit 1; }; };;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+   { (exit 1); exit 1; }; };;
+      esac
+      ac_file_inputs="$ac_file_inputs $ac_f"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input="Generated from "`IFS=:
+	  echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure."
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+    fi
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$tmp/stdin";;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  { as_dir="$ac_dir"
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+echo "$as_me: error: cannot create directory $as_dir" >&2;}
+   { (exit 1); exit 1; }; }; }
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+
+case `sed -n '/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p
+' $ac_file_inputs` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+    s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF
+  sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s&@configure_input@&$configure_input&;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+  { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&5
+echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&2;}
+
+  rm -f "$tmp/stdin"
+  case $ac_file in
+  -) cat "$tmp/out"; rm -f "$tmp/out";;
+  *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;;
+  esac
+ ;;
+
+
+
+  esac
+
+done # for ac_tag
+
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || { (exit 1); exit 1; }
+fi
diff --git a/configure.ac b/configure.ac
new file mode 100644
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,12 @@
+AC_INIT([HsOpenSSL], [], [phonohawk@ps.sakura.ne.jp])
+
+AC_CONFIG_SRCDIR([OpenSSL/SSL.hsc])
+
+PKG_CHECK_MODULES(
+        [OPENSSL], [openssl >= 0.9.7l], [],
+        [AC_MSG_ERROR([openssl >= 0.9.7l is required to build this package.])])
+
+AC_CONFIG_FILES([
+        HsOpenSSL.buildinfo
+])
+AC_OUTPUT
diff --git a/examples/GenRSAKey.hs b/examples/GenRSAKey.hs
new file mode 100644
--- /dev/null
+++ b/examples/GenRSAKey.hs
@@ -0,0 +1,48 @@
+import Control.Monad hiding (join)
+import OpenSSL
+import OpenSSL.BN
+import OpenSSL.BIO
+import OpenSSL.EVP.PKey
+import OpenSSL.PEM
+import OpenSSL.RSA
+import System.IO
+import Text.Printf
+
+main = withOpenSSL $
+       do let keyBits = 512
+              keyE    = 65537
+
+          printf "Generating RSA key-pair, nbits = %d, e = %d:\n" keyBits keyE
+          
+          rsa  <- generateKey keyBits keyE $ Just $ \ phase _ ->
+                  do hPutChar stdout $ case phase of
+                                         0 -> '.'
+                                         1 -> '+'
+                                         2 -> '*'
+                                         3 -> '\n'
+                                         n -> head $ show n
+                     hFlush stdout
+
+          printf "Done.\n"
+          
+          n    <- rsaN rsa
+          e    <- rsaE rsa
+          d    <- rsaD rsa
+          p    <- rsaP rsa
+          q    <- rsaQ rsa
+          dmp1 <- rsaDMP1 rsa
+          dmq1 <- rsaDMQ1 rsa
+          iqmp <- rsaIQMP rsa
+
+          printf "n (public modulus) = %s\n" (show n)
+          printf "e (public exponent) = %s\n" (show e)
+          printf "d (private exponent) = %s\n" (show d)
+          printf "p (secret prime factor) = %s\n" (show p)
+          printf "q (secret prime factor) = %s\n" (show q)
+          printf "dmp1 (d mod (p-1)) = %s\n" (show dmp1)
+          printf "dmq1 (d mod (q-1)) = %s\n" (show dmq1)
+          printf "iqmp (q^-1 mod p) = %s\n" (show iqmp)
+
+          let pkey = newPKeyRSA rsa
+          writePKCS8PrivateKey pkey Nothing >>= putStr
+          -- writePublicKey pkey >>= putStr
diff --git a/examples/HelloWorld.hs b/examples/HelloWorld.hs
new file mode 100644
--- /dev/null
+++ b/examples/HelloWorld.hs
@@ -0,0 +1,43 @@
+import Control.Monad
+import Data.List
+import Data.Maybe
+import OpenSSL
+import OpenSSL.BN
+import OpenSSL.EVP.Cipher
+import OpenSSL.EVP.Open
+import OpenSSL.EVP.PKey
+import OpenSSL.EVP.Seal
+import OpenSSL.PEM
+import OpenSSL.RSA
+import Text.Printf
+
+
+main = withOpenSSL $
+       do putStrLn "cipher: DES-CBC"
+          des <- liftM fromJust $ getCipherByName "DES-CBC"
+
+          putStrLn "generating RSA keypair..."
+          pkey <- liftM newPKeyRSA $ generateKey 512 65537 Nothing
+
+          let plainText = "Hello, world!"
+          putStrLn ("plain text to encrypt: " ++ plainText)
+
+          putStrLn ""
+
+          putStrLn "encrypting..."
+          (encrypted, [encKey], iv) <- seal des [pkey] plainText
+          
+          putStrLn ("encrypted symmetric key: " ++ binToHex encKey)
+          putStrLn ("IV: " ++ binToHex iv)
+          putStrLn ("encrypted message: " ++ binToHex encrypted)
+
+          putStrLn ""
+
+          putStrLn "decrypting..."
+          let decrypted = open des encKey iv pkey encrypted
+
+          putStrLn ("decrypted message: " ++ decrypted)
+
+
+binToHex :: String -> String
+binToHex bin = concat $ intersperse ":" $ map (printf "%02x" . fromEnum) bin
diff --git a/examples/Makefile b/examples/Makefile
new file mode 100644
--- /dev/null
+++ b/examples/Makefile
@@ -0,0 +1,15 @@
+GHCFLAGS = -O2 -fglasgow-exts
+
+build:
+	ghc $(GHCFLAGS) --make GenRSAKey
+	ghc $(GHCFLAGS) --make HelloWorld
+	ghc $(GHCFLAGS) --make PKCS7
+
+run: build
+	./PKCS7
+#	./HelloWorld
+
+clean:
+	rm -f HelloWorld GenRSAKey PKCS7 *.hi *.o
+
+.PHONY: build run clean
diff --git a/examples/PKCS7.hs b/examples/PKCS7.hs
new file mode 100644
--- /dev/null
+++ b/examples/PKCS7.hs
@@ -0,0 +1,38 @@
+import Control.Monad
+import Data.Time.Clock
+import Data.Time.Calendar
+import Data.Maybe
+import OpenSSL
+import OpenSSL.PKCS7
+import OpenSSL.EVP.Cipher
+import OpenSSL.EVP.PKey
+import OpenSSL.PEM
+import OpenSSL.RSA
+import OpenSSL.X509
+import OpenSSL.X509.Store
+
+main = withOpenSSL $
+       do pkey <- liftM newPKeyRSA $ generateKey 512 65537 Nothing
+          cert <- genCert pkey
+
+          pkcs7 <- pkcs7Sign cert pkey [] "Hello, world!" [Pkcs7NoCerts]
+
+          store <- newX509Store
+          addCertToStore store cert
+
+          pkcs7Verify pkcs7 [cert] store Nothing [] >>= print
+          return ()
+
+
+genCert :: PKey -> IO X509
+genCert pkey
+    = do x509 <- newX509
+         setVersion x509 2
+         setSerialNumber x509 1
+         setIssuerName  x509 [("C", "JP")]
+         setSubjectName x509 [("C", "JP")]
+         setNotBefore x509 =<< liftM (addUTCTime (-1)) getCurrentTime
+         setNotAfter  x509 =<< liftM (addUTCTime (365 * 24 * 60 * 60)) getCurrentTime
+         setPublicKey x509 pkey
+         signX509 x509 pkey Nothing
+         return x509
