-- | -- Module : Crypto.Store.CMS.Digested -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- {-# 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 -- | Digested content information. data DigestedData content = forall hashAlg. HashAlgorithm hashAlg => DigestedData { ddDigestAlgorithm :: DigestProxy hashAlg -- ^ Digest algorithm , ddContentType :: ContentType -- ^ Inner content type , ddEncapsulatedContent :: content -- ^ Encapsulated content , ddDigest :: Digest hashAlg -- ^ Digest value } 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 }