Safe Haskell | None |
---|---|
Language | Haskell2010 |
TLS bindings for Rustls via rustls-ffi.
See the README on GitHub for setup instructions.
Currently, most of the functionality exposed by rustls-ffi is available, while rustls-ffi is still missing some more niche Rustls features.
Also see http-client-rustls for making HTTPS requests using http-client and Rustls.
Client example
Suppose you have alread opened a Socket
to example.org
,
port 443 (see e.g. the examples at Network.Socket). This small example
showcases how to perform a simple HTTP GET request:
>>>
:set -XOverloadedStrings
>>>
import qualified Rustls
>>>
import Network.Socket (Socket)
>>>
import Data.Acquire (withAcquire)
>>>
:{
example :: Socket -> IO () example socket = do -- It is encouraged to share a single `clientConfig` when creating multiple -- TLS connections. clientConfig <- Rustls.buildClientConfig $ Rustls.defaultClientConfigBuilder roots let newConnection = Rustls.newClientConnection socket clientConfig "example.org" withAcquire newConnection $ \conn -> do Rustls.writeBS conn "GET /" recv <- Rustls.readBS conn 1000 -- max number of bytes to read print recv where -- For now, rustls-ffi does not provide a built-in way to access -- the OS certificate store. roots = Rustls.ClientRootsFromFile "/etc/ssl/certs/ca-certificates.crt" :}
Using Acquire
Some API functions (like newClientConnection
and newServerConnection
)
return an Acquire
from
resourcet, as it is a
convenient abstraction for exposing a value that should be consumed in a
"bracketed" manner.
Usually, it can be used via with
or withAcquire
, or via
allocateAcquire
when a MonadResource
constraint is available. If you really need the extra flexibility, you can
also access separate open…
and close…
functions by reaching for
Data.Acquire.Internal.
Synopsis
- data ClientConfigBuilder = ClientConfigBuilder {}
- defaultClientConfigBuilder :: ClientRoots -> ClientConfigBuilder
- data ClientRoots
- data PEMCertificates
- data ClientConfig
- clientConfigLogCallback :: ClientConfig -> Maybe LogCallback
- buildClientConfig :: MonadIO m => ClientConfigBuilder -> m ClientConfig
- newClientConnection :: Backend b => b -> ClientConfig -> Text -> Acquire (Connection Client)
- data ServerConfigBuilder = ServerConfigBuilder {}
- defaultServerConfigBuilder :: NonEmpty CertifiedKey -> ServerConfigBuilder
- data ClientCertVerifier
- data ServerConfig
- serverConfigLogCallback :: ServerConfig -> Maybe LogCallback
- buildServerConfig :: MonadIO m => ServerConfigBuilder -> m ServerConfig
- newServerConnection :: Backend b => b -> ServerConfig -> Acquire (Connection Server)
- data Connection (side :: Side)
- data Side
- readBS :: MonadIO m => Connection side -> Int -> m ByteString
- writeBS :: MonadIO m => Connection side -> ByteString -> m ()
- handshake :: MonadIO m => Connection side -> HandshakeQuery side a -> m a
- data HandshakeQuery (side :: Side) a
- getALPNProtocol :: HandshakeQuery side (Maybe ALPNProtocol)
- getTLSVersion :: HandshakeQuery side TLSVersion
- getCipherSuite :: HandshakeQuery side CipherSuite
- getSNIHostname :: HandshakeQuery Server (Maybe Text)
- getPeerCertificate :: CSize -> HandshakeQuery side (Maybe DERCertificate)
- sendCloseNotify :: MonadIO m => Connection side -> m ()
- data LogCallback
- newLogCallback :: (LogLevel -> Text -> IO ()) -> Acquire LogCallback
- data LogLevel
- readPtr :: MonadIO m => Connection side -> Ptr Word8 -> CSize -> m CSize
- writePtr :: MonadIO m => Connection side -> Ptr Word8 -> CSize -> m CSize
- version :: Text
- class Backend b where
- data ByteStringBackend = ByteStringBackend {
- bsbRead :: Int -> IO ByteString
- bsbWrite :: ByteString -> IO ()
- newtype ALPNProtocol = ALPNProtocol {}
- data CertifiedKey = CertifiedKey {}
- newtype DERCertificate = DERCertificate {}
- data TLSVersion where
- pattern TLS12 :: TLSVersion
- pattern TLS13 :: TLSVersion
- defaultTLSVersions :: NonEmpty TLSVersion
- allTLSVersions :: NonEmpty TLSVersion
- data CipherSuite
- cipherSuiteID :: CipherSuite -> Word16
- showCipherSuite :: CipherSuite -> Text
- defaultCipherSuites :: NonEmpty CipherSuite
- allCipherSuites :: NonEmpty CipherSuite
- data RustlsException
- isCertError :: RustlsException -> Bool
Client
Builder
data ClientConfigBuilder Source #
Rustls client config builder.
ClientConfigBuilder | |
|
Instances
defaultClientConfigBuilder :: ClientRoots -> ClientConfigBuilder Source #
A ClientConfigBuilder
with good defaults.
data ClientRoots Source #
How to look up root certificates.
ClientRootsFromFile FilePath | Fetch PEM-encoded root certificates from a file. |
ClientRootsInMemory [PEMCertificates] | Use in-memory PEM-encoded certificates. |
Instances
Show ClientRoots Source # | |
Defined in Rustls.Internal showsPrec :: Int -> ClientRoots -> ShowS # show :: ClientRoots -> String # showList :: [ClientRoots] -> ShowS # | |
Generic ClientRoots Source # | |
Defined in Rustls.Internal type Rep ClientRoots :: Type -> Type # from :: ClientRoots -> Rep ClientRoots x # to :: Rep ClientRoots x -> ClientRoots # | |
type Rep ClientRoots Source # | |
Defined in Rustls.Internal type Rep ClientRoots = D1 ('MetaData "ClientRoots" "Rustls.Internal" "rustls-0.0.0.0-inplace" 'False) (C1 ('MetaCons "ClientRootsFromFile" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 FilePath)) :+: C1 ('MetaCons "ClientRootsInMemory" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 [PEMCertificates]))) |
data PEMCertificates Source #
In-memory PEM-encoded certificates.
PEMCertificatesStrict ByteString | Syntactically valid PEM-encoded certificates. |
PEMCertificatesLax ByteString | PEM-encoded certificates, ignored if syntactically invalid. This may be useful on systems that have syntactically invalid root certificates. |
Instances
Show PEMCertificates Source # | |
Defined in Rustls.Internal showsPrec :: Int -> PEMCertificates -> ShowS # show :: PEMCertificates -> String # showList :: [PEMCertificates] -> ShowS # | |
Generic PEMCertificates Source # | |
Defined in Rustls.Internal type Rep PEMCertificates :: Type -> Type # from :: PEMCertificates -> Rep PEMCertificates x # to :: Rep PEMCertificates x -> PEMCertificates # | |
type Rep PEMCertificates Source # | |
Defined in Rustls.Internal type Rep PEMCertificates = D1 ('MetaData "PEMCertificates" "Rustls.Internal" "rustls-0.0.0.0-inplace" 'False) (C1 ('MetaCons "PEMCertificatesStrict" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 ByteString)) :+: C1 ('MetaCons "PEMCertificatesLax" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 ByteString))) |
Config
data ClientConfig Source #
Assembled configuration for a Rustls client connection.
clientConfigLogCallback :: ClientConfig -> Maybe LogCallback Source #
A logging callback. If it throws an exception, a note will be printed to stderr.
Note that this is a record selector, so you can use it as a setter:
>>>
:{
setLogCallback :: LogCallback -> ClientConfig -> ClientConfig setLogCallback logCallback clientConfig = clientConfig { clientConfigLogCallback = Just logCallback } :}
buildClientConfig :: MonadIO m => ClientConfigBuilder -> m ClientConfig Source #
Build a ClientConfigBuilder
into a ClientConfig
.
This is a relatively expensive operation, so it is a good idea to share one
ClientConfig
when creating multiple Connection
s.
Open a connection
:: Backend b | |
=> b | |
-> ClientConfig | |
-> Text | Hostname. |
-> Acquire (Connection Client) |
Initialize a TLS connection as a client.
Server
Builder
data ServerConfigBuilder Source #
Rustls client config builder.
ServerConfigBuilder | |
|
Instances
defaultServerConfigBuilder :: NonEmpty CertifiedKey -> ServerConfigBuilder Source #
A ServerConfigBuilder
with good defaults.
data ClientCertVerifier Source #
How to verify TLS client certificates.
ClientCertVerifier [PEMCertificates] | Root certificates used to verify TLS client certificates. |
ClientCertVerifierOptional [PEMCertificates] | Root certificates used to verify TLS client certificates if present, but does not reject clients which provide no certificate. |
Instances
Show ClientCertVerifier Source # | |
Defined in Rustls.Internal showsPrec :: Int -> ClientCertVerifier -> ShowS # show :: ClientCertVerifier -> String # showList :: [ClientCertVerifier] -> ShowS # | |
Generic ClientCertVerifier Source # | |
Defined in Rustls.Internal type Rep ClientCertVerifier :: Type -> Type # from :: ClientCertVerifier -> Rep ClientCertVerifier x # to :: Rep ClientCertVerifier x -> ClientCertVerifier # | |
type Rep ClientCertVerifier Source # | |
Defined in Rustls.Internal type Rep ClientCertVerifier = D1 ('MetaData "ClientCertVerifier" "Rustls.Internal" "rustls-0.0.0.0-inplace" 'False) (C1 ('MetaCons "ClientCertVerifier" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 [PEMCertificates])) :+: C1 ('MetaCons "ClientCertVerifierOptional" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 [PEMCertificates]))) |
Config
data ServerConfig Source #
Assembled configuration for a Rustls server connection.
serverConfigLogCallback :: ServerConfig -> Maybe LogCallback Source #
A logging callback. If it throws an exception, a note will be printed to stderr.
Note that this is a record selector, so you can use it as a setter:
>>>
:{
setLogCallback :: LogCallback -> ServerConfig -> ServerConfig setLogCallback logCallback serverConfig = serverConfig { serverConfigLogCallback = Just logCallback } :}
buildServerConfig :: MonadIO m => ServerConfigBuilder -> m ServerConfig Source #
Build a ServerConfigBuilder
into a ServerConfig
.
This is a relatively expensive operation, so it is a good idea to share one
ServerConfig
when creating multiple Connection
s.
Open a connection
newServerConnection :: Backend b => b -> ServerConfig -> Acquire (Connection Server) Source #
Initialize a TLS connection as a server.
Connection
data Connection (side :: Side) Source #
A Rustls connection.
Read and write
:: MonadIO m | |
=> Connection side | |
-> Int | Maximum result length. Note that a buffer of this size will be allocated. |
-> m ByteString |
Read data from the Rustls Connection
into a ByteString
. The result will
not be longer than the given length.
writeBS :: MonadIO m => Connection side -> ByteString -> m () Source #
Write a ByteString
to the Rustls Connection
.
Handshaking
handshake :: MonadIO m => Connection side -> HandshakeQuery side a -> m a Source #
Ensure that the connection is handshaked. It is only necessary to call this
if you want to obtain connection information. You can do so by providing a
HandshakeQuery
.
>>>
:{
getALPNAndTLSVersion :: MonadIO m => Connection side -> m (Maybe ALPNProtocol, TLSVersion) getALPNAndTLSVersion conn = handshake conn $ (,) <$> getALPNProtocol <*> getTLSVersion :}
data HandshakeQuery (side :: Side) a Source #
Instances
Monad (HandshakeQuery side) Source # | |
Defined in Rustls.Internal (>>=) :: HandshakeQuery side a -> (a -> HandshakeQuery side b) -> HandshakeQuery side b # (>>) :: HandshakeQuery side a -> HandshakeQuery side b -> HandshakeQuery side b # return :: a -> HandshakeQuery side a # | |
Functor (HandshakeQuery side) Source # | |
Defined in Rustls.Internal fmap :: (a -> b) -> HandshakeQuery side a -> HandshakeQuery side b # (<$) :: a -> HandshakeQuery side b -> HandshakeQuery side a # | |
Applicative (HandshakeQuery side) Source # | |
Defined in Rustls.Internal pure :: a -> HandshakeQuery side a # (<*>) :: HandshakeQuery side (a -> b) -> HandshakeQuery side a -> HandshakeQuery side b # liftA2 :: (a -> b -> c) -> HandshakeQuery side a -> HandshakeQuery side b -> HandshakeQuery side c # (*>) :: HandshakeQuery side a -> HandshakeQuery side b -> HandshakeQuery side b # (<*) :: HandshakeQuery side a -> HandshakeQuery side b -> HandshakeQuery side a # |
getALPNProtocol :: HandshakeQuery side (Maybe ALPNProtocol) Source #
Get the negotiated ALPN protocol, if any.
getTLSVersion :: HandshakeQuery side TLSVersion Source #
Get the negotiated TLS protocol version.
getCipherSuite :: HandshakeQuery side CipherSuite Source #
Get the negotiated cipher suite.
getSNIHostname :: HandshakeQuery Server (Maybe Text) Source #
Get the SNI hostname set by the client, if any.
getPeerCertificate :: CSize -> HandshakeQuery side (Maybe DERCertificate) Source #
Get the i
-th certificate provided by the peer.
Index 0
is the end entity certificate. Higher indices are certificates in
the chain. Requesting an index higher than what is available returns
Nothing
.
Closing
sendCloseNotify :: MonadIO m => Connection side -> m () Source #
Send a close_notify
warning alert. This informs the peer that the
connection is being closed.
Logging
data LogCallback Source #
A Rustls connection logging callback.
newLogCallback :: (LogLevel -> Text -> IO ()) -> Acquire LogCallback Source #
Allocate a new logging callback, taking a LogLevel
and a message.
🚫 Make sure that its lifetime encloses those of the Connection
s which you
configured to use it.
Rustls log level.
Instances
Bounded LogLevel Source # | |
Enum LogLevel Source # | |
Eq LogLevel Source # | |
Ord LogLevel Source # | |
Defined in Rustls.Internal | |
Show LogLevel Source # | |
Generic LogLevel Source # | |
type Rep LogLevel Source # | |
Defined in Rustls.Internal type Rep LogLevel = D1 ('MetaData "LogLevel" "Rustls.Internal" "rustls-0.0.0.0-inplace" 'False) ((C1 ('MetaCons "LogLevelError" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "LogLevelWarn" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "LogLevelInfo" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "LogLevelDebug" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "LogLevelTrace" 'PrefixI 'False) (U1 :: Type -> Type)))) |
Raw Ptr
-based API
readPtr :: MonadIO m => Connection side -> Ptr Word8 -> CSize -> m CSize Source #
Read data from the Rustls Connection
into the given buffer.
writePtr :: MonadIO m => Connection side -> Ptr Word8 -> CSize -> m CSize Source #
Write data to the Rustls Connection
from the given buffer.
Misc
Combined version string of Rustls and rustls-ffi.
>>>
version
"rustls-ffi/0.9.1/rustls/0.20.4"
Backend
class Backend b where Source #
Underlying data sources for Rustls.
:: b | |
-> Ptr Word8 | Target buffer pointer. |
-> CSize | Target buffer length. |
-> IO CSize | Amount of bytes read. |
Read data from the backend into the given buffer.
:: b | |
-> Ptr Word8 | Source buffer pointer. |
-> CSize | Source buffer length. |
-> IO CSize | Amount of bytes written. |
Write data from the given buffer to the backend.
Instances
Backend Socket Source # | |
Backend ByteStringBackend Source # | This instance will silently truncate |
Defined in Rustls.Internal backendRead :: ByteStringBackend -> Ptr Word8 -> CSize -> IO CSize Source # backendWrite :: ByteStringBackend -> Ptr Word8 -> CSize -> IO CSize Source # |
data ByteStringBackend Source #
An in-memory Backend
.
ByteStringBackend | |
|
Instances
Generic ByteStringBackend Source # | |
Defined in Rustls.Internal type Rep ByteStringBackend :: Type -> Type # from :: ByteStringBackend -> Rep ByteStringBackend x # to :: Rep ByteStringBackend x -> ByteStringBackend # | |
Backend ByteStringBackend Source # | This instance will silently truncate |
Defined in Rustls.Internal backendRead :: ByteStringBackend -> Ptr Word8 -> CSize -> IO CSize Source # backendWrite :: ByteStringBackend -> Ptr Word8 -> CSize -> IO CSize Source # | |
type Rep ByteStringBackend Source # | |
Defined in Rustls.Internal type Rep ByteStringBackend = D1 ('MetaData "ByteStringBackend" "Rustls.Internal" "rustls-0.0.0.0-inplace" 'False) (C1 ('MetaCons "ByteStringBackend" 'PrefixI 'True) (S1 ('MetaSel ('Just "bsbRead") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 (Int -> IO ByteString)) :*: S1 ('MetaSel ('Just "bsbWrite") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 (ByteString -> IO ())))) |
Types
newtype ALPNProtocol Source #
An ALPN protocol ID. See https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids for a list of registered IDs.
Instances
data CertifiedKey Source #
A complete chain of certificates plus a private key for the leaf certificate.
CertifiedKey | |
|
Instances
Show CertifiedKey Source # | |
Defined in Rustls.Internal showsPrec :: Int -> CertifiedKey -> ShowS # show :: CertifiedKey -> String # showList :: [CertifiedKey] -> ShowS # | |
Generic CertifiedKey Source # | |
Defined in Rustls.Internal type Rep CertifiedKey :: Type -> Type # from :: CertifiedKey -> Rep CertifiedKey x # to :: Rep CertifiedKey x -> CertifiedKey # | |
type Rep CertifiedKey Source # | |
Defined in Rustls.Internal type Rep CertifiedKey = D1 ('MetaData "CertifiedKey" "Rustls.Internal" "rustls-0.0.0.0-inplace" 'False) (C1 ('MetaCons "CertifiedKey" 'PrefixI 'True) (S1 ('MetaSel ('Just "certificateChain") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 ByteString) :*: S1 ('MetaSel ('Just "privateKey") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 ByteString))) |
newtype DERCertificate Source #
A DER-encoded certificate.
Instances
data TLSVersion where Source #
A TLS protocol version supported by Rustls.
pattern TLS12 :: TLSVersion | |
pattern TLS13 :: TLSVersion |
Instances
defaultTLSVersions :: NonEmpty TLSVersion Source #
The default TLSVersion
s used by Rustls. A subset of defaultTLSVersions
.
allTLSVersions :: NonEmpty TLSVersion Source #
All TLSVersion
s supported by Rustls.
data CipherSuite Source #
A TLS cipher suite supported by Rustls.
Instances
Eq CipherSuite Source # | |
Defined in Rustls.Internal (==) :: CipherSuite -> CipherSuite -> Bool # (/=) :: CipherSuite -> CipherSuite -> Bool # | |
Ord CipherSuite Source # | |
Defined in Rustls.Internal compare :: CipherSuite -> CipherSuite -> Ordering # (<) :: CipherSuite -> CipherSuite -> Bool # (<=) :: CipherSuite -> CipherSuite -> Bool # (>) :: CipherSuite -> CipherSuite -> Bool # (>=) :: CipherSuite -> CipherSuite -> Bool # max :: CipherSuite -> CipherSuite -> CipherSuite # min :: CipherSuite -> CipherSuite -> CipherSuite # | |
Show CipherSuite Source # | |
Defined in Rustls.Internal showsPrec :: Int -> CipherSuite -> ShowS # show :: CipherSuite -> String # showList :: [CipherSuite] -> ShowS # |
cipherSuiteID :: CipherSuite -> Word16 Source #
Get the IANA value from a cipher suite. The bytes are interpreted in network order.
See https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4 for a list.
showCipherSuite :: CipherSuite -> Text Source #
Get the text representation of a cipher suite.
defaultCipherSuites :: NonEmpty CipherSuite Source #
The default CipherSuite
s used by Rustls. A subset of allCipherSuites
.
allCipherSuites :: NonEmpty CipherSuite Source #
All CipherSuite
s supported by Rustls.
Exceptions
data RustlsException Source #
TLS exception thrown by Rustls.
Use displayException
for a human-friendly representation.
Instances
Show RustlsException Source # | |
Defined in Rustls.Internal showsPrec :: Int -> RustlsException -> ShowS # show :: RustlsException -> String # showList :: [RustlsException] -> ShowS # | |
Exception RustlsException Source # | |
Defined in Rustls.Internal |
isCertError :: RustlsException -> Bool Source #
Checks if the given RustlsException
represents a certificate error.