-- | -- Module : Data.Certificate.X509 -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : experimental -- Portability : unknown -- -- Read/Write X509 certificate -- module Data.Certificate.X509 ( -- * Data Structure X509(..) -- * Data Structure (reexported from X509Cert) , SignatureALG(..) , PubKeyALG(..) , PubKey(..) , ASN1StringType(..) , ASN1String , Certificate(..) , CertificateExts(..) -- * helper for signing/veryfing certificate , getSigningData -- * serialization from ASN1 bytestring , decodeCertificate , encodeCertificate ) where import Data.Word import Data.ASN1.DER import Data.ASN1.Stream (getConstructedEndRepr) import Data.ASN1.Raw (toBytes) import qualified Data.ByteString.Lazy as L import Data.Certificate.X509Internal import Data.Certificate.X509Cert data X509 = X509 Certificate (Maybe L.ByteString) SignatureALG [Word8] deriving (Show,Eq) {- | get signing data related to a X509 message, - which is either the cached data or the encoded certificate -} getSigningData :: X509 -> L.ByteString getSigningData (X509 _ (Just e) _ _) = e getSigningData (X509 cert Nothing _ _) = e where (Right e) = encodeASN1Stream header header = asn1Container Sequence $ encodeCertificateHeader cert {- | decode an X509 from a bytestring - the structure is the following: - Certificate - Certificate Signature Algorithm - Certificate Signature -} decodeCertificate :: L.ByteString -> Either String X509 decodeCertificate by = either (Left . show) parseRootASN1 $ decodeASN1StreamRepr by where {- | parse root structure of a x509 certificate. this has to be a sequence of 3 objects : - * the header - * the signature algorithm - * the signature -} parseRootASN1 l = onContainer rootseq $ \l2 -> let (certrepr,rem1) = getConstructedEndRepr l2 in let (sigalgseq,rem2) = getConstructedEndRepr rem1 in let (sigseq,_) = getConstructedEndRepr rem2 in let cert = onContainer certrepr (runParseASN1 parseCertificate . map fst) in case (cert, map fst sigseq) of (Right c, [BitString _ b]) -> let certevs = toBytes $ concatMap snd certrepr in let sigalg = onContainer sigalgseq (parseSigAlg . map fst) in Right $ X509 c (Just certevs) sigalg (L.unpack b) (Left err, _) -> Left $ ("certificate error: " ++ show err) _ -> Left $ "certificate structure error" where (rootseq, _) = getConstructedEndRepr l onContainer ((Start _, _) : l) f = case reverse l of ((End _, _) : l2) -> f $ reverse l2 _ -> f [] onContainer _ f = f [] parseSigAlg [ OID oid, Null ] = oidSig oid parseSigAlg _ = SignatureALG_Unknown [] {-| encode a X509 certificate to a bytestring -} encodeCertificate :: X509 -> L.ByteString encodeCertificate (X509 cert _ sigalg sigbits) = case encodeASN1Stream rootSeq of Right x -> x Left err -> error (show err) where esigalg = asn1Container Sequence [OID (sigOID sigalg), Null] esig = BitString 0 $ L.pack sigbits header = asn1Container Sequence $ encodeCertificateHeader cert rootSeq = asn1Container Sequence (header ++ esigalg ++ [esig])