module Data.Certificate.X509
(
X509(..)
, SignatureALG(..)
, HashALG(..)
, PubKeyALG(..)
, PubKey(..)
, OID
, ASN1StringType(..)
, ASN1String
, DistinguishedName
, Certificate(..)
, module Data.Certificate.X509.Ext
, getSigningData
, decodeCertificate
, encodeCertificate
, decodeDN
, encodeDN
) where
import Data.Word
import Data.ASN1.Encoding
import Data.ASN1.BinaryEncoding
import qualified Data.ASN1.BinaryEncoding.Raw as Raw (toLazyByteString)
import Data.ASN1.Stream
import Data.ASN1.BitArray
import qualified Data.ByteString.Lazy as L
import Data.Certificate.X509.Internal
import Data.Certificate.X509.Cert hiding (encodeDN)
import qualified Data.Certificate.X509.Cert as Cert
import Data.Certificate.X509.Ext
data X509 = X509
{ x509Cert :: Certificate
, x509CachedSigningData :: (Maybe L.ByteString)
, x509CachedData :: (Maybe L.ByteString)
, x509SignatureALG :: SignatureALG
, x509Signature :: [Word8]
} deriving (Show)
instance Eq X509 where
x1 == x2 =
(x509Cert x1 == x509Cert x2) &&
(x509SignatureALG x1 == x509SignatureALG x2) &&
(x509Signature x1 == x509Signature x2)
getSigningData :: X509 -> L.ByteString
getSigningData (X509 _ (Just e) _ _ _) = e
getSigningData (X509 cert Nothing _ _ _) = encodeASN1 DER header
where header = asn1Container Sequence $ encodeCertificateHeader cert
decodeCertificate :: L.ByteString -> Either String X509
decodeCertificate by = either (Left . show) parseRootASN1 $ decodeASN1Repr BER 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 = Raw.toLazyByteString $ concatMap snd certrepr in
let sigalg = onContainer sigalgseq (parseSigAlg . map fst) in
Right $ X509 c (Just certevs) (Just by) sigalg (L.unpack $ bitArrayGetData 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) = encodeASN1 DER rootSeq
where
esigalg = asn1Container Sequence [OID (sigOID sigalg), Null]
esig = BitString $ toBitArray (L.pack sigbits) 0
header = asn1Container Sequence $ encodeCertificateHeader cert
rootSeq = asn1Container Sequence (header ++ esigalg ++ [esig])
decodeDN :: L.ByteString -> Either String DistinguishedName
decodeDN by = either (Left . show) (runParseASN1 parseDN) $ decodeASN1 BER by
encodeDN :: DistinguishedName -> L.ByteString
encodeDN dn = encodeASN1 DER $ Cert.encodeDN dn