data-rfc5280-0.1.0.0: test/Rfc5280Spec.hs
{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Rfc5280Spec
Copyright : (c) 2026 Tim Emiola
Maintainer : Tim Emiola <adetokunbo@emio.la>
SPDX-License-Identifier: BSD3
-}
module Rfc5280Spec (spec) where
import Data.Rfc5280
import Test.Hspec
spec :: Spec
spec = describe "module Data.Rfc5280" $ do
context "BasicConstraints" $ do
it "renders a non-CA certificate" $
renderConfig notCA `shouldBe` "CA:FALSE"
it "renders a CA certificate" $
renderConfig isCA `shouldBe` "CA:TRUE"
it "renders a CA certificate with path length" $
renderConfig caWithPathLen `shouldBe` "CA:TRUE,pathLen3"
context "KeyUsage" $ do
it "renders multiple bits" $
renderConfig simpleKeyUsage `shouldBe` "digitalSignature,cRLSign"
it "renders a single bit without a comma" $
renderConfig singleKeyUsage `shouldBe` "digitalSignature"
it "renders all bits in Enum order" $
renderConfig allKeyUsageBits
`shouldBe` "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign,encipherOnly,decipherOnly"
context "ExtKeyUsage" $ do
it "renders multiple purposes" $
renderConfig simpleExtKeyUsage `shouldBe` "serverAuth,codeSigning"
it "renders a single purpose without a comma" $
renderConfig singleExtKeyUsage `shouldBe` "serverAuth"
it "renders all purposes in Enum order" $
renderConfig allExtKeyUsagePurposes
`shouldBe` "serverAuth,clientAuth,codeSigning,emailProtection,timeStamping,OCSPSigning,anyExtendedKeyUsage"
context "SubjectKeyIdentifier" $ do
it "renders the hash method" $
renderConfig HashMethod `shouldBe` "hash"
it "renders raw bytes" $
renderConfig (Raw "abc") `shouldBe` "abc"
context "AuthorityKeyIdentifier" $ do
it "renders keyid:always" $
renderConfig simpleAKI `shouldBe` "keyid:always"
it "renders keyid" $
renderConfig keyIdOnly `shouldBe` "keyid"
it "renders issuer" $
renderConfig issuerOnly `shouldBe` "issuer"
it "renders issuer:always" $
renderConfig issuerAlwaysAKI `shouldBe` "issuer:always"
it "renders keyid:always and issuer:always combined" $
renderConfig bothAlways `shouldBe` "keyid:always,issuer:always"
it "renders empty when all flags are disabled" $
renderConfig allDisabled `shouldBe` ""
context "CertificatePolicies" $ do
it "renders a single OID" $
renderConfig simpleCP `shouldBe` "1.2.3.4"
it "renders multiple OIDs" $
renderConfig twoOIDs `shouldBe` "1.2.3.4,2.5.4.3"
context "mkBasicConstraints" $ do
it "accepts a non-CA without path length" $
mkBasicConstraints False Nothing `shouldBe` Right notCA
it "accepts a CA without path length" $
mkBasicConstraints True Nothing `shouldBe` Right isCA
it "accepts a CA with path length" $
mkBasicConstraints True (Just 3) `shouldBe` Right caWithPathLen
it "rejects a non-CA with path length" $
mkBasicConstraints False (Just 0) `shouldBe` Left PathLenWithoutCA
context "mkAuthorityKeyIdentifier" $
it "sets keyId when keyIdAlways is True" $
mkAuthorityKeyIdentifier False True False False
`shouldBe` AuthorityKeyIdentifier
{ akiKeyId = True
, akiKeyIdAlways = True
, akiIssuer = False
, akiIssuerAlways = False
}
context "mkOID" $ do
it "accepts a valid OID" $
mkOID 1 [2, 3, 4] `shouldBe` Right (1 :| [2, 3, 4])
it "rejects a negative first arc" $
mkOID (-1) [] `shouldBe` Left InvalidFirstArc
it "rejects a first arc greater than 2" $
mkOID 3 [] `shouldBe` Left InvalidFirstArc
it "rejects a negative subsequent arc" $
mkOID 1 [-1] `shouldBe` Left NegativeArc
notCA :: BasicConstraints
notCA = BasicConstraints{bcIsCA = False, bcPathLength = Nothing}
isCA :: BasicConstraints
isCA = BasicConstraints{bcIsCA = True, bcPathLength = Nothing}
caWithPathLen :: BasicConstraints
caWithPathLen = BasicConstraints{bcIsCA = True, bcPathLength = Just 3}
simpleKeyUsage :: KeyUsage
simpleKeyUsage = fromList $ DigitalSignature :| [CRLSign]
singleKeyUsage :: KeyUsage
singleKeyUsage = fromList $ DigitalSignature :| []
allKeyUsageBits :: KeyUsage
allKeyUsageBits = fromList $ DigitalSignature :| [NonRepudiation, KeyEncipherment, DataEncipherment, KeyAgreement, KeyCertSign, CRLSign, EncipherOnly, DecipherOnly]
simpleExtKeyUsage :: ExtKeyUsage
simpleExtKeyUsage = fromList $ ServerAuth :| [CodeSigning]
singleExtKeyUsage :: ExtKeyUsage
singleExtKeyUsage = fromList $ ServerAuth :| []
allExtKeyUsagePurposes :: ExtKeyUsage
allExtKeyUsagePurposes = fromList $ ServerAuth :| [ClientAuth, CodeSigning, EmailProtection, TimeStamping, OCSPSigning, AnyExtendedKeyUsage]
simpleAKI :: AuthorityKeyIdentifier
simpleAKI = AuthorityKeyIdentifier{akiKeyId = True, akiKeyIdAlways = True, akiIssuer = False, akiIssuerAlways = False}
keyIdOnly :: AuthorityKeyIdentifier
keyIdOnly = AuthorityKeyIdentifier{akiKeyId = True, akiKeyIdAlways = False, akiIssuer = False, akiIssuerAlways = False}
issuerOnly :: AuthorityKeyIdentifier
issuerOnly = AuthorityKeyIdentifier{akiKeyId = False, akiKeyIdAlways = False, akiIssuer = True, akiIssuerAlways = False}
issuerAlwaysAKI :: AuthorityKeyIdentifier
issuerAlwaysAKI = AuthorityKeyIdentifier{akiKeyId = False, akiKeyIdAlways = False, akiIssuer = False, akiIssuerAlways = True}
bothAlways :: AuthorityKeyIdentifier
bothAlways = AuthorityKeyIdentifier{akiKeyId = False, akiKeyIdAlways = True, akiIssuer = False, akiIssuerAlways = True}
allDisabled :: AuthorityKeyIdentifier
allDisabled = AuthorityKeyIdentifier{akiKeyId = False, akiKeyIdAlways = False, akiIssuer = False, akiIssuerAlways = False}
simpleCP :: CertificatePolicies
simpleCP = mkCertificatePolicies (1 :| [2, 3, 4]) []
twoOIDs :: CertificatePolicies
twoOIDs = mkCertificatePolicies (1 :| [2, 3, 4]) [2 :| [5, 4, 3]]