{-# LINE 1 "OpenSSL/DSA.hsc" #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# OPTIONS_HADDOCK prune #-}
module OpenSSL.DSA
(
DSAKey(..)
, DSAPubKey
, DSAKeyPair
, DSA
, generateDSAParameters
, generateDSAKey
, generateDSAParametersAndKey
, signDigestedDataWithDSA
, verifyDigestedDataWithDSA
, dsaPrivate
, dsaPubKeyToTuple
, dsaKeyPairToTuple
, tupleToDSAPubKey
, tupleToDSAKeyPair
) where
import Control.Monad
import qualified Data.ByteString as BS
import Data.Typeable
import Foreign.C.String (CString)
{-# LINE 36 "OpenSSL/DSA.hsc" #-}
import Foreign.C.Types (CChar(..), CInt(..))
{-# LINE 40 "OpenSSL/DSA.hsc" #-}
import Foreign.ForeignPtr (ForeignPtr, newForeignPtr, withForeignPtr)
import Foreign.Marshal.Alloc (alloca)
import Foreign.Ptr (FunPtr, Ptr, nullPtr)
import Foreign.Storable (Storable(..))
import OpenSSL.BN
import OpenSSL.Utils
import System.IO.Unsafe (unsafePerformIO)
newtype DSAPubKey = DSAPubKey (ForeignPtr DSA)
deriving Typeable
newtype DSAKeyPair = DSAKeyPair (ForeignPtr DSA)
deriving Typeable
data DSA
class DSAKey k where
dsaSize :: k -> Int
dsaSize dsa
= unsafePerformIO $
withDSAPtr dsa $ \ dsaPtr ->
fmap fromIntegral (_size dsaPtr)
dsaP :: k -> Integer
dsaP = peekI dsa_p
dsaQ :: k -> Integer
dsaQ = peekI dsa_q
dsaG :: k -> Integer
dsaG = peekI dsa_g
dsaPublic :: k -> Integer
dsaPublic = peekI dsa_pub_key
withDSAPtr :: k -> (Ptr DSA -> IO a) -> IO a
peekDSAPtr :: Ptr DSA -> IO (Maybe k)
absorbDSAPtr :: Ptr DSA -> IO (Maybe k)
instance DSAKey DSAPubKey where
withDSAPtr (DSAPubKey fp) = withForeignPtr fp
peekDSAPtr dsaPtr = _pubDup dsaPtr >>= absorbDSAPtr
absorbDSAPtr dsaPtr = fmap (Just . DSAPubKey) (newForeignPtr _free dsaPtr)
instance DSAKey DSAKeyPair where
withDSAPtr (DSAKeyPair fp) = withForeignPtr fp
peekDSAPtr dsaPtr
= do hasP <- hasDSAPrivateKey dsaPtr
if hasP then
_privDup dsaPtr >>= absorbDSAPtr
else
return Nothing
absorbDSAPtr dsaPtr
= do hasP <- hasDSAPrivateKey dsaPtr
if hasP then
fmap (Just . DSAKeyPair) (newForeignPtr _free dsaPtr)
else
return Nothing
hasDSAPrivateKey :: Ptr DSA -> IO Bool
hasDSAPrivateKey dsaPtr
= fmap (/= nullPtr) (dsa_priv_key dsaPtr)
foreign import ccall unsafe "&DSA_free"
_free :: FunPtr (Ptr DSA -> IO ())
foreign import ccall unsafe "DSA_free"
dsa_free :: Ptr DSA -> IO ()
foreign import ccall unsafe "BN_free"
_bn_free :: Ptr BIGNUM -> IO ()
foreign import ccall unsafe "DSA_new"
_dsa_new :: IO (Ptr DSA)
foreign import ccall unsafe "DSA_generate_key"
_dsa_generate_key :: Ptr DSA -> IO ()
foreign import ccall unsafe "HsOpenSSL_dsa_sign"
_dsa_sign :: Ptr DSA -> CString -> CInt -> Ptr (Ptr BIGNUM) -> Ptr (Ptr BIGNUM) -> IO CInt
foreign import ccall unsafe "HsOpenSSL_dsa_verify"
_dsa_verify :: Ptr DSA -> CString -> CInt -> Ptr BIGNUM -> Ptr BIGNUM -> IO CInt
foreign import ccall safe "DSA_generate_parameters"
_generate_params :: CInt -> Ptr CChar -> CInt -> Ptr CInt -> Ptr CInt -> Ptr () -> Ptr () -> IO (Ptr DSA)
foreign import ccall unsafe "HsOpenSSL_DSAPublicKey_dup"
_pubDup :: Ptr DSA -> IO (Ptr DSA)
foreign import ccall unsafe "HsOpenSSL_DSAPrivateKey_dup"
_privDup :: Ptr DSA -> IO (Ptr DSA)
foreign import ccall unsafe "DSA_size"
_size :: Ptr DSA -> IO CInt
dsa_p, dsa_q, dsa_g, dsa_pub_key, dsa_priv_key :: Ptr DSA -> IO (Ptr BIGNUM)
setPQG :: Ptr DSA -> Integer -> Integer -> Integer -> IO ()
setKey :: Ptr DSA -> Ptr BIGNUM -> Ptr BIGNUM -> IO ()
{-# LINE 200 "OpenSSL/DSA.hsc" #-}
dsa_p = ((\hsc_ptr -> peekByteOff hsc_ptr 24))
{-# LINE 202 "OpenSSL/DSA.hsc" #-}
dsa_q = ((\hsc_ptr -> peekByteOff hsc_ptr 32))
{-# LINE 203 "OpenSSL/DSA.hsc" #-}
dsa_g = ((\hsc_ptr -> peekByteOff hsc_ptr 40))
{-# LINE 204 "OpenSSL/DSA.hsc" #-}
dsa_pub_key = ((\hsc_ptr -> peekByteOff hsc_ptr 48))
{-# LINE 205 "OpenSSL/DSA.hsc" #-}
dsa_priv_key = ((\hsc_ptr -> peekByteOff hsc_ptr 56))
{-# LINE 206 "OpenSSL/DSA.hsc" #-}
setPQG ptr p q g = do
fmap unwrapBN (newBN p) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 24)) ptr
{-# LINE 209 "OpenSSL/DSA.hsc" #-}
fmap unwrapBN (newBN q) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 32)) ptr
{-# LINE 210 "OpenSSL/DSA.hsc" #-}
fmap unwrapBN (newBN g) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 40)) ptr
{-# LINE 211 "OpenSSL/DSA.hsc" #-}
setKey ptr pub priv = do
((\hsc_ptr -> pokeByteOff hsc_ptr 48)) ptr pub
{-# LINE 214 "OpenSSL/DSA.hsc" #-}
((\hsc_ptr -> pokeByteOff hsc_ptr 56)) ptr priv
{-# LINE 215 "OpenSSL/DSA.hsc" #-}
{-# LINE 217 "OpenSSL/DSA.hsc" #-}
peekI :: DSAKey k => (Ptr DSA -> IO (Ptr BIGNUM)) -> k -> Integer
peekI peeker dsa
= unsafePerformIO $
withDSAPtr dsa $ \ dsaPtr ->
do bn <- peeker dsaPtr
when (bn == nullPtr) $ fail "peekI: got a nullPtr"
peekBN (wrapBN bn)
generateDSAParameters :: Int
-> Maybe BS.ByteString
-> IO (Int, Int, Integer, Integer, Integer)
generateDSAParameters nbits mseed = do
when (nbits < 512 || nbits > 1024) $ fail "Invalid DSA bit size"
alloca (\i1 ->
alloca (\i2 ->
(\x -> case mseed of
Nothing -> x (nullPtr, 0)
Just seed -> BS.useAsCStringLen seed x) (\(seedptr, seedlen) -> do
ptr <- _generate_params (fromIntegral nbits) seedptr (fromIntegral seedlen) i1 i2 nullPtr nullPtr
failIfNull_ ptr
itcount <- peek i1
gencount <- peek i2
p <- dsa_p ptr >>= peekBN . wrapBN
q <- dsa_q ptr >>= peekBN . wrapBN
g <- dsa_g ptr >>= peekBN . wrapBN
dsa_free ptr
return (fromIntegral itcount, fromIntegral gencount, p, q, g))))
generateDSAKey :: Integer
-> Integer
-> Integer
-> IO DSAKeyPair
generateDSAKey p q g = do
ptr <- _dsa_new
setPQG ptr p q g
_dsa_generate_key ptr
fmap DSAKeyPair (newForeignPtr _free ptr)
dsaPrivate :: DSAKeyPair -> Integer
dsaPrivate = peekI dsa_priv_key
dsaPubKeyToTuple :: DSAKeyPair -> (Integer, Integer, Integer, Integer)
dsaPubKeyToTuple dsa
= let p = peekI dsa_p dsa
q = peekI dsa_q dsa
g = peekI dsa_g dsa
pub = peekI dsa_pub_key dsa
in
(p, q, g, pub)
dsaKeyPairToTuple :: DSAKeyPair -> (Integer, Integer, Integer, Integer, Integer)
dsaKeyPairToTuple dsa
= let p = peekI dsa_p dsa
q = peekI dsa_q dsa
g = peekI dsa_g dsa
pub = peekI dsa_pub_key dsa
pri = peekI dsa_priv_key dsa
in
(p, q, g, pub, pri)
tupleToDSAPubKey :: (Integer, Integer, Integer, Integer) -> DSAPubKey
tupleToDSAPubKey (p, q, g, pub) = unsafePerformIO $ do
ptr <- _dsa_new
setPQG ptr p q g
pub' <- fmap unwrapBN (newBN pub)
setKey ptr pub' nullPtr
fmap DSAPubKey (newForeignPtr _free ptr)
tupleToDSAKeyPair :: (Integer, Integer, Integer, Integer, Integer) -> DSAKeyPair
tupleToDSAKeyPair (p, q, g, pub, pri) = unsafePerformIO $ do
ptr <- _dsa_new
setPQG ptr p q g
pub' <- fmap unwrapBN (newBN pub)
priv' <- fmap unwrapBN (newBN pri)
setKey ptr pub' priv'
fmap DSAKeyPair (newForeignPtr _free ptr)
generateDSAParametersAndKey :: Int
-> Maybe BS.ByteString
-> IO DSAKeyPair
generateDSAParametersAndKey nbits mseed =
(\x -> case mseed of
Nothing -> x (nullPtr, 0)
Just seed -> BS.useAsCStringLen seed x) (\(seedptr, seedlen) -> do
ptr <- _generate_params (fromIntegral nbits) seedptr (fromIntegral seedlen) nullPtr nullPtr nullPtr nullPtr
failIfNull_ ptr
_dsa_generate_key ptr
fmap DSAKeyPair (newForeignPtr _free ptr))
signDigestedDataWithDSA :: DSAKeyPair -> BS.ByteString -> IO (Integer, Integer)
signDigestedDataWithDSA dsa bytes =
BS.useAsCStringLen bytes (\(ptr, len) ->
alloca (\rptr ->
alloca (\sptr ->
withDSAPtr dsa (\dsaptr -> do
_dsa_sign dsaptr ptr (fromIntegral len) rptr sptr >>= failIf_ (== 0)
r <- peek rptr >>= peekBN . wrapBN
peek rptr >>= _bn_free
s <- peek sptr >>= peekBN . wrapBN
peek sptr >>= _bn_free
return (r, s)))))
verifyDigestedDataWithDSA :: DSAKey k => k -> BS.ByteString -> (Integer, Integer) -> IO Bool
verifyDigestedDataWithDSA dsa bytes (r, s) =
BS.useAsCStringLen bytes (\(ptr, len) ->
withBN r (\bnR ->
withBN s (\bnS ->
withDSAPtr dsa (\dsaptr ->
fmap (== 1)
(_dsa_verify dsaptr ptr (fromIntegral len) (unwrapBN bnR) (unwrapBN bnS))))))
instance Eq DSAPubKey where
a == b
= dsaP a == dsaP b &&
dsaQ a == dsaQ b &&
dsaG a == dsaG b &&
dsaPublic a == dsaPublic b
instance Eq DSAKeyPair where
a == b
= dsaP a == dsaP b &&
dsaQ a == dsaQ b &&
dsaG a == dsaG b &&
dsaPublic a == dsaPublic b &&
dsaPrivate a == dsaPrivate b
instance Ord DSAPubKey where
a `compare` b
| dsaP a < dsaP b = LT
| dsaP a > dsaP b = GT
| dsaQ a < dsaQ b = LT
| dsaQ a > dsaQ b = GT
| dsaG a < dsaG b = LT
| dsaG a > dsaG b = GT
| dsaPublic a < dsaPublic b = LT
| dsaPublic a > dsaPublic b = GT
| otherwise = EQ
instance Ord DSAKeyPair where
a `compare` b
| dsaP a < dsaP b = LT
| dsaP a > dsaP b = GT
| dsaQ a < dsaQ b = LT
| dsaQ a > dsaQ b = GT
| dsaG a < dsaG b = LT
| dsaG a > dsaG b = GT
| dsaPublic a < dsaPublic b = LT
| dsaPublic a > dsaPublic b = GT
| dsaPrivate a < dsaPrivate b = LT
| dsaPrivate a > dsaPrivate b = GT
| otherwise = EQ
instance Show DSAPubKey where
show a
= concat [ "DSAPubKey {"
, "dsaP = ", show (dsaP a), ", "
, "dsaQ = ", show (dsaQ a), ", "
, "dsaG = ", show (dsaG a), ", "
, "dsaPublic = ", show (dsaPublic a)
, "}"
]
instance Show DSAKeyPair where
show a
= concat [ "DSAPubKey {"
, "dsaP = ", show (dsaP a), ", "
, "dsaQ = ", show (dsaQ a), ", "
, "dsaG = ", show (dsaG a), ", "
, "dsaPublic = ", show (dsaPublic a), ", "
, "dsaPrivate = ", show (dsaPrivate a)
, "}"
]