packages feed

x509-ocsp-0.1.0.0: Data/X509/AIA.hs

{-# LANGUAGE RecordWildCards, PatternSynonyms #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Data.X509.AIA
-- Copyright   :  (c) Alexey Radkov 2024
-- License     :  BSD-style
--
-- Maintainer  :  alexey.radkov@gmail.com
-- Stability   :  experimental
-- Portability :  portable
--
-- Encode and decode X509 Authority Information Access extension.
--
-- This module complies with /rfc5280/.
-----------------------------------------------------------------------------

module Data.X509.AIA (ExtAuthorityInfoAccess (..)
                     ,AuthorityInfoAccess (..)
                     ,AIAMethod (..)
                     ) where

import Data.X509
import Data.ASN1.Types
import Data.ByteString (ByteString)

pattern OidAIA :: [Integer]
pattern OidAIA = [1, 3, 6, 1, 5, 5, 7, 1, 1]

pattern OidOCSP :: [Integer]
pattern OidOCSP = [1, 3, 6, 1, 5, 5, 7, 48, 1]

pattern OidCAIssuers :: [Integer]
pattern OidCAIssuers = [1, 3, 6, 1, 5, 5, 7, 48, 2]

-- | Authority Info Access extension.
newtype ExtAuthorityInfoAccess = ExtAuthorityInfoAccess [AuthorityInfoAccess]
    deriving (Show, Eq)

-- | Authority Info Access description.
data AuthorityInfoAccess = AuthorityInfoAccess { aiaMethod :: AIAMethod
                                               , aiaLocation :: ByteString
                                               } deriving (Show, Eq)

-- | Method of Authority Info Access (/OCSP/ or /CA issuers/).
data AIAMethod = OCSP | CAIssuers deriving (Show, Eq)

instance OIDable AIAMethod where
    getObjectID OCSP = OidOCSP
    getObjectID CAIssuers = OidCAIssuers

instance OIDNameable AIAMethod where
    fromObjectID OidOCSP = Just OCSP
    fromObjectID OidCAIssuers = Just CAIssuers
    fromObjectID _ = Nothing

data DecState = DecStart | DecMethod | DecLocation | DecEnd

instance Extension ExtAuthorityInfoAccess where
    extOID = const OidAIA
    extHasNestedASN1 = const True
    extEncode (ExtAuthorityInfoAccess aia) =
        Start Sequence
        : concatMap (\AuthorityInfoAccess {..} ->
                        [ Start Sequence
                        , OID $ getObjectID aiaMethod
                        , Other Context 6 aiaLocation
                        , End Sequence
                        ]
                    ) aia
        ++ [End Sequence]
    extDecode [Start Sequence, End Sequence] =
        Right $ ExtAuthorityInfoAccess []
    extDecode (Start Sequence : encAia) =
        go DecStart Nothing encAia []
        where go DecStart Nothing (Start Sequence : next) =
                  go DecMethod Nothing next
              go DecMethod Nothing (OID v : next) =
                  go DecLocation (Just v) next
              go DecLocation (Just v) (Other Context 6 s : next) =
                  case fromObjectID v of
                      Nothing -> const $ Left "bad AIA method"
                      Just v' -> go DecEnd Nothing next
                                        . (AuthorityInfoAccess v' s :)
              go DecEnd Nothing (End Sequence : next@(Start Sequence : _)) =
                  go DecStart Nothing next
              go DecEnd Nothing [End Sequence, End Sequence] =
                  Right . ExtAuthorityInfoAccess . reverse
              go _ _ _ = const $ Left "bad or incompatible AIA sequence"
    extDecode _ =
        Left "bad AIA sequence"