HsOpenSSL 0.11.2.4 → 0.11.3
raw patch · 6 files changed
+126/−57 lines, 6 filesdep ~HUnitPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: HUnit
API changes (from Hackage documentation)
- OpenSSL.RSA: fromDERPub :: ByteString -> Maybe RSAPubKey
- OpenSSL.RSA: toDERPub :: RSAKey k => k -> ByteString
+ OpenSSL.DER: fromDERPriv :: RSAKey k => ByteString -> Maybe k
+ OpenSSL.DER: fromDERPub :: ByteString -> Maybe RSAPubKey
+ OpenSSL.DER: toDERPriv :: RSAKeyPair -> ByteString
+ OpenSSL.DER: toDERPub :: RSAKey k => k -> ByteString
Files
- ChangeLog +10/−0
- HsOpenSSL.cabal +8/−7
- OpenSSL/DER.hsc +89/−0
- OpenSSL/RSA.hsc +3/−36
- Test/OpenSSL/DER.hs +16/−0
- Test/OpenSSL/RSA.hs +0/−14
ChangeLog view
@@ -1,3 +1,13 @@+2016-10-14 Vladimir Shabanov <vshabanoff@gmail.com>++ * HsOpenSSL.cabal (Version): Bump version to 0.11.3++ * HsOpenSSL.cabal (Build-Depends): Bump HUnit upper bound,++ * OpenSSL/RSA.hsc, OpenSSL/DER.hsc: moved DER function from RSA to DER+ module. Added encoding/decoding of private keys in ASN.1 DER.+ by @shak-mar (#12).+ 2016-10-08 Vladimir Shabanov <vshabanoff@gmail.com> * HsOpenSSL.cabal (Version): Bump version to 0.11.2.4
HsOpenSSL.cabal view
@@ -12,7 +12,7 @@ <http://hackage.haskell.org/package/tls>, which is a pure Haskell implementation of SSL. .-Version: 0.11.2.4+Version: 0.11.3 License: PublicDomain License-File: COPYING Author: Adam Langley, Mikhail Vorozhtsov, PHO, Taru Karttunen@@ -100,6 +100,7 @@ Exposed-Modules: OpenSSL OpenSSL.BN+ OpenSSL.DER OpenSSL.EVP.Base64 OpenSSL.EVP.Cipher OpenSSL.EVP.Digest@@ -148,7 +149,7 @@ Main-Is: Test/OpenSSL/Cipher.hs Build-Depends: HsOpenSSL,- HUnit >= 1.0 && < 1.4,+ HUnit >= 1.0 && < 1.5, base >= 4.4 && < 5, bytestring >= 0.9 && < 0.11, test-framework >= 0.8 && < 0.9,@@ -163,7 +164,7 @@ Main-Is: Test/OpenSSL/DSA.hs Build-Depends: HsOpenSSL,- HUnit >= 1.0 && < 1.4,+ HUnit >= 1.0 && < 1.5, base >= 4.4 && < 5, bytestring >= 0.9 && < 0.11, test-framework >= 0.8 && < 0.9,@@ -173,12 +174,12 @@ GHC-Options: -Wall -Test-Suite test-rsa+Test-Suite test-der Type: exitcode-stdio-1.0- Main-Is: Test/OpenSSL/RSA.hs+ Main-Is: Test/OpenSSL/DER.hs Build-Depends: HsOpenSSL,- HUnit >= 1.0 && < 1.4,+ HUnit >= 1.0 && < 1.5, base >= 4.4 && < 5, bytestring >= 0.9 && < 0.11, test-framework >= 0.8 && < 0.9,@@ -193,7 +194,7 @@ Main-Is: Test/OpenSSL/EVP/Base64.hs Build-Depends: HsOpenSSL,- HUnit >= 1.0 && < 1.4,+ HUnit >= 1.0 && < 1.5, base >= 4.4 && < 5, bytestring >= 0.9 && < 0.11, test-framework >= 0.8 && < 0.9,
+ OpenSSL/DER.hsc view
@@ -0,0 +1,89 @@+{-# LANGUAGE ForeignFunctionInterface #-}+-- |Encoding and decoding of RSA keys using the ASN.1 DER format+module OpenSSL.DER+ ( toDERPub+ , fromDERPub+ , toDERPriv+ , fromDERPriv+ )+ where++#if !MIN_VERSION_base(4,8,0)+import Control.Applicative ((<$>))+#endif+import OpenSSL.RSA (RSA, RSAKey, RSAKeyPair, RSAPubKey,+ absorbRSAPtr, withRSAPtr)++import Data.ByteString (ByteString)+import qualified Data.ByteString as B (useAsCStringLen)+import qualified Data.ByteString.Internal as BI (createAndTrim)+import Foreign.Ptr (Ptr, nullPtr)+import Foreign.C.String (CString)+import Foreign.C.Types (CLong(..), CInt(..))+import Foreign.Marshal.Alloc (alloca)+import Foreign.Storable (poke)+import GHC.Word (Word8)+import System.IO.Unsafe (unsafePerformIO)++type CDecodeFun = Ptr (Ptr RSA) -> Ptr CString -> CLong -> IO (Ptr RSA)+type CEncodeFun = Ptr RSA -> Ptr (Ptr Word8) -> IO CInt++foreign import ccall unsafe "d2i_RSAPublicKey"+ _fromDERPub :: CDecodeFun++foreign import ccall unsafe "i2d_RSAPublicKey"+ _toDERPub :: CEncodeFun++foreign import ccall unsafe "d2i_RSAPrivateKey"+ _fromDERPriv :: CDecodeFun++foreign import ccall unsafe "i2d_RSAPrivateKey"+ _toDERPriv :: CEncodeFun++-- | Generate a function that decodes a key from ASN.1 DER format+makeDecodeFun :: RSAKey k => CDecodeFun -> ByteString -> Maybe k+makeDecodeFun fun bs = unsafePerformIO . usingConvedBS $ \(csPtr, ci) -> do+ -- When you pass a null pointer to this function, it will allocate the memory+ -- space required for the RSA key all by itself. It will be freed whenever+ -- the haskell object is garbage collected, as they are stored in ForeignPtrs+ -- internally.+ rsaPtr <- fun nullPtr csPtr ci+ if rsaPtr == nullPtr then return Nothing else absorbRSAPtr rsaPtr+ where usingConvedBS io = B.useAsCStringLen bs $ \(cs, len) ->+ alloca $ \csPtr -> poke csPtr cs >> io (csPtr, fromIntegral len)++-- | Generate a function that encodes a key in ASN.1 DER format+makeEncodeFun :: RSAKey k => CEncodeFun -> k -> ByteString+makeEncodeFun fun k = unsafePerformIO $ do+ -- When you pass a null pointer to this function, it will only compute the+ -- required buffer size. See https://www.openssl.org/docs/faq.html#PROG3+ requiredSize <- withRSAPtr k $ flip fun nullPtr+ -- It’s too sad BI.createAndTrim is considered internal, as it does a great+ -- job here. See https://hackage.haskell.org/package/bytestring-0.9.1.4/docs/Data-ByteString-Internal.html#v%3AcreateAndTrim+ BI.createAndTrim (fromIntegral requiredSize) $ \ptr ->+ alloca $ \pptr ->+ (fromIntegral <$>) . withRSAPtr k $ \key ->+ poke pptr ptr >> fun key pptr++-- | Dump a public key to ASN.1 DER format+toDERPub :: RSAKey k+ => k -- ^ You can pass either 'RSAPubKey' or 'RSAKeyPair'+ -- because both contain the necessary information.+ -> ByteString -- ^ The public key information encoded in ASN.1 DER+toDERPub = makeEncodeFun _toDERPub++-- | Parse a public key from ASN.1 DER format+fromDERPub :: ByteString -> Maybe RSAPubKey+fromDERPub = makeDecodeFun _fromDERPub++-- | Dump a private key to ASN.1 DER format+toDERPriv :: RSAKeyPair -> ByteString+toDERPriv = makeEncodeFun _toDERPriv++-- | Parse a private key from ASN.1 DER format+fromDERPriv :: RSAKey k+ => ByteString -- ^ The private key information encoded in ASN.1 DER+ -> Maybe k -- ^ This can return either 'RSAPubKey' or+ -- 'RSAKeyPair' because there’s sufficient+ -- information for both.+fromDERPriv = makeDecodeFun _fromDERPriv
OpenSSL/RSA.hsc view
@@ -24,9 +24,6 @@ , rsaIQMP , rsaCopyPublic , rsaKeyPairFinalize -- private- -- * DER encoding- , fromDERPub- , toDERPub ) where #include "HsOpenSSL.h"@@ -34,21 +31,16 @@ #if !MIN_VERSION_base(4,8,0) import Control.Applicative ((<$>)) #endif-import Data.ByteString (ByteString)-import qualified Data.ByteString as B (useAsCStringLen)-import qualified Data.ByteString.Internal as BI (createAndTrim) import Data.Typeable-import Foreign.C.String (CString)+ #if MIN_VERSION_base(4,5,0)-import Foreign.C.Types (CInt(..), CLong(..))+import Foreign.C.Types (CInt(..)) #else-import Foreign.C.Types (CInt, CLong)+import Foreign.C.Types (CInt) #endif import Foreign.ForeignPtr (ForeignPtr, finalizeForeignPtr, newForeignPtr, withForeignPtr)-import Foreign.Marshal.Alloc (alloca) import Foreign.Ptr (FunPtr, Ptr, freeHaskellFunPtr, nullFunPtr, nullPtr) import Foreign.Storable (Storable(..))-import GHC.Word (Word8) import OpenSSL.BN import OpenSSL.Utils import System.IO.Unsafe (unsafePerformIO)@@ -244,31 +236,6 @@ -- |@'rsaIQMP' privkey@ returns @q^-1 mod p@ of the key. rsaIQMP :: RSAKeyPair -> Maybe Integer rsaIQMP = peekMI (#peek RSA, iqmp)--{- DER encoding ------------------------------------------------------------- -}--foreign import ccall unsafe "d2i_RSAPublicKey"- _fromDERPub :: Ptr (Ptr RSA) -> Ptr CString -> CLong -> IO (Ptr RSA)--foreign import ccall unsafe "i2d_RSAPublicKey"- _toDERPub :: Ptr RSA -> Ptr (Ptr Word8) -> IO CInt---- |Parse a public key from ASN.1 DER format-fromDERPub :: ByteString -> Maybe RSAPubKey-fromDERPub bs = unsafePerformIO . usingConvedBS $ \(csPtr, ci) -> do- rsaPtr <- _fromDERPub nullPtr csPtr ci- if rsaPtr == nullPtr then return Nothing else absorbRSAPtr rsaPtr- where usingConvedBS io = B.useAsCStringLen bs $ \(cs, len) ->- alloca $ \csPtr -> poke csPtr cs >> io (csPtr, fromIntegral len)---- |Dump a public key to ASN.1 DER format-toDERPub :: RSAKey k => k -> ByteString-toDERPub k = unsafePerformIO $ do- requiredSize <- withRSAPtr k $ flip _toDERPub nullPtr- BI.createAndTrim (fromIntegral requiredSize) $ \ptr ->- alloca $ \pptr ->- (fromIntegral <$>) $ withRSAPtr k $ \key ->- poke pptr ptr >> _toDERPub key pptr {- instances ---------------------------------------------------------------- -}
+ Test/OpenSSL/DER.hs view
@@ -0,0 +1,16 @@+module Main (main) where++import OpenSSL.RSA+import OpenSSL.DER+import qualified Test.Framework as TF+import qualified Test.Framework.Providers.HUnit as TF+import Test.HUnit++test_encodeDecodeEqual :: Test+test_encodeDecodeEqual = TestCase $ do+ keyPair <- generateRSAKey 1024 3 Nothing+ pubKey <- rsaCopyPublic keyPair+ assertEqual "encodeDecode" (Just pubKey) (fromDERPub (toDERPub keyPair))++main :: IO ()+main = TF.defaultMain $ TF.hUnitTestToTests test_encodeDecodeEqual
− Test/OpenSSL/RSA.hs
@@ -1,14 +0,0 @@-module Main (main) where-import OpenSSL.RSA-import qualified Test.Framework as TF-import qualified Test.Framework.Providers.HUnit as TF-import Test.HUnit--test_encodeDecodeEqual :: Test-test_encodeDecodeEqual = TestCase $ do- keyPair <- generateRSAKey 1024 3 Nothing- pubKey <- rsaCopyPublic keyPair- assertEqual "encodeDecode" (Just pubKey) (fromDERPub (toDERPub keyPair))--main :: IO ()-main = TF.defaultMain $ TF.hUnitTestToTests test_encodeDecodeEqual