Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions build/crypto.m4
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,31 @@ AC_DEFUN([TS_CHECK_CRYPTO_SET_CIPHERSUITES], [
TS_ARG_ENABLE_VAR([use], [tls-set-ciphersuites])
AC_SUBST(use_tls_set_ciphersuites)
])

dnl
dnl Since OpenSSL 1.1.1
dnl
AC_DEFUN([TS_CHECK_EARLY_DATA], [
_set_ciphersuites_saved_LIBS=$LIBS

TS_ADDTO(LIBS, [$OPENSSL_LIBS])
AC_CHECK_HEADERS(openssl/ssl.h)
AC_CHECK_FUNCS(
SSL_set_max_early_data,
[
has_tls_early_data=1
early_data_check=yes
],
[
has_tls_early_data=0
early_data_check=no
]
)

LIBS=$_set_ciphersuites_saved_LIBS

AC_MSG_CHECKING([for OpenSSL early data support])
AC_MSG_RESULT([$early_data_check])

AC_SUBST(has_tls_early_data)
])
3 changes: 3 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,9 @@ TS_CHECK_CRYPTO_OCSP
# Check for SSL_CTX_set_ciphersuites call
TS_CHECK_CRYPTO_SET_CIPHERSUITES

# Check for openssl early data support
TS_CHECK_EARLY_DATA

saved_LIBS="$LIBS"
TS_ADDTO([LIBS], ["$OPENSSL_LIBS"])

Expand Down
18 changes: 18 additions & 0 deletions doc/admin-guide/files/records.config.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3497,6 +3497,24 @@ Client-Related Configuration
engines. This setting assumes an absolute path. An example config file is at
:ts:git:`contrib/openssl/load_engine.cnf`.

TLS v1.3 0-RTT Configuration
----------------------------

.. note::
TLS v1.3 must be enabled in order to utilize 0-RTT early data.

.. ts:cv:: CONFIG proxy.config.ssl.server.max_early_data INT 0

Specifies the maximum amount of early data in bytes that is permitted to be sent on a single connection.

The minimum value that enables early data, and the suggested value for this option are both 16384 (16KB).

Setting to ``0`` effectively disables 0-RTT.

.. ts:cv:: CONFIG proxy.config.ssl.server.allow_early_data_params INT 0

Set to ``1`` to allow HTTP parameters on early data requests.

OCSP Stapling Configuration
===========================

Expand Down
1 change: 1 addition & 0 deletions include/tscore/ink_config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
#define TS_USE_LINUX_NATIVE_AIO @use_linux_native_aio@
#define TS_USE_REMOTE_UNWINDING @use_remote_unwinding@
#define TS_USE_TLS_OCSP @use_tls_ocsp@
#define TS_HAS_TLS_EARLY_DATA @has_tls_early_data@

#define TS_HAS_SO_PEERCRED @has_so_peercred@

Expand Down
6 changes: 6 additions & 0 deletions iocore/net/P_SSLConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
#include "SSLSessionCache.h"
#include "YamlSNIConfig.h"

#include "P_SSLUtils.h"

struct SSLCertLookup;
struct ssl_ticket_key_block;

