Overhaul session resumption documentation. This has come up a few times and our docs aren't great. This hopefully describes the sharp edges better. Change-Id: I5d4044449f74ec116838fd1bba629cd90dc0d1ac Reviewed-on: https://boringssl-review.googlesource.com/17504 Reviewed-by: Adam Langley <agl@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 3b91e00..59fbeb8 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h
@@ -1706,25 +1706,39 @@ /* Session caching. * - * Session caching allows clients to reconnect to a server based on saved - * parameters from a previous connection. + * Session caching allows connections to be established more efficiently based + * on saved parameters from a previous connection, called a session (see + * |SSL_SESSION|). The client offers a saved session, using an opaque identifier + * from a previous connection. The server may accept the session, if it has the + * parameters available. Otherwise, it will decline and continue with a full + * handshake. + * + * This requires both the client and the server to retain session state. A + * client does so with a stateful session cache. A server may do the same or, if + * supported by both sides, statelessly using session tickets. For more + * information on the latter, see the next section. * * For a server, the library implements a built-in internal session cache as an - * in-memory hash table. One may also register callbacks to implement a custom - * external session cache. An external cache may be used in addition to or - * instead of the internal one. Use |SSL_CTX_set_session_cache_mode| to toggle - * the internal cache. + * in-memory hash table. Servers may also use |SSL_CTX_sess_set_get_cb| and + * |SSL_CTX_sess_set_new_cb| to implement a custom external session cache. In + * particular, this may be used to share a session cache between multiple + * servers in a large deployment. An external cache may be used in addition to + * or instead of the internal one. Use |SSL_CTX_set_session_cache_mode| to + * toggle the internal cache. * - * For a client, the only option is an external session cache. Prior to - * handshaking, the consumer should look up a session externally (keyed, for - * instance, by hostname) and use |SSL_set_session| to configure which session - * to offer. The callbacks may be used to determine when new sessions are - * available. + * For a client, the only option is an external session cache. Clients may use + * |SSL_CTX_sess_set_new_cb| to register a callback for when new sessions are + * available. These may be cached and, in subsequent compatible connections, + * configured with |SSL_set_session|. * - * Note that offering or accepting a session short-circuits most parameter - * negotiation. Resuming sessions across different configurations may result in - * surprising behavior. So, for instance, a client implementing a version - * fallback should shard its session cache by maximum protocol version. */ + * Note that offering or accepting a session short-circuits certificate + * verification and most parameter negotiation. Resuming sessions across + * different contexts may result in security failures and surprising + * behavior. For a typical client, this means sessions for different hosts must + * be cached under different keys. A client that connects to the same host with, + * e.g., different cipher suite settings or client certificates should also use + * separate session caches between those contexts. Servers should also partition + * session caches between SNI hosts with |SSL_CTX_set_session_id_context|. */ /* SSL_SESS_CACHE_OFF disables all session caching. */ #define SSL_SESS_CACHE_OFF 0x0000 @@ -1771,25 +1785,6 @@ * It is an error to call this function after the handshake has begun. */ OPENSSL_EXPORT int SSL_set_session(SSL *ssl, SSL_SESSION *session); -/* SSL_get_session returns a non-owning pointer to |ssl|'s session. For - * historical reasons, which session it returns depends on |ssl|'s state. - * - * Prior to the start of the initial handshake, it returns the session the - * caller set with |SSL_set_session|. After the initial handshake has finished - * and if no additional handshakes are in progress, it returns the currently - * active session. Its behavior is undefined while a handshake is in progress. - * - * Using this function to add new sessions to an external session cache is - * deprecated. Use |SSL_CTX_sess_set_new_cb| instead. */ -OPENSSL_EXPORT SSL_SESSION *SSL_get_session(const SSL *ssl); - -/* SSL_get0_session is an alias for |SSL_get_session|. */ -#define SSL_get0_session SSL_get_session - -/* SSL_get1_session acts like |SSL_get_session| but returns a new reference to - * the session. */ -OPENSSL_EXPORT SSL_SESSION *SSL_get1_session(SSL *ssl); - /* SSL_DEFAULT_SESSION_TIMEOUT is the default lifetime, in seconds, of a * session in TLS 1.2 or earlier. This is how long we are willing to use the * secret to encrypt traffic without fresh key material. */ @@ -1824,11 +1819,7 @@ * connection without a matching session ID context. * * For a server, if |SSL_VERIFY_PEER| is enabled, it is an error to not set a - * session ID context. - * - * TODO(davidben): Is that check needed? That seems a special case of taking - * care not to cross-resume across configuration changes, and this is only - * relevant if a server requires client auth. */ + * session ID context. */ OPENSSL_EXPORT int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const uint8_t *sid_ctx, size_t sid_ctx_len); @@ -1889,12 +1880,7 @@ * ticket is renewed. Further, it may not be called until some time after * |SSL_do_handshake| or |SSL_connect| completes if False Start is enabled. Thus * it's recommended to use this callback over checking |SSL_session_reused| on - * handshake completion. - * - * TODO(davidben): Conditioning callbacks on |SSL_SESS_CACHE_CLIENT| or - * |SSL_SESS_CACHE_SERVER| doesn't make any sense when one could just as easily - * not supply the callbacks. Removing that condition and the client internal - * cache would simplify things. */ + * handshake completion. */ OPENSSL_EXPORT void SSL_CTX_sess_set_new_cb( SSL_CTX *ctx, int (*new_session_cb)(SSL *ssl, SSL_SESSION *session)); @@ -1959,23 +1945,36 @@ /* Session tickets. * * Session tickets, from RFC 5077, allow session resumption without server-side - * state. Session tickets are supported in by default but may be disabled with + * state. The server maintains a secret ticket key and sends the client opaque + * encrypted session parameters, called a ticket. When offering the session, the + * client sends the ticket which the server decrypts to recover session state. + * Session tickets are enabled by default but may be disabled with * |SSL_OP_NO_TICKET|. * * On the client, ticket-based sessions use the same APIs as ID-based tickets. * Callers do not need to handle them differently. * * On the server, tickets are encrypted and authenticated with a secret key. By - * default, an |SSL_CTX| generates a key on creation. Tickets are minted and - * processed transparently. The following functions may be used to configure a - * persistent key or implement more custom behavior. There are three levels of - * customisation possible: + * default, an |SSL_CTX| generates a key on creation and uses it for the + * lifetime of the |SSL_CTX|. Tickets are minted and processed + * transparently. The following functions may be used to configure a persistent + * key or implement more custom behavior, including key rotation and sharing + * keys between multiple servers in a large deployment. There are three levels + * of customisation possible: * * 1) One can simply set the keys with |SSL_CTX_set_tlsext_ticket_keys|. * 2) One can configure an |EVP_CIPHER_CTX| and |HMAC_CTX| directly for * encryption and authentication. * 3) One can configure an |SSL_TICKET_ENCRYPTION_METHOD| to have more control - * and the option of asynchronous decryption. */ + * and the option of asynchronous decryption. + * + * An attacker that compromises a server's session ticket key can impersonate + * the server and, prior to TLS 1.3, retroactively decrypt all application + * traffic from sessions using that ticket key. Thus ticket keys must be + * regularly rotated for forward secrecy. Note the default key is currently not + * rotated. + * + * TODO(davidben): This is silly. Rotate the default key automatically. */ /* SSL_CTX_get_tlsext_ticket_keys writes |ctx|'s session ticket key material to * |len| bytes of |out|. It returns one on success and zero if |len| is not @@ -3884,6 +3883,29 @@ /* SSL_set_ecdh_auto returns one. */ #define SSL_set_ecdh_auto(ssl, onoff) 1 +/* SSL_get_session returns a non-owning pointer to |ssl|'s session. For + * historical reasons, which session it returns depends on |ssl|'s state. + * + * Prior to the start of the initial handshake, it returns the session the + * caller set with |SSL_set_session|. After the initial handshake has finished + * and if no additional handshakes are in progress, it returns the currently + * active session. Its behavior is undefined while a handshake is in progress. + * + * If trying to add new sessions to an external session cache, use + * |SSL_CTX_sess_set_new_cb| instead. In particular, using the callback is + * required as of TLS 1.3. For compatibility, this function will return an + * unresumable session which may be cached, but will never be resumed. + * + * If querying properties of the connection, use APIs on the |SSL| object. */ +OPENSSL_EXPORT SSL_SESSION *SSL_get_session(const SSL *ssl); + +/* SSL_get0_session is an alias for |SSL_get_session|. */ +#define SSL_get0_session SSL_get_session + +/* SSL_get1_session acts like |SSL_get_session| but returns a new reference to + * the session. */ +OPENSSL_EXPORT SSL_SESSION *SSL_get1_session(SSL *ssl); + /* Private structures. *