{-# LINE 1 "OpenSSL/DSA.hsc" #-}
{-# LANGUAGE DeriveDataTypeable       #-}
{-# LINE 2 "OpenSSL/DSA.hsc" #-}
{-# LANGUAGE EmptyDataDecls           #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# OPTIONS_HADDOCK prune             #-}
-- | The Digital Signature Algorithm (FIPS 186-2).
--   See <http://www.openssl.org/docs/crypto/dsa.html>
module OpenSSL.DSA
    ( -- * Type
      DSAKey(..)
    , DSAPubKey
    , DSAKeyPair
    , DSA -- private

      -- * Key and parameter generation
    , generateDSAParameters
    , generateDSAKey
    , generateDSAParametersAndKey

      -- * Signing and verification
    , signDigestedDataWithDSA
    , verifyDigestedDataWithDSA

      -- * Extracting fields of DSA objects
    , dsaPrivate
    , dsaPubKeyToTuple
    , dsaKeyPairToTuple
    , tupleToDSAPubKey
    , tupleToDSAKeyPair
    ) where

{-# LINE 31 "OpenSSL/DSA.hsc" #-}
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)

-- | The type of a DSA public key, includes parameters p, q, g and public.
newtype DSAPubKey = DSAPubKey (ForeignPtr DSA)
    deriving Typeable

-- | The type of a DSA keypair, includes parameters p, q, g, public and private.
newtype DSAKeyPair = DSAKeyPair (ForeignPtr DSA)
    deriving Typeable

-- DSAPubKey and DSAKeyPair are in fact the same type at the OpenSSL
-- level, but we want to treat them differently for type-safety.
data DSA

-- |@'DSAKey' a@ is either 'DSAPubKey' or 'DSAKeyPair'.
class DSAKey k where
    -- |Return the length of key.
    dsaSize :: k -> Int
    dsaSize dsa
        = unsafePerformIO $
          withDSAPtr dsa $ \ dsaPtr ->
              fmap fromIntegral (_size dsaPtr)

    -- |Return the public prime number of the key.
    dsaP :: k -> Integer
    dsaP = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 24))
{-# LINE 72 "OpenSSL/DSA.hsc" #-}

    -- |Return the public 160-bit subprime, @q | p - 1@ of the key.
    dsaQ :: k -> Integer
    dsaQ = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 32))
{-# LINE 76 "OpenSSL/DSA.hsc" #-}

    -- |Return the public generator of subgroup of the key.
    dsaG :: k -> Integer
    dsaG = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 40))
{-# LINE 80 "OpenSSL/DSA.hsc" #-}

    -- |Return the public key @y = g^x@.
    dsaPublic :: k -> Integer
    dsaPublic = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 48))
{-# LINE 84 "OpenSSL/DSA.hsc" #-}

    -- private
    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)
{-# LINE 116 "OpenSSL/DSA.hsc" #-}


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)

-- | Generate DSA parameters (*not* a key, but required for a key). This is a
--   compute intensive operation. See FIPS 186-2, app 2. This agrees with the
--   test vectors given in FIP 186-2, app 5
generateDSAParameters :: Int  -- ^ The number of bits in the generated prime: 512 <= x <= 1024
                      -> Maybe BS.ByteString  -- ^ optional seed, its length must be 20 bytes
                      -> IO (Int, Int, Integer, Integer, Integer)  -- ^ (iteration count, generator count, p, q, g)
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
{-# LINE 177 "OpenSSL/DSA.hsc" #-}
        q <- ((\hsc_ptr -> peekByteOff hsc_ptr 32)) ptr >>= peekBN . wrapBN
{-# LINE 178 "OpenSSL/DSA.hsc" #-}
        g <- ((\hsc_ptr -> peekByteOff hsc_ptr 40)) ptr >>= peekBN . wrapBN
{-# LINE 179 "OpenSSL/DSA.hsc" #-}
        dsa_free ptr
        return (fromIntegral itcount, fromIntegral gencount, p, q, g))))

{-
-- | This function just runs the example DSA generation, as given in FIP 186-2,
--   app 5. The return values should be:
--   (105,
--    "8df2a494492276aa3d25759bb06869cbeac0d83afb8d0cf7cbb8324f0d7882e5d0762fc5b7210
--     eafc2e9adac32ab7aac49693dfbf83724c2ec0736ee31c80291",
--     "c773218c737ec8ee993b4f2ded30f48edace915f",
--     "626d027839ea0a13413163a55b4cb500299d5522956cefcb3bff10f399ce2c2e71cb9de5fa24
--      babf58e5b79521925c9cc42e9f6f464b088cc572af53e6d78802"), as given at the bottom of
--    page 21
  -- space requir 
  ,/8an class='hs-
  ,/8an class='hs-
  import Foreign.ForeignPtr (ForeignPtrmaxLen) >>= interpret
    where
 ->dointerpret
<='hs-varid'an>
  ,/8an class='hs-               else           Foreign.C
import           Forndn class='hs-conid'>ASN1ld be:
  interpret
<='hs-varid'an>
    )
\ () -> Ptpan class='hsd'>ForeignPtrfespan> CUChar)   -- the encrypted counter (CTR mode)
     )          () ptr 
foreign BIGNUM) interpret
<='hs-varid'an>
<ithe en-EVP-Internal.html#t:EVP_PKEY">EVP_PKEY.

:: CInt :: CInt :: CInt2espn4lass=&src"> conid'>CInt208s=pan class='hs(>IO /8an classe5bbd9>.

<s 5romPKey ::i"df496ted by HsColour,class='hs-cilass='hs-keyglyph'><- .

The new format, whose header is "NEW CERTIFICATE REQUEST".

ReqOldFormat

The old format, whose header is "CERTIFICATE REQUEST".< id'>dsaPtr Nothing -> x xhs-key>Nothing x (\hsc_ptr -> peekByteOff d'>Just seed ->Zspan> <Ptpan class='hsd'>ForeignPtvarihs-varid'>d'>Justxdaaaaaaaaaaaaaaaar333333333333333333666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666/a> x>IO x>IO x>IO x>IO \>>=) )) #endif import Foreign.Ptr .Ptr .Ptr ..withBNCtx (\ctx Ptr .Ptr .>>= intun class='hs-varident'>-- hc ever, in some cases you cannot do without using the OpenSSL -- fuctions directly. ByteString -> CryptoMode -> dsa_free :: Pty DSA x>IO \>>=) lyph'>\buffer -> &/tr>xdaaaaaaaaaaaaaaaar3333333333333333336666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666633366666666666666666666666666666666666666666addock version 2.17.2

ÄÞÏåla:s='hs-keygly:ss=&srcroot name="line-29"> sc/span>Just .Just sc/span> (unsafe <66666666666span> <6tut'>( :2baries/bysout'>(> =/span>n> withForeignPtr b $ \ bPpan clasa16d40='hs-varb4'>b $s-keyglyph'>\ bPpan clasa16d40='hs-varb40>b $me="li> createAndTp'>$me="eyglyph'0>