warp-s2n-tls-0.1.0.0: test/CertLoadingTests.hs
module CertLoadingTests (certLoadingSpec) where
import Control.Exception (SomeException, try)
import Data.ByteString qualified as BS
import S2nTls (S2nTls (..))
import Test.Hspec (SpecWith, describe, expectationFailure, it, shouldBe, shouldSatisfy)
import Network.Wai.Handler.WarpS2N (
CertSettings (..),
TLSSettings (..),
defaultTlsSettings,
tlsSettings,
tlsSettingsChain,
tlsSettingsChainMemory,
tlsSettingsMemory,
)
import TestUtils
certLoadingSpec :: SpecWith S2nTls
certLoadingSpec = do
describe "Smart constructors" smartConstructorsSpec
describe "File loading" fileLoadingSpec
describe "Memory loading" memoryLoadingSpec
describe "Invalid certificates" invalidCertsSpec
smartConstructorsSpec :: SpecWith S2nTls
smartConstructorsSpec = do
it "tlsSettings creates CertFromFile with empty chain" $ \_ -> do
let settings = tlsSettings "cert.pem" "key.pem"
case tlsCertSettings settings of
CertFromFile cert chain key -> do
cert `shouldBe` "cert.pem"
chain `shouldBe` []
key `shouldBe` "key.pem"
_ -> expectationFailure "Expected CertFromFile"
it "tlsSettingsChain includes chain files" $ \_ -> do
let settings = tlsSettingsChain "cert.pem" ["inter1.pem", "inter2.pem"] "key.pem"
case tlsCertSettings settings of
CertFromFile cert chain key -> do
cert `shouldBe` "cert.pem"
chain `shouldBe` ["inter1.pem", "inter2.pem"]
key `shouldBe` "key.pem"
_ -> expectationFailure "Expected CertFromFile"
it "tlsSettingsMemory creates CertFromMemory" $ \_ -> do
let settings = tlsSettingsMemory "CERT" "KEY"
case tlsCertSettings settings of
CertFromMemory cert chain key -> do
cert `shouldBe` "CERT"
chain `shouldBe` []
key `shouldBe` "KEY"
_ -> expectationFailure "Expected CertFromMemory"
it "tlsSettingsChainMemory includes chain data" $ \_ -> do
let settings = tlsSettingsChainMemory "CERT" ["INTER1", "INTER2"] "KEY"
case tlsCertSettings settings of
CertFromMemory cert chain key -> do
cert `shouldBe` "CERT"
chain `shouldBe` ["INTER1", "INTER2"]
key `shouldBe` "KEY"
_ -> expectationFailure "Expected CertFromMemory"
it "defaultTlsSettings has expected defaults" $ \_ -> do
let settings = defaultTlsSettings
tlsCipherPreferences settings `shouldBe` "default_tls13"
case tlsCertSettings settings of
CertFromFile cert _ key -> do
cert `shouldBe` "certificate.pem"
key `shouldBe` "key.pem"
_ -> expectationFailure "Expected CertFromFile"
fileLoadingSpec :: SpecWith S2nTls
fileLoadingSpec = do
it "loads valid cert and key from files" $ \tls -> do
let settings = tlsSettings testCertPath testKeyPath
result <- try @SomeException $ withTestServer tls settings $ \_ -> pure ()
result `shouldSatisfy` isRight
it "loads cert with empty chain" $ \tls -> do
let settings = tlsSettingsChain testCertPath [] testKeyPath
result <- try @SomeException $ withTestServer tls settings $ \_ -> pure ()
result `shouldSatisfy` isRight
memoryLoadingSpec :: SpecWith S2nTls
memoryLoadingSpec = do
it "loads valid cert and key from memory" $ \tls -> do
cert <- loadTestCert
key <- loadTestKey
let settings = tlsSettingsMemory cert key
result <- try @SomeException $ withTestServer tls settings $ \_ -> pure ()
result `shouldSatisfy` isRight
it "loads cert with empty chain from memory" $ \tls -> do
cert <- loadTestCert
key <- loadTestKey
let settings = tlsSettingsChainMemory cert [] key
result <- try @SomeException $ withTestServer tls settings $ \_ -> pure ()
result `shouldSatisfy` isRight
invalidCertsSpec :: SpecWith S2nTls
invalidCertsSpec = do
it "fails with nonexistent cert file" $ \tls -> do
let settings = tlsSettings "nonexistent-cert.pem" testKeyPath
result <- try @SomeException $ withTestServer tls settings $ \_ -> pure ()
result `shouldSatisfy` isLeft
it "fails with nonexistent key file" $ \tls -> do
let settings = tlsSettings testCertPath "nonexistent-key.pem"
result <- try @SomeException $ withTestServer tls settings $ \_ -> pure ()
result `shouldSatisfy` isLeft
it "fails with invalid PEM data" $ \tls -> do
let settings = tlsSettingsMemory "not a valid cert" "not a valid key"
result <- try @SomeException $ withTestServer tls settings $ \_ -> pure ()
result `shouldSatisfy` isLeft
it "fails with empty cert" $ \tls -> do
let settings = tlsSettingsMemory BS.empty BS.empty
result <- try @SomeException $ withTestServer tls settings $ \_ -> pure ()
result `shouldSatisfy` isLeft
it "fails with mismatched cert and key" $ \tls -> do
cert <- loadTestCert
let fakeKey = "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7\n-----END PRIVATE KEY-----\n"
let settings = tlsSettingsMemory cert fakeKey
result <- try @SomeException $ withTestServer tls settings $ \_ -> pure ()
result `shouldSatisfy` isLeft
-- Helpers
isRight :: Either a b -> Bool
isRight (Right _) = True
isRight _ = False
isLeft :: Either a b -> Bool
isLeft (Left _) = True
isLeft _ = False