module Metro.TP.TLSSetting
(
makeClientParams
, makeClientParams'
, makeServerParams
, makeServerParams'
) where
import qualified Data.ByteString as B (empty, readFile)
import Data.Default.Class (def)
import qualified Data.PEM as X509 (pemContent, pemParseBS)
import qualified Data.X509 as X509 (CertificateChain (..),
HashALG (..),
decodeSignedCertificate)
import qualified Data.X509.CertificateStore as X509 (CertificateStore,
makeCertificateStore)
import qualified Data.X509.Validation as X509 (ServiceID, checkFQHN,
validate)
import qualified Network.TLS as TLS
import qualified Network.TLS.Extra as TLS (ciphersuite_strong)
makeCAStore :: FilePath -> IO X509.CertificateStore
makeCAStore fp = do
bs <- B.readFile fp
let Right pems = X509.pemParseBS bs
case mapM (X509.decodeSignedCertificate . X509.pemContent) pems of
Right cas -> return (X509.makeCertificateStore cas)
Left err -> error err
makeClientParams :: FilePath
-> X509.ServiceID
-> IO TLS.ClientParams
makeClientParams tca servid = do
caStore <- makeCAStore tca
return (TLS.defaultParamsClient "" B.empty)
{ TLS.clientSupported = def { TLS.supportedCiphers = TLS.ciphersuite_strong }
, TLS.clientServerIdentification = servid
, TLS.clientShared = def
{ TLS.sharedCAStore = caStore
, TLS.sharedValidationCache = def
}
}
makeClientParams' :: FilePath
-> [FilePath]
-> FilePath
-> FilePath
-> X509.ServiceID
-> IO TLS.ClientParams
makeClientParams' pub certs priv tca servid = do
p <- makeClientParams tca servid
c <- TLS.credentialLoadX509Chain pub certs priv
case c of
Right c' ->
return p
{ TLS.clientShared = (TLS.clientShared p)
{
TLS.sharedCredentials = TLS.Credentials [c']
}
, TLS.clientHooks = (TLS.clientHooks p)
{
TLS.onCertificateRequest = const . return $ Just c'
}
}
Left err -> error err
makeServerParams :: FilePath
-> [FilePath]
-> FilePath
-> IO TLS.ServerParams
makeServerParams pub certs priv = do
c <- TLS.credentialLoadX509Chain pub certs priv
case c of
Right c'@(X509.CertificateChain c'', _) ->
return def
{ TLS.serverCACertificates = c''
, TLS.serverShared = def
{
TLS.sharedCredentials = TLS.Credentials [c']
}
, TLS.serverSupported = def { TLS.supportedCiphers = TLS.ciphersuite_strong }
}
Left err -> error err
makeServerParams' :: FilePath
-> [FilePath]
-> FilePath
-> FilePath
-> IO TLS.ServerParams
makeServerParams' pub certs priv tca = do
caStore <- makeCAStore tca
p <- makeServerParams pub certs priv
return p
{ TLS.serverWantClientCert = True
, TLS.serverShared = (TLS.serverShared p)
{ TLS.sharedCAStore = caStore
}
, TLS.serverHooks = def
{ TLS.onClientCertificate = \chain -> do
errs <- X509.validate X509.HashSHA256 def (def { X509.checkFQHN = False }) caStore def ("", B.empty) chain
case errs of
[] -> return TLS.CertificateUsageAccept
xs -> return . TLS.CertificateUsageReject . TLS.CertificateRejectOther $ show xs
}
}