module Data.X509.Cert (Certificate(..)) where
import Data.ASN1.Types
import Control.Applicative ((<$>), (<*>))
import Data.X509.Internal
import Data.X509.PublicKey
import Data.X509.AlgorithmIdentifier
import Data.X509.DistinguishedName
import Data.X509.ExtensionRaw
import Data.Hourglass
data CertKeyUsage =
CertKeyUsageDigitalSignature
| CertKeyUsageNonRepudiation
| CertKeyUsageKeyEncipherment
| CertKeyUsageDataEncipherment
| CertKeyUsageKeyAgreement
| CertKeyUsageKeyCertSign
| CertKeyUsageCRLSign
| CertKeyUsageEncipherOnly
| CertKeyUsageDecipherOnly
deriving (Show, Eq)
data Certificate = Certificate
{ certVersion :: Int
, certSerial :: Integer
, certSignatureAlg :: SignatureALG
, certIssuerDN :: DistinguishedName
, certValidity :: (DateTime, DateTime)
, certSubjectDN :: DistinguishedName
, certPubKey :: PubKey
, certExtensions :: Extensions
} deriving (Show,Eq)
instance ASN1Object Certificate where
toASN1 certificate = \xs -> encodeCertificateHeader certificate ++ xs
fromASN1 s = runParseASN1State parseCertificate s
parseCertHeaderVersion :: ParseASN1 Int
parseCertHeaderVersion =
maybe 1 id <$> onNextContainerMaybe (Container Context 0) (getNext >>= getVer)
where getVer (IntVal v) = return $ fromIntegral v
getVer _ = throwError "unexpected type for version"
parseCertHeaderSerial :: ParseASN1 Integer
parseCertHeaderSerial = do
n <- getNext
case n of
IntVal v -> return v
_ -> throwError ("missing serial" ++ show n)
parseCertHeaderValidity :: ParseASN1 (DateTime, DateTime)
parseCertHeaderValidity = getNextContainer Sequence >>= toTimeBound
where toTimeBound [ ASN1Time _ t1 _, ASN1Time _ t2 _ ] = return (t1,t2)
toTimeBound _ = throwError "bad validity format"
parseCertificate :: ParseASN1 Certificate
parseCertificate =
Certificate <$> parseCertHeaderVersion
<*> parseCertHeaderSerial
<*> getObject
<*> getObject
<*> parseCertHeaderValidity
<*> getObject
<*> getObject
<*> getObject
encodeCertificateHeader :: Certificate -> [ASN1]
encodeCertificateHeader cert =
eVer ++ eSerial ++ eAlgId ++ eIssuer ++ eValidity ++ eSubject ++ epkinfo ++ eexts
where eVer = asn1Container (Container Context 0) [IntVal (fromIntegral $ certVersion cert)]
eSerial = [IntVal $ certSerial cert]
eAlgId = toASN1 (certSignatureAlg cert) []
eIssuer = toASN1 (certIssuerDN cert) []
(t1, t2) = certValidity cert
eValidity = asn1Container Sequence [ASN1Time (timeType t1) t1 (Just (TimezoneOffset 0))
,ASN1Time (timeType t2) t2 (Just (TimezoneOffset 0))]
eSubject = toASN1 (certSubjectDN cert) []
epkinfo = toASN1 (certPubKey cert) []
eexts = toASN1 (certExtensions cert) []
timeType t =
if t >= timeConvert (Date 2050 January 1)
then TimeGeneralized
else TimeUTC