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)
import Foreign.C.Types (CChar(..), CInt(..))
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 ((\hsc_ptr -> peekByteOff hsc_ptr 24))
dsaQ :: k -> Integer
dsaQ = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 32))
dsaG :: k -> Integer
dsaG = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 40))
dsaPublic :: k -> Integer
dsaPublic = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 48))
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) (((\hsc_ptr -> peekByteOff hsc_ptr 56)) 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
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 <- ((\hsc_ptr -> peekByteOff hsc_ptr 24)) ptr >>= peekBN . wrapBN
q <- ((\hsc_ptr -> peekByteOff hsc_ptr 32)) ptr >>= peekBN . wrapBN
g <- ((\hsc_ptr -> peekByteOff hsc_ptr 40)) 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
fmap unwrapBN (newBN p) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 24)) ptr
fmap unwrapBN (newBN q) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 32)) ptr
fmap unwrapBN (newBN g) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 40)) ptr
_dsa_generate_key ptr
fmap DSAKeyPair (newForeignPtr _free ptr)
dsaPrivate :: DSAKeyPair -> Integer
dsaPrivate = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 56))
dsaPubKeyToTuple :: DSAKeyPair -> (Integer, Integer, Integer, Integer)
dsaPubKeyToTuple dsa
= let p = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 24)) dsa
q = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 32)) dsa
g = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 40)) dsa
pub = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 48)) dsa
in
(p, q, g, pub)
dsaKeyPairToTuple :: DSAKeyPair -> (Integer, Integer, Integer, Integer, Integer)
dsaKeyPairToTuple dsa
= let p = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 24)) dsa
q = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 32)) dsa
g = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 40)) dsa
pub = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 48)) dsa
pri = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 56)) dsa
in
(p, q, g, pub, pri)
tupleToDSAPubKey :: (Integer, Integer, Integer, Integer) -> DSAPubKey
tupleToDSAPubKey (p, q, g, pub) = unsafePerformIO $ do
ptr <- _dsa_new
fmap unwrapBN (newBN p ) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 24)) ptr
fmap unwrapBN (newBN q ) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 32)) ptr
fmap unwrapBN (newBN g ) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 40)) ptr
fmap unwrapBN (newBN pub) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 48)) ptr
((\hsc_ptr -> pokeByteOff hsc_ptr 56)) ptr nullPtr
fmap DSAPubKey (newForeignPtr _free ptr)
tupleToDSAKeyPair :: (Integer, Integer, Integer, Integer, Integer) -> DSAKeyPair
tupleToDSAKeyPair (p, q, g, pub, pri) = unsafePerformIO $ do
ptr <- _dsa_new
fmap unwrapBN (newBN p ) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 24)) ptr
fmap unwrapBN (newBN q ) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 32)) ptr
fmap unwrapBN (newBN g ) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 40)) ptr
fmap unwrapBN (newBN pub) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 48)) ptr
fmap unwrapBN (newBN pri) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 56)) ptr
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)
, "}"
]