1-- |
2-- Module      : Data.X509
3-- License     : BSD-style
4-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
5-- Stability   : experimental
6-- Portability : unknown
7--
8-- Read/Write X509 Certificate, CRL and their signed equivalents.
9--
10-- Follows RFC5280 / RFC6818
11--
12module Data.X509
13    (
14    -- * Types
15      SignedCertificate
16    , SignedCRL
17    , Certificate(..)
18    , PubKey(..)
19    , PubKeyEC(..)
20    , SerializedPoint(..)
21    , PrivKey(..)
22    , PrivKeyEC(..)
23    , pubkeyToAlg
24    , privkeyToAlg
25    , module Data.X509.AlgorithmIdentifier
26    , module Data.X509.Ext
27    , module Data.X509.ExtensionRaw
28
29    -- * Certificate Revocation List (CRL)
30    , module Data.X509.CRL
31
32    -- * Naming
33    , DistinguishedName(..)
34    , DnElement(..)
35    , ASN1CharacterString(..)
36    , getDnElement
37
38    -- * Certificate Chain
39    , module Data.X509.CertificateChain
40
41    -- * Signed types and marshalling
42    , Signed(..)
43    , SignedExact
44    , getSigned
45    , getSignedData
46    , objectToSignedExact
47    , objectToSignedExactF
48    , encodeSignedObject
49    , decodeSignedObject
50
51    -- * Parametrized Signed accessor
52    , getCertificate
53    , getCRL
54    , decodeSignedCertificate
55    , decodeSignedCRL
56
57    -- * Hash distinguished names related function
58    , hashDN
59    , hashDN_old
60    ) where
61
62import Control.Arrow (second)
63
64import Data.ASN1.Types
65import Data.ASN1.Encoding
66import Data.ASN1.BinaryEncoding
67import qualified Data.ByteString as B
68import qualified Data.ByteArray as BA
69
70import Data.X509.Cert
71import Data.X509.Ext
72import Data.X509.ExtensionRaw
73import Data.X509.CRL
74import Data.X509.CertificateChain
75import Data.X509.DistinguishedName
76import Data.X509.Signed
77import Data.X509.PublicKey
78import Data.X509.PrivateKey
79import Data.X509.AlgorithmIdentifier
80
81import Crypto.Hash
82
83-- | A Signed Certificate
84type SignedCertificate = SignedExact Certificate
85
86-- | A Signed CRL
87type SignedCRL         = SignedExact CRL
88
89-- | Get the Certificate associated to a SignedCertificate
90getCertificate :: SignedCertificate -> Certificate
91getCertificate = signedObject . getSigned
92
93-- | Get the CRL associated to a SignedCRL
94getCRL :: SignedCRL -> CRL
95getCRL = signedObject . getSigned
96
97-- | Try to decode a bytestring to a SignedCertificate
98decodeSignedCertificate :: B.ByteString -> Either String SignedCertificate
99decodeSignedCertificate = decodeSignedObject
100
101-- | Try to decode a bytestring to a SignedCRL
102decodeSignedCRL :: B.ByteString -> Either String SignedCRL
103decodeSignedCRL = decodeSignedObject
104
105-- | Make an OpenSSL style hash of distinguished name
106--
107-- OpenSSL algorithm is odd, and has been replicated here somewhat.
108-- only lower the case of ascii character.
109hashDN :: DistinguishedName -> B.ByteString
110hashDN = shorten . hashWith SHA1 . encodeASN1' DER . flip toASN1 [] . DistinguishedNameInner . dnLowerUTF8
111    where dnLowerUTF8 (DistinguishedName l) = DistinguishedName $ map (second toLowerUTF8) l
112          toLowerUTF8 (ASN1CharacterString _ s) = ASN1CharacterString UTF8 (B.map asciiToLower s)
113          asciiToLower c
114            | c >= w8A && c <= w8Z = fromIntegral (fromIntegral c - fromEnum 'A' + fromEnum 'a')
115            | otherwise            = c
116          w8A = fromIntegral $ fromEnum 'A'
117          w8Z = fromIntegral $ fromEnum 'Z'
118
119-- | Create an openssl style old hash of distinguished name
120hashDN_old :: DistinguishedName -> B.ByteString
121hashDN_old = shorten . hashWith MD5 . encodeASN1' DER . flip toASN1 []
122
123shorten :: Digest a -> B.ByteString
124shorten b = B.pack $ map i [3,2,1,0]
125    where i n = BA.index b n
126