{-# LANGUAGE DeriveDataTypeable       #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE CApiFFI #-}
-- |Message verification using asymmetric cipher and message digest
-- algorithm. This is an opposite of "OpenSSL.EVP.Sign".
module OpenSSL.EVP.Verify
    ( VerifyStatus(..)
    , verify
    , verifyBS
    , verifyLBS
    )
    where
import qualified Data.ByteString.Char8 as B8
import qualified Data.ByteString.Lazy.Char8 as L8
import qualified Data.ByteString.Unsafe as B8
import           Data.Typeable
import           Foreign
import           Foreign.C
import           OpenSSL.EVP.Digest
import           OpenSSL.EVP.PKey
import           OpenSSL.EVP.Internal
import           OpenSSL.Utils

-- |@'VerifyStatus'@ represents a result of verification.
data VerifyStatus = VerifySuccess
                  | VerifyFailure
                    deriving (Int -> VerifyStatus -> ShowS
[VerifyStatus] -> ShowS
VerifyStatus -> String
(Int -> VerifyStatus -> ShowS)
-> (VerifyStatus -> String)
-> ([VerifyStatus] -> ShowS)
-> Show VerifyStatus
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [VerifyStatus] -> ShowS
$cshowList :: [VerifyStatus] -> ShowS
show :: VerifyStatus -> String
$cshow :: VerifyStatus -> String
showsPrec :: Int -> VerifyStatus -> ShowS
$cshowsPrec :: Int -> VerifyStatus -> ShowS
Show, VerifyStatus -> VerifyStatus -> Bool
(VerifyStatus -> VerifyStatus -> Bool)
-> (VerifyStatus -> VerifyStatus -> Bool) -> Eq VerifyStatus
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: VerifyStatus -> VerifyStatus -> Bool
$c/= :: VerifyStatus -> VerifyStatus -> Bool
== :: VerifyStatus -> VerifyStatus -> Bool
$c== :: VerifyStatus -> VerifyStatus -> Bool
Eq, Typeable)


foreign import capi unsafe "openssl/evp.h EVP_VerifyFinal"
        _VerifyFinal :: Ptr EVP_MD_CTX -> Ptr CChar -> CUInt -> Ptr EVP_PKEY -> IO CInt


verifyFinalBS :: PublicKey k =>
                 DigestCtx
              -> B8.ByteString
              -> k
              -> IO VerifyStatus
verifyFinalBS :: forall k.
PublicKey k =>
DigestCtx -> ByteString -> k -> IO VerifyStatus
verifyFinalBS DigestCtx
ctx ByteString
sig k
k
    = DigestCtx -> (Ptr EVP_MD_CTX -> IO VerifyStatus) -> IO VerifyStatus
forall a. DigestCtx -> (Ptr EVP_MD_CTX -> IO a) -> IO a
withDigestCtxPtr DigestCtx
ctx ((Ptr EVP_MD_CTX -> IO VerifyStatus) -> IO VerifyStatus)
-> (Ptr EVP_MD_CTX -> IO VerifyStatus) -> IO VerifyStatus
forall a b. (a -> b) -> a -> b
$ \ Ptr EVP_MD_CTX
ctxPtr ->
      ByteString -> (CStringLen -> IO VerifyStatus) -> IO VerifyStatus
forall a. ByteString -> (CStringLen -> IO a) -> IO a
B8.unsafeUseAsCStringLen ByteString
sig ((CStringLen -> IO VerifyStatus) -> IO VerifyStatus)
-> (CStringLen -> IO VerifyStatus) -> IO VerifyStatus
forall a b. (a -> b) -> a -> b
$ \ (Ptr CChar
buf, Int
len) ->
      k -> (Ptr EVP_PKEY -> IO VerifyStatus) -> IO VerifyStatus
forall k a. PKey k => k -> (Ptr EVP_PKEY -> IO a) -> IO a
withPKeyPtr' k
k ((Ptr EVP_PKEY -> IO VerifyStatus) -> IO VerifyStatus)
-> (Ptr EVP_PKEY -> IO VerifyStatus) -> IO VerifyStatus
forall a b. (a -> b) -> a -> b
$ \ Ptr EVP_PKEY
pkeyPtr ->
      Ptr EVP_MD_CTX -> Ptr CChar -> CUInt -> Ptr EVP_PKEY -> IO CInt
_VerifyFinal Ptr EVP_MD_CTX
ctxPtr Ptr CChar
buf (Int -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len) Ptr EVP_PKEY
pkeyPtr IO CInt -> (CInt -> IO VerifyStatus) -> IO VerifyStatus
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CInt -> IO VerifyStatus
interpret
    where
      interpret :: CInt -> IO VerifyStatus
      interpret :: CInt -> IO VerifyStatus
interpret CInt
1 = VerifyStatus -> IO VerifyStatus
forall (m :: * -> *) a. Monad m => a -> m a
return VerifyStatus
VerifySuccess
      interpret CInt
0 = VerifyStatus -> IO VerifyStatus
forall (m :: * -> *) a. Monad m => a -> m a
return VerifyStatus
VerifyFailure
      interpret CInt
_ = IO VerifyStatus
forall a. IO a
raiseOpenSSLError

-- |@'verify'@ verifies a signature and a stream of data. The string
-- must not contain any letters which aren't in the range of U+0000 -
-- U+00FF.
verify :: PublicKey key =>
          Digest          -- ^ message digest algorithm to use
       -> String          -- ^ message signature
       -> key             -- ^ public key to verify the signature
       -> String          -- ^ input string to verify
       -> IO VerifyStatus -- ^ the result of verification
{-# DEPRECATED verify "Use verifyBS or verifyLBS instead." #-}
verify :: forall key.
PublicKey key =>
Digest -> String -> key -> String -> IO VerifyStatus
verify Digest
md String
sig key
pkey String
input
    = Digest -> ByteString -> key -> ByteString -> IO VerifyStatus
forall key.
PublicKey key =>
Digest -> ByteString -> key -> ByteString -> IO VerifyStatus
verifyLBS Digest
md (String -> ByteString
B8.pack String
sig) key
pkey (String -> ByteString
L8.pack String
input)

-- |@'verifyBS'@ verifies a signature and a chunk of data.
verifyBS :: PublicKey key =>
            Digest          -- ^ message digest algorithm to use
         -> B8.ByteString   -- ^ message signature
         -> key             -- ^ public key to verify the signature
         -> B8.ByteString   -- ^ input string to verify
         -> IO VerifyStatus -- ^ the result of verification
verifyBS :: forall key.
PublicKey key =>
Digest -> ByteString -> key -> ByteString -> IO VerifyStatus
verifyBS Digest
md ByteString
sig key
pkey ByteString
input
    = do DigestCtx
ctx <- Digest -> ByteString -> IO DigestCtx
digestStrictly Digest
md ByteString
input
         DigestCtx -> ByteString -> key -> IO VerifyStatus
forall k.
PublicKey k =>
DigestCtx -> ByteString -> k -> IO VerifyStatus
verifyFinalBS DigestCtx
ctx ByteString
sig key
pkey

-- |@'verifyLBS'@ verifies a signature of a stream of data.
verifyLBS :: PublicKey key =>
             Digest          -- ^ message digest algorithm to use
          -> B8.ByteString   -- ^ message signature
          -> key             -- ^ public key to verify the signature
          -> L8.ByteString   -- ^ input string to verify
          -> IO VerifyStatus -- ^ the result of verification
verifyLBS :: forall key.
PublicKey key =>
Digest -> ByteString -> key -> ByteString -> IO VerifyStatus
verifyLBS Digest
md ByteString
sig key
pkey ByteString
input
    = do DigestCtx
ctx <- Digest -> ByteString -> IO DigestCtx
digestLazily Digest
md ByteString
input
         DigestCtx -> ByteString -> key -> IO VerifyStatus
forall k.
PublicKey k =>
DigestCtx -> ByteString -> k -> IO VerifyStatus
verifyFinalBS DigestCtx
ctx ByteString
sig key
pkey