packages feed

xml-verify-0.1.0.0: src/Crypto/PubKey/Xml.hs

{-# LANGUAGE ForeignFunctionInterface, ViewPatterns #-}

{-|
Description: Library for Verifying XML Signatures
-}


module Crypto.PubKey.Xml
( -- * Verifying
  verifyXml
, verifyXmlFile
, verifyXmlPem
, verifyXmlFilePem
) where

import Text.XML.HXT.Core
import Control.Monad.Trans
import Data.X509
import Data.PEM
import Data.Maybe
import qualified Data.ByteString as BS
import Crypto.Store.X509
import Foreign.C.Types
import Foreign.C.String
import Crypto.PubKey.Xml.Errors

foreign import ccall "verify_file" cVerifyFile :: CString -> CString -> CSize -> IO CInt
foreign import ccall "verify_file_pem" cVerifyFilePem :: CString -> CString -> IO CInt
foreign import ccall "verify_doc" cVerifyDoc :: CString -> CSize -> CString -> CSize -> IO CInt
foreign import ccall "verify_doc_pem" cVerifyDocPem :: CString -> CSize -> CString -> IO CInt

returnCode :: CInt -> Either XmlVerifyError Bool
returnCode ( 0 ) = Right True
returnCode (-1 ) = Right False
returnCode (-2 ) = Left XmlSecInitFailed
returnCode (-3 ) = Left XmlSecIncomp     
returnCode (-4 ) = Left XmlSecCryptoFail
returnCode (-5 ) = Left CryptoInitFailed
returnCode (-6 ) = Left XmlCryptoFailed 
returnCode (-7 ) = Left XmlParseFail    
returnCode (-8 ) = Left XmlNoStartNode  
returnCode (-9 ) = Left XmlSigCreateFail
returnCode (-10) = Left XmlPemLoadFail  
returnCode (-11) = Left XmlPemNameFail  
returnCode (-12) = Left VeryifyFail
returnCode  _    = Right False

-- | verify XML file with given public key
verifyXmlFile :: (MonadIO m) => FilePath -> PubKey -> m (Either XmlVerifyError Bool)
verifyXmlFile xml key = do
  let pem = writePubKeyFileToMemory [key]
  ret <- liftIO $ withCString xml $
    \cXml -> BS.useAsCStringLen pem $
    \(cPem, fromIntegral -> len) -> fromIntegral <$> cVerifyFile cXml cPem len
  return $ returnCode ret

-- | verify XML document with given public key
verifyXml :: (MonadIO m) => XmlTree -> PubKey -> m (Either XmlVerifyError Bool)
verifyXml xml key = do
  let pem = writePubKeyFileToMemory [key]
  let xml' = listToMaybe $ runLA (writeDocumentToString []) xml
  case xml' of
    Nothing  -> return $ Left XmlParseFail
    Just xml -> do
      ret <- liftIO $ withCStringLen xml $
        \(cXml, fromIntegral -> xLen) -> BS.useAsCStringLen pem $
        \(cPem, fromIntegral -> pLen) -> fromIntegral <$> cVerifyDoc cXml xLen cPem pLen
      return $ returnCode ret

-- | verify XML file against a public key in a pem file
verifyXmlFilePem :: (MonadIO m) => FilePath -- ^ XML document path
                                -> FilePath -- ^ PEM file path
                                -> m (Either XmlVerifyError Bool)
verifyXmlFilePem xml pem = do
  ret <- liftIO $ withCString xml $
    \cXml -> withCString pem $ 
    \cPem -> fromIntegral <$> cVerifyFilePem cXml cPem
  return $ returnCode ret

-- | Verify XML against a public key provided in a pem file
verifyXmlPem :: (MonadIO m) => XmlTree -> FilePath -> m (Either XmlVerifyError Bool)
verifyXmlPem xml pem = do
  let xml' = listToMaybe $ runLA (writeDocumentToString []) xml
  case xml' of
    Nothing  -> return $ Left XmlParseFail
    Just xml -> do
      ret <- liftIO $ withCStringLen xml $
        \(cXml, fromIntegral -> xLen) -> withCString pem $
        \cPem                         -> fromIntegral <$> cVerifyDocPem cXml xLen cPem
      return $ returnCode ret