Merge branch 'artem-backport-tls-related-fixes-from-loopmgr-branch-v9-18' into 'v9_18'

[Backport to 9.18] Backport TLS-related fixes from the loopmgr-branch

See merge request isc-projects/bind9!6550
This commit is contained in:
Artem Boldariev 2022-07-12 13:13:39 +00:00
commit 3d98312a7b
5 changed files with 154 additions and 49 deletions

View file

@ -1787,6 +1787,10 @@ void
isc__nm_async_tls_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx,
const int tid);
void
isc__nmhandle_tls_setwritetimeout(isc_nmhandle_t *handle,
uint64_t write_timeout);
void
isc__nm_http_stoplistening(isc_nmsocket_t *sock);

View file

@ -572,8 +572,24 @@ void
isc_nmhandle_setwritetimeout(isc_nmhandle_t *handle, uint64_t write_timeout) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
REQUIRE(handle->sock->tid == isc_nm_tid());
handle->sock->write_timeout = write_timeout;
switch (handle->sock->type) {
case isc_nm_tcpsocket:
case isc_nm_udpsocket:
case isc_nm_tcpdnssocket:
case isc_nm_tlsdnssocket:
handle->sock->write_timeout = write_timeout;
break;
#ifdef HAVE_LIBNGHTTP2
case isc_nm_tlssocket:
isc__nmhandle_tls_setwritetimeout(handle, write_timeout);
break;
#endif /* HAVE_LIBNGHTTP2 */
default:
UNREACHABLE();
break;
}
}
void

View file

