rustls-0.0.0.0: TLS bindings for Rustls
Safe HaskellNone
LanguageHaskell2010

Rustls

Description

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

Client

Builder

data ClientConfigBuilder Source #

Rustls client config builder.

Constructors

ClientConfigBuilder 

Fields

Instances

Instances details
Show ClientConfigBuilder Source # 
Instance details

Defined in Rustls.Internal

Generic ClientConfigBuilder Source # 
Instance details

Defined in Rustls.Internal

Associated Types

type Rep ClientConfigBuilder :: Type -> Type #

type Rep ClientConfigBuilder Source # 
Instance details

Defined in Rustls.Internal

type Rep ClientConfigBuilder = D1 ('MetaData "ClientConfigBuilder" "Rustls.Internal" "rustls-0.0.0.0-inplace" 'False) (C1 ('MetaCons "ClientConfigBuilder" 'PrefixI 'True) ((S1 ('MetaSel ('Just "clientConfigRoots") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 ClientRoots) :*: (S1 ('MetaSel ('Just "clientConfigTLSVersions") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 [TLSVersion]) :*: S1 ('MetaSel ('Just "clientConfigCipherSuites") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 [CipherSuite]))) :*: (S1 ('MetaSel ('Just "clientConfigALPNProtocols") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 [ALPNProtocol]) :*: (S1 ('MetaSel ('Just "clientConfigEnableSNI") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Bool) :*: S1 ('MetaSel ('Just "clientConfigCertifiedKeys") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 [CertifiedKey])))))

data ClientRoots Source #

How to look up root certificates.

Constructors

ClientRootsFromFile FilePath

Fetch PEM-encoded root certificates from a file.

ClientRootsInMemory [PEMCertificates]

Use in-memory PEM-encoded certificates.

Instances

Instances details
Show ClientRoots Source # 
Instance details

Defined in Rustls.Internal

Generic ClientRoots Source # 
Instance details

Defined in Rustls.Internal

Associated Types

type Rep ClientRoots :: Type -> Type #

type Rep ClientRoots Source # 
Instance details

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.

Constructors

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

Instances details
Show PEMCertificates Source # 
Instance details

Defined in Rustls.Internal

Generic PEMCertificates Source # 
Instance details

Defined in Rustls.Internal

Associated Types

type Rep PEMCertificates :: Type -> Type #

type Rep PEMCertificates Source # 
Instance details

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 Connections.

Open a connection

newClientConnection Source #

Arguments

:: 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.

Constructors

ServerConfigBuilder 

Fields

Instances

Instances details
Show ServerConfigBuilder Source # 
Instance details

Defined in Rustls.Internal

Generic ServerConfigBuilder Source # 
Instance details

Defined in Rustls.Internal

Associated Types

type Rep ServerConfigBuilder :: Type -> Type #

type Rep ServerConfigBuilder Source # 
Instance details

Defined in Rustls.Internal

type Rep ServerConfigBuilder = D1 ('MetaData "ServerConfigBuilder" "Rustls.Internal" "rustls-0.0.0.0-inplace" 'False) (C1 ('MetaCons "ServerConfigBuilder" 'PrefixI 'True) ((S1 ('MetaSel ('Just "serverConfigCertifiedKeys") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 (NonEmpty CertifiedKey)) :*: (S1 ('MetaSel ('Just "serverConfigTLSVersions") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 [TLSVersion]) :*: S1 ('MetaSel ('Just "serverConfigCipherSuites") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 [CipherSuite]))) :*: (S1 ('MetaSel ('Just "serverConfigALPNProtocols") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 [ALPNProtocol]) :*: (S1 ('MetaSel ('Just "serverConfigIgnoreClientOrder") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Bool) :*: S1 ('MetaSel ('Just "serverConfigClientCertVerifier") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 (Maybe ClientCertVerifier))))))

data ClientCertVerifier Source #

How to verify TLS client certificates.

Constructors

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

Instances details
Show ClientCertVerifier Source # 
Instance details

Defined in Rustls.Internal

Generic ClientCertVerifier Source # 
Instance details

Defined in Rustls.Internal

Associated Types

type Rep ClientCertVerifier :: Type -> Type #

type Rep ClientCertVerifier Source # 
Instance details

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 Connections.

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.

data Side Source #

Type-level indicator whether a Connection is client- or server-side.

Constructors

Client 
Server 

Read and write

readBS Source #

Arguments

:: 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 #

A Monad to get TLS connection information via handshake.

Instances

Instances details
Monad (HandshakeQuery side) Source # 
Instance details

Defined in Rustls.Internal

Methods

(>>=) :: 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 # 
Instance details

Defined in Rustls.Internal

Methods

fmap :: (a -> b) -> HandshakeQuery side a -> HandshakeQuery side b #

(<$) :: a -> HandshakeQuery side b -> HandshakeQuery side a #

Applicative (HandshakeQuery side) Source # 
Instance details

Defined in Rustls.Internal

Methods

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 Connections which you configured to use it.

data LogLevel Source #

Rustls log level.

Instances

Instances details
Bounded LogLevel Source # 
Instance details

Defined in Rustls.Internal

Enum LogLevel Source # 
Instance details

Defined in Rustls.Internal

Eq LogLevel Source # 
Instance details

Defined in Rustls.Internal

Ord LogLevel Source # 
Instance details

Defined in Rustls.Internal

Show LogLevel Source # 
Instance details

Defined in Rustls.Internal

Generic LogLevel Source # 
Instance details

Defined in Rustls.Internal

Associated Types

type Rep LogLevel :: Type -> Type #

Methods

from :: LogLevel -> Rep LogLevel x #

to :: Rep LogLevel x -> LogLevel #

type Rep LogLevel Source # 
Instance details

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

version :: Text Source #

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.

Methods

backendRead Source #

Arguments

:: 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.

backendWrite Source #

Arguments

:: 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

Instances details
Backend Socket Source # 
Instance details

Defined in Rustls.Internal

Backend ByteStringBackend Source #

This instance will silently truncate ByteStrings which are too long.

Instance details

Defined in Rustls.Internal

data ByteStringBackend Source #

An in-memory Backend.

Constructors

ByteStringBackend 

Fields

Instances

Instances details
Generic ByteStringBackend Source # 
Instance details

Defined in Rustls.Internal

Associated Types

type Rep ByteStringBackend :: Type -> Type #

Backend ByteStringBackend Source #

This instance will silently truncate ByteStrings which are too long.

Instance details

Defined in Rustls.Internal

type Rep ByteStringBackend Source # 
Instance details

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 #

Constructors

ALPNProtocol 

Instances

Instances details
Eq ALPNProtocol Source # 
Instance details

Defined in Rustls.Internal

Ord ALPNProtocol Source # 
Instance details

Defined in Rustls.Internal

Show ALPNProtocol Source # 
Instance details

Defined in Rustls.Internal

Generic ALPNProtocol Source # 
Instance details

Defined in Rustls.Internal

Associated Types

type Rep ALPNProtocol :: Type -> Type #

type Rep ALPNProtocol Source # 
Instance details

Defined in Rustls.Internal

type Rep ALPNProtocol = D1 ('MetaData "ALPNProtocol" "Rustls.Internal" "rustls-0.0.0.0-inplace" 'True) (C1 ('MetaCons "ALPNProtocol" 'PrefixI 'True) (S1 ('MetaSel ('Just "unALPNProtocol") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ByteString)))

data CertifiedKey Source #

A complete chain of certificates plus a private key for the leaf certificate.

Constructors

CertifiedKey 

Fields

Instances

Instances details
Show CertifiedKey Source # 
Instance details

Defined in Rustls.Internal

Generic CertifiedKey Source # 
Instance details

Defined in Rustls.Internal

Associated Types

type Rep CertifiedKey :: Type -> Type #

type Rep CertifiedKey Source # 
Instance details

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

Instances details
Eq DERCertificate Source # 
Instance details

Defined in Rustls

Ord DERCertificate Source # 
Instance details

Defined in Rustls

Show DERCertificate Source # 
Instance details

Defined in Rustls

Generic DERCertificate Source # 
Instance details

Defined in Rustls

Associated Types

type Rep DERCertificate :: Type -> Type #

type Rep DERCertificate Source # 
Instance details

Defined in Rustls

type Rep DERCertificate = D1 ('MetaData "DERCertificate" "Rustls" "rustls-0.0.0.0-inplace" 'True) (C1 ('MetaCons "DERCertificate" 'PrefixI 'True) (S1 ('MetaSel ('Just "unDERCertificate") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ByteString)))

data TLSVersion where Source #

A TLS protocol version supported by Rustls.

Bundled Patterns

pattern TLS12 :: TLSVersion 
pattern TLS13 :: TLSVersion 

defaultTLSVersions :: NonEmpty TLSVersion Source #

The default TLSVersions used by Rustls. A subset of defaultTLSVersions.

allTLSVersions :: NonEmpty TLSVersion Source #

All TLSVersions supported by Rustls.

data CipherSuite Source #

A TLS cipher suite supported by Rustls.

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 CipherSuites used by Rustls. A subset of allCipherSuites.

Exceptions

data RustlsException Source #

TLS exception thrown by Rustls.

Use displayException for a human-friendly representation.

isCertError :: RustlsException -> Bool Source #

Checks if the given RustlsException represents a certificate error.