]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
DoT: implement TLS client session resumption
authorArtem Boldariev <artem@boldariev.com>
Mon, 25 Apr 2022 13:47:06 +0000 (16:47 +0300)
committerArtem Boldariev <artem@boldariev.com>
Fri, 20 May 2022 17:17:48 +0000 (20:17 +0300)
This commit extends DoT code with TLS client session resumption
support implemented on top of the TLS client session cache.

bin/dig/dighost.c
bin/tests/test_client.c
lib/dns/xfrin.c
lib/isc/include/isc/netmgr.h
lib/isc/netmgr/netmgr-int.h
lib/isc/netmgr/tlsdns.c
lib/isc/tests/netmgr_test.c

index ce550fe7bf4b6f9fba6c1fc44a8829d0f8125f2f..14f626785941dc77bbd14f56419cd58b231526a4 100644 (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 };
index 226aac72906120edfa79f15d5cfe3e864c8c24b6..c7615e27d993c06a403fdf164c178bd82a2690c8 100644 (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
index 42f8114e9d3a7cb95e635c58d2bace7cad75efb7..c3971b8ffa1a11da37a53eecb28603fdd67041bf 100644 (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();
index 830fc327a854b8e11ed013452429b0e838c79f05..71878f1099fd8f4303495134072ae8748ee2a31f 100644 (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'.
index b6a10a16f57f9cfd60675b1d1a14aa6d281fe503..1a9114f8ae7a6010286c0788183284d2f17acec6 100644 (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;
index 7e5fd597b92aa3d4267b3b32e8b184650b5861d5..b3164496471736f1be3876782a359a96969450d5 100644 (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)
+       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(ISC_LIST_EMPTY(sock->tls.sendreqs));
-               isc_tlsctx_free(&sock->tls.ctx);
+               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;
        }
 }
index 8cf0187cec7059b016a1fff4628138f652f57575..6388aa4270fb8da3a79cf7985f746dc53394edbb 100644 (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);