@ -1061,38 +1061,46 @@ tls_cycle_input(isc_nmsocket_t *sock) {
pending = (int)ISC_NETMGR_TCP_RECVBUF_SIZE;
}
if ((sock->buf_len + pending) > sock->buf_size) {
isc__nm_alloc_dnsbuf(sock,
sock->buf_len + pending);
}
len = 0;
rv = SSL_read_ex(sock->tls.tls,
sock->buf + sock->buf_len,
sock->buf_size - sock->buf_len, &len);
if (rv != 1) {
/*
* Process what's in the buffer so far
*/
result = isc__nm_process_sock_buffer(sock);
if (result != ISC_R_SUCCESS) {
goto failure;
if (pending != 0) {
if ((sock->buf_len + pending) > sock->buf_size)
{
isc__nm_alloc_dnsbuf(
sock, sock->buf_len + pending);
}
/*
* FIXME: Should we call
* isc__nm_failed_read_cb()?
*/
break;
len = 0;
rv = SSL_read_ex(sock->tls.tls,
sock->buf + sock->buf_len,
sock->buf_size - sock->buf_len,
&len);
if (rv != 1) {
/*
* Process what's in the buffer so far
*/
result = isc__nm_process_sock_buffer(
sock);
if (result != ISC_R_SUCCESS) {
goto failure;
}
/*
* FIXME: Should we call
* isc__nm_failed_read_cb()?
*/
break;
}
INSIST((size_t)pending == len);
sock->buf_len += len;
}
INSIST((size_t)pending == len);
sock->buf_len += len;
result = isc__nm_process_sock_buffer(sock);
if (result != ISC_R_SUCCESS) {
goto failure;
}
if (pending == 0) {
break;
}
}
} else if (!SSL_is_init_finished(sock->tls.tls)) {
if (SSL_is_server(sock->tls.tls)) {

View file

@ -324,7 +324,7 @@ tls_process_outgoing(isc_nmsocket_t *sock, bool finish,
}
static int
tls_try_handshake(isc_nmsocket_t *sock) {
tls_try_handshake(isc_nmsocket_t *sock, isc_result_t *presult) {
int rv = 0;
isc_nmhandle_t *tlshandle = NULL;
@ -342,18 +342,40 @@ tls_try_handshake(isc_nmsocket_t *sock) {
isc__nmsocket_log_tls_session_reuse(sock, sock->tlsstream.tls);
tlshandle = isc__nmhandle_get(sock, &sock->peer, &sock->iface);
if (sock->tlsstream.server) {
sock->listener->accept_cb(tlshandle, result,
sock->listener->accept_cbarg);
result = sock->listener->accept_cb(
tlshandle, result,
sock->listener->accept_cbarg);
} else {
tls_call_connect_cb(sock, tlshandle, result);
}
isc_nmhandle_detach(&tlshandle);
sock->tlsstream.state = TLS_IO;
if (presult != NULL) {
*presult = result;
}
}
return (rv);
}
static bool
tls_try_to_close_unused_socket(isc_nmsocket_t *sock) {
if (sock->tlsstream.state > TLS_HANDSHAKE &&
sock->statichandle == NULL && sock->tlsstream.nsending == 0)
{
/*
* It seems that no action on the socket has been
* scheduled on some point after the handshake, let's
* close the connection.
*/
isc__nmsocket_prep_destroy(sock);
return (true);
}
return (false);
}
static void
tls_do_bio(isc_nmsocket_t *sock, isc_region_t *received_data,
isc__nm_uvreq_t *send_data, bool finish) {
@ -380,7 +402,7 @@ tls_do_bio(isc_nmsocket_t *sock, isc_region_t *received_data,
SSL_set_connect_state(sock->tlsstream.tls);
}
sock->tlsstream.state = TLS_HANDSHAKE;
rv = tls_try_handshake(sock);
rv = tls_try_handshake(sock, NULL);
INSIST(SSL_is_init_finished(sock->tlsstream.tls) == 0);
} else if (sock->tlsstream.state == TLS_CLOSED) {
return;
@ -403,7 +425,21 @@ tls_do_bio(isc_nmsocket_t *sock, isc_region_t *received_data,
* handshake is done.
*/
if (sock->tlsstream.state == TLS_HANDSHAKE) {
rv = tls_try_handshake(sock);
isc_result_t hs_result = ISC_R_UNSET;
rv = tls_try_handshake(sock, &hs_result);
if (sock->tlsstream.state == TLS_IO &&
hs_result != ISC_R_SUCCESS) {
/*
* The accept callback has been called
* unsuccessfully. Let's try to shut
* down the TLS connection gracefully.
*/
INSIST(SSL_is_init_finished(
sock->tlsstream.tls) ==
1);
INSIST(!atomic_load(&sock->client));
finish = true;
}
}
} else if (send_data != NULL) {
INSIST(received_data == NULL);
@ -431,7 +467,7 @@ tls_do_bio(isc_nmsocket_t *sock, isc_region_t *received_data,
/* Decrypt and pass data from network to client */
if (sock->tlsstream.state >= TLS_IO && sock->recv_cb != NULL &&
!atomic_load(&sock->readpaused) &&
sock->statichandle != NULL)
sock->statichandle != NULL && !finish)
{
uint8_t recv_buf[TLS_BUF_SIZE];
INSIST(sock->tlsstream.state > TLS_HANDSHAKE);
@ -450,9 +486,9 @@ tls_do_bio(isc_nmsocket_t *sock, isc_region_t *received_data,
* nullified (it happens in netmgr.c). If it is
* the case, then it means that we are not
* interested in keeping the connection alive
* anymore. Let's shutdown the SSL session, send
* what we have in the SSL buffers, and close
* the connection.
* anymore. Let's shut down the SSL session,
* send what we have in the SSL buffers,
* and close the connection.
*/
if (sock->statichandle == NULL) {
finish = true;
@ -494,6 +530,7 @@ tls_do_bio(isc_nmsocket_t *sock, isc_region_t *received_data,
switch (tls_status) {
case SSL_ERROR_NONE:
case SSL_ERROR_ZERO_RETURN:
(void)tls_try_to_close_unused_socket(sock);
return;
case SSL_ERROR_WANT_WRITE:
if (sock->tlsstream.nsending == 0) {
@ -505,8 +542,17 @@ tls_do_bio(isc_nmsocket_t *sock, isc_region_t *received_data,
}
return;
case SSL_ERROR_WANT_READ:
if (tls_try_to_close_unused_socket(sock)) {
return;
}
if (sock->outerhandle == NULL) {
return;
}
INSIST(VALID_NMHANDLE(sock->outerhandle));
if (sock->tlsstream.reading) {
INSIST(VALID_NMHANDLE(sock->outerhandle));
isc_nm_resumeread(sock->outerhandle);
} else if (sock->tlsstream.state == TLS_HANDSHAKE) {
sock->tlsstream.reading = true;
@ -652,6 +698,9 @@ isc_nm_listentls(isc_nm_t *mgr, isc_sockaddr_t *iface,
isc_nmsocket_t *tsock = NULL;
REQUIRE(VALID_NM(mgr));
if (atomic_load(&mgr->closing)) {
return (ISC_R_SHUTTINGDOWN);
}
tlssock = isc_mem_get(mgr->mctx, sizeof(*tlssock));
@ -812,6 +861,10 @@ isc__nm_tls_resumeread(isc_nmhandle_t *handle) {
if (!atomic_compare_exchange_strong(&handle->sock->readpaused,
&(bool){ false }, false))
{
if (inactive(handle->sock)) {
return;
}
async_tls_do_bio(handle->sock);
}
}
@ -909,6 +962,11 @@ isc_nm_tlsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
REQUIRE(VALID_NM(mgr));
if (atomic_load(&mgr->closing)) {
cb(NULL, ISC_R_SHUTTINGDOWN, cbarg);
return;
}
nsock = isc_mem_get(mgr->mctx, sizeof(*nsock));
isc__nmsocket_init(nsock, mgr, isc_nm_tlssocket, local);
nsock->extrahandlesize = extrahandlesize;
@ -935,13 +993,14 @@ tcp_connected(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
isc_nmhandle_t *tlshandle = NULL;
REQUIRE(VALID_NMSOCK(tlssock));
REQUIRE(VALID_NMHANDLE(handle));
tlssock->tid = isc_nm_tid();
if (result != ISC_R_SUCCESS) {
goto error;
}
INSIST(VALID_NMHANDLE(handle));
tlssock->iface = handle->sock->iface;
tlssock->peer = handle->sock->peer;
if (isc__nm_closing(tlssock)) {
@ -1051,8 +1110,8 @@ isc__nm_tls_cleanup_data(isc_nmsocket_t *sock) {
} else if (sock->type == isc_nm_tlssocket) {
if (sock->tlsstream.tls != NULL) {
/*
* Let's shutdown the TLS session properly so that the
* session will remain resumable, if required.
* Let's shut down the TLS session properly so that
* the session will remain resumable, if required.
*/
tls_try_shutdown(sock->tlsstream.tls, true);
tls_keep_client_tls_session(sock);
@ -1125,6 +1184,23 @@ isc__nmhandle_tls_keepalive(isc_nmhandle_t *handle, bool value) {
}
}
void
isc__nmhandle_tls_setwritetimeout(isc_nmhandle_t *handle,
uint64_t write_timeout) {
isc_nmsocket_t *sock = NULL;
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
REQUIRE(handle->sock->type == isc_nm_tlssocket);
sock = handle->sock;
if (sock->outerhandle != NULL) {
INSIST(VALID_NMHANDLE(sock->outerhandle));
isc_nmhandle_setwritetimeout(sock->outerhandle, write_timeout);
}
}
const char *
isc__nm_tls_verify_tls_peer_result_string(const isc_nmhandle_t *handle) {
isc_nmsocket_t *sock = NULL;

View file

@ -386,9 +386,12 @@ noop_recv_cb(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
static unsigned int
noop_accept_cb(isc_nmhandle_t *handle, unsigned int result, void *cbarg) {
UNUSED(handle);
UNUSED(result);
UNUSED(cbarg);
if (result == ISC_R_SUCCESS) {
(void)atomic_fetch_add(&saccepts, 1);
}
return (0);
}
@ -1209,7 +1212,7 @@ stream_noresponse(void **state __attribute__((unused))) {
stream_connect(connect_connect_cb, NULL, T_CONNECT, 0);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_EQ(csends, 1);
WAIT_FOR_EQ(saccepts, 1);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
@ -1223,7 +1226,7 @@ stream_noresponse(void **state __attribute__((unused))) {
X(ssends);
atomic_assert_int_eq(cconnects, 1);
atomic_assert_int_eq(csends, 1);
atomic_assert_int_eq(saccepts, 1);
atomic_assert_int_eq(creads, 0);
atomic_assert_int_eq(sreads, 0);
atomic_assert_int_eq(ssends, 0);
@ -1728,7 +1731,7 @@ ISC_RUN_TEST_IMPL(tcpdns_noresponse) {
connect_connect_cb, NULL, T_CONNECT, 0);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_EQ(csends, 1);
WAIT_FOR_EQ(saccepts, 1);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
@ -1742,7 +1745,7 @@ ISC_RUN_TEST_IMPL(tcpdns_noresponse) {
X(ssends);
atomic_assert_int_eq(cconnects, 1);
atomic_assert_int_eq(csends, 1);
atomic_assert_int_eq(saccepts, 1);
atomic_assert_int_eq(creads, 0);
atomic_assert_int_eq(sreads, 0);
atomic_assert_int_eq(ssends, 0);
@ -2279,7 +2282,7 @@ ISC_RUN_TEST_IMPL(tlsdns_noresponse) {
tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_EQ(csends, 1);
WAIT_FOR_EQ(saccepts, 1);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
@ -2293,7 +2296,7 @@ ISC_RUN_TEST_IMPL(tlsdns_noresponse) {
X(ssends);
atomic_assert_int_eq(cconnects, 1);
atomic_assert_int_eq(csends, 1);
atomic_assert_int_eq(saccepts, 1);
atomic_assert_int_eq(creads, 0);
atomic_assert_int_eq(sreads, 0);
atomic_assert_int_eq(ssends, 0);
@ -2743,7 +2746,6 @@ ISC_RUN_TEST_IMPL(tlsdns_listen_noalpn) {
WAIT_FOR_EQ(saccepts, 1);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_EQ(csends, 1);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
@ -2758,7 +2760,6 @@ ISC_RUN_TEST_IMPL(tlsdns_listen_noalpn) {
atomic_assert_int_eq(saccepts, 1);
atomic_assert_int_eq(cconnects, 1);
atomic_assert_int_eq(csends, 1);
atomic_assert_int_eq(creads, 0);
atomic_assert_int_eq(sreads, 0);
atomic_assert_int_eq(ssends, 0);