Skip to content

Repository files navigation

data-rfc5280

GitHub CI Stackage Nightly Hackage BSD3

data-rfc5280 provides Haskell types that represent the standard X.509v3 certificate extensions defined in RFC 5280.

Extensions covered include BasicConstraints, KeyUsage, ExtendedKeyUsage, SubjectAltName, IssuerAltName, AuthorityKeyIdentifier, SubjectKeyIdentifier, CertificatePolicies, PolicyMappings, NameConstraints, CRLDistributionPoints, AuthorityInfoAccess, and InhibitAnyPolicy.

Each extension value can be serialised to OpenSSL configuration format as a ByteString, suitable for use with OpenSSL config files.

Example

{-# LANGUAGE OverloadedStrings #-}

import qualified Data.ByteString.Char8 as BC8
import Data.Rfc5280

-- Render a critical nameConstraints extension restricting issuance to
-- .example.com while excluding .evil.example.com.
example :: IO ()
example = do
  permitted <- assertRight $ mkDnsConstraint ".example.com"
  excluded <- assertRight $ mkDnsConstraint ".evil.example.com"
  let nc = mkNameConstraints (Permitted (DNS permitted)) [Excluded (DNS excluded)]
      ext = Extension {extCritical = True, extValue = nc}
  BC8.putStrLn $ renderConfig ext
  -- critical,permitted;DNS:.example.com,excluded;DNS:.evil.example.com

Example: TLS end-entity certificate

{-# LANGUAGE OverloadedStrings #-}

import qualified Data.ByteString.Char8 as BC8
import Data.Rfc5280
import qualified Net.IP as IP

-- Build and render the core extensions for a TLS end-entity certificate.
example2 :: IO ()
example2 = do
  bc  <- assertRight $ mkBasicConstraints False Nothing
  dn1 <- assertRight $ mkDnsName "example.com"
  dn2 <- assertRight $ mkDnsName "www.example.com"
  ip  <- assertJust "invalid IP" $ IP.decode "192.0.2.1"
  let ku  = fromList (DigitalSignature :| [KeyEncipherment]) :: KeyUsage
      eku = fromList (ServerAuth :| [ClientAuth]) :: ExtKeyUsage
      san = mkSubjectAltName (DNS dn1) [DNS dn2, IPAddr ip]
      aki = mkAuthorityKeyIdentifier True False False False
  BC8.putStrLn $ renderConfig $ Extension {extCritical = True,  extValue = bc}
  -- critical,CA:FALSE
  BC8.putStrLn $ renderConfig $ Extension {extCritical = True,  extValue = ku}
  -- critical,digitalSignature,keyEncipherment
  BC8.putStrLn $ renderConfig $ Extension {extCritical = False, extValue = eku}
  -- serverAuth,clientAuth
  BC8.putStrLn $ renderConfig $ Extension {extCritical = False, extValue = san}
  -- DNS:example.com,DNS:www.example.com,IP:192.0.2.1
  BC8.putStrLn $ renderConfig $ Extension {extCritical = False, extValue = HashMethod}
  -- hash
  BC8.putStrLn $ renderConfig $ Extension {extCritical = False, extValue = aki}
  -- keyid

Example: CA infrastructure extensions

{-# LANGUAGE OverloadedStrings #-}

import qualified Data.ByteString.Char8 as BC8
import Data.Rfc5280
import Data.Rfc5280.AuthorityInfoAccess (AccessDescription (..), mkAuthorityInfoAccess)
import Text.URI (mkURI)

-- Build and render CA-infrastructure extensions: certificate policies,
-- authority info access, CRL distribution points, policy mappings, and
-- inhibitAnyPolicy.
example3 :: IO ()
example3 = do
  ocspUri       <- mkURI "https://ocsp.example.com"
  caUri         <- mkURI "https://ca.example.com/ca.crt"
  crlUri        <- mkURI "https://crl.example.com/root.crl"
  anyPolicy     <- assertRight $ mkOID 2 [5, 29, 32, 0]
  customPolicy  <- assertRight $ mkOID 1 [3, 6, 1, 4, 1, 99999, 1]
  issuerDomain  <- assertRight $ mkOID 2 [5, 29, 32, 1]
  subjectDomain <- assertRight $ mkOID 2 [5, 29, 32, 2]
  inhibit       <- assertRight $ mkInhibitAnyPolicy 0
  let cp  = mkCertificatePolicies anyPolicy [customPolicy]
      aia = mkAuthorityInfoAccess
              (OCSP (URIName ocspUri))
              [CAIssuers (URIName caUri)]
      crl = mkCRLDistributionPoints
              (mkDistributionPoint (URIName crlUri))
              []
      pm  = mkPolicyMappings (mkPolicyMapping issuerDomain subjectDomain) []
  BC8.putStrLn $ renderConfig $ Extension {extCritical = False, extValue = cp}
  -- 2.5.29.32.0,1.3.6.1.4.1.99999.1
  BC8.putStrLn $ renderConfig $ Extension {extCritical = False, extValue = aia}
  -- OCSP;URI:https://ocsp.example.com,caIssuers;URI:https://ca.example.com/ca.crt
  BC8.putStrLn $ renderConfig $ Extension {extCritical = False, extValue = crl}
  -- URI:https://crl.example.com/root.crl
  BC8.putStrLn $ renderConfig $ Extension {extCritical = False, extValue = pm}
  -- 2.5.29.32.1:2.5.29.32.2
  BC8.putStrLn $ renderConfig $ Extension {extCritical = True,  extValue = inhibit}
  -- critical,0

About

A haskell library to represent the standard X.509v3 certificate extensions from RFC 5280

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages