Test that session renewals interact with lifetimes correctly.
A renewed session does not refresh the timeout. Add tests for this in preparation for future changes which will revise this logic. Specifically, TLS 1.3 draft 18's ticket_age_add logic will require some tweaks in lifetime tracking to record when the ticket was minted. We'll also likely wish to tweak the parameters for 1.3 to account for (a) ECDHE-PSK means we're only worried about expiring a short-circuited authentication rather than forward secrecy and (b) two hours is too short for a QUIC 0-RTT replacement. Change-Id: I0f1edd09151e7fcb5aee2742ef8600fbd7080df6 Reviewed-on: https://boringssl-review.googlesource.com/12002 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
c034e2d3ce
commit
3c51d9b1b9
106
ssl/ssl_test.cc
106
ssl/ssl_test.cc
@ -23,11 +23,14 @@
|
|||||||
|
|
||||||
#include <openssl/base64.h>
|
#include <openssl/base64.h>
|
||||||
#include <openssl/bio.h>
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/cipher.h>
|
||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/hmac.h>
|
||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
@ -1972,6 +1975,41 @@ static bool ExpectSessionReused(SSL_CTX *client_ctx, SSL_CTX *server_ctx,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bssl::UniquePtr<SSL_SESSION> ExpectSessionRenewed(SSL_CTX *client_ctx,
|
||||||
|
SSL_CTX *server_ctx,
|
||||||
|
SSL_SESSION *session) {
|
||||||
|
g_last_session = nullptr;
|
||||||
|
SSL_CTX_sess_set_new_cb(client_ctx, SaveLastSession);
|
||||||
|
|
||||||
|
bssl::UniquePtr<SSL> client, server;
|
||||||
|
if (!ConnectClientAndServer(&client, &server, client_ctx,
|
||||||
|
server_ctx, session)) {
|
||||||
|
fprintf(stderr, "Failed to connect client and server.\n");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SSL_session_reused(client.get()) != SSL_session_reused(server.get())) {
|
||||||
|
fprintf(stderr, "Client and server were inconsistent.\n");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SSL_session_reused(client.get())) {
|
||||||
|
fprintf(stderr, "Session was not reused.\n");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the read loop to account for post-handshake tickets in TLS 1.3.
|
||||||
|
SSL_read(client.get(), nullptr, 0);
|
||||||
|
|
||||||
|
SSL_CTX_sess_set_new_cb(client_ctx, nullptr);
|
||||||
|
|
||||||
|
if (!g_last_session) {
|
||||||
|
fprintf(stderr, "Client did not receive a renewed session.\n");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return std::move(g_last_session);
|
||||||
|
}
|
||||||
|
|
||||||
static bool TestSessionIDContext() {
|
static bool TestSessionIDContext() {
|
||||||
bssl::UniquePtr<X509> cert = GetTestCertificate();
|
bssl::UniquePtr<X509> cert = GetTestCertificate();
|
||||||
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
|
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
|
||||||
@ -2037,6 +2075,28 @@ static void CurrentTimeCallback(const SSL *ssl, timeval *out_clock) {
|
|||||||
*out_clock = g_current_time;
|
*out_clock = g_current_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int RenewTicketCallback(SSL *ssl, uint8_t *key_name, uint8_t *iv,
|
||||||
|
EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx,
|
||||||
|
int encrypt) {
|
||||||
|
static const uint8_t kZeros[16] = {0};
|
||||||
|
|
||||||
|
if (encrypt) {
|
||||||
|
memcpy(key_name, kZeros, sizeof(kZeros));
|
||||||
|
RAND_bytes(iv, 16);
|
||||||
|
} else if (memcmp(key_name, kZeros, 16) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HMAC_Init_ex(hmac_ctx, kZeros, sizeof(kZeros), EVP_sha256(), NULL) ||
|
||||||
|
!EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, kZeros, iv, encrypt)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returning two from the callback in decrypt mode renews the
|
||||||
|
// session in TLS 1.2 and below.
|
||||||
|
return encrypt ? 1 : 2;
|
||||||
|
}
|
||||||
|
|
||||||
static bool TestSessionTimeout() {
|
static bool TestSessionTimeout() {
|
||||||
bssl::UniquePtr<X509> cert = GetTestCertificate();
|
bssl::UniquePtr<X509> cert = GetTestCertificate();
|
||||||
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
|
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
|
||||||
@ -2071,6 +2131,9 @@ static bool TestSessionTimeout() {
|
|||||||
SSL_CTX_set_current_time_cb(client_ctx.get(), CurrentTimeCallback);
|
SSL_CTX_set_current_time_cb(client_ctx.get(), CurrentTimeCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configure a ticket callback which renews tickets.
|
||||||
|
SSL_CTX_set_tlsext_ticket_key_cb(server_ctx.get(), RenewTicketCallback);
|
||||||
|
|
||||||
bssl::UniquePtr<SSL_SESSION> session =
|
bssl::UniquePtr<SSL_SESSION> session =
|
||||||
CreateClientSession(client_ctx.get(), server_ctx.get());
|
CreateClientSession(client_ctx.get(), server_ctx.get());
|
||||||
if (!session) {
|
if (!session) {
|
||||||
@ -2107,6 +2170,49 @@ static bool TestSessionTimeout() {
|
|||||||
fprintf(stderr, "Error resuming session (version = %04x).\n", version);
|
fprintf(stderr, "Error resuming session (version = %04x).\n", version);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SSL 3.0 cannot renew sessions.
|
||||||
|
if (version == SSL3_VERSION) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renew the session 10 seconds before expiration.
|
||||||
|
g_current_time.tv_sec = kStartTime + SSL_DEFAULT_SESSION_TIMEOUT - 10;
|
||||||
|
bssl::UniquePtr<SSL_SESSION> new_session = ExpectSessionRenewed(
|
||||||
|
client_ctx.get(), server_ctx.get(), session.get());
|
||||||
|
if (!new_session) {
|
||||||
|
fprintf(stderr, "Error renewing session (version = %04x).\n", version);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This new session is not the same object as before.
|
||||||
|
if (session.get() == new_session.get()) {
|
||||||
|
fprintf(stderr, "New and old sessions alias (version = %04x).\n",
|
||||||
|
version);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The new session is usable just before the old expiration.
|
||||||
|
g_current_time.tv_sec = kStartTime + SSL_DEFAULT_SESSION_TIMEOUT - 1;
|
||||||
|
if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
|
||||||
|
new_session.get(),
|
||||||
|
true /* expect session reused */)) {
|
||||||
|
fprintf(stderr, "Error resuming renewed session (version = %04x).\n",
|
||||||
|
version);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renewal does not extend the lifetime, so it is not usable beyond the
|
||||||
|
// old expiration.
|
||||||
|
g_current_time.tv_sec = kStartTime + SSL_DEFAULT_SESSION_TIMEOUT + 1;
|
||||||
|
if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
|
||||||
|
new_session.get(),
|
||||||
|
false /* expect session not reused */)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Renewed session's lifetime is too long (version = %04x).\n",
|
||||||
|
version);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user