network-simple-tls 0.3.2 → 0.4
raw patch · 4 files changed
+245/−173 lines, 4 filesdep +tls-session-managerdep ~tls
Dependencies added: tls-session-manager
Dependency ranges changed: tls
Files
- LICENSE +1/−1
- changelog.md +36/−0
- network-simple-tls.cabal +4/−3
- src/Network/Simple/TCP/TLS.hs +204/−169
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2013-2018, Renzo Carbonara <renλren.zone>+Copyright (c) 2013-2019, Renzo Carbonara <renλren.zone> All rights reserved.
changelog.md view
@@ -1,3 +1,39 @@+# Version 0.4++* COMPILER ASSISTED BREAKING CHANGE: `ClientSettings` and `ServerSettings` are+ gone. Instead, `ClientParams` and `ServerParams` from the `tls` package are+ now used throughout.++ The related functions `updateClientParams`, `clientParams`,+ `updateServerParams`, `serverParams` are gone.++ `makeClientSettings` was renamed to `makeClientParams`, which returns+ `ClientParams` and takes `[Credential]` rather than `Credentials`.++ `makeServerSettings` was renamed to `makeServerParams`, which returns+ `ServerParams`.++ `getDefaultClientSettings` was replaced by `newDefaultClientParams`, which adds+ an in-memory `SessionManager` to the `ClientParams`.++* COMPILER ASSISTED BREAKING CHANGE: `Credentials` from `Network.TLS` is not+ re-exported anymore.++* Added `newDefaultServerParams`, which creates a `ServerParams` with an+ in-memory `SessionManager`.++* Re-export `ServerParams`, `ClientParams` from `Network.TLS`.++* Export `credentialLoadX509`, which is the same as+ `Network.TLS.credentialLoadX509` but runs in `MonadIO`.++* Support TLS 1.3, TLS 1.2 and TLS 1.1 by default.++* Bump version dependency on `tls` to `>= 1.5`.++* Add dependency on `tls-session-manager`.++ # Version 0.3.2 * Added `sendLazy`.
network-simple-tls.cabal view
@@ -1,5 +1,5 @@ name: network-simple-tls-version: 0.3.2+version: 0.4 synopsis: Simple interface to TLS secured network sockets. description: Simple interface to TLS secured network sockets. homepage: https://github.com/k0001/network-simple-tls@@ -8,7 +8,7 @@ license-file: LICENSE author: Renzo Carbonara maintainer: renλren.zone-copyright: Copyright (c) Renzo Carbonara 2013-2018+copyright: Copyright (c) Renzo Carbonara 2013-2019 category: Network build-type: Simple cabal-version: >=1.8@@ -27,7 +27,8 @@ , network , network-simple >=0.4.3 , safe-exceptions- , tls+ , tls >=1.5+ , tls-session-manager , transformers , x509 , x509-store
src/Network/Simple/TCP/TLS.hs view
@@ -6,14 +6,15 @@ -- connections, relevant to both the client side and server side of the -- connection. ----- This module re-exports some functions from the "Network.Simple.TCP" module--- in the @network-simple@ package. Consider using that module directly if you--- need a similar API without TLS support.+-- This module re-exports some functions from the "Network.Simple.TCP" module in+-- the [network-simple](https://hackage.haskell.org/package/network-simple)+-- package. Consider using that module directly if you need a similar API+-- without TLS support. -- -- This module uses 'MonadIO' and 'E.MonadMask' extensively so that you can -- reuse these functions in monads other than 'IO'. However, if you don't care--- about any of that, just pretend you are using the 'IO' monad all the time--- and everything will work as expected.+-- about any of that, just pretend you are using the 'IO' monad all the time and+-- everything will work as expected. module Network.Simple.TCP.TLS ( -- * Server side@@ -24,20 +25,15 @@ , accept , acceptFork -- ** Server TLS Settings- , ServerSettings- , makeServerSettings- , updateServerParams- , serverParams+ , newDefaultServerParams+ , makeServerParams -- * Client side , connect , connectOverSOCKS5 -- ** Client TLS Settings- , ClientSettings- , makeClientSettings- , getDefaultClientSettings- , updateClientParams- , clientParams+ , newDefaultClientParams+ , makeClientParams -- * Utils , recv@@ -54,15 +50,30 @@ , makeClientContext , makeServerContext - -- * Note to Windows users- , NS.withSocketsDo- -- * Re-exports -- $reexports- , module Network.Simple.TCP- , module Network.Socket- , module Network.TLS- , T.Credentials+ , NS.withSocketsDo+ , S.HostPreference(..)+ , NS.HostName+ , NS.ServiceName+ -- | A service port like @"80"@ or its name @"www"@.+ , NS.Socket+ , NS.SockAddr+ , T.Context+ , T.ClientParams+ -- | Please refer to the "Network.TLS" module for more documentation on+ -- 'T.ClientParams`.+ --+ -- There's plenty to be changed, but the documentation for+ -- 'T.ClientParams' is not rendered inside "Network.Simple.TCP.TLS" module.+ , T.ServerParams+ -- | Please refer to the "Network.TLS" module for more documentation on+ -- 'T.ServerParams`.+ --+ -- There's plenty to be changed, but the documentation for+ -- 'T.ServerParams' is not rendered inside "Network.Simple.TCP.TLS" module.+ , T.Credential+ , credentialLoadX509 ) where @@ -81,12 +92,10 @@ import Foreign.C.Error (Errno(Errno), ePIPE) import qualified GHC.IO.Exception as Eg import qualified Network.Simple.TCP as S-import Network.Simple.TCP (HostPreference(Host, HostAny, HostIPv4, HostIPv6))-import Network.Socket (HostName, ServiceName, Socket, SockAddr) import qualified Network.Socket as NS import qualified Network.TLS as T-import Network.TLS (Context)-import Network.TLS.Extra as TE+import qualified Network.TLS.SessionManager as TSM+import qualified Network.TLS.Extra as TE import System.X509 (getSystemCertificateStore) --------------------------------------------------------------------------------@@ -97,53 +106,81 @@ -- For your convenience, this module module also re-exports the following types -- from other modules: ----- [From "Network.Socket"] 'HostName', 'ServiceName', 'Socket', 'SockAddr'.+-- [From "Network.Socket"] 'NS.HostName', 'NS.ServiceName', 'NS.Socket',+-- 'NS.SockAddr', 'NS.withSocketsDo'. -- -- [From "Network.Simple.TCP"]--- @'HostPreference'('Host','HostAny','HostIPv4','HostIPv6')@.+-- @'S.HostPreference'('S.Host','S.HostAny','S.HostIPv4','S.HostIPv6')@. ----- [From "Network.TLS"] 'Context'.+-- [From "Network.TLS"] 'T.Context', 'T.Credential', 'T.ServerParams',+-- 'T.ClientParams', 'credentialLoadX509'. -------------------------------------------------------------------------------- -- Client side TLS settings --- | Abstract type representing the configuration settings for a TLS client.+-- | Obtain new default 'T.ClientParams' for a particular 'X.ServiceID'. ----- Use 'makeClientSettings' or 'getDefaultClientSettings' to obtain a--- 'ClientSettings' value.-data ClientSettings = ClientSettings { unClientSettings :: T.ClientParams }---- | Get the system default 'ClientSettings' for a particular 'X.ServiceID'.+-- * No client credentials sumbitted to the server. ----- Defaults: No client credentials, system certificate store.+-- * Use system-wide CA certificate store. ----- See 'makeClientSettings' to better understand the default settings used.-getDefaultClientSettings :: MonadIO m => X.ServiceID -> m ClientSettings-getDefaultClientSettings sid = liftIO $ do- makeClientSettings sid (T.Credentials []) <$> getSystemCertificateStore-+-- * Use an in-memory TLS session manager from the+-- [tls-session-manager](https://hackage.haskell.org/package/tls-session-manager)+-- package.+--+-- * Everything else as proposed by 'makeClientParams'.+newDefaultClientParams+ :: MonadIO m+ => X.ServiceID+ -- ^+ -- @+ -- 'X.ServiceID' ~ ('S.HostName', 'B.ByteString')+ -- @+ --+ -- Identification of the connection consisting of the fully qualified host+ -- name for the server (e.g. www.example.com) and an optional suffix.+ --+ -- It is important that the hostname part is properly filled for security+ -- reasons, as it allow to properly associate the remote side with the given+ -- certificate during a handshake.+ --+ -- The suffix is used to identity a certificate per service on a specific+ -- host. For example, a same host might have different certificates on+ -- differents ports (443 and 995). For TCP connections, it's recommended+ -- to use: @:port@, or @:service@ for the blob (e.g., \@":443"@, @\":https"@).+ -> m T.ClientParams+newDefaultClientParams sid = liftIO $ do+ cs <- getSystemCertificateStore+ sm <- TSM.newSessionManager TSM.defaultConfig+ let cp0 = makeClientParams sid [] cs+ pure $ cp0+ { T.clientShared = (T.clientShared cp0)+ { T.sharedSessionManager = sm }+ } --- | Make defaults 'ClientSettings'.+-- | Make defaults 'T.ClientParams'. ----- Certificate chain validation is done by 'X.validateDefault' from the+-- * Certificate chain validation is done by 'X.validateDefault' from the -- "Data.X509.Validation" module. ----- The Server Name Indication (SNI) TLS extension is enabled.+-- * The Server Name Indication (SNI) TLS extension is enabled. ----- The supported cipher suites are those enumerated by 'TE.ciphersuite_default',+-- * The supported cipher suites are those enumerated by 'TE.ciphersuite_default', -- in decreasing order of preference. ----- Secure renegotiation is enabled.+-- * Secure renegotiation is enabled. ----- Only the __TLS 1.1__ and __TLS 1.2__ protocols are supported by default.+-- * Only the __TLS 1.1__, __TLS 1.2__ and __TLS 1.3__ protocols are supported by default. ----- If you are unsatisfied with any of these settings, use 'updateClientParams'--- to change them.-makeClientSettings+-- If you are unsatisfied with any of these settings, please+-- please refer to the "Network.TLS" module for more documentation on+-- 'T.ClientParams`.+makeClientParams :: X.ServiceID- -- ^ @- -- 'X.ServiceID' ~ ('HostName', 'B.ByteString')+ -- ^ -- @+ -- 'X.ServiceID' ~ ('S.HostName', 'B.ByteString')+ -- @ -- -- Identification of the connection consisting of the fully qualified host -- name for the server (e.g. www.example.com) and an optional suffix.@@ -156,21 +193,21 @@ -- host. For example, a same host might have different certificates on -- differents ports (443 and 995). For TCP connections, it's recommended -- to use: @:port@, or @:service@ for the blob (e.g., \@":443"@, @\":https"@).- -> T.Credentials+ -> [T.Credential] -- ^ Credentials to provide to the server if requested. Only credentials -- matching the server's 'X.DistinguishedName' will be submitted. --- -- Initial credentials can be loaded with 'T.credentialLoadX509'+ -- Can be loaded with 'credentialLoadX509' or similar functions. -> X.CertificateStore -- ^ CAs used to verify the server certificate. -- -- Use 'getSystemCertificateStore' to obtain the operating system's defaults.- -> ClientSettings-makeClientSettings (hn, sp) (T.Credentials creds) cStore =- ClientSettings $ (T.defaultParamsClient hn sp)+ -> T.ClientParams+makeClientParams (hn, sp) creds cStore =+ (T.defaultParamsClient hn sp) { T.clientUseServerNameIndication = True , T.clientSupported = def- { T.supportedVersions = [T.TLS12, T.TLS11]+ { T.supportedVersions = [T.TLS13, T.TLS12, T.TLS11] , T.supportedCiphers = TE.ciphersuite_default , T.supportedSecureRenegotiation = True , T.supportedClientInitiatedRenegotiation = True }@@ -192,47 +229,28 @@ isSubject (X.CertificateChain cc, _) = any (\c -> (X.certSubjectDN . X.getCertificate) c `elem` dns) cc --- | Update advanced TLS client configuration 'T.ClientParams'.------ See the "Network.TLS" module for details.-updateClientParams- :: (T.ClientParams -> T.ClientParams) -> ClientSettings -> ClientSettings-updateClientParams f = ClientSettings . f . unClientSettings---- | A 'Control.Lens.Lens' into the TLS client configuration 'T.ClientParams'.------ See the "Network.TLS" and the @lens@ package for details.-clientParams- :: Functor f- => (T.ClientParams -> f T.ClientParams)- -> (ClientSettings -> f ClientSettings)-clientParams f = fmap ClientSettings . f . unClientSettings- -------------------------------------------------------------------------------- -- Server side TLS settings --- | Abstract type representing the configuration settings for a TLS server.------ Use 'makeServerSettings' to construct a 'ServerSettings' value, and--- 'updateServerParams' to update it.-data ServerSettings = ServerSettings { unServerSettings :: T.ServerParams }---- | Make default 'ServerSettings'.+-- | Make default 'T.ServerParams'. ----- The supported cipher suites are those enumerated by 'TE.ciphersuite_strong',+-- * The supported cipher suites are those enumerated by 'TE.ciphersuite_strong', -- in decreasing order of preference. The cipher suite preferred by the server -- is used. ----- Secure renegotiation initiated by the server is enabled, but renegotiation+-- * Secure renegotiation initiated by the server is enabled, but renegotiation -- initiated by the client is disabled. ----- Only the __TLS 1.1__ and __TLS 1.2__ protocols are supported by default.+-- * Only the __TLS 1.1__, __TLS 1.2__ and __TLS 1.3__ protocols are supported by default. ----- If you are unsatisfied with any of these settings, use 'updateServerParams'--- to change them.-makeServerSettings+-- If you are unsatisfied with any of these settings, please+-- please refer to the "Network.TLS" module for more documentation on+-- 'T.ServerParams`.+makeServerParams :: T.Credential -- ^ Server credential.+ --+ -- Can be loaded with 'credentialLoadX509' or similar functions. -> Maybe X.CertificateStore -- ^ CAs used to verify the client certificate. --@@ -240,15 +258,14 @@ -- handshake. -- -- Use 'getSystemCertificateStore' to obtain the operating system's defaults.- -> ServerSettings-makeServerSettings cred ycStore =- ServerSettings $ def+ -> T.ServerParams+makeServerParams cred ycStore = def { T.serverWantClientCert = isJust ycStore , T.serverShared = def { T.sharedCredentials = T.Credentials [cred] } , T.serverCACertificates = [] , T.serverSupported = def- { T.supportedVersions = [T.TLS12, T.TLS11]+ { T.supportedVersions = [T.TLS13, T.TLS12, T.TLS11] , T.supportedCiphers = TE.ciphersuite_strong , T.supportedSession = True , T.supportedSecureRenegotiation = True@@ -272,20 +289,29 @@ chooseCipher :: T.Version -> [T.Cipher] -> T.Cipher chooseCipher _ cCiphs = head (intersect TE.ciphersuite_strong cCiphs) --- | Update advanced TLS server configuration 'T.Params'.+-- | Obtain new default 'T.ServerParams' for a particular server 'T.Credential'. ----- See the "Network.TLS" module for details.-updateServerParams- :: (T.ServerParams -> T.ServerParams) -> ServerSettings -> ServerSettings-updateServerParams f = ServerSettings . f . unServerSettings---- | A 'Control.Lens.Lens' into the TLS server configuration 'T.Params'.--- See the "Network.TLS" and the @lens@ package for details.-serverParams- :: Functor f- => (T.ServerParams -> f T.ServerParams)- -> (ServerSettings -> f ServerSettings)-serverParams f = fmap ServerSettings . f . unServerSettings+-- * Don't require credentials from clients.+--+-- * Use an in-memory TLS session manager from the+-- [tls-session-manager](https://hackage.haskell.org/package/tls-session-manager)+-- package.+--+-- * Everything else as proposed by 'makeServerParams'.+newDefaultServerParams+ :: MonadIO m+ => T.Credential+ -- ^ Server credential.+ --+ -- Can be loaded with 'credentialLoadX509' or similar functions.+ -> m T.ServerParams+newDefaultServerParams cred = liftIO $ do+ sm <- TSM.newSessionManager TSM.defaultConfig+ let sp0 = makeServerParams cred Nothing+ pure $ sp0+ { T.serverShared = (T.serverShared sp0)+ { T.sharedSessionManager = sm }+ } -------------------------------------------------------------------------------- @@ -299,10 +325,10 @@ -- of those steps manually. serve :: MonadIO m- => ServerSettings -- ^TLS settings.+ => T.ServerParams -- ^TLS settings. -> S.HostPreference -- ^Preferred host to bind.- -> ServiceName -- ^Service port to bind.- -> ((Context, SockAddr) -> IO ())+ -> S.ServiceName -- ^Service port to bind.+ -> ((T.Context, S.SockAddr) -> IO ()) -- ^Computation to run in a different thread -- once an incomming connection is accepted and a -- TLS-secured communication is established. Takes the@@ -322,9 +348,9 @@ -- resources yourself, then use 'acceptTls' instead. accept :: (MonadIO m, E.MonadMask m)- => ServerSettings -- ^TLS settings.- -> Socket -- ^Listening and bound socket.- -> ((Context, SockAddr) -> m r)+ => T.ServerParams -- ^TLS settings.+ -> S.Socket -- ^Listening and bound socket.+ -> ((T.Context, S.SockAddr) -> m r) -- ^Computation to run in a different thread -- once an incomming connection is accepted and a -- TLS-secured communication is established. Takes the@@ -338,9 +364,9 @@ -- handshake and run the given computation. acceptFork :: MonadIO m- => ServerSettings -- ^TLS settings.- -> Socket -- ^Listening and bound socket.- -> ((Context, SockAddr) -> IO ())+ => T.ServerParams -- ^TLS settings.+ -> S.Socket -- ^Listening and bound socket.+ -> ((T.Context, S.SockAddr) -> IO ()) -- ^Computation to run in a different thread -- once an incomming connection is accepted and a -- TLS-secured communication is established. Takes the@@ -361,10 +387,10 @@ -- resources yourself, then use 'connectTls' instead. connect :: (MonadIO m, E.MonadMask m)- => ClientSettings -- ^ TLS settings.- -> HostName -- ^ Server hostname.- -> ServiceName -- ^ Destination server service port name or number.- -> ((Context, SockAddr) -> m r)+ => T.ClientParams -- ^ TLS settings.+ -> S.HostName -- ^ Server hostname.+ -> S.ServiceName -- ^ Destination server service port name or number.+ -> ((T.Context, S.SockAddr) -> m r) -- ^ Computation to run after establishing TLS-secured TCP connection to the -- remote server. Takes the TLS connection context and remote end address. -> m r@@ -375,17 +401,17 @@ -- | Like 'connect', but connects to the destination server over a SOCKS5 proxy. connectOverSOCKS5 :: (MonadIO m, E.MonadMask m)- => HostName -- ^ SOCKS5 proxy server hostname or IP address.- -> ServiceName -- ^ SOCKS5 proxy server service port name or number.- -> ClientSettings -- ^ TLS settings.- -> HostName+ => S.HostName -- ^ SOCKS5 proxy server hostname or IP address.+ -> S.ServiceName -- ^ SOCKS5 proxy server service port name or number.+ -> T.ClientParams -- ^ TLS settings.+ -> S.HostName -- ^ Destination server hostname or IP address. We connect to this host -- /through/ the SOCKS5 proxy specified in the previous arguments. --- -- Note that if hostname resolution on this 'HostName' is necessary, it+ -- Note that if hostname resolution on this 'S.HostName' is necessary, it -- will happen on the proxy side for security reasons, not locally.- -> ServiceName -- ^ Destination server service port name or number.- -> ((Context, SockAddr, SockAddr) -> m r)+ -> S.ServiceName -- ^ Destination server service port name or number.+ -> ((T.Context, S.SockAddr, S.SockAddr) -> m r) -- ^ Computation to run after establishing TLS-secured TCP connection to the -- remote server. Takes the TLS connection that can be used to interact with -- the destination server, as well as the address of the SOCKS5 server and the@@ -401,22 +427,22 @@ -------------------------------------------------------------------------------- -- | Estalbishes a TCP connection to a remote server and returns a TLS--- 'Context' configured on top of it using the given 'ClientSettings'.+-- 'T.Context' configured on top of it using the given 'T.ClientParams'. -- The remote end address is also returned. ----- Prefer to use 'connect' if you will be using the obtained 'Context' within a+-- Prefer to use 'connect' if you will be using the obtained 'T.Context' within a -- limited scope. ----- You need to perform a TLS handshake on the resulting 'Context' before using+-- You need to perform a TLS handshake on the resulting 'T.Context' before using -- it for communication purposes, and gracefully close the TLS and TCP -- connections afterwards using. The 'useTls', 'useTlsThenClose' and -- 'useTlsThenCloseFork' can help you with that. connectTls :: MonadIO m- => ClientSettings -- ^ TLS settings.- -> HostName -- ^ Server hostname.- -> ServiceName -- ^ Server service name or port number.- -> m (Context, SockAddr)+ => T.ClientParams -- ^ TLS settings.+ -> S.HostName -- ^ Server hostname.+ -> S.ServiceName -- ^ Server service name or port number.+ -> m (T.Context, S.SockAddr) connectTls cs host port = liftIO $ do E.bracketOnError (S.connectSock host port)@@ -429,18 +455,18 @@ -- proxy. connectTlsOverSOCKS5 :: MonadIO m- => HostName -- ^ SOCKS5 proxy server hostname or IP address.- -> ServiceName -- ^ SOCKS5 proxy server service port name or number.- -> ClientSettings -- ^ TLS settings.- -> HostName+ => S.HostName -- ^ SOCKS5 proxy server hostname or IP address.+ -> S.ServiceName -- ^ SOCKS5 proxy server service port name or number.+ -> T.ClientParams -- ^ TLS settings.+ -> S.HostName -- ^ Destination server hostname or IP address. We connect to this host -- /through/ the SOCKS5 proxy specified in the previous arguments. --- -- Note that if hostname resolution on this 'HostName' is necessary, it+ -- Note that if hostname resolution on this 'S.HostName' is necessary, it -- will happen on the proxy side for security reasons, not locally.- -> ServiceName -- ^ Destination server service port name or number.- -> m (Context, SockAddr, SockAddr)- -- ^ Returns the 'Context' that can be used to interact with the destination+ -> S.ServiceName -- ^ Destination server service port name or number.+ -> m (T.Context, S.SockAddr, S.SockAddr)+ -- ^ Returns the 'T.Context' that can be used to interact with the destination -- server, as well as the address of the SOCKS5 server and the address of the -- destination server, in that order. connectTlsOverSOCKS5 phn psn cs dhn dsn = liftIO $ do@@ -452,30 +478,29 @@ ctx <- makeClientContext cs psock return (ctx, paddr, daddr)) --- | Make a client-side TLS 'Context' for the given settings, on top of the--- given TCP `Socket` connected to the remote end.-makeClientContext :: MonadIO m => ClientSettings -> Socket -> m Context-makeClientContext (ClientSettings params) sock = liftIO $ do- T.contextNew sock params+-- | Make a client-side TLS 'T.Context' for the given settings, on top of the+-- given TCP `S.Socket` connected to the remote end.+makeClientContext :: MonadIO m => T.ClientParams -> S.Socket -> m T.Context+makeClientContext params sock = liftIO $ T.contextNew sock params -------------------------------------------------------------------------------- --- | Accepts an incoming TCP connection and returns a TLS 'Context' configured--- on top of it using the given 'ServerSettings'. The remote end address is also+-- | Accepts an incoming TCP connection and returns a TLS 'T.Context' configured+-- on top of it using the given 'T.ServerParams'. The remote end address is also -- returned. ----- Prefer to use 'accept' if you will be using the obtained 'Context' within a+-- Prefer to use 'accept' if you will be using the obtained 'T.Context' within a -- limited scope. ----- You need to perform a TLS handshake on the resulting 'Context' before using+-- You need to perform a TLS handshake on the resulting 'T.Context' before using -- it for communication purposes, and gracefully close the TLS and TCP -- connections afterwards using. The 'useTls', 'useTlsThenClose' and -- 'useTlsThenCloseFork' can help you with that. acceptTls :: MonadIO m- => ServerSettings -- ^TLS settings.- -> Socket -- ^Listening and bound socket.- -> m (Context, SockAddr)+ => T.ServerParams -- ^TLS settings.+ -> S.Socket -- ^Listening and bound socket.+ -> m (T.Context, S.SockAddr) acceptTls sp lsock = liftIO $ do E.bracketOnError (NS.accept lsock)@@ -484,15 +509,14 @@ ctx <- makeServerContext sp sock return (ctx, addr)) --- | Make a server-side TLS 'Context' for the given settings, on top of the--- given TCP `Socket` connected to the remote end.-makeServerContext :: MonadIO m => ServerSettings -> Socket -> m Context-makeServerContext (ServerSettings params) sock = liftIO $ do- T.contextNew sock params+-- | Make a server-side TLS 'T.Context' for the given settings, on top of the+-- given TCP `S.Socket` connected to the remote end.+makeServerContext :: MonadIO m => T.ServerParams -> S.Socket -> m T.Context+makeServerContext params sock = liftIO $ T.contextNew sock params -------------------------------------------------------------------------------- --- | Perform a TLS handshake on the given 'Context', then perform the+-- | Perform a TLS handshake on the given 'T.Context', then perform the -- given action and at last gracefully close the TLS session using `T.bye`. -- -- This function does not close the underlying TCP connection when done.@@ -500,8 +524,8 @@ -- behavior. Otherwise, you must call `T.contextClose` yourself at some point. useTls :: (MonadIO m, E.MonadMask m)- => ((Context, SockAddr) -> m a)- -> ((Context, SockAddr) -> m a)+ => ((T.Context, S.SockAddr) -> m a)+ -> ((T.Context, S.SockAddr) -> m a) useTls k conn@(ctx,_) = E.bracket_ (T.handshake ctx) (liftIO $ silentBye ctx) (k conn)@@ -509,8 +533,8 @@ -- | Like 'useTls', except it also fully closes the TCP connection when done. useTlsThenClose :: (MonadIO m, E.MonadMask m)- => ((Context, SockAddr) -> m a)- -> ((Context, SockAddr) -> m a)+ => ((T.Context, S.SockAddr) -> m a)+ -> ((T.Context, S.SockAddr) -> m a) useTlsThenClose k conn@(ctx,_) = do useTls k conn `E.finally` liftIO (T.contextClose ctx) @@ -521,8 +545,8 @@ -- the right behavior. useTlsThenCloseFork :: MonadIO m- => ((Context, SockAddr) -> IO ())- -> ((Context, SockAddr) -> m ThreadId)+ => ((T.Context, S.SockAddr) -> IO ())+ -> ((T.Context, S.SockAddr) -> m ThreadId) useTlsThenCloseFork k conn@(ctx,_) = liftIO $ do forkFinally (E.bracket_ (T.handshake ctx) (silentBye ctx) (k conn)) (\eu -> T.contextClose ctx >> either E.throwIO return eu)@@ -530,11 +554,11 @@ -------------------------------------------------------------------------------- -- Utils --- | Receives decrypted bytes from the given 'Context'. Returns 'Nothing'+-- | Receives decrypted bytes from the given 'T.Context'. Returns 'Nothing' -- on EOF. -- -- Up to @16384@ decrypted bytes will be received at once.-recv :: MonadIO m => Context -> m (Maybe B.ByteString)+recv :: MonadIO m => T.Context -> m (Maybe B.ByteString) recv ctx = liftIO $ do E.handle (\T.Error_EOF -> return Nothing) (do bs <- T.recvData ctx@@ -544,23 +568,34 @@ {-# INLINABLE recv #-} -- | Encrypts the given strict 'B.ByteString' and sends it through the--- 'Context'.-send :: MonadIO m => Context -> B.ByteString -> m ()+-- 'T.Context'.+send :: MonadIO m => T.Context -> B.ByteString -> m () send ctx = \bs -> T.sendData ctx (BL.fromStrict bs) {-# INLINABLE send #-} -- | Encrypts the given lazy 'BL.ByteString' and sends it through the--- 'Context'.-sendLazy :: MonadIO m => Context -> BL.ByteString -> m ()+-- 'T.Context'.+sendLazy :: MonadIO m => T.Context -> BL.ByteString -> m () sendLazy = T.sendData {-# INLINE sendLazy #-} --------------------------------------------------------------------------------++-- | Try to create a new credential object from a public certificate and the+-- associated private key that are stored on the filesystem in PEM format.+credentialLoadX509+ :: MonadIO m+ => FilePath -- ^ Public certificate (X.509 format).+ -> FilePath -- ^ Private key associated with the certificate.+ -> m (Either String T.Credential)+credentialLoadX509 cert key = liftIO $ T.credentialLoadX509 cert key++-------------------------------------------------------------------------------- -- Internal utils -- | Like 'T.bye' from the "Network.TLS" module, except it ignores 'ePIPE' -- errors which might happen if the remote peer closes the connection first.-silentBye :: Context -> IO ()+silentBye :: T.Context -> IO () silentBye ctx = do E.catch (T.bye ctx) $ \e -> case e of Eg.IOError{ Eg.ioe_type = Eg.ResourceVanished