{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RecordWildCards #-}
module Crypto.Store.CMS.Digested
( DigestedData(..)
) where
import Control.Monad
import Data.ASN1.Types
import qualified Data.ByteArray as B
import Crypto.Hash hiding (MD5)
import Crypto.Store.ASN1.Generate
import Crypto.Store.ASN1.Parse
import Crypto.Store.CMS.Algorithms
import Crypto.Store.CMS.Signed
import Crypto.Store.CMS.Type
import Crypto.Store.CMS.Util
data DigestedData content = forall hashAlg. HashAlgorithm hashAlg => DigestedData
{ ddDigestAlgorithm :: DigestProxy hashAlg
, ddContentType :: ContentType
, ddEncapsulatedContent :: content
, ddDigest :: Digest hashAlg
}
instance Show content => Show (DigestedData content) where
showsPrec d DigestedData{..} = showParen (d > 10) $
showString "DigestedData "
. showString "{ ddDigestAlgorithm = " . shows ddDigestAlgorithm
. showString ", ddContentType = " . shows ddContentType
. showString ", ddEncapsulatedContent = " . shows ddEncapsulatedContent
. showString ", ddDigest = " . shows ddDigest
. showString " }"
instance Eq content => Eq (DigestedData content) where
DigestedData a1 t1 e1 d1 == DigestedData a2 t2 e2 d2 =
DigestAlgorithm a1 == DigestAlgorithm a2 && d1 `B.eq` d2 && t1 == t2 && e1 == e2
instance ASN1Elem e => ProduceASN1Object e (DigestedData (Encap EncapsulatedContent)) where
asn1s DigestedData{..} =
asn1Container Sequence (ver . alg . ci . dig)
where
v = if ddContentType == DataType then 0 else 2
d = DigestAlgorithm ddDigestAlgorithm
ver = gIntVal v
alg = algorithmASN1S Sequence d
ci = encapsulatedContentInfoASN1S ddContentType ddEncapsulatedContent
dig = gOctetString (B.convert ddDigest)
instance Monoid e => ParseASN1Object e (DigestedData (Encap EncapsulatedContent)) where
parse =
onNextContainer Sequence $ do
IntVal v <- getNext
when (v /= 0 && v /= 2) $
throwParseError ("DigestedData: parsed invalid version: " ++ show v)
alg <- parseAlgorithm Sequence
(ct, bs) <- parseEncapsulatedContentInfo
OctetString digValue <- getNext
case alg of
DigestAlgorithm digAlg ->
case digestFromByteString digValue of
Nothing -> throwParseError "DigestedData: parsed invalid digest"
Just d ->
return DigestedData { ddDigestAlgorithm = digAlg
, ddContentType = ct
, ddEncapsulatedContent = bs
, ddDigest = d
}