Expand Down Expand Up @@ -100,6 +102,10 @@ struct SSLConfigParams : public ConfigInfo {
char *server_groups_list;
char *client_groups_list;

static uint32_t server_max_early_data;
static uint32_t server_recv_max_early_data;
static bool server_allow_early_data_params;

static int ssl_maxrecord;
static bool ssl_allow_client_renegotiation;

Expand Down
6 changes: 6 additions & 0 deletions iocore/net/P_SSLNetVConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,12 @@ class SSLNetVConnection : public UnixNetVConnection, public ALPNSupport
bool protocol_mask_set = false;
unsigned long protocol_mask;

// early data related stuff
bool early_data_finish = false;
MIOBuffer *early_data_buf = nullptr;
IOBufferReader *early_data_reader = nullptr;
int64_t read_from_early_data = 0;

// Only applies during the VERIFY certificate hooks (client and server side)
// Means to give the plugin access to the data structure passed in during the underlying
// openssl callback so the plugin can make more detailed decisions about the
Expand Down
13 changes: 12 additions & 1 deletion iocore/net/SSLConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
#include "HttpConfig.h"

#include "P_Net.h"
#include "P_SSLUtils.h"
#include "P_SSLClientUtils.h"
#include "P_SSLCertLookup.h"
#include "SSLDiags.h"
Expand All @@ -66,6 +65,11 @@ init_ssl_ctx_func SSLConfigParams::init_ssl_ctx_cb = nullptr;
load_ssl_file_func SSLConfigParams::load_ssl_file_cb = nullptr;
IpMap *SSLConfigParams::proxy_protocol_ipmap = nullptr;

const uint32_t EARLY_DATA_DEFAULT_SIZE = 16384;
uint32_t SSLConfigParams::server_max_early_data = 0;
uint32_t SSLConfigParams::server_recv_max_early_data = EARLY_DATA_DEFAULT_SIZE;
bool SSLConfigParams::server_allow_early_data_params = false;

int SSLConfigParams::async_handshake_enabled = 0;
char *SSLConfigParams::engine_conf_file = nullptr;

Expand Down Expand Up @@ -278,6 +282,13 @@ SSLConfigParams::initialize()
ssl_client_ctx_options |= SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
#endif

REC_ReadConfigInteger(server_max_early_data, "proxy.config.ssl.server.max_early_data");
REC_ReadConfigInt32(server_allow_early_data_params, "proxy.config.ssl.server.allow_early_data_params");

// According to OpenSSL the default value is 16384,
// we keep it unless "server_max_early_data" is higher.
server_recv_max_early_data = std::max(server_max_early_data, EARLY_DATA_DEFAULT_SIZE);

REC_ReadConfigStringAlloc(serverCertChainFilename, "proxy.config.ssl.server.cert_chain.filename");
REC_ReadConfigStringAlloc(serverCertRelativePath, "proxy.config.ssl.server.cert.path");
set_paths_helper(serverCertRelativePath, nullptr, &serverCertPathOnly, nullptr);
Expand Down
44 changes: 44 additions & 0 deletions iocore/net/SSLNetVConnection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

#include "P_Net.h"
#include "P_SSLUtils.h"
#include "P_SSLNextProtocolSet.h"
#include "P_SSLConfig.h"
#include "P_SSLClientUtils.h"
#include "P_SSLSNI.h"
Expand Down Expand Up @@ -175,6 +176,38 @@ make_ssl_connection(SSL_CTX *ctx, SSLNetVConnection *netvc)
BIO *wbio = BIO_new_fd(netvc->get_socket(), BIO_NOCLOSE);
BIO_set_mem_eof_return(wbio, -1);
SSL_set_bio(ssl, rbio, wbio);

#if TS_HAS_TLS_EARLY_DATA
// Must disable OpenSSL's internal anti-replay if external cache is used with
// 0-rtt, otherwise session reuse will be broken. The freshness check described
// in https://tools.ietf.org/html/rfc8446#section-8.3 is still performed. But we
// still need to implement something to try to prevent replay atacks.
//
// We are now also disabling this when using OpenSSL's internal cache, since we
// are calling "ssl_accept" non-blocking, it seems to be confusing the anti-replay
// mechanism and causing session resumption to fail.
SSLConfig::scoped_config params;
if (SSL_version(ssl) >= TLS1_3_VERSION && params->server_max_early_data > 0) {
bool ret1 = false;
bool ret2 = false;
if ((ret1 = SSL_set_max_early_data(ssl, params->server_max_early_data)) == 1) {
Debug("ssl_early_data", "SSL_set_max_early_data: success");
} else {
Debug("ssl_early_data", "SSL_set_max_early_data: failed");
}

if ((ret2 = SSL_set_recv_max_early_data(ssl, params->server_recv_max_early_data)) == 1) {
Debug("ssl_early_data", "SSL_set_recv_max_early_data: success");
} else {
Debug("ssl_early_data", "SSL_set_recv_max_early_data: failed");
}

if (ret1 && ret2) {
Debug("ssl_early_data", "Must disable anti-replay if 0-rtt is enabled.");
SSL_set_options(ssl, SSL_OP_NO_ANTI_REPLAY);
}
}
#endif
}

SSLNetVCAttach(ssl, netvc);
Expand Down Expand Up @@ -923,6 +956,17 @@ SSLNetVConnection::free(EThread *t)

ats_free(tunnel_host);

if (early_data_reader != nullptr) {
early_data_reader->dealloc();
}

if (early_data_buf != nullptr) {
free_MIOBuffer(early_data_buf);
}

early_data_reader = nullptr;
early_data_buf = nullptr;

clear();
SET_CONTINUATION_HANDLER(this, (SSLNetVConnHandler)&SSLNetVConnection::startEvent);
ink_assert(con.fd == NO_FD);
Expand Down
15 changes: 12 additions & 3 deletions iocore/net/SSLSessionTicket.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ int
ssl_callback_session_ticket(SSL *ssl, unsigned char *keyname, unsigned char *iv, EVP_CIPHER_CTX *cipher_ctx, HMAC_CTX *hctx,
int enc)
{
SSLConfig::scoped_config config;
SSLCertificateConfig::scoped_config lookup;
SSLTicketKeyConfig::scoped_config params;
SSLNetVConnection &netvc = *SSLNetVCAccess(ssl);
Expand Down Expand Up @@ -82,7 +83,7 @@ ssl_callback_session_ticket(SSL *ssl, unsigned char *keyname, unsigned char *iv,
EVP_EncryptInit_ex(cipher_ctx, EVP_aes_128_cbc(), nullptr, most_recent_key.aes_key, iv);
HMAC_Init_ex(hctx, most_recent_key.hmac_secret, sizeof(most_recent_key.hmac_secret), evp_md_func, nullptr);

Debug("ssl", "create ticket for a new session.");
Debug("ssl_session_ticket", "create ticket for a new session.");
SSL_INCREMENT_DYN_STAT(ssl_total_tickets_created_stat);
return 1;
} else if (enc == 0) {
Expand All @@ -91,7 +92,7 @@ ssl_callback_session_ticket(SSL *ssl, unsigned char *keyname, unsigned char *iv,
EVP_DecryptInit_ex(cipher_ctx, EVP_aes_128_cbc(), nullptr, keyblock->keys[i].aes_key, iv);
HMAC_Init_ex(hctx, keyblock->keys[i].hmac_secret, sizeof(keyblock->keys[i].hmac_secret), evp_md_func, nullptr);

Debug("ssl", "verify the ticket for an existing session.");
Debug("ssl_session_ticket", "verify the ticket for an existing session.");
// Increase the total number of decrypted tickets.
SSL_INCREMENT_DYN_STAT(ssl_total_tickets_verified_stat);

Expand All @@ -100,12 +101,20 @@ ssl_callback_session_ticket(SSL *ssl, unsigned char *keyname, unsigned char *iv,
}

netvc.setSSLSessionCacheHit(true);

#if TS_HAS_TLS_EARLY_DATA
if (SSL_version(ssl) >= TLS1_3_VERSION && config->server_max_early_data > 0) {
Debug("ssl_session_ticket", "make sure tickets are only used once.");
return 2;
}
#endif

// When we decrypt with an "older" key, encrypt the ticket again with the most recent key.
return (i == 0) ? 1 : 2;
}
}

Debug("ssl", "keyname is not consistent.");
Debug("ssl_session_ticket", "keyname is not consistent.");
SSL_INCREMENT_DYN_STAT(ssl_total_tickets_not_found_stat);
return 0;
}
Expand Down
12 changes: 8 additions & 4 deletions iocore/net/SSLStats.cc
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,15 @@ SSLInitializeStatistics()
RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_lock_contention", RECD_COUNTER, RECP_PERSISTENT,
(int)ssl_session_cache_lock_contention, RecRawStatSyncCount);

/* Track dynamic record size */
// Track dynamic record size
RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.default_record_size_count", RECD_COUNTER, RECP_PERSISTENT,
(int)ssl_total_dyn_def_tls_record_count, RecRawStatSyncSum);
RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.max_record_size_count", RECD_COUNTER, RECP_PERSISTENT,
(int)ssl_total_dyn_max_tls_record_count, RecRawStatSyncSum);
RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.redo_record_size_count", RECD_COUNTER, RECP_PERSISTENT,
(int)ssl_total_dyn_redo_tls_record_count, RecRawStatSyncCount);

/* error stats */
// error stats
RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_syscall", RECD_COUNTER, RECP_PERSISTENT,
(int)ssl_error_syscall, RecRawStatSyncCount);
RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_read_eos", RECD_COUNTER, RECP_PERSISTENT,
Expand All @@ -187,7 +187,7 @@ SSLInitializeStatistics()
RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_sni_name_set_failure", RECD_COUNTER, RECP_PERSISTENT,
(int)ssl_sni_name_set_failure, RecRawStatSyncCount);

/* ocsp stapling stats */
// ocsp stapling stats
RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_ocsp_revoked_cert_stat", RECD_COUNTER, RECP_PERSISTENT,
(int)ssl_ocsp_revoked_cert_stat, RecRawStatSyncCount);
RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_ocsp_unknown_cert_stat", RECD_COUNTER, RECP_PERSISTENT,
Expand All @@ -197,7 +197,7 @@ SSLInitializeStatistics()
RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_ocsp_refresh_cert_failure", RECD_INT, RECP_PERSISTENT,
(int)ssl_ocsp_refresh_cert_failure_stat, RecRawStatSyncCount);

/* SSL Version stats */
// SSL Version stats
RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_total_sslv3", RECD_COUNTER, RECP_PERSISTENT,
(int)ssl_total_sslv3, RecRawStatSyncCount);
RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_total_tlsv1", RECD_COUNTER, RECP_PERSISTENT,
Expand All @@ -209,6 +209,10 @@ SSLInitializeStatistics()
RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_total_tlsv13", RECD_COUNTER, RECP_PERSISTENT,
(int)ssl_total_tlsv13, RecRawStatSyncCount);

// TLSv1.3 0-RTT stats
RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.early_data_received", RECD_INT, RECP_PERSISTENT,
(int)ssl_early_data_received_count, RecRawStatSyncCount);

// Get and register the SSL cipher stats. Note that we are using the default SSL context to obtain
// the cipher list. This means that the set of ciphers is fixed by the build configuration and not
// filtered by proxy.config.ssl.server.cipher_suite. This keeps the set of cipher suites stable across
Expand Down
1 change: 1 addition & 0 deletions iocore/net/SSLStats.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ enum SSL_Stats {
ssl_session_cache_eviction,
ssl_session_cache_lock_contention,
ssl_session_cache_new_session,
ssl_early_data_received_count, // how many times we received early data

/* error stats */
ssl_error_syscall,
Expand Down
Loading