libfilezilla
|
A Transport Layer Security (TLS) layer. More...
#include <tls_layer.hpp>
Public Member Functions | |
tls_layer (event_loop &event_loop, event_handler *evt_handler, socket_interface &layer, tls_system_trust_store *system_trust_store, logger_interface &logger) | |
bool | client_handshake (std::vector< uint8_t > const &required_certificate, std::vector< uint8_t > const &session_to_resume=std::vector< uint8_t >(), native_string const &session_hostname=native_string()) |
Starts shaking hands for a new TLS session as client. More... | |
bool | client_handshake (event_handler *const verification_handler, std::vector< uint8_t > const &session_to_resume=std::vector< uint8_t >(), native_string const &session_hostname=native_string()) |
Starts shaking hands for a new TLS session as client. More... | |
bool | server_handshake (std::vector< uint8_t > const &session_to_resume={}, std::string_view const &preamble={}, tls_server_flags flags={}) |
Starts shaking hand for a new TLS session as server. More... | |
std::vector< uint8_t > | get_session_parameters () const |
Gets session parameters for resumption. | |
std::vector< uint8_t > | get_raw_certificate () const |
Gets the session's peer certificate in DER. | |
void | set_verification_result (bool trusted) |
Must be called after having received certificate_verification_event. More... | |
std::string | get_protocol () const |
std::string | get_key_exchange () const |
std::string | get_cipher () const |
std::string | get_mac () const |
int | get_algorithm_warnings () const |
bool | resumed_session () const |
After a successful handshake, returns whether the session has been resumed. | |
bool | set_certificate_file (native_string const &keyfile, native_string const &certsfile, native_string const &password, bool pem=true) |
Sets the file containing the certificate (and its chain) and the file with the corresponding private key. More... | |
bool | set_certificate (std::string_view const &key, std::string_view const &certs, native_string const &password, bool pem=true) |
Sets the certificate (and its chain) and the private key. More... | |
bool | set_alpn (std::string_view const &alpn) |
Negotiate application protocol. More... | |
bool | set_alpn (std::vector< std::string > const &alpns, bool server_priority=false) |
void | set_min_tls_ver (tls_ver ver) |
Sets minimum allowed TLS version. | |
void | set_max_tls_ver (tls_ver ver) |
Sets maximum allowed TLS versions. More... | |
std::string | get_alpn () const |
After a successful handshake, returns which protocol, if any, has been negotiated. | |
native_string | get_hostname () const |
If running as server, get the SNI sent by the client. | |
bool | is_server () const |
int | new_session_ticket () |
If running as server with TLS1.3, send out a new session ticket before the next data payload. More... | |
void | set_unexpected_eof_cb (std::function< bool()> const &cb) |
Sets a callback to control whether unexpected eof is seen as error. More... | |
void | set_unexpected_eof_cb (std::function< bool()> &&cb) |
virtual socket_state | get_state () const override |
virtual int | connect (native_string const &host, unsigned int port, address_type family=address_type::unknown) override |
virtual int | read (void *buffer, unsigned int size, int &error) override |
virtual int | write (void const *buffer, unsigned int size, int &error) override |
virtual int | shutdown () override |
Signals peers that we want to close the connections. More... | |
virtual int | shutdown_read () override |
Check that all layers further down also have reached EOF. More... | |
virtual void | set_event_handler (event_handler *pEvtHandler, fz::socket_event_flag retrigger_block=socket_event_flag{}) override |
The handler for any events generated (or forwarded) by this layer. | |
Public Member Functions inherited from socket_layer | |
socket_layer (event_handler *handler, socket_interface &next_layer, bool event_passthrough) | |
socket_layer (socket_layer const &)=delete | |
socket_layer & | operator= (socket_layer const &)=delete |
virtual native_string | peer_host () const override |
virtual int | peer_port (int &error) const override |
socket_interface & | next () |
The next layer further down. Usually another layer or the actual socket. | |
Public Member Functions inherited from socket_interface | |
socket_interface (socket_interface const &)=delete | |
socket_interface & | operator= (socket_interface const &)=delete |
template<typename T , std::enable_if_t< std::is_signed_v< T >, int > = 0> | |
int | read (void *buffer, T size, int &error) |
template<typename T , std::enable_if_t< std::is_unsigned_v< T > &&(sizeof(T) > sizeof(unsigned int)), int > = 0> | |
int | read (void *buffer, T size, int &error) |
template<typename T , std::enable_if_t< std::is_signed_v< T >, int > = 0> | |
int | write (void const *buffer, T size, int &error) |
template<typename T , std::enable_if_t< std::is_unsigned_v< T > &&(sizeof(T) > sizeof(unsigned int)), int > = 0> | |
int | write (void const *buffer, T size, int &error) |
Public Member Functions inherited from socket_event_source | |
socket_event_source * | root () const |
Gets the root source. More... | |
Static Public Member Functions | |
static std::string | list_tls_ciphers (std::string const &priority) |
Returns a human-readable list of all TLS ciphers available with the passed priority string. | |
static std::string | get_gnutls_version () |
Returns the version of the loaded GnuTLS library, may be different than the version used at compile-time. | |
static std::pair< std::string, std::string > | generate_selfsigned_certificate (native_string const &password, std::string const &distinguished_name, std::vector< std::string > const &hostnames) |
Creates a new private key and a self-signed certificate. More... | |
static std::pair< std::string, std::string > | generate_csr (native_string const &password, std::string const &distinguished_name, std::vector< std::string > const &hostnames, bool csr_as_pem=true) |
Friends | |
class | tls_layer_impl |
Additional Inherited Members | |
Protected Member Functions inherited from event_handler | |
event_handler (event_loop &loop) | |
event_handler (event_handler const &h) | |
event_handler & | operator= (event_handler const &)=delete |
void | remove_handler () |
Deactivates handler, removes all pending events and stops all timers for this handler. More... | |
template<typename T , typename... Args> | |
void | send_event (Args &&... args) |
Sends the passed event asynchronously to the handler. More... | |
template<typename T > | |
void | send_event (T *evt) |
timer_id | add_timer (monotonic_clock const &deadline, duration const &interval={}) |
Adds a timer, returns the timer id. More... | |
timer_id | add_timer (duration const &interval, bool one_shot) |
Adds a timer, returns the timer id. More... | |
void | stop_timer (timer_id id) |
timer_id | stop_add_timer (timer_id id, monotonic_clock const &deadline, duration const &interval={}) |
timer_id | stop_add_timer (timer_id id, duration const &interval, bool one_shot) |
Protected Member Functions inherited from socket_layer | |
void | forward_socket_event (socket_event_source *source, socket_event_flag t, int error) |
void | forward_hostaddress_event (socket_event_source *source, std::string const &address) |
void | set_event_passthrough (socket_event_flag retrigger_block=socket_event_flag{}) |
socket_layer (event_handler *handler, socket_interface &next_layer, bool event_passthrough) | |
socket_layer (socket_layer const &)=delete | |
socket_layer & | operator= (socket_layer const &)=delete |
virtual native_string | peer_host () const override |
virtual int | peer_port (int &error) const override |
socket_interface & | next () |
The next layer further down. Usually another layer or the actual socket. | |
Protected Member Functions inherited from socket_interface | |
socket_interface (socket_event_source *root) | |
socket_interface (socket_interface const &)=delete | |
socket_interface & | operator= (socket_interface const &)=delete |
template<typename T , std::enable_if_t< std::is_signed_v< T >, int > = 0> | |
int | read (void *buffer, T size, int &error) |
template<typename T , std::enable_if_t< std::is_unsigned_v< T > &&(sizeof(T) > sizeof(unsigned int)), int > = 0> | |
int | read (void *buffer, T size, int &error) |
template<typename T , std::enable_if_t< std::is_signed_v< T >, int > = 0> | |
int | write (void const *buffer, T size, int &error) |
template<typename T , std::enable_if_t< std::is_unsigned_v< T > &&(sizeof(T) > sizeof(unsigned int)), int > = 0> | |
int | write (void const *buffer, T size, int &error) |
Protected Member Functions inherited from socket_event_source | |
socket_event_source (socket_event_source *root) | |
socket_event_source * | root () const |
Gets the root source. More... | |
Protected Attributes inherited from event_handler | |
event_loop & | event_loop_ |
Protected Attributes inherited from socket_layer | |
event_handler * | event_handler_ {} |
socket_interface & | next_layer_ |
bool | event_passthrough_ {} |
Protected Attributes inherited from socket_event_source | |
socket_event_source *const | root_ {} |
A Transport Layer Security (TLS) layer.
Can be used both for client- and server-side TLS.
This class also supports TLS session resumption. Resumption has to be requested explicitly, there is no shared state between unrelated sessions.
Two trust models are possible with this class for client-side TLS: Certificates can either be evaluated against the system trust store, or you can implement a custom trust model such as TOFU.
bool client_handshake | ( | event_handler *const | verification_handler, |
std::vector< uint8_t > const & | session_to_resume = std::vector< uint8_t >() , |
||
native_string const & | session_hostname = native_string() |
||
) |
Starts shaking hands for a new TLS session as client.
Returns true if the handshake has started, false on error.
If the handshake is started, wait for a connection event for the result.
If no verification handler is passed, verification is done solely using the system trust store.
If a verification handler is passed, it will receive a certificate_verification_event event upon which the handshake is paused until set_verification_result gets called including a tls_session_info structure. The handler is called even for certificates not trusted by the system trust store, allowing the following impairments: Unknown issuer, wrong hostname and certificates used outside their validity time.
bool client_handshake | ( | std::vector< uint8_t > const & | required_certificate, |
std::vector< uint8_t > const & | session_to_resume = std::vector< uint8_t >() , |
||
native_string const & | session_hostname = native_string() |
||
) |
Starts shaking hands for a new TLS session as client.
Returns true if the handshake has started, false on error.
If the handshake is started, wait for a connection event for the result.
The certificate that eventually gets negotiated for the session must match the passed required_certificate
, either in DER or PEM, or the handshake will fail.
|
static |
Creates a new private key and a self-signed certificate.
The distinguished name must be a RFC4514-compliant string.
If the password is non-empty, the private key gets encrypted using it.
The output pair is in PEM, first element is the key and the second the certificate.
int new_session_ticket | ( | ) |
If running as server with TLS1.3, send out a new session ticket before the next data payload.
Returns 0 on success, socket error otheerwise. Never returns EAGAIN.
It's a NOOP if TLS version != 1.3
Returns EINVAL if not server.
bool server_handshake | ( | std::vector< uint8_t > const & | session_to_resume = {} , |
std::string_view const & | preamble = {} , |
||
tls_server_flags | flags = {} |
||
) |
Starts shaking hand for a new TLS session as server.
Returns true if the handshake has started, false on error.
If the handshake is started, wait for a connection event for the result.
Before calling server_handshake, a valid certificate and key must be passed in through set_certificate.
Session parameters of an existing session can be passed to allow session resumption. Check after handshake completion with resumed_session()
The preamble is sent out after setting up all the parameters, but before the first handshake message
bool set_alpn | ( | std::string_view const & | alpn | ) |
Negotiate application protocol.
If the peer makes use of ALPN, the handshake fails if no matching protocol is found. If the peer does not use/support ALPN, the handshake continues and no protocol is negotiated.
Needs to be called prior to handshaking.
Which protocol is eventually chosen is always a server-side decsion. Iff running as server, server_priority controls the ALPN should be chosen based on the server's or the client's order in the list of ALPNs supported by both. server_priority is ignored if unning as client.
bool set_certificate | ( | std::string_view const & | key, |
std::string_view const & | certs, | ||
native_string const & | password, | ||
bool | pem = true |
||
) |
Sets the certificate (and its chain) and the private key.
For servers it is mandatory and is the certificate the server presents to the client.
For clients it is the optional client certificate.
If the pem flag is set, the input is assumed to be in PEM, otherwise DER.
bool set_certificate_file | ( | native_string const & | keyfile, |
native_string const & | certsfile, | ||
native_string const & | password, | ||
bool | pem = true |
||
) |
Sets the file containing the certificate (and its chain) and the file with the corresponding private key.
For servers a certificate is mandatory, it is presented to the client during the handshake.
For clients it is the optional client certificate.
If the pem flag is set, the input is assumed to be in PEM, otherwise DER.
void set_max_tls_ver | ( | tls_ver | ver | ) |
Sets maximum allowed TLS versions.
Don't set a max version in production, it is for testing things.
void set_unexpected_eof_cb | ( | std::function< bool()> const & | cb | ) |
Sets a callback to control whether unexpected eof is seen as error.
With TLS, an EOF on the socket prior to receiving a closure alert normally is an error. In many cases this is harmless though, e.g. if the connection is idle.
If this callback is set, premature termination is no longer seen as error if the callback returns false.
Callback must not call any tls_layer function.
Only controls the layer's own logging. Functions such as read will still return ECONNABORTED.
void set_verification_result | ( | bool | trusted | ) |
Must be called after having received certificate_verification_event.
Can be used to trust a certificate even if it is not trusted via the system trust store.
|
overridevirtual |
Signals peers that we want to close the connections.
Only disallows further sends, does not affect reading from the socket.
Returns 0 on success, an error code otherwise. If it returns EGAIN, shutdown is not yet complete. Call shutdown again after the next write event.
Reimplemented from socket_layer.
|
overridevirtual |
Check that all layers further down also have reached EOF.
Can only be called after read has returned 0, calling it earlier is undefined. shutdown_read should be called after eof to ensure all layers have reached EOF.
On an ordinary socket, this is a no-op. Some layers however may return an EOF before the next lower layer has reached its own EOF, such as the EOF of the secure channel from fz::tls_layer.
Closing the layer stack without all layers having reached EOF can lead to truncation on the write side: With a lower layer's EOF waiting in TCP's receive buffer and data pending in the send buffer, closing the socket is not graceful, it discards all pending data. Through shutdown_read you can assure that no pending data is left to receive, on this or any lower layer, so that closing the socket is done graceful ensuring delivery of all data in the send buffer (assuming there are no network errors).
Reimplemented from socket_layer.