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.

(cherry picked from commit 86465c1dac)
This commit is contained in:
Artem Boldariev 2022-04-25 16:47:06 +03:00
parent 0a4a76ff7a
commit e02284354a
7 changed files with 86 additions and 22 deletions

View file

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

View file

@ -407,7 +407,8 @@ run(void) {
isc_tlsctx_createclient(&tls_ctx);
isc_nm_tlsdnsconnect(netmgr, &sockaddr_local, &sockaddr_remote,
connect_cb, NULL, timeout, 0, tls_ctx);
connect_cb, NULL, timeout, 0, 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, 0, tlsctx);
connect_xfr, 30000, 0, tlsctx, sess_cache);
} break;
default:
UNREACHABLE();

View file

@ -519,7 +519,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,
size_t extrahandlesize, isc_tlsctx_t *sslctx);
size_t extrahandlesize, 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

@ -940,6 +940,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

@ -80,6 +80,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 &&
@ -295,11 +303,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;
@ -324,7 +338,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,
size_t extrahandlesize, isc_tlsctx_t *sslctx) {
size_t extrahandlesize, 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;
@ -355,6 +370,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;
@ -1014,6 +1036,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);
}
@ -1116,6 +1143,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,
@ -1841,6 +1870,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);
}
@ -2021,7 +2056,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)) {
@ -2152,10 +2187,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)
{
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

@ -2229,7 +2229,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, 0,
tcp_connect_tlsctx);
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
}
ISC_RUN_TEST_IMPL(tlsdns_noop) {
@ -2249,7 +2249,7 @@ ISC_RUN_TEST_IMPL(tlsdns_noop) {
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0,
tcp_connect_tlsctx);
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
isc__netmgr_shutdown(connect_nm);
@ -2276,7 +2276,7 @@ ISC_RUN_TEST_IMPL(tlsdns_noresponse) {
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, &connect_addr, &tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0,
tcp_connect_tlsctx);
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_EQ(csends, 1);
@ -2330,7 +2330,7 @@ ISC_RUN_TEST_IMPL(tlsdns_timeout_recovery) {
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
connect_connect_cb, NULL, T_SOFT, 0,
tcp_connect_tlsctx);
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_GE(csends, 1);
@ -2361,7 +2361,7 @@ ISC_RUN_TEST_IMPL(tlsdns_recv_one) {
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0,
tcp_connect_tlsctx);
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_LE(nsends, 0);
@ -2403,14 +2403,14 @@ ISC_RUN_TEST_IMPL(tlsdns_recv_two) {
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0,
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, 0,
tcp_connect_tlsctx);
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
WAIT_FOR_EQ(cconnects, 2);
@ -2673,7 +2673,7 @@ ISC_RUN_TEST_IMPL(tlsdns_connect_noalpn) {
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, &connect_addr, &tcp_listen_addr,
tlsdns_connect_connect_noalpn, NULL, T_CONNECT, 0,
connect_tlsctx_noalpn);
connect_tlsctx_noalpn, NULL);
WAIT_FOR_EQ(active_cconnects, 0);
@ -2739,7 +2739,7 @@ ISC_RUN_TEST_IMPL(tlsdns_listen_noalpn) {
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, &connect_addr, &tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0,
tcp_connect_tlsctx);
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
WAIT_FOR_EQ(saccepts, 1);
WAIT_FOR_EQ(cconnects, 1);