get the client certificate from the connection's context

...instead of the janky thing we were doing before
This commit is contained in:
Jonathan Lamothe 2021-11-27 23:52:37 -05:00
parent 77cfcce5df
commit a45a75c3e2

View File

@ -34,12 +34,12 @@ import Control.Concurrent (forkIO)
import Control.Exception (SomeException, try) import Control.Exception (SomeException, try)
import Control.Exception.Base (bracket, finally) import Control.Exception.Base (bracket, finally)
import Control.Monad (void) import Control.Monad (void)
import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT)
import qualified Data.Connection as C import qualified Data.Connection as C
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import Data.TLSSetting (makeServerParams) import Data.TLSSetting (makeServerParams)
import Data.X509 (Certificate, CertificateChain (..), getSigned, signedObject) import Data.X509 (CertificateChain (..), getSigned, signedObject)
import qualified Network.Socket as S import qualified Network.Socket as S
import Network.TLS (ServerParams, onClientCertificate, serverHooks) import Network.TLS (ServerParams, getClientCertificateChain)
import System.IO.Streams.TCP (bindAndListen) import System.IO.Streams.TCP (bindAndListen)
import System.IO.Streams.TLS (accept) import System.IO.Streams.TLS (accept)
@ -69,32 +69,18 @@ runGemCapsule settings handler = bracket
listenLoop :: S.Socket -> ServerParams -> GemHandler -> IO a listenLoop :: S.Socket -> ServerParams -> GemHandler -> IO a
listenLoop sock params handler = do listenLoop sock params handler = do
certRef <- newIORef Nothing try (accept params sock) >>= \case
let params' = adjustServerParams certRef params
try (accept params' sock) >>= \case
Left (_::SomeException) -> return () Left (_::SomeException) -> return ()
Right conn -> void $ forkIO $ finally Right conn -> void $ forkIO $ finally
(readIORef certRef >>= runConnection conn handler) ( do
let (context, _) = C.connExtraInfo conn
mCert <- runMaybeT $
MaybeT (getClientCertificateChain context) >>= \case
CertificateChain [] -> fail "no certificate"
CertificateChain (se:_) -> return $ signedObject $ getSigned se
runConnection conn handler mCert
)
(C.close conn) (C.close conn)
listenLoop sock params handler listenLoop sock params handler
adjustServerParams
:: IORef (Maybe Certificate)
-> ServerParams
-> ServerParams
adjustServerParams certRef params = let
hooks = serverHooks params
certHook = onClientCertificate hooks
certHook' chain = do
case chain of
CertificateChain [] -> return ()
CertificateChain (se:_) -> do
let cert = signedObject $ getSigned se
writeIORef certRef (Just cert)
certHook chain
hooks' = hooks { onClientCertificate = certHook' }
in params { serverHooks = hooks' }
--jl --jl