Support setting per-connection default session lifetime value
Due to recent changes, changing the SSL session timeout from cert_cb is not possible anymore since the new |SSL_SESSION| is initialized *after* cert_cb is run. The alternative would be using |SSL_CTX_set_timeout| but the specific |SSL_CTX| could be shared by multiple |SSL|s. Setting a value on a per-connection basis is useful in case timeouts need to be calculated dynamically based on specific certificate/domain information that would be retrieved from inside cert_cb (or other callbacks). It would also be possible to set the value to 0 to prevent session resumption, which is not otherwise doable in the handshake callbacks. Change-Id: I730a528c647f83f7f77f59b5b21d7e060e4c9843 Reviewed-on: https://boringssl-review.googlesource.com/12440 Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
This commit is contained in:
parent
15073af5b7
commit
bf48364a8c
@ -1721,6 +1721,15 @@ OPENSSL_EXPORT long SSL_CTX_set_timeout(SSL_CTX *ctx, long timeout);
|
||||
* |ctx|. */
|
||||
OPENSSL_EXPORT long SSL_CTX_get_timeout(const SSL_CTX *ctx);
|
||||
|
||||
/* SSL_set_session_timeout sets the default lifetime, in seconds, of the
|
||||
* session created in |ssl| to |timeout|, and returns the old value.
|
||||
*
|
||||
* By default the value |SSL_DEFAULT_SESSION_TIMEOUT| is used, which can be
|
||||
* overridden at the context level by calling |SSL_CTX_set_timeout|.
|
||||
*
|
||||
* If |timeout| is zero the newly created session will not be resumable. */
|
||||
OPENSSL_EXPORT long SSL_set_session_timeout(SSL *ssl, long timeout);
|
||||
|
||||
/* SSL_CTX_set_session_id_context sets |ctx|'s session ID context to |sid_ctx|.
|
||||
* It returns one on success and zero on error. The session ID context is an
|
||||
* application-defined opaque byte string. A session will not be used in a
|
||||
@ -4215,6 +4224,10 @@ struct ssl_st {
|
||||
|
||||
/* TODO(agl): remove once node.js not longer references this. */
|
||||
int tlsext_status_type;
|
||||
|
||||
/* session_timeout is the default lifetime in seconds of the session
|
||||
* created in this connection. */
|
||||
long session_timeout;
|
||||
};
|
||||
|
||||
|
||||
|
@ -477,6 +477,13 @@ SSL *SSL_new(SSL_CTX *ctx) {
|
||||
ssl->ctx->signed_cert_timestamps_enabled;
|
||||
ssl->ocsp_stapling_enabled = ssl->ctx->ocsp_stapling_enabled;
|
||||
|
||||
ssl->session_timeout = SSL_DEFAULT_SESSION_TIMEOUT;
|
||||
|
||||
/* If the context has a default timeout, use it over the default. */
|
||||
if (ctx->session_timeout != 0) {
|
||||
ssl->session_timeout = ctx->session_timeout;
|
||||
}
|
||||
|
||||
return ssl;
|
||||
|
||||
err:
|
||||
|
@ -465,10 +465,7 @@ int ssl_get_new_session(SSL *ssl, int is_server) {
|
||||
ssl_get_current_time(ssl, &now);
|
||||
session->time = now.tv_sec;
|
||||
|
||||
/* If the context has a default timeout, use it over the default. */
|
||||
if (ssl->initial_ctx->session_timeout != 0) {
|
||||
session->timeout = ssl->initial_ctx->session_timeout;
|
||||
}
|
||||
session->timeout = ssl->session_timeout;
|
||||
|
||||
session->ssl_version = ssl->version;
|
||||
|
||||
@ -875,6 +872,12 @@ long SSL_CTX_get_timeout(const SSL_CTX *ctx) {
|
||||
return ctx->session_timeout;
|
||||
}
|
||||
|
||||
long SSL_set_session_timeout(SSL *ssl, long timeout) {
|
||||
long old_timeout = ssl->session_timeout;
|
||||
ssl->session_timeout = timeout;
|
||||
return old_timeout;
|
||||
}
|
||||
|
||||
typedef struct timeout_param_st {
|
||||
SSL_CTX *ctx;
|
||||
long time;
|
||||
|
126
ssl/ssl_test.cc
126
ssl/ssl_test.cc
@ -2319,6 +2319,131 @@ static bool TestSessionTimeout(bool is_dtls, const SSL_METHOD *method,
|
||||
return true;
|
||||
}
|
||||
|
||||
static int SetSessionTimeoutCallback(SSL *ssl, void *arg) {
|
||||
long timeout = *(long *) arg;
|
||||
SSL_set_session_timeout(ssl, timeout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool TestSessionTimeoutCertCallback(bool is_dtls,
|
||||
const SSL_METHOD *method,
|
||||
uint16_t version) {
|
||||
static const int kStartTime = 1000;
|
||||
g_current_time.tv_sec = kStartTime;
|
||||
|
||||
bssl::UniquePtr<X509> cert = GetTestCertificate();
|
||||
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
|
||||
if (!cert || !key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
|
||||
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
|
||||
if (!server_ctx || !client_ctx ||
|
||||
!SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
|
||||
!SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
|
||||
!SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
|
||||
!SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
|
||||
!SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
|
||||
!SSL_CTX_set_max_proto_version(server_ctx.get(), version)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH);
|
||||
SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH);
|
||||
|
||||
SSL_CTX_set_current_time_cb(server_ctx.get(), CurrentTimeCallback);
|
||||
|
||||
long timeout = 25;
|
||||
SSL_CTX_set_cert_cb(server_ctx.get(), SetSessionTimeoutCallback, &timeout);
|
||||
|
||||
bssl::UniquePtr<SSL_SESSION> session =
|
||||
CreateClientSession(client_ctx.get(), server_ctx.get());
|
||||
if (!session) {
|
||||
fprintf(stderr, "Error getting session.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Advance the clock just behind the timeout.
|
||||
g_current_time.tv_sec += timeout - 1;
|
||||
|
||||
if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
|
||||
true /* expect session reused */)) {
|
||||
fprintf(stderr, "Error resuming session.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Advance the clock one more second.
|
||||
g_current_time.tv_sec++;
|
||||
|
||||
if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
|
||||
false /* expect session not reused */)) {
|
||||
fprintf(stderr, "Error resuming session.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set session timeout to 0 to disable resumption.
|
||||
timeout = 0;
|
||||
g_current_time.tv_sec = kStartTime;
|
||||
|
||||
bssl::UniquePtr<SSL_SESSION> not_resumable_session =
|
||||
CreateClientSession(client_ctx.get(), server_ctx.get());
|
||||
if (!not_resumable_session) {
|
||||
fprintf(stderr, "Error getting session.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
|
||||
not_resumable_session.get(),
|
||||
false /* expect session not reused */)) {
|
||||
fprintf(stderr, "Error resuming session with timeout of 0.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set both context and connection (via callback) default session timeout.
|
||||
// The connection one is the one that ends up being used.
|
||||
timeout = 25;
|
||||
g_current_time.tv_sec = kStartTime;
|
||||
|
||||
SSL_CTX_set_timeout(server_ctx.get(), timeout - 10);
|
||||
|
||||
bssl::UniquePtr<SSL_SESSION> ctx_and_cb_session =
|
||||
CreateClientSession(client_ctx.get(), server_ctx.get());
|
||||
if (!ctx_and_cb_session) {
|
||||
fprintf(stderr, "Error getting session.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
|
||||
ctx_and_cb_session.get(),
|
||||
true /* expect session reused */)) {
|
||||
fprintf(stderr, "Error resuming session with timeout of 0.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Advance the clock just behind the timeout.
|
||||
g_current_time.tv_sec += timeout - 1;
|
||||
|
||||
if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
|
||||
ctx_and_cb_session.get(),
|
||||
true /* expect session reused */)) {
|
||||
fprintf(stderr, "Error resuming session.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Advance the clock one more second.
|
||||
g_current_time.tv_sec++;
|
||||
|
||||
if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
|
||||
ctx_and_cb_session.get(),
|
||||
false /* expect session not reused */)) {
|
||||
fprintf(stderr, "Error resuming session.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int SwitchContext(SSL *ssl, int *out_alert, void *arg) {
|
||||
SSL_CTX *ctx = reinterpret_cast<SSL_CTX*>(arg);
|
||||
SSL_set_SSL_CTX(ssl, ctx);
|
||||
@ -2664,6 +2789,7 @@ int main() {
|
||||
!TestClientHello() ||
|
||||
!ForEachVersion(TestSessionIDContext) ||
|
||||
!ForEachVersion(TestSessionTimeout) ||
|
||||
!ForEachVersion(TestSessionTimeoutCertCallback) ||
|
||||
!ForEachVersion(TestSNICallback) ||
|
||||
!TestEarlyCallbackVersionSwitch() ||
|
||||
!TestSetVersion() ||
|
||||
|
Loading…
Reference in New Issue
Block a user