diff options
Diffstat (limited to 'doc/tls.rst')
-rw-r--r-- | doc/tls.rst | 620 |
1 files changed, 620 insertions, 0 deletions
diff --git a/doc/tls.rst b/doc/tls.rst new file mode 100644 index 000000000..e5e9dc91d --- /dev/null +++ b/doc/tls.rst @@ -0,0 +1,620 @@ + +Transport Layer Security (TLS) +======================================== + +.. versionadded:: 1.11.0 + +Botan supports both client and server implementations of the SSL/TLS +protocols, including SSL v3, TLS v1.0, TLS v1.1, and TLS v1.2 (the +insecure and obsolete SSL v2 protocol is not supported, beyond +processing SSL v2 client hellos which some clients still send for +backwards compatability with ancient servers). + +The TLS implementation does not know anything about sockets or +networks. Instead, it calls a user provided callback (hereafter +``output_fn``) whenever it has data that it would want to send to the +other party, and whenever the application receives some data from the +counterparty it passes that information to TLS using +:cpp:func:`TLS::Channel::received_data`. If the data passed in results +in a handshake completing, then the user provided +``handshake_complete`` is called, and if some application data being +received, or a TLS :ref:`alert <tls_alerts>` is received, the another +user provided callback, hereafter ``proc_fn``, is called. + +The callbacks that TLS calls have the signatures + + .. cpp:function:: void output_fn(const byte data[], size_t data_len) + + TLS requests that all bytes of *data* be queued up to send. After + this function returns, *data* will be overwritten, so a copy + should be made if the callback cannot send the immediately. + + .. cpp:function:: void proc_fn(const byte data[], size_t data_len, \ + const TLS::Alert& alert) + + Called whenever application data or an alert is received from the + other side of the connection, in which case *data* and *data_len* + specify the data received. This array will be overwritten + sometime after the callback returns, so again a copy should be + made if need be. + + If :cpp:func:`TLS::Alert::is_valid` is true then *alert* + specifies a valid alert that was received. Note that if received + before the handshake has completed, an attacker can easily insert + false alert values. + + .. note:: + + Currently, if an alert was passed in then no other data was + provided. This allows an appliction to easily distinguish + between data sent before and after the alert was received. + + .. cpp:function:: bool handshake_complete(const TLS::Session& session) + + Called whenever a negotiation completes. This can happen more + than once on any connection. The *session* parameter provides + information about the session which was established. + + If this function returns false, the session will not be cached + for later resumption. + + If this function wishes to cancel the handshake, it can throw an + exception which will send a close message to the counterparty and + reset the connection state. + +You can of course use tools like ``std::bind`` to bind additional +parameters to your callback functions. + + +TLS Channels +---------------------------------------- + +TLS servers and clients share an interface called `TLS::Channel`. A +TLS channel (either client or server object) has these methods +available: + +.. cpp:class:: TLS::Channel + + .. cpp:function:: size_t received_data(const byte buf[], size_t buf_size) + + This function is used to provide data sent by the counterparty + (eg data that you read off the socket layer). Depending on the + current protocol state and the amount of data provided this may + result in one or more callback functions that were provided to + the constructor being called. + + The return value of ``received_data`` specifies how many more + bytes of input are needed to make any progress, unless the end of + the data fell exactly on a message boundary, in which case it + will return 0 instead. + + .. cpp:function:: void send(const byte buf[], size_t buf_size) + + If the connection has completed the initial handshake process, + the data provided is sent to the counterparty as TLS + traffic. Otherwise, an exception is thrown. + + .. cpp:function:: void close() + + A close notification is sent to the counterparty, and the + internal state is cleared. + + .. cpp:function:: bool is_active() + + Returns true if and only if a handshake has been completed on + this connection and the connection has not been subsequently + closed. + + .. cpp:function:: bool is_closed() + + Returns true if and only if either a close notification or a + fatal alert message have been either sent or received. + + .. cpp:function:: void renegotiate(bool force_full_renegotiation = false) + + Initiates a renegotiation. The counterparty is allowed by the + protocol to ignore this request. If a successful renegotiation + occurs, the *handshake_complete* callback will be called again. + + If *force_full_renegotiation* is false, then the client will + attempt to simply renew the current session - this will refresh + the symmetric keys but will not change the session master + secret. Otherwise it will initiate a completely new session. + + For a server, if *force_full_renegotiation* is false, then a + session resumption will be allowed if the client attempts + it. Otherwise the server will prevent resumption and force the + creation of a new session. + + .. cpp:function:: std::vector<X509_Certificate> peer_cert_chain() + + Returns the certificate chain of the counterparty. When acting + as a client, this value will be non-empty unless the client's + policy allowed anonymous connections and the server then chose + an anonymous ciphersuite. Acting as a server, this value will + ordinarily be empty, unless the server requested a certificate + and the client responded with one. + +.. _tls_client: + +TLS Clients +---------------------------------------- + +.. cpp:class:: TLS::Client + + .. cpp:function:: TLS::Client( \ + std::function<void, const byte*, size_t> output_fn, \ + std::function<void, const byte*, size_t, TLS::Alert> proc_fn, \ + std::function<bool, const TLS::Session&> handshake_complete, \ + TLS::Session_Manager& session_manager, \ + Credentials_Manager& credendials_manager, \ + const TLS::Policy& policy, \ + RandomNumberGenerator& rng, \ + const std::string& servername = "", \ + std::function<std::string, std::vector<std::string> > next_protocol) + + Initialize a new TLS client. The constructor will immediately + initiate a new session. + + The *output_fn* callback will be called with output that + should be sent to the counterparty. For instance this will be + called immediately from the constructor after the client hello + message is constructed. An implementation of *output_fn* is + allowed to defer the write (for instance if writing when the + callback occurs would block), but should eventually write the data + to the counterparty *in order*. + + The *proc_fn* will be called with data sent by the counterparty + after it has been processed. The byte array and size_t represent + the plaintext; the :cpp:class:`TLS::Alert` value provides + notification if the counterparty sent an alert via the TLS alert + system. Possible values of alert data are included in the + Alert_Type enum. Particularly relevant is the CLOSE_NOTIFY value. + + The *handshake_complete* function is called when a handshake + (either initial or renegotiation) is completed. The return value of + the callback specifies if the session should be cached for later + resumption. If the function for some reason desires to prevent the + connection from completing, it should throw an exception + (preferably a TLS::Exception, which can provide more specific alert + information to the counterparty). The :cpp:class:`TLS::Session` + provides information about the session that was just established. + + The *session_manager* is an interface for storing TLS sessions, + which allows for session resumption upon reconnecting to a server. + In the absence of a need for persistent sessions, use + :cpp:class:`TLS::Session_Manager_In_Memory` which caches + connections for the lifetime of a single process. See + :ref:`tls_session_managers` for more about session managers. + + The *credentials_manager* is an interface that will be called to + retrieve any certificates, secret keys, pre-shared keys, or SRP + intformation; see :doc:`credentials_manager` for more information. + + Use *servername* to specify the DNS name of the server you are + attempting to connect to, if you know it. This helps the server + select what certificate to use and helps the client validate the + connection. + + The optional *next_protocol* callback is called if the server + indicates it supports the next protocol notification extension. + The callback wlil be called with a list of protocol names that the + server advertises, and the client can select from them or return an + unadvertised protocol. + +A simple TLS client example: + +.. literalinclude:: examples/tls_client.cpp + +TLS Servers +---------------------------------------- + +.. cpp:class:: TLS::Server + + .. cpp:function:: TLS::Server( \ + std::function<void, const byte*, size_t> output_fn, \ + std::function<void, const byte*, size_t, TLS::Alert> proc_fn, \ + std::function<bool, const TLS::Session&> handshake_complete, \ + TLS::Session_Manager& session_manager, \ + Credentials_Manager& creds, \ + const TLS::Policy& policy, \ + RandomNumberGenerator& rng, \ + const std::vector<std::string>& protocols) + +The first 7 arguments are treated similiarly to the :ref:`client +<tls_client>`. The final (optional) argument, protocols, specifies +the protocols the server is willing to advertise it supports. + +A TLS server that can handle concurrent connections using asio: + +.. literalinclude:: examples/asio_tls_server.cpp + +.. _tls_sessions: + +TLS Sessions +---------------------------------------- + +TLS allows clients and servers to support *session resumption*, where +the end point retains some information about an established session +and then reuse that information to bootstrap a new session in way that +is much cheaper computationally than a full handshake. + +Every time your handshake callback is called, a new session has been +established, and a ``TLS::Session`` is included that provides +information about that session: + +.. cpp:class:: TLS::Session + + .. cpp:function:: Protocol_Version version() const + + Returns the protocol version that was negotiated + + .. cpp:function:: Ciphersuite ciphersite() const + + Returns the :ref:`ciphersuite <tls_ciphersuite>` that was negotiated. + + .. cpp:function:: std::string sni_hostname() const + + Returns the hostname the client indicated in the hello message. + + .. cpp:function:: std::vector<X509_Certificate> peer_certs() const + + Returns the certificate chain of the peer + + .. cpp:function:: std::string srp_identifier() const + + If an SRP ciphersuite was used, then this is the identifier + that was used for authentication. + + .. cpp:function:: bool secure_renegotiation() const + + Returns ``true`` if the connection was negotiated with the + correct extensions to prevent the renegotiation attack. + +There are also functions for serialization and deserializing sessions: + +.. cpp:class:: TLS::Session + + .. cpp:function:: std::vector<byte> encrypt(const SymmetricKey& key, \ + RandomNumberGenerator& rng) + + Encrypts a session using a symmetric key *key* and returns a raw + binary value that can later be passed to ``decrypt``. + + .. cpp:function:: static Session decrypt(const byte ciphertext[], \ + size_t length, \ + const SymmetricKey& key) + + Decrypts a session that was encrypted previously with + ``encrypt`` and *key*, or throws an exception if decryption + fails. + + .. cpp:function:: secure_vector<byte> DER_encode() const + + Returns a serialized version of the session. + + .. warning:: The return value contains the master secret for + the session, and an attacker who recovers it could + recover plaintext of previous sessions or + impersonate one side to the other. + +.. _tls_session_managers: + +TLS Session Managers +---------------------------------------- + +You may want sessions stored in a specific format or storage type. To +do so, implement the ``TLS::Session_Manager`` interface and pass your +implementation to the ``TLS::Client`` or ``TLS::Server`` constructor. + +.. cpp:class:: TLS::Session_Mananger + + .. cpp:function:: void save(const Session& session) + + Save a new *session*. It is possible that this sessions session + ID will replicate a session ID already stored, in which case the + new session information should overwrite the previous information. + + .. cpp:function:: void remove_entry(const std::vector<byte>& session_id) + + Remove the session identified by *session_id*. Future attempts + at resumption should fail for this session. + + .. cpp:function:: bool load_from_session_id(const std::vector<byte>& session_id, \ + Session& session) + + Attempt to resume a session identified by *session_id*. If + located, *session* is set to the session data previously passed + to *save*, and ``true`` is returned. Otherwise *session* is not + modified and ``false`` is returned. + + .. cpp:function:: bool load_from_host_info(const std::string& hostname, u16bit port, \ + Session& session) + + Attempt to resume a session for *hostname* / *port*. If *port* + is zero, try to find a session for *hostname* on any port. With + the current client implementation, *port* is always zero. + + + .. cpp:function:: std::chrono::seconds session_lifetime() const + + Returns the expected maximum lifetime of a session when using + this session manager. Will return 0 if the lifetime is unknown + or has no explicit expiration policy. + +.. _tls_session_manager_inmem: + +In Memory Session Manager +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``TLS::Session_Manager_In_Memory`` implementation saves sessions +in memory, with an upper bound on the maximum number of sessions and +the lifetime of a session. + +.. cpp:class:: TLS::Session_Manager_In_Memory + + .. cpp:function:: Session_Manager_In_Memory(size_t max_sessions = 1000, \ + std::chrono::seconds session_lifetime = 7200) + + Limits the maximum number of saved sessions to *max_sessions*, and + expires all sessions older than *session_lifetime*. + +Noop Session Mananger +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``TLS::Session_Manager_Noop`` implementation does not save +sessions at all, and thus session resumption always fails. Its +constructor has no arguments. + +SQLite3 Session Manager +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This session manager is only available if support for SQLite3 was +enabled at build time. If the macro +``BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER`` is defined, then +``botan/tls_session_manager_sqlite.h`` contains +``TLS::Session_Manager_SQLite`` which stores sessions persistently to +a sqlite3 database. The session data is encrypted using a passphrase, +and stored in two tables, named ``tls_sessions`` (which holds the +actual session information) and ``tls_sessions_metadata`` (which holds +the PBKDF information). + +.. warning:: The hostnames associated with the saved sessions are + stored in the database in plaintext. This may be a + serious privacy risk in some applications. + +.. cpp:class:: TLS::Session_Manager_SQLite + + .. cpp:function:: Session_Manager_SQLite( \ + const std::string& passphrase, \ + RandomNumberGenerator& rng, \ + const std::string& db_filename, \ + size_t max_sessions = 1000, \ + std::chrono::seconds session_lifetime = 7200) + + Uses the sqlite3 database named by *db_filename*. + +TLS Policies +---------------------------------------- + +``TLS::Policy`` is how an application can control details of what will +be negotiated during a handshake. + +.. cpp:class:: TLS::Policy + + .. cpp:function:: Protocol_Version min_version() const + + Returns the minimum protocol version we are willing to negotiate. + + Default: SSL v3 + + .. cpp:function:: Protocol_Version pref_version() const + + Return the protocol version we would prefer to negotiate. This is + the version that clients will offer to servers. + + Default: TLS v1.2 + + .. cpp:function:: std::vector<std::string> allowed_ciphers() const + + Returns the list of ciphers we are willing to negotiate, in order + of preference. + + Default: "AES-256", "AES-128", "ARC4", "3DES" + + Also allowed: "Camellia-256", "Camellia-128", "SEED" + + .. cpp:function:: std::vector<std::string> allowed_macs() const + + Returns the list of algorithms we are willing to use for + message authentication, in order of preference. + + Default: "SHA-384", "SHA-256", "SHA-1" + + Also allowed: "MD5" + + .. cpp:function:: std::vector<std::string> allowed_key_exchange_methods() const + + Returns the list of key exchange methods we are willing to use, + in order of preference. + + Default: "ECDH", "DH", "RSA" + + Also allowed: "SRP_SHA", "ECDHE_PSK", "DHE_PSK", "PSK" + + .. cpp:function:: std::vector<std::string> allowed_signature_hashes() const + + Returns the list of algorithms we are willing to use for + public key signatures, in order of preference. + + Default: "SHA-512", "SHA-384", "SHA-256", "SHA-224", "SHA-1" + + Also allowed (although **not recommended**): "MD5" + + .. note:: + + This is only used with TLS v1.2. In earlier versions of the + protocol, signatures are fixed to using only SHA-1 (for + DSA/ECDSA) or a MD5/SHA-1 pair (for RSA). + + .. cpp:function:: std::vector<std::string> allowed_signature_methods() const + + Default: "ECDSA", "RSA", "DSA" + + Also allowed: "" (meaning anonymous) + + .. cpp:function:: std::vector<std::string> allowed_ecc_curves() const + + Return a list of ECC curves we are willing to use, in order of preference. + + Default: "secp521r1", "secp384r1", "secp256r1", + "secp256k1", "secp224r1", "secp224k1" + + Also allowed: "secp192r1", "secp192k1", "secp160r2", "secp160r1", "secp160k1" + + .. cpp:function:: std::vector<byte> compression() const + + Return the list of compression methods we are willing to use, in order of + preference. + + .. note:: + + TLS compression is not currently supported. + + .. cpp:function:: bool allow_insecure_renegotiation() const + + If this function returns true, we will allow renegotiation attempts + even if the counterparty does not support the RFC 5746 extensions. + + .. warning:: Returning true here could expose you to attacks + + Default: false + + .. cpp:function:: DL_Group dh_group() const + + For ephemeral Diffie-Hellman key exchange, the server sends a + group parameter. Return the group parameter a server should + use. + + Default: 2048 bit IETF IPsec group ("modp/ietf/2048") + + .. cpp:function:: size_t minimum_dh_group_size() const + + Return the minimum size in bits for a Diffie-Hellman group that a + client will accept. Due to the design of the protocol the client + has only two options - accept the group, or reject it with a + fatal alert then attempt to reconnect after disabling ephemeral + Diffie-Hellman. + + Default: 1024 bits + + .. cpp:function:: bool hide_unknown_users() const + + The SRP and PSK suites work using an identifier along with a + shared secret. If this function returns true, when an identifier + that the server does not recognize is provided by a client, a + random shared secret will be generated in such a way that a + client should not be able to tell the difference between the + identifier not being known and the secret being wrong. This can + help protect against some username probing attacks. If it + returns false, the server will instead send an + ``unknown_psk_identity`` alert when an unknown identifier is + used. + + Default: false + + .. cpp:function:: u32bit session_ticket_lifetime() const + + Return the lifetime of session tickets. Each session includes the + start time. Sessions resumptions using tickets older than + ``session_ticket_lifetime`` seconds will fail, forcing a full + renegotiation. + + Default: 86400 seconds (1 day) + +.. _tls_ciphersuite: + +TLS Ciphersuites +---------------------------------------- + +.. cpp:class:: TLS::Ciphersuite + + .. cpp:function:: u16bit ciphersuite_code() const + + Return the numerical code for this ciphersuite + + .. cpp:function:: std::string to_string() const + + Return name of ciphersuite + + .. cpp:function:: std::string kex_algo() const + + Return the key exchange algorithm of this ciphersuite + + .. cpp:function:: std::string sig_algo() const + + Return the signature algorithm of this ciphersuite + + .. cpp:function:: std::string cipher_algo() const + + Return the cipher algorithm of this ciphersuite + + .. cpp:function:: std::string mac_algo() const + + Return the authentication algorithm of this ciphersuite + +.. _tls_alerts: + +TLS Alerts +---------------------------------------- + +A ``TLS::Alert`` is passed to every invocation of a channel's +*proc_fn*. Most of the time, no alert was sent and so the alert will +be of type ``NULL_ALERT``. + +.. cpp:class:: TLS::Alert + + .. cpp:function:: is_valid() const + + Return true if this alert is not a null alert + + .. cpp:function:: is_fatal() const + + Return if this alert is fatal or a warning alert + + .. cpp:function:: Type type() const + + Returns the type of the alert as an enum + + .. cpp:function:: std::string type_string() + + Returns the type of the alert as a string + +TLS Protocol Version +---------------------------------------- + +TLS has several different versions with slightly different behaviors. +The ``TLS::Protocol_Version`` class represents a specific version: + +.. cpp:class:: TLS::Protocol_Version + + .. cpp:type:: enum Version_Code + + ``SSL_V3``, ``TLS_V10``, ``TLS_V11``, ``TLS_V12`` + + .. cpp:function:: Protocol_Version(Version_Code named_version) + + Create a specific version + + .. cpp:function:: byte major_version() const + + Returns major number of the protocol version + + .. cpp:function:: byte minor_version() const + + Returns minor number of the protocol version + + .. cpp:function:: std::string to_string() const + + Returns string description of the version, typically "SSL v3" or + "TLS v1.n" |