DoT: implement TLS client session resumption

This commit extends DoT code with TLS client session resumption
support implemented on top of the TLS client session cache.
This commit is contained in:
Artem Boldariev 2022-04-25 16:47:06 +03:00
parent 90bc13a5d5
commit 86465c1dac
7 changed files with 85 additions and 23 deletions

View file

@ -3000,7 +3000,7 @@ start_tcp(dig_query_t *query) {
isc_nm_tlsdnsconnect(netmgr, &localaddr,
&query->sockaddr, tcp_connected,
connectquery, local_timeout,
tlsctx);
tlsctx, sess_cache);
#if HAVE_LIBNGHTTP2
} else if (query->lookup->https_mode) {
char uri[4096] = { 0 };

View file

@ -407,7 +407,7 @@ run(void) {
isc_tlsctx_createclient(&tls_ctx);
isc_nm_tlsdnsconnect(netmgr, &sockaddr_local, &sockaddr_remote,
connect_cb, NULL, timeout, tls_ctx);
connect_cb, NULL, timeout, tls_ctx, NULL);
break;
}
#if HAVE_LIBNGHTTP2

View file

@ -1118,7 +1118,7 @@ xfrin_start(dns_xfrin_ctx_t *xfr) {
}
isc_nm_tlsdnsconnect(xfr->netmgr, &xfr->sourceaddr,
&xfr->primaryaddr, xfrin_connect_done,
connect_xfr, 30000, tlsctx);
connect_xfr, 30000, tlsctx, sess_cache);
} break;
default:
UNREACHABLE();

View file

@ -484,7 +484,8 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
void
isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
isc_tlsctx_t *sslctx);
isc_tlsctx_t *sslctx,
isc_tlsctx_client_session_cache_t *client_sess_cache);
/*%<
* Establish a DNS client connection via a TCP or TLS connection, bound to
* the address 'local' and connected to the address 'peer'.

View file

@ -932,6 +932,8 @@ struct isc_nmsocket {
struct tls {
isc_tls_t *tls;
isc_tlsctx_t *ctx;
isc_tlsctx_client_session_cache_t *client_sess_cache;
bool client_session_saved;
BIO *app_rbio;
BIO *app_wbio;
BIO *ssl_rbio;

View file

@ -79,6 +79,14 @@ tls_cycle(isc_nmsocket_t *sock);
static void
call_pending_send_callbacks(isc_nmsocket_t *sock, const isc_result_t result);
static void
tlsdns_keep_client_tls_session(isc_nmsocket_t *sock);
static void
tlsdns_set_tls_shutdown(isc_tls_t *tls) {
(void)SSL_set_shutdown(tls, SSL_SENT_SHUTDOWN);
}
static bool
peer_verification_has_failed(isc_nmsocket_t *sock) {
if (sock->tls.tls != NULL && sock->tls.state == TLS_STATE_HANDSHAKE &&
@ -294,11 +302,17 @@ tlsdns_connect_cb(uv_connect_t *uvreq, int status) {
SSL_set_bio(sock->tls.tls, sock->tls.ssl_rbio, sock->tls.ssl_wbio);
#endif
SSL_set_connect_state(sock->tls.tls);
result = isc_sockaddr_fromsockaddr(&sock->peer, (struct sockaddr *)&ss);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (sock->tls.client_sess_cache != NULL) {
isc_tlsctx_client_session_cache_reuse_sockaddr(
sock->tls.client_sess_cache, &sock->peer,
sock->tls.tls);
}
SSL_set_connect_state(sock->tls.tls);
/* Setting pending req */
sock->tls.pending_req = req;
@ -319,7 +333,8 @@ error:
void
isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
isc_tlsctx_t *sslctx) {
isc_tlsctx_t *sslctx,
isc_tlsctx_client_session_cache_t *client_sess_cache) {
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *sock = NULL;
isc__netievent_tlsdnsconnect_t *ievent = NULL;
@ -349,6 +364,13 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
req->local = *local;
req->handle = isc__nmhandle_get(sock, &req->peer, &sock->iface);
if (client_sess_cache != NULL) {
INSIST(isc_tlsctx_client_session_cache_getctx(
client_sess_cache) == sslctx);
isc_tlsctx_client_session_cache_attach(
client_sess_cache, &sock->tls.client_sess_cache);
}
result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &sock->fd);
if (result != ISC_R_SUCCESS) {
goto failure;
@ -1008,6 +1030,11 @@ isc__nm_tlsdns_processbuffer(isc_nmsocket_t *sock) {
isc_nmhandle_detach(&handle);
if (isc__nmsocket_closing(sock)) {
tlsdns_set_tls_shutdown(sock->tls.tls);
tlsdns_keep_client_tls_session(sock);
}
return (ISC_R_SUCCESS);
}
@ -1102,6 +1129,8 @@ tls_cycle_input(isc_nmsocket_t *sock) {
const unsigned char *alpn = NULL;
unsigned int alpnlen = 0;
isc__nmsocket_log_tls_session_reuse(sock, sock->tls.tls);
isc_tls_get_selected_alpn(sock->tls.tls, &alpn, &alpnlen);
if (alpn != NULL && alpnlen == ISC_TLS_DOT_PROTO_ALPN_ID_LEN &&
memcmp(ISC_TLS_DOT_PROTO_ALPN_ID, alpn,
@ -1835,6 +1864,12 @@ tlsdns_close_sock(isc_nmsocket_t *sock) {
atomic_store(&sock->connected, false);
if (sock->tls.tls != NULL) {
/*
* Let's shutdown the TLS session properly so that the session
* will remain resumable, if required.
*/
tlsdns_set_tls_shutdown(sock->tls.tls);
tlsdns_keep_client_tls_session(sock);
isc_tls_free(&sock->tls.tls);
}
@ -2015,7 +2050,7 @@ isc__nm_tlsdns_shutdown(isc_nmsocket_t *sock) {
if (sock->tls.tls) {
/* Shutdown any active TLS connections */
(void)SSL_shutdown(sock->tls.tls);
tlsdns_set_tls_shutdown(sock->tls.tls);
}
if (atomic_load(&sock->accepting)) {
@ -2146,11 +2181,35 @@ isc__nm_async_tlsdns_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx,
void
isc__nm_tlsdns_cleanup_data(isc_nmsocket_t *sock) {
if ((sock->type == isc_nm_tlsdnslistener ||
sock->type == isc_nm_tlsdnssocket) &&
sock->tls.ctx != NULL)
{
INSIST(ISC_LIST_EMPTY(sock->tls.sendreqs));
isc_tlsctx_free(&sock->tls.ctx);
if (sock->type == isc_nm_tlsdnslistener ||
sock->type == isc_nm_tlsdnssocket) {
if (sock->tls.client_sess_cache != NULL) {
INSIST(atomic_load(&sock->client));
INSIST(sock->type == isc_nm_tlsdnssocket);
isc_tlsctx_client_session_cache_detach(
&sock->tls.client_sess_cache);
}
if (sock->tls.ctx != NULL) {
INSIST(ISC_LIST_EMPTY(sock->tls.sendreqs));
isc_tlsctx_free(&sock->tls.ctx);
}
}
}
static void
tlsdns_keep_client_tls_session(isc_nmsocket_t *sock) {
/*
* Ensure that the isc_tls_t is being accessed from
* within the worker thread the socket is bound to.
*/
REQUIRE(sock->tid == isc_nm_tid());
if (sock->tls.client_sess_cache != NULL &&
sock->tls.client_session_saved == false)
{
INSIST(atomic_load(&sock->client));
isc_tlsctx_client_session_cache_keep_sockaddr(
sock->tls.client_sess_cache, &sock->peer,
sock->tls.tls);
sock->tls.client_session_saved = true;
}
}

View file

@ -2331,7 +2331,7 @@ static void
tlsdns_connect(isc_nm_t *nm) {
isc_nm_tlsdnsconnect(nm, &tcp_connect_addr, &tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT,
tcp_connect_tlsctx);
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
}
static void
@ -2353,7 +2353,7 @@ tlsdns_noop(void **state __attribute__((unused))) {
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT,
tcp_connect_tlsctx);
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
isc__netmgr_shutdown(connect_nm);
@ -2382,7 +2382,7 @@ tlsdns_noresponse(void **state __attribute__((unused))) {
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, &connect_addr, &tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT,
tcp_connect_tlsctx);
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_EQ(csends, 1);
@ -2437,7 +2437,7 @@ tlsdns_timeout_recovery(void **state __attribute__((unused))) {
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
connect_connect_cb, NULL, T_SOFT,
tcp_connect_tlsctx);
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_GE(csends, 1);
@ -2469,7 +2469,7 @@ tlsdns_recv_one(void **state __attribute__((unused))) {
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT,
tcp_connect_tlsctx);
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_LE(nsends, 0);
@ -2512,14 +2512,14 @@ tlsdns_recv_two(void **state __attribute__((unused))) {
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT,
tcp_connect_tlsctx);
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
WAIT_FOR_EQ(cconnects, 1);
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT,
tcp_connect_tlsctx);
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
WAIT_FOR_EQ(cconnects, 2);
@ -2788,7 +2788,7 @@ tlsdns_connect_noalpn(void **state __attribute__((unused))) {
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, &connect_addr, &tcp_listen_addr,
tlsdns_connect_connect_noalpn, NULL, T_CONNECT,
connect_tlsctx_noalpn);
connect_tlsctx_noalpn, NULL);
WAIT_FOR_EQ(active_cconnects, 0);
@ -2855,7 +2855,7 @@ tlsdns_listen_noalpn(void **state __attribute__((unused))) {
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, &connect_addr, &tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT,
tcp_connect_tlsctx);
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
WAIT_FOR_EQ(saccepts, 1);
WAIT_FOR_EQ(cconnects, 1);