module Data.Certificate.X509
(
X509(..)
, SignatureALG(..)
, PubKeyALG(..)
, PubKey(..)
, ASN1StringType(..)
, ASN1String
, Certificate(..)
, CertificateExts(..)
, getSigningData
, 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) (Maybe L.ByteString) SignatureALG [Word8]
deriving (Show,Eq)
getSigningData :: X509 -> L.ByteString
getSigningData (X509 _ (Just e) _ _ _) = e
getSigningData (X509 cert Nothing _ _ _) = e
where
(Right e) = encodeASN1Stream header
header = asn1Container Sequence $ encodeCertificateHeader cert
decodeCertificate :: L.ByteString -> Either String X509
decodeCertificate by = either (Left . show) parseRootASN1 $ decodeASN1StreamRepr by
where
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) (Just by) 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 []
encodeCertificate :: X509 -> L.ByteString
encodeCertificate (X509 _ _ (Just lbs) _ _ ) = lbs
encodeCertificate (X509 cert _ Nothing 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])