HsOpenSSL 0.10.1.4 → 0.10.2
raw patch · 13 files changed
+557/−514 lines, 13 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ OpenSSL.Session: readPtr :: SSL -> Ptr a -> Int -> IO Int
+ OpenSSL.Session: tryReadPtr :: SSL -> Ptr a -> Int -> IO (SSLResult Int)
+ OpenSSL.Session: tryWritePtr :: SSL -> Ptr a -> Int -> IO (SSLResult ())
+ OpenSSL.Session: writePtr :: SSL -> Ptr a -> Int -> IO ()
Files
- HsOpenSSL.cabal +1/−1
- NEWS +16/−0
- OpenSSL/BN.hsc +9/−9
- OpenSSL/DH.hs +98/−0
- OpenSSL/DH.hsc +0/−97
- OpenSSL/DSA.hsc +0/−3
- OpenSSL/EVP/Internal.hsc +2/−3
- OpenSSL/RSA.hsc +0/−3
- OpenSSL/Session.hsc +33/−7
- OpenSSL/Utils.hs +6/−10
- OpenSSL/X509.hs +382/−0
- OpenSSL/X509.hsc +0/−381
- cbits/HsOpenSSL.h +10/−0
HsOpenSSL.cabal view
@@ -15,7 +15,7 @@ encourages you to use and improve the tls package instead as long as possible. .-Version: 0.10.1.4+Version: 0.10.2 License: PublicDomain License-File: COPYING Author: Adam Langley, Mikhail Vorozhtsov, PHO, Taru Karttunen
NEWS view
@@ -1,5 +1,21 @@ -*- coding: utf-8 -*- +Changes from 0.10.1.4 to 0.10.2+-------------------------------+* Merged #9 "Add raw pointer read/write operations" by Iavor+ S. Diatchki:++ - OpenSSL.Session.readPtr+ - OpenSSL.Session.tryReadPtr+ - OpenSSL.Session.writePtr+ - OpenSSL.Session.tryWritePtr++* Fixed #8 "HsOpenSSL 0.10.1.4 won't build" reported by vcxp:++ - Workaround for broken versions of Cabal, including one that comes+ with ghc-7.0.4.++ Changes from 0.10.1.3 to 0.10.1.4 --------------------------------- * Fixed #7 "Haskell Platform 2011.4 Support", reported by stepcut:
OpenSSL/BN.hsc view
@@ -50,20 +50,20 @@ import OpenSSL.Utils import System.IO.Unsafe -#ifndef __GLASGOW_HASKELL__-import Control.Monad-import Foreign.C-#else+#ifdef __GLASGOW_HASKELL__ import Foreign.C.Types import GHC.Base-#if __GLASGOW_HASKELL__ < 612+# if MIN_VERSION_integer_gmp(0,2,0)+import GHC.Integer.GMP.Internals+# else import GHC.Num import GHC.Prim import GHC.Integer.Internals import GHC.IOBase (IO(..))+# endif #else-import GHC.Integer.GMP.Internals-#endif+import Control.Monad+import Foreign.C #endif -- |'BigNum' is an opaque object representing a big number.@@ -282,11 +282,11 @@ BS.useAsCStringLen mpi (\(ptr, len) -> do _mpi2bn ptr (fromIntegral len) nullPtr) >>= return . wrapBN --- | Convert an Integer to an MPI. SEe bnToMPI for the format+-- | Convert an Integer to an MPI. See bnToMPI for the format integerToMPI :: Integer -> IO BS.ByteString integerToMPI v = bracket (integerToBN v) (_free . unwrapBN) bnToMPI --- | Convert an MPI to an Integer. SEe bnToMPI for the format+-- | Convert an MPI to an Integer. See bnToMPI for the format mpiToInteger :: BS.ByteString -> IO Integer mpiToInteger mpi = do bn <- mpiToBN mpi
+ OpenSSL/DH.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE CPP #-}+-- | Diffie-Hellman key exchange+module OpenSSL.DH+ ( DHP+ , DH+ , DHGen(..)+ , genDHParams+ , getDHLength+ , checkDHParams+ , genDH+ , getDHParams+ , getDHPublicKey+ , computeDHKey+ )+ where+import Data.Word (Word8)+import Data.ByteString (ByteString)+import qualified Data.ByteString.Internal as BS+import Control.Applicative ((<$>))+import Foreign.Ptr (Ptr, nullPtr)+#if MIN_VERSION_base(4,5,0)+import Foreign.C.Types (CInt(..))+#else+import Foreign.C.Types (CInt)+#endif+import Foreign.Marshal.Alloc (alloca)+import OpenSSL.BN+import OpenSSL.DH.Internal+import OpenSSL.Utils++data DHGen = DHGen2+ | DHGen5+ deriving (Eq, Ord, Show)++-- | @'genDHParams' gen n@ generates @n@-bit long DH parameters.+genDHParams :: DHGen -> Int -> IO DHP+genDHParams gen len = do+ _DH_generate_parameters (fromIntegral len) gen' nullPtr nullPtr+ >>= failIfNull+ >>= wrapDHPPtr+ where gen' = case gen of+ DHGen2 -> 2+ DHGen5 -> 5++-- | Get DH parameters length (in bits).+getDHLength :: DHP -> IO Int+getDHLength dh = fromIntegral <$> withDHPPtr dh _DH_length++-- | Check that DH parameters are coherent.+checkDHParams :: DHP -> IO Bool+checkDHParams dh = alloca $ \pErr ->+ withDHPPtr dh $ \dhPtr -> _DH_check dhPtr pErr++-- | The first step of a key exchange. Public and private keys are generated.+genDH :: DHP -> IO DH+genDH dh = do+ dh' <- withDHPPtr dh _DH_dup >>= failIfNull >>= wrapDHPPtr+ withDHPPtr dh' _DH_generate_key >>= failIf_ (/= 1)+ return $ asDH dh'++-- | Get parameters of a key exchange.+getDHParams :: DH -> DHP+getDHParams = asDHP++-- | Get the public key.+getDHPublicKey :: DH -> IO Integer+getDHPublicKey dh =+ withDHPtr dh $ \dhPtr -> do+ pKey <- _DH_get_pub_key dhPtr+ bnToInteger (wrapBN pKey)++-- | Compute the shared key using the other party's public key.+computeDHKey :: DH -> Integer -> IO ByteString+computeDHKey dh pubKey =+ withDHPtr dh $ \dhPtr ->+ withBN pubKey $ \bn -> do+ size <- fromIntegral <$> _DH_size dhPtr+ BS.createAndTrim size $ \bsPtr ->+ fromIntegral <$> _DH_compute_key bsPtr (unwrapBN bn) dhPtr+ >>= failIf (< 0)++foreign import ccall "DH_generate_parameters"+ _DH_generate_parameters :: CInt -> CInt -> Ptr () -> Ptr () -> IO (Ptr DH_)+foreign import ccall "DH_generate_key"+ _DH_generate_key :: Ptr DH_ -> IO CInt+foreign import ccall "DH_compute_key"+ _DH_compute_key :: Ptr Word8 -> Ptr BIGNUM -> Ptr DH_ -> IO CInt+foreign import ccall "DH_check"+ _DH_check :: Ptr DH_ -> Ptr CInt -> IO Bool+foreign import ccall unsafe "DH_size"+ _DH_size :: Ptr DH_ -> IO CInt+foreign import ccall unsafe "HsOpenSSL_DHparams_dup"+ _DH_dup :: Ptr DH_ -> IO (Ptr DH_)+foreign import ccall unsafe "HsOpenSSL_DH_get_pub_key"+ _DH_get_pub_key :: Ptr DH_ -> IO (Ptr BIGNUM)+foreign import ccall unsafe "HsOpenSSL_DH_length"+ _DH_length :: Ptr DH_ -> IO CInt+
− OpenSSL/DH.hsc
@@ -1,97 +0,0 @@--- | Diffie-Hellman key exchange-module OpenSSL.DH- ( DHP- , DH- , DHGen(..)- , genDHParams- , getDHLength- , checkDHParams- , genDH- , getDHParams- , getDHPublicKey- , computeDHKey- )- where-import Data.Word (Word8)-import Data.ByteString (ByteString)-import qualified Data.ByteString.Internal as BS-import Control.Applicative ((<$>))-import Foreign.Ptr (Ptr, nullPtr)-#if __GLASGOW_HASKELL__ >= 703-import Foreign.C.Types (CInt(..))-#else-import Foreign.C.Types (CInt)-#endif-import Foreign.Marshal.Alloc (alloca)-import OpenSSL.BN-import OpenSSL.DH.Internal-import OpenSSL.Utils--data DHGen = DHGen2- | DHGen5- deriving (Eq, Ord, Show)---- | @'genDHParams' gen n@ generates @n@-bit long DH parameters.-genDHParams :: DHGen -> Int -> IO DHP-genDHParams gen len = do- _DH_generate_parameters (fromIntegral len) gen' nullPtr nullPtr- >>= failIfNull- >>= wrapDHPPtr- where gen' = case gen of- DHGen2 -> 2- DHGen5 -> 5---- | Get DH parameters length (in bits).-getDHLength :: DHP -> IO Int-getDHLength dh = fromIntegral <$> withDHPPtr dh _DH_length---- | Check that DH parameters are coherent.-checkDHParams :: DHP -> IO Bool-checkDHParams dh = alloca $ \pErr ->- withDHPPtr dh $ \dhPtr -> _DH_check dhPtr pErr---- | The first step of a key exchange. Public and private keys are generated.-genDH :: DHP -> IO DH-genDH dh = do- dh' <- withDHPPtr dh _DH_dup >>= failIfNull >>= wrapDHPPtr- withDHPPtr dh' _DH_generate_key >>= failIf_ (/= 1)- return $ asDH dh'---- | Get parameters of a key exchange.-getDHParams :: DH -> DHP-getDHParams = asDHP---- | Get the public key.-getDHPublicKey :: DH -> IO Integer-getDHPublicKey dh =- withDHPtr dh $ \dhPtr -> do- pKey <- _DH_get_pub_key dhPtr- bnToInteger (wrapBN pKey)---- | Compute the shared key using the other party's public key.-computeDHKey :: DH -> Integer -> IO ByteString-computeDHKey dh pubKey =- withDHPtr dh $ \dhPtr ->- withBN pubKey $ \bn -> do- size <- fromIntegral <$> _DH_size dhPtr- BS.createAndTrim size $ \bsPtr ->- fromIntegral <$> _DH_compute_key bsPtr (unwrapBN bn) dhPtr- >>= failIf (< 0)--foreign import ccall "DH_generate_parameters"- _DH_generate_parameters :: CInt -> CInt -> Ptr () -> Ptr () -> IO (Ptr DH_)-foreign import ccall "DH_generate_key"- _DH_generate_key :: Ptr DH_ -> IO CInt-foreign import ccall "DH_compute_key"- _DH_compute_key :: Ptr Word8 -> Ptr BIGNUM -> Ptr DH_ -> IO CInt-foreign import ccall "DH_check"- _DH_check :: Ptr DH_ -> Ptr CInt -> IO Bool-foreign import ccall unsafe "DH_size"- _DH_size :: Ptr DH_ -> IO CInt-foreign import ccall unsafe "HsOpenSSL_DHparams_dup"- _DH_dup :: Ptr DH_ -> IO (Ptr DH_)-foreign import ccall unsafe "HsOpenSSL_DH_get_pub_key"- _DH_get_pub_key :: Ptr DH_ -> IO (Ptr BIGNUM)-foreign import ccall unsafe "HsOpenSSL_DH_length"- _DH_length :: Ptr DH_ -> IO CInt-
OpenSSL/DSA.hsc view
@@ -40,9 +40,6 @@ import Foreign.C.Types import OpenSSL.BN import OpenSSL.Utils-#if !(defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 612)-import System.IO.Unsafe-#endif -- | The type of a DSA public key, includes parameters p, q, g and public. newtype DSAPubKey = DSAPubKey (ForeignPtr DSA)
OpenSSL/EVP/Internal.hsc view
@@ -1,4 +1,4 @@-module OpenSSL.EVP.Internal ( +module OpenSSL.EVP.Internal ( Cipher(..), EVP_CIPHER, withCipherPtr,@@ -51,7 +51,7 @@ import Control.Applicative ((<$>)) import Control.Exception (mask, mask_, bracket_, onException) import Foreign.C.Types (CChar)-#if __GLASGOW_HASKELL__ >= 703+#if MIN_VERSION_base(4,5,0) import Foreign.C.Types (CInt(..), CUInt(..), CSize(..)) #else import Foreign.C.Types (CInt, CUInt, CSize)@@ -306,4 +306,3 @@ touchPKey :: VaguePKey -> IO () touchPKey (VaguePKey pkey) = touchForeignPtr pkey-
OpenSSL/RSA.hsc view
@@ -37,9 +37,6 @@ import Foreign.C import OpenSSL.BN import OpenSSL.Utils-#if !(defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__)-import System.IO.Unsafe-#endif -- |@'RSAPubKey'@ is an opaque object that represents RSA public key. newtype RSAPubKey = RSAPubKey (ForeignPtr RSA)
OpenSSL/Session.hsc view
@@ -34,8 +34,12 @@ , tryConnect , read , tryRead+ , readPtr+ , tryReadPtr , write , tryWrite+ , writePtr+ , tryWritePtr , lazyRead , lazyWrite , shutdown@@ -444,6 +448,17 @@ WantWrite -> return (0, 0, WantWrite ) return $ bs <$ result +-- | Read some data into a raw pointer buffer.+-- Retrns the number of bytes read.+readPtr :: SSL -> Ptr a -> Int -> IO Int+readPtr ssl ptr len = sslBlock (\h -> tryReadPtr h ptr len) ssl++-- | Try to read some data into a raw pointer buffer, without blocking.+tryReadPtr :: SSL -> Ptr a -> Int -> IO (SSLResult Int)+tryReadPtr ssl bufPtr nBytes =+ fmap (fmap fromIntegral) (sslIOInner "SSL_read" _ssl_read (castPtr bufPtr) nBytes ssl)++ foreign import ccall "SSL_write" _ssl_write :: Ptr SSL_ -> Ptr Word8 -> CInt -> IO CInt -- | Write a given ByteString to the SSL connection. Either all the data is@@ -456,13 +471,24 @@ tryWrite ssl bs | B.null bs = return $ SSLDone () | otherwise- = B.unsafeUseAsCStringLen bs $ \(ptr, len) ->- do result <- sslIOInner "SSL_write" _ssl_write ptr len ssl- case result of- SSLDone 0 -> ioError $ errnoToIOError "SSL_write" ePIPE Nothing Nothing- SSLDone _ -> return $ SSLDone ()- WantRead -> return WantRead- WantWrite -> return WantWrite+ = B.unsafeUseAsCStringLen bs $ \(ptr, len) -> tryWritePtr ssl ptr len++-- | Send some data from a raw pointer buffer.+writePtr :: SSL -> Ptr a -> Int -> IO ()+writePtr ssl ptr len = sslBlock (\h -> tryWritePtr h ptr len) ssl >> return ()++-- | Send some data from a raw pointer buffer, without blocking.+tryWritePtr :: SSL -> Ptr a -> Int -> IO (SSLResult ())+tryWritePtr ssl ptr len =+ do result <- sslIOInner "SSL_write" _ssl_write (castPtr ptr) len ssl+ case result of+ SSLDone 0 -> ioError $ errnoToIOError "SSL_write" ePIPE Nothing Nothing+ SSLDone _ -> return $ SSLDone ()+ WantRead -> return WantRead+ WantWrite -> return WantWrite+++ -- | Lazily read all data until reaching EOF. If the connection dies -- without a graceful SSL shutdown, an exception is raised.
OpenSSL/Utils.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} module OpenSSL.Utils ( failIfNull , failIfNull_@@ -10,14 +9,12 @@ , peekCStringCLen ) where--import Foreign-import Foreign.C-import OpenSSL.ERR-import Data.List (unfoldr)-#if !(defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__)-import Data.Bits ((.&.), (.|.), shiftR, shiftL)-#endif+import Foreign.C.String+import Foreign.C.Types+import Foreign.Ptr+import OpenSSL.ERR+import Data.Bits+import Data.List failIfNull :: Ptr a -> IO (Ptr a) failIfNull ptr@@ -96,7 +93,6 @@ byteHex 'E' = 14 byteHex 'F' = 15 byteHex _ = undefined- peekCStringCLen :: (Ptr CChar, CInt) -> IO String peekCStringCLen (p, n)
+ OpenSSL/X509.hs view
@@ -0,0 +1,382 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_HADDOCK 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 Data.Maybe+import Foreign.ForeignPtr+#if MIN_VERSION_base(4,4,0)+import Foreign.ForeignPtr.Unsafe as Unsafe+#else+import Foreign.ForeignPtr as Unsafe+#endif+import Foreign.Ptr+import Foreign.C+import OpenSSL.ASN1+import OpenSSL.BIO+import OpenSSL.EVP.Digest+import OpenSSL.EVP.PKey+import OpenSSL.EVP.Verify+import OpenSSL.EVP.Internal+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 CInt++foreign import ccall unsafe "X509_cmp"+ _cmp :: Ptr X509_ -> Ptr X509_ -> IO CInt++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 CInt++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 CInt++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 CInt++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 CInt++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 CInt++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 CInt++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 CInt++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 CInt++foreign import ccall unsafe "X509_verify"+ _verify :: Ptr X509_ -> Ptr EVP_PKEY -> IO CInt++-- |@'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 = fmap X509 . newForeignPtr _free+++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) = Unsafe.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 ->+ fmap interpret (_cmp cert1Ptr cert2Ptr)+ where+ interpret :: CInt -> Ordering+ interpret n+ | n > 0 = GT+ | n < 0 = LT+ | otherwise = EQ++-- |@'signX509'@ signs a certificate with an issuer private key.+signX509 :: KeyPair key =>+ X509 -- ^ The certificate to be signed.+ -> key -- ^ 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 key mDigest+ = withX509Ptr x509 $ \ x509Ptr ->+ withPKeyPtr' key $ \ pkeyPtr ->+ do dig <- case mDigest of+ Just md -> return md+ Nothing -> pkeyDefaultMD key+ withMDPtr dig $ \ digestPtr ->+ _sign x509Ptr pkeyPtr digestPtr+ >>= failIf_ (== 0)+ return ()++-- |@'verifyX509'@ verifies a signature of certificate with an issuer+-- public key.+verifyX509 :: PublicKey key =>+ X509 -- ^ The certificate to be verified.+ -> key -- ^ The public key to verify with.+ -> IO VerifyStatus+verifyX509 x509 key+ = withX509Ptr x509 $ \ x509Ptr ->+ withPKeyPtr' key $ \ pkeyPtr ->+ _verify x509Ptr pkeyPtr+ >>= interpret+ where+ interpret :: CInt -> 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 SomePublicKey+getPublicKey x509+ = withX509Ptr x509 $ \ x509Ptr ->+ fmap fromJust ( _get_pubkey x509Ptr+ >>= failIfNull+ >>= wrapPKeyPtr+ >>= fromPKey+ )++-- |@'setPublicKey' cert pubkey@ updates the public key of the subject+-- of certificate.+setPublicKey :: PublicKey key => X509 -> key -> IO ()+setPublicKey x509 key+ = withX509Ptr x509 $ \ x509Ptr ->+ withPKeyPtr' key $ \ 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
− OpenSSL/X509.hsc
@@ -1,381 +0,0 @@-{-# OPTIONS_HADDOCK 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 Data.Maybe-import Foreign.ForeignPtr-#if MIN_VERSION_base(4,4,0)-import Foreign.ForeignPtr.Unsafe as Unsafe-#else-import Foreign.ForeignPtr as Unsafe-#endif-import Foreign.Ptr-import Foreign.C-import OpenSSL.ASN1-import OpenSSL.BIO-import OpenSSL.EVP.Digest-import OpenSSL.EVP.PKey-import OpenSSL.EVP.Verify-import OpenSSL.EVP.Internal-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 CInt--foreign import ccall unsafe "X509_cmp"- _cmp :: Ptr X509_ -> Ptr X509_ -> IO CInt--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 CInt--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 CInt--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 CInt--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 CInt--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 CInt--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 CInt--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 CInt--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 CInt--foreign import ccall unsafe "X509_verify"- _verify :: Ptr X509_ -> Ptr EVP_PKEY -> IO CInt---- |@'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 = fmap X509 . newForeignPtr _free---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) = Unsafe.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 ->- fmap interpret (_cmp cert1Ptr cert2Ptr)- where- interpret :: CInt -> Ordering- interpret n- | n > 0 = GT- | n < 0 = LT- | otherwise = EQ---- |@'signX509'@ signs a certificate with an issuer private key.-signX509 :: KeyPair key =>- X509 -- ^ The certificate to be signed.- -> key -- ^ 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 key mDigest- = withX509Ptr x509 $ \ x509Ptr ->- withPKeyPtr' key $ \ pkeyPtr ->- do dig <- case mDigest of- Just md -> return md- Nothing -> pkeyDefaultMD key- withMDPtr dig $ \ digestPtr ->- _sign x509Ptr pkeyPtr digestPtr- >>= failIf_ (== 0)- return ()---- |@'verifyX509'@ verifies a signature of certificate with an issuer--- public key.-verifyX509 :: PublicKey key =>- X509 -- ^ The certificate to be verified.- -> key -- ^ The public key to verify with.- -> IO VerifyStatus-verifyX509 x509 key- = withX509Ptr x509 $ \ x509Ptr ->- withPKeyPtr' key $ \ pkeyPtr ->- _verify x509Ptr pkeyPtr- >>= interpret- where- interpret :: CInt -> 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 SomePublicKey-getPublicKey x509- = withX509Ptr x509 $ \ x509Ptr ->- fmap fromJust ( _get_pubkey x509Ptr- >>= failIfNull- >>= wrapPKeyPtr- >>= fromPKey- )---- |@'setPublicKey' cert pubkey@ updates the public key of the subject--- of certificate.-setPublicKey :: PublicKey key => X509 -> key -> IO ()-setPublicKey x509 key- = withX509Ptr x509 $ \ x509Ptr ->- withPKeyPtr' key $ \ 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
cbits/HsOpenSSL.h view
@@ -20,6 +20,16 @@ #include <openssl/x509v3.h> #include <openssl/dsa.h> +/* A dirty hack to work around for broken versions of Cabal:+ * https://github.com/phonohawk/HsOpenSSL/issues/8+ *+ * The trick is to abuse the fact that -Icbits is always passed to+ * hsc2hs so we can reach the cabal_macros.h from cbits.+ */+#if !defined(MIN_VERSION_base)+# include "../dist/build/autogen/cabal_macros.h"+#endif+ /* OpenSSL ********************************************************************/ void HsOpenSSL_OpenSSL_add_all_algorithms(); void HsOpenSSL_OPENSSL_free(void* ptr);