mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
Merge branch 'artem-client-tls-sessions-reuse-backport-v9_18' into 'v9_18'
[Backport to 9.18]: TLS session resumption support See merge request isc-projects/bind9!6445
This commit is contained in:
commit
63aef08ea2
16 changed files with 1053 additions and 259 deletions
3
CHANGES
3
CHANGES
|
|
@ -32,6 +32,9 @@
|
|||
5895. [test] Add new set of unit test macros and move the unit
|
||||
tests under single namespace in /tests/. [GL !6243]
|
||||
|
||||
5893. [func] Add TLS session resumption support to the client-side
|
||||
TLS code. [GL !6274]
|
||||
|
||||
5891. [func] Key timing options for `dnssec-settime` and related
|
||||
utilities now accept "UNSET" times as printed by
|
||||
`dnssec-settime -p`. [GL #3361]
|
||||
|
|
|
|||
|
|
@ -2760,7 +2760,8 @@ _cancel_lookup(dig_lookup_t *lookup, const char *file, unsigned int line) {
|
|||
debug("canceling pending query %p, belonging to %p", query,
|
||||
query->lookup);
|
||||
query->canceled = true;
|
||||
if (query->readhandle != NULL) {
|
||||
if (query->readhandle != NULL &&
|
||||
!isc_nm_is_http_handle(query->readhandle)) {
|
||||
isc_nm_cancelread(query->readhandle);
|
||||
}
|
||||
query_detach(&query);
|
||||
|
|
@ -2772,7 +2773,8 @@ _cancel_lookup(dig_lookup_t *lookup, const char *file, unsigned int line) {
|
|||
}
|
||||
|
||||
static isc_tlsctx_t *
|
||||
get_create_tls_context(dig_query_t *query, const bool is_https) {
|
||||
get_create_tls_context(dig_query_t *query, const bool is_https,
|
||||
isc_tlsctx_client_session_cache_t **psess_cache) {
|
||||
isc_result_t result;
|
||||
isc_tlsctx_t *ctx = NULL, *found_ctx = NULL;
|
||||
isc_tls_cert_store_t *store = NULL, *found_store = NULL;
|
||||
|
|
@ -2783,6 +2785,8 @@ get_create_tls_context(dig_query_t *query, const bool is_https) {
|
|||
isc_tlsctx_cache_transport_t transport =
|
||||
is_https ? isc_tlsctx_cache_https : isc_tlsctx_cache_tls;
|
||||
const bool hostname_ignore_subject = !is_https;
|
||||
isc_tlsctx_client_session_cache_t *sess_cache = NULL,
|
||||
*found_sess_cache = NULL;
|
||||
|
||||
if (query->lookup->tls_key_file_set != query->lookup->tls_cert_file_set)
|
||||
{
|
||||
|
|
@ -2793,7 +2797,7 @@ get_create_tls_context(dig_query_t *query, const bool is_https) {
|
|||
|
||||
result = isc_tlsctx_cache_find(query->lookup->tls_ctx_cache, tlsctxname,
|
||||
transport, family, &found_ctx,
|
||||
&found_store);
|
||||
&found_store, &found_sess_cache);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
if (query->lookup->tls_ca_set) {
|
||||
if (found_store == NULL) {
|
||||
|
|
@ -2852,19 +2856,39 @@ get_create_tls_context(dig_query_t *query, const bool is_https) {
|
|||
}
|
||||
#endif /* HAVE_LIBNGHTTP2 */
|
||||
|
||||
result = isc_tlsctx_cache_add(query->lookup->tls_ctx_cache,
|
||||
tlsctxname, transport, family,
|
||||
ctx, store, NULL, NULL);
|
||||
sess_cache = isc_tlsctx_client_session_cache_new(
|
||||
mctx, ctx,
|
||||
ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE);
|
||||
|
||||
result = isc_tlsctx_cache_add(
|
||||
query->lookup->tls_ctx_cache, tlsctxname, transport,
|
||||
family, ctx, store, sess_cache, NULL, NULL, NULL);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
if (psess_cache != NULL) {
|
||||
INSIST(*psess_cache == NULL);
|
||||
*psess_cache = sess_cache;
|
||||
}
|
||||
return (ctx);
|
||||
}
|
||||
|
||||
if (psess_cache != NULL) {
|
||||
INSIST(*psess_cache == NULL);
|
||||
*psess_cache = found_sess_cache;
|
||||
}
|
||||
|
||||
INSIST(!query->lookup->tls_ca_set || found_store != NULL);
|
||||
return (found_ctx);
|
||||
failure:
|
||||
if (ctx != NULL && found_ctx != ctx) {
|
||||
if (ctx != NULL) {
|
||||
isc_tlsctx_free(&ctx);
|
||||
}
|
||||
/*
|
||||
* The 'found_store' is being managed by the TLS context
|
||||
* cache. Thus, we should keep it as it is, as it will get
|
||||
* destroyed alongside the cache. As there is one store per
|
||||
* multiple TLS contexts, we need to handle store deletion in a
|
||||
* special way.
|
||||
*/
|
||||
if (store != NULL && store != found_store) {
|
||||
isc_tls_cert_store_free(&store);
|
||||
}
|
||||
|
|
@ -2886,6 +2910,7 @@ start_tcp(dig_query_t *query) {
|
|||
dig_query_t *connectquery = NULL;
|
||||
isc_tlsctx_t *tlsctx = NULL;
|
||||
bool tls_mode = false;
|
||||
isc_tlsctx_client_session_cache_t *sess_cache = NULL;
|
||||
REQUIRE(DIG_VALID_QUERY(query));
|
||||
|
||||
debug("start_tcp(%p)", query);
|
||||
|
|
@ -2980,14 +3005,15 @@ start_tcp(dig_query_t *query) {
|
|||
query_attach(query, &connectquery);
|
||||
|
||||
if (tls_mode) {
|
||||
tlsctx = get_create_tls_context(connectquery, false);
|
||||
tlsctx = get_create_tls_context(connectquery, false,
|
||||
&sess_cache);
|
||||
if (tlsctx == NULL) {
|
||||
goto failure_tls;
|
||||
}
|
||||
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 };
|
||||
|
|
@ -2997,8 +3023,8 @@ start_tcp(dig_query_t *query) {
|
|||
uri, sizeof(uri));
|
||||
|
||||
if (!query->lookup->http_plain) {
|
||||
tlsctx = get_create_tls_context(connectquery,
|
||||
true);
|
||||
tlsctx = get_create_tls_context(
|
||||
connectquery, true, &sess_cache);
|
||||
if (tlsctx == NULL) {
|
||||
goto failure_tls;
|
||||
}
|
||||
|
|
@ -3007,7 +3033,7 @@ start_tcp(dig_query_t *query) {
|
|||
isc_nm_httpconnect(netmgr, &localaddr, &query->sockaddr,
|
||||
uri, !query->lookup->https_get,
|
||||
tcp_connected, connectquery, tlsctx,
|
||||
local_timeout, 0);
|
||||
sess_cache, 0, local_timeout);
|
||||
#endif
|
||||
} else {
|
||||
isc_nm_tcpdnsconnect(netmgr, &localaddr,
|
||||
|
|
@ -4597,7 +4623,8 @@ cancel_all(void) {
|
|||
debug("canceling pending query %p, belonging to %p", q,
|
||||
current_lookup);
|
||||
q->canceled = true;
|
||||
if (q->readhandle != NULL) {
|
||||
if (q->readhandle != NULL &&
|
||||
!isc_nm_is_http_handle(q->readhandle)) {
|
||||
isc_nm_cancelread(q->readhandle);
|
||||
}
|
||||
query_detach(&q);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -428,7 +429,7 @@ run(void) {
|
|||
}
|
||||
isc_nm_httpconnect(netmgr, &sockaddr_local, &sockaddr_remote,
|
||||
req_url, is_post, connect_cb, NULL, tls_ctx,
|
||||
timeout, 0);
|
||||
NULL, timeout, 0);
|
||||
} break;
|
||||
#endif
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -663,6 +663,7 @@ AC_CHECK_FUNCS([SSL_CTX_set_min_proto_version])
|
|||
AC_CHECK_FUNCS([SSL_CTX_up_ref])
|
||||
AC_CHECK_FUNCS([SSL_read_ex SSL_peek_ex SSL_write_ex])
|
||||
AC_CHECK_FUNCS([SSL_CTX_set1_cert_store X509_STORE_up_ref])
|
||||
AC_CHECK_FUNCS([SSL_SESSION_is_resumable])
|
||||
|
||||
#
|
||||
# Check for algorithm support in OpenSSL
|
||||
|
|
|
|||
382
lib/dns/xfrin.c
382
lib/dns/xfrin.c
|
|
@ -927,13 +927,223 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_nm_t *netmgr,
|
|||
*xfrp = xfr;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
get_create_tlsctx(const dns_xfrin_ctx_t *xfr, isc_tlsctx_t **pctx,
|
||||
isc_tlsctx_client_session_cache_t **psess_cache) {
|
||||
isc_result_t result = ISC_R_FAILURE;
|
||||
isc_tlsctx_t *tlsctx = NULL, *found = NULL;
|
||||
isc_tls_cert_store_t *store = NULL, *found_store = NULL;
|
||||
isc_tlsctx_client_session_cache_t *sess_cache = NULL,
|
||||
*found_sess_cache = NULL;
|
||||
uint32_t tls_versions;
|
||||
const char *ciphers = NULL;
|
||||
bool prefer_server_ciphers;
|
||||
const uint16_t family = isc_sockaddr_pf(&xfr->primaryaddr) == PF_INET6
|
||||
? AF_INET6
|
||||
: AF_INET;
|
||||
const char *tlsname = NULL;
|
||||
|
||||
REQUIRE(psess_cache != NULL && *psess_cache == NULL);
|
||||
REQUIRE(pctx != NULL && *pctx == NULL);
|
||||
|
||||
INSIST(xfr->transport != NULL);
|
||||
tlsname = dns_transport_get_tlsname(xfr->transport);
|
||||
INSIST(tlsname != NULL && *tlsname != '\0');
|
||||
|
||||
/*
|
||||
* Let's try to re-use the already created context. This way
|
||||
* we have a chance to resume the TLS session, bypassing the
|
||||
* full TLS handshake procedure, making establishing
|
||||
* subsequent TLS connections for XoT faster.
|
||||
*/
|
||||
result = isc_tlsctx_cache_find(xfr->tlsctx_cache, tlsname,
|
||||
isc_tlsctx_cache_tls, family, &found,
|
||||
&found_store, &found_sess_cache);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
const char *hostname =
|
||||
dns_transport_get_remote_hostname(xfr->transport);
|
||||
const char *ca_file = dns_transport_get_cafile(xfr->transport);
|
||||
const char *cert_file =
|
||||
dns_transport_get_certfile(xfr->transport);
|
||||
const char *key_file =
|
||||
dns_transport_get_keyfile(xfr->transport);
|
||||
char primary_addr_str[INET6_ADDRSTRLEN] = { 0 };
|
||||
isc_netaddr_t primary_netaddr = { 0 };
|
||||
bool hostname_ignore_subject;
|
||||
/*
|
||||
* So, no context exists. Let's create one using the
|
||||
* parameters from the configuration file and try to
|
||||
* store it for further reuse.
|
||||
*/
|
||||
result = isc_tlsctx_createclient(&tlsctx);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto failure;
|
||||
}
|
||||
tls_versions = dns_transport_get_tls_versions(xfr->transport);
|
||||
if (tls_versions != 0) {
|
||||
isc_tlsctx_set_protocols(tlsctx, tls_versions);
|
||||
}
|
||||
ciphers = dns_transport_get_ciphers(xfr->transport);
|
||||
if (ciphers != NULL) {
|
||||
isc_tlsctx_set_cipherlist(tlsctx, ciphers);
|
||||
}
|
||||
|
||||
if (dns_transport_get_prefer_server_ciphers(
|
||||
xfr->transport, &prefer_server_ciphers))
|
||||
{
|
||||
isc_tlsctx_prefer_server_ciphers(tlsctx,
|
||||
prefer_server_ciphers);
|
||||
}
|
||||
|
||||
if (hostname != NULL || ca_file != NULL) {
|
||||
/*
|
||||
* The situation when 'found_store != NULL' while 'found
|
||||
* == NULL' might appear as there is one to many
|
||||
* relation between per transport TLS contexts and cert
|
||||
* stores. That is, there could be one store shared
|
||||
* between multiple contexts.
|
||||
*/
|
||||
if (found_store == NULL) {
|
||||
/*
|
||||
* 'ca_file' can equal 'NULL' here, in
|
||||
* that case the store with system-wide
|
||||
* CA certificates will be created, just
|
||||
* as planned.
|
||||
*/
|
||||
result = isc_tls_cert_store_create(ca_file,
|
||||
&store);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto failure;
|
||||
}
|
||||
} else {
|
||||
store = found_store;
|
||||
}
|
||||
|
||||
INSIST(store != NULL);
|
||||
if (hostname == NULL) {
|
||||
/*
|
||||
* If CA bundle file is specified, but
|
||||
* hostname is not, then use the primary
|
||||
* IP address for validation, just like
|
||||
* dig does.
|
||||
*/
|
||||
INSIST(ca_file != NULL);
|
||||
isc_netaddr_fromsockaddr(&primary_netaddr,
|
||||
&xfr->primaryaddr);
|
||||
isc_netaddr_format(&primary_netaddr,
|
||||
primary_addr_str,
|
||||
sizeof(primary_addr_str));
|
||||
hostname = primary_addr_str;
|
||||
}
|
||||
/*
|
||||
* According to RFC 8310, Subject field MUST NOT
|
||||
* be inspected when verifying hostname for DoT.
|
||||
* Only SubjectAltName must be checked.
|
||||
*/
|
||||
hostname_ignore_subject = true;
|
||||
result = isc_tlsctx_enable_peer_verification(
|
||||
tlsctx, false, store, hostname,
|
||||
hostname_ignore_subject);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/*
|
||||
* Let's load client certificate and enable
|
||||
* Mutual TLS. We do that only in the case when
|
||||
* Strict TLS is enabled, because Mutual TLS is
|
||||
* an extension of it.
|
||||
*/
|
||||
if (cert_file != NULL) {
|
||||
INSIST(key_file != NULL);
|
||||
|
||||
result = isc_tlsctx_load_certificate(
|
||||
tlsctx, key_file, cert_file);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isc_tlsctx_enable_dot_client_alpn(tlsctx);
|
||||
|
||||
sess_cache = isc_tlsctx_client_session_cache_new(
|
||||
xfr->mctx, tlsctx,
|
||||
ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE);
|
||||
|
||||
found_store = NULL;
|
||||
result = isc_tlsctx_cache_add(xfr->tlsctx_cache, tlsname,
|
||||
isc_tlsctx_cache_tls, family,
|
||||
tlsctx, store, sess_cache, &found,
|
||||
&found_store, &found_sess_cache);
|
||||
if (result == ISC_R_EXISTS) {
|
||||
/*
|
||||
* It seems the entry has just been created from within
|
||||
* another thread while we were initialising
|
||||
* ours. Although this is unlikely, it could happen
|
||||
* after startup/re-initialisation. In such a case,
|
||||
* discard the new context and associated data and use
|
||||
* the already established one from now on.
|
||||
*
|
||||
* Such situation will not occur after the
|
||||
* initial 'warm-up', so it is not critical
|
||||
* performance-wise.
|
||||
*/
|
||||
INSIST(found != NULL);
|
||||
isc_tlsctx_free(&tlsctx);
|
||||
isc_tls_cert_store_free(&store);
|
||||
isc_tlsctx_client_session_cache_detach(&sess_cache);
|
||||
/* Let's return the data from the cache. */
|
||||
*psess_cache = found_sess_cache;
|
||||
*pctx = found;
|
||||
} else {
|
||||
/*
|
||||
* Adding the fresh values into the cache has been
|
||||
* successful, let's return them
|
||||
*/
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
*psess_cache = sess_cache;
|
||||
*pctx = tlsctx;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* The cache lookup has been successful, let's return the
|
||||
* results.
|
||||
*/
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
*psess_cache = found_sess_cache;
|
||||
*pctx = found;
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
failure:
|
||||
if (tlsctx != NULL) {
|
||||
isc_tlsctx_free(&tlsctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* The 'found_store' is being managed by the TLS context
|
||||
* cache. Thus, we should keep it as it is, as it will get
|
||||
* destroyed alongside the cache. As there is one store per
|
||||
* multiple TLS contexts, we need to handle store deletion in a
|
||||
* special way.
|
||||
*/
|
||||
if (store != NULL && store != found_store) {
|
||||
isc_tls_cert_store_free(&store);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
xfrin_start(dns_xfrin_ctx_t *xfr) {
|
||||
isc_result_t result;
|
||||
dns_xfrin_ctx_t *connect_xfr = NULL;
|
||||
dns_transport_type_t transport_type = DNS_TRANSPORT_TCP;
|
||||
isc_tlsctx_t *tlsctx = NULL, *found = NULL;
|
||||
isc_tls_cert_store_t *store = NULL, *found_store = NULL;
|
||||
isc_tlsctx_t *tlsctx = NULL;
|
||||
isc_tlsctx_client_session_cache_t *sess_cache = NULL;
|
||||
|
||||
(void)isc_refcount_increment0(&xfr->connects);
|
||||
dns_xfrin_attach(xfr, &connect_xfr);
|
||||
|
|
@ -953,162 +1163,14 @@ xfrin_start(dns_xfrin_ctx_t *xfr) {
|
|||
connect_xfr, 30000, 0);
|
||||
break;
|
||||
case DNS_TRANSPORT_TLS: {
|
||||
uint32_t tls_versions;
|
||||
const char *ciphers = NULL;
|
||||
bool prefer_server_ciphers;
|
||||
const uint16_t family = isc_sockaddr_pf(&xfr->primaryaddr) ==
|
||||
PF_INET6
|
||||
? AF_INET6
|
||||
: AF_INET;
|
||||
const char *tlsname = NULL;
|
||||
|
||||
INSIST(xfr->transport != NULL);
|
||||
tlsname = dns_transport_get_tlsname(xfr->transport);
|
||||
INSIST(tlsname != NULL && *tlsname != '\0');
|
||||
|
||||
/*
|
||||
* Let's try to re-use the already created context. This way
|
||||
* we have a chance to resume the TLS session, bypassing the
|
||||
* full TLS handshake procedure, making establishing
|
||||
* subsequent TLS connections for XoT faster.
|
||||
*/
|
||||
result = isc_tlsctx_cache_find(xfr->tlsctx_cache, tlsname,
|
||||
isc_tlsctx_cache_tls, family,
|
||||
&tlsctx, &found_store);
|
||||
result = get_create_tlsctx(xfr, &tlsctx, &sess_cache);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
const char *hostname =
|
||||
dns_transport_get_remote_hostname(
|
||||
xfr->transport);
|
||||
const char *ca_file =
|
||||
dns_transport_get_cafile(xfr->transport);
|
||||
const char *cert_file =
|
||||
dns_transport_get_certfile(xfr->transport);
|
||||
const char *key_file =
|
||||
dns_transport_get_keyfile(xfr->transport);
|
||||
char primary_addr_str[INET6_ADDRSTRLEN] = { 0 };
|
||||
isc_netaddr_t primary_netaddr = { 0 };
|
||||
bool hostname_ignore_subject;
|
||||
/*
|
||||
* So, no context exists. Let's create one using the
|
||||
* parameters from the configuration file and try to
|
||||
* store it for further reuse.
|
||||
*/
|
||||
CHECK(isc_tlsctx_createclient(&tlsctx));
|
||||
tls_versions =
|
||||
dns_transport_get_tls_versions(xfr->transport);
|
||||
if (tls_versions != 0) {
|
||||
isc_tlsctx_set_protocols(tlsctx, tls_versions);
|
||||
}
|
||||
ciphers = dns_transport_get_ciphers(xfr->transport);
|
||||
if (ciphers != NULL) {
|
||||
isc_tlsctx_set_cipherlist(tlsctx, ciphers);
|
||||
}
|
||||
|
||||
if (dns_transport_get_prefer_server_ciphers(
|
||||
xfr->transport, &prefer_server_ciphers))
|
||||
{
|
||||
isc_tlsctx_prefer_server_ciphers(
|
||||
tlsctx, prefer_server_ciphers);
|
||||
}
|
||||
|
||||
if (hostname != NULL || ca_file != NULL) {
|
||||
if (found_store == NULL) {
|
||||
/*
|
||||
* 'ca_file' can equal 'NULL' here, in
|
||||
* that case the store with system-wide
|
||||
* CA certificates will be created, just
|
||||
* as planned.
|
||||
*/
|
||||
result = isc_tls_cert_store_create(
|
||||
ca_file, &store);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto failure;
|
||||
}
|
||||
} else {
|
||||
store = found_store;
|
||||
}
|
||||
|
||||
INSIST(store != NULL);
|
||||
if (hostname == NULL) {
|
||||
/*
|
||||
* If CA bundle file is specified, but
|
||||
* hostname is not, then use the primary
|
||||
* IP address for validation, just like
|
||||
* dig does.
|
||||
*/
|
||||
INSIST(ca_file != NULL);
|
||||
isc_netaddr_fromsockaddr(
|
||||
&primary_netaddr,
|
||||
&xfr->primaryaddr);
|
||||
isc_netaddr_format(
|
||||
&primary_netaddr,
|
||||
primary_addr_str,
|
||||
sizeof(primary_addr_str));
|
||||
hostname = primary_addr_str;
|
||||
}
|
||||
/*
|
||||
* According to RFC 8310, Subject field MUST NOT
|
||||
* be inspected when verifying hostname for DoT.
|
||||
* Only SubjectAltName must be checked.
|
||||
*/
|
||||
hostname_ignore_subject = true;
|
||||
result = isc_tlsctx_enable_peer_verification(
|
||||
tlsctx, false, store, hostname,
|
||||
hostname_ignore_subject);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/*
|
||||
* Let's load client certificate and enable
|
||||
* Mutual TLS. We do that only in the case when
|
||||
* Strict TLS is enabled, because Mutual TLS is
|
||||
* an extension of it.
|
||||
*/
|
||||
if (cert_file != NULL) {
|
||||
INSIST(key_file != NULL);
|
||||
|
||||
result = isc_tlsctx_load_certificate(
|
||||
tlsctx, key_file, cert_file);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isc_tlsctx_enable_dot_client_alpn(tlsctx);
|
||||
|
||||
found_store = NULL;
|
||||
result = isc_tlsctx_cache_add(
|
||||
xfr->tlsctx_cache, tlsname,
|
||||
isc_tlsctx_cache_tls, family, tlsctx, store,
|
||||
&found, &found_store);
|
||||
if (result == ISC_R_EXISTS) {
|
||||
/*
|
||||
* It seems the entry has just been created
|
||||
* from within another thread while we were
|
||||
* initialising ours. Although this is
|
||||
* unlikely, it could happen after
|
||||
* startup/re-initialisation. In such a case,
|
||||
* discard the new context and use the already
|
||||
* established one from now on.
|
||||
*
|
||||
* Such situation will not occur after the
|
||||
* initial 'warm-up', so it is not critical
|
||||
* performance-wise.
|
||||
*/
|
||||
INSIST(found != NULL);
|
||||
isc_tlsctx_free(&tlsctx);
|
||||
isc_tls_cert_store_free(&store);
|
||||
tlsctx = found;
|
||||
} else {
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
}
|
||||
goto failure;
|
||||
}
|
||||
INSIST(tlsctx != NULL);
|
||||
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();
|
||||
|
|
@ -1117,18 +1179,6 @@ xfrin_start(dns_xfrin_ctx_t *xfr) {
|
|||
return (ISC_R_SUCCESS);
|
||||
|
||||
failure:
|
||||
/*
|
||||
* The 'found' context is being managed by the TLS context cache.
|
||||
* Thus, we should keep it as it is, as it will get destroyed
|
||||
* alongside the cache.
|
||||
*/
|
||||
if (tlsctx != NULL && found != tlsctx) {
|
||||
isc_tlsctx_free(&tlsctx);
|
||||
}
|
||||
|
||||
if (store != NULL && store != found_store) {
|
||||
isc_tls_cert_store_free(&store);
|
||||
}
|
||||
isc_refcount_decrement0(&xfr->connects);
|
||||
dns_xfrin_detach(&connect_xfr);
|
||||
return (result);
|
||||
|
|
|
|||
|
|
@ -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'.
|
||||
|
|
@ -559,13 +560,15 @@ isc_nm_listentls(isc_nm_t *mgr, isc_sockaddr_t *iface,
|
|||
void
|
||||
isc_nm_tlsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
|
||||
isc_nm_cb_t cb, void *cbarg, isc_tlsctx_t *ctx,
|
||||
isc_tlsctx_client_session_cache_t *client_sess_cache,
|
||||
unsigned int timeout, size_t extrahandlesize);
|
||||
|
||||
void
|
||||
isc_nm_httpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
|
||||
const char *uri, bool POST, isc_nm_cb_t cb, void *cbarg,
|
||||
isc_tlsctx_t *ctx, unsigned int timeout,
|
||||
size_t extrahandlesize);
|
||||
isc_tlsctx_t *ctx,
|
||||
isc_tlsctx_client_session_cache_t *client_sess_cache,
|
||||
unsigned int timeout, size_t extrahandlesize);
|
||||
|
||||
isc_result_t
|
||||
isc_nm_listenhttp(isc_nm_t *mgr, isc_sockaddr_t *iface, int backlog,
|
||||
|
|
|
|||
|
|
@ -267,6 +267,169 @@ isc_tls_cert_store_free(isc_tls_cert_store_t **pstore);
|
|||
*\li 'pstore' is a valid pointer to a pointer containing a non-'NULL' value.
|
||||
*/
|
||||
|
||||
typedef struct isc_tlsctx_client_session_cache isc_tlsctx_client_session_cache_t;
|
||||
/*%<
|
||||
* TLS client session cache is an object which allows efficient
|
||||
* storing and retrieval of previously saved TLS sessions so that they
|
||||
* can be resumed. This object is supposed to be a foundation for
|
||||
* implementing TLS session resumption - a standard technique to
|
||||
* reduce the cost of re-establishing a connection to the remote
|
||||
* server endpoint.
|
||||
*
|
||||
* OpenSSL does server-side TLS session caching transparently by
|
||||
* default. However, on the client-side, a TLS session to resume must
|
||||
* be manually specified when establishing the TLS connection. The TLS
|
||||
* client session cache is precisely the foundation for that.
|
||||
*
|
||||
* The cache has been designed to have the following characteristics:
|
||||
*
|
||||
* - Fixed maximal number of entries to not keep too many obsolete
|
||||
* sessions within the cache;
|
||||
*
|
||||
* - The cache is indexed by character string keys. Each string is a
|
||||
* key representing a remote endpoint (unique remote endpoint name,
|
||||
* e.g. combination of the remote IP address and port);
|
||||
*
|
||||
* - Least Recently Used (LRU) cache replacement policy while allowing
|
||||
* easy removal of obsolete entries;
|
||||
*
|
||||
* - Ability to store multiple TLS sessions associated with the given
|
||||
* key (remote endpoint name). This characteristic is important if
|
||||
* multiple connections to the same remote server can be established;
|
||||
*
|
||||
* - Ability to efficiently retrieve the most recent TLS sessions
|
||||
* associated with the key (remote endpoint name).
|
||||
*
|
||||
* Because of these characteristics, the cache will end up having the
|
||||
* necessary amount of resumable TLS session parameters to the most
|
||||
* used remote endpoints ("hot entries") after a short period of
|
||||
* initial use ("warmup").
|
||||
*
|
||||
* Attempting to resume TLS sessions is an optimisation, which is not
|
||||
* guaranteed to succeed because it requires the same session to be
|
||||
* present in the server session caches. If it is not the case, the
|
||||
* usual handshake procedure takes place. However, when session
|
||||
* resumption is successful, it reduces the amount of the
|
||||
* computational resources required as well as the amount of data to
|
||||
* be transmitted when (re)establishing the connection. Also, it
|
||||
* reduces round trip time (by reducing the number of packets to
|
||||
* transmit).
|
||||
*
|
||||
* This optimisation is important in the context of DNS because the
|
||||
* amount of data within the full handshake messages might be
|
||||
* comparable to or surpass the size of a typical DNS message.
|
||||
*/
|
||||
|
||||
isc_tlsctx_client_session_cache_t *
|
||||
isc_tlsctx_client_session_cache_new(isc_mem_t *mctx, isc_tlsctx_t *ctx,
|
||||
const size_t max_entries);
|
||||
/*%<
|
||||
* Create a new TLS client session cache object.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'mctx' is a valid memory context object;
|
||||
*\li 'ctx' is a valid TLS context object;
|
||||
*\li 'max_entries' is a positive number;
|
||||
*/
|
||||
|
||||
void
|
||||
isc_tlsctx_client_session_cache_attach(
|
||||
isc_tlsctx_client_session_cache_t *source,
|
||||
isc_tlsctx_client_session_cache_t **targetp);
|
||||
/*%<
|
||||
* Create a reference to the TLS client session cache object.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'source' is a valid TLS client session cache object;
|
||||
*\li 'targetp' is a valid pointer to a pointer which must equal NULL.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_tlsctx_client_session_cache_detach(
|
||||
isc_tlsctx_client_session_cache_t **cachep);
|
||||
/*%<
|
||||
* Remove a reference to the TLS client session cache object.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'cachep' is a pointer to a pointer to a valid TLS client session cache
|
||||
*object.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_tlsctx_client_session_cache_keep(isc_tlsctx_client_session_cache_t *cache,
|
||||
char *remote_peer_name, isc_tls_t *tls);
|
||||
/*%<
|
||||
* Add a resumable TLS client session within 'tls' to the TLS client
|
||||
* session cache object 'cache' and associate it with
|
||||
* 'remote_server_name' string. Also, the oldest entry from the cache
|
||||
* might get removed if the cache is full.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'cache' is a pointer to a valid TLS client session cache object;
|
||||
*\li 'remote_peer_name' is a pointer to a non empty character string;
|
||||
*\li 'tls' is a valid, non-'NULL' pointer to a TLS connection state object.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_tlsctx_client_session_cache_keep_sockaddr(
|
||||
isc_tlsctx_client_session_cache_t *cache, isc_sockaddr_t *remote_peer,
|
||||
isc_tls_t *tls);
|
||||
/*%<
|
||||
* The same as 'isc_tlsctx_client_session_cache_keep()', but uses a
|
||||
* 'isc_sockaddr_t' as a key, instead of a character string.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'remote_peer' is a valid, non-'NULL', pointer to an 'isc_sockaddr_t'
|
||||
*object.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_tlsctx_client_session_cache_reuse(isc_tlsctx_client_session_cache_t *cache,
|
||||
char *remote_server_name, isc_tls_t *tls);
|
||||
/*%
|
||||
* Try to restore a previously stored TLS session denoted by a remote
|
||||
* server name as a key ('remote_server_name') into the given TLS
|
||||
* connection state object ('tls'). The successfully restored session
|
||||
* gets removed from the cache.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'cache' is a pointer to a valid TLS client session cache object;
|
||||
*\li 'remote_peer_name' is a pointer to a non empty character string;
|
||||
*\li 'tls' is a valid, non-'NULL' pointer to a TLS connection state object.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_tlsctx_client_session_cache_reuse_sockaddr(
|
||||
isc_tlsctx_client_session_cache_t *cache, isc_sockaddr_t *remote_peer,
|
||||
isc_tls_t *tls);
|
||||
/*%<
|
||||
* The same as 'isc_tlsctx_client_session_cache_reuse()', but uses a
|
||||
* 'isc_sockaddr_t' as a key, instead of a character string.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'remote_peer' is a valid, non-'NULL' pointer to an 'isc_sockaddr_t'
|
||||
*object.
|
||||
*/
|
||||
|
||||
const isc_tlsctx_t *
|
||||
isc_tlsctx_client_session_cache_getctx(isc_tlsctx_client_session_cache_t *cache);
|
||||
/*%<
|
||||
* Returns a TLS context associated with the given TLS client
|
||||
* session cache object. The function is intended to be used to
|
||||
* implement the sanity checks ('INSIST()'s and 'REQUIRE()'s).
|
||||
*
|
||||
* Requires:
|
||||
*\li 'cache' is a pointer to a valid TLS client session cache object.
|
||||
*/
|
||||
|
||||
#define ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE (150)
|
||||
/*%<
|
||||
* The default maximum size of a TLS client session cache. The value
|
||||
* should be large enough to hold enough sessions to successfully
|
||||
* re-establish connections to the most remote TLS servers, but not
|
||||
* too big to avoid keeping too much obsolete sessions.
|
||||
*/
|
||||
|
||||
typedef struct isc_tlsctx_cache isc_tlsctx_cache_t;
|
||||
/*%<
|
||||
* The TLS context cache is an object which allows retrieving a
|
||||
|
|
@ -334,28 +497,39 @@ isc_tlsctx_cache_detach(isc_tlsctx_cache_t **cachep);
|
|||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_tlsctx_cache_add(isc_tlsctx_cache_t *cache, const char *name,
|
||||
const isc_tlsctx_cache_transport_t transport,
|
||||
const uint16_t family, isc_tlsctx_t *ctx,
|
||||
isc_tls_cert_store_t *store, isc_tlsctx_t **pfound,
|
||||
isc_tls_cert_store_t **pfound_store);
|
||||
isc_tlsctx_cache_add(
|
||||
isc_tlsctx_cache_t *cache, const char *name,
|
||||
const isc_tlsctx_cache_transport_t transport, const uint16_t family,
|
||||
isc_tlsctx_t *ctx, isc_tls_cert_store_t *store,
|
||||
isc_tlsctx_client_session_cache_t *client_sess_cache,
|
||||
isc_tlsctx_t **pfound, isc_tls_cert_store_t **pfound_store,
|
||||
isc_tlsctx_client_session_cache_t **pfound_client_sess_cache);
|
||||
/*%<
|
||||
*
|
||||
* Add a new TLS context to the TLS context cache. 'pfound' is an
|
||||
* optional pointer, which can be used to retrieve an already
|
||||
* existing TLS context object in a case it exists.
|
||||
* Add a new TLS context and its associated data to the TLS context
|
||||
* cache. 'pfound' is an optional pointer, which can be used to
|
||||
* retrieve an already existing TLS context object in a case it
|
||||
* exists.
|
||||
*
|
||||
* The passed certificates store object ('store') possession is
|
||||
* transferred to the cache object in a case of success. In some cases
|
||||
* it might be destroyed immediately upon the call completion.
|
||||
*
|
||||
* The possession of the passed TLS client session cache
|
||||
* ('client_sess_cache') is also transferred to the cache object in a
|
||||
* case of success.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'cache' is a valid pointer to a TLS context cache object;
|
||||
*\li 'name' is a valid pointer to a non-empty string;
|
||||
*\li 'transport' is a valid transport identifier (currently only
|
||||
* TLS/DoT and HTTPS/DoH are supported);
|
||||
*\li 'family' - either 'AF_INET' or 'AF_INET6';
|
||||
*\li 'ctx' - a valid pointer to a valid TLS context object.
|
||||
*\li 'ctx' - a valid pointer to a valid TLS context object;
|
||||
*\li 'store' - a valid pointer to a valid TLS certificates store object or
|
||||
* 'NULL';
|
||||
*\li 'client_sess_cache' - a valid pointer to a valid TLS client sessions
|
||||
*cache object or 'NULL.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_EXISTS - node of the same key already exists;
|
||||
|
|
@ -363,12 +537,13 @@ isc_tlsctx_cache_add(isc_tlsctx_cache_t *cache, const char *name,
|
|||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_tlsctx_cache_find(isc_tlsctx_cache_t *cache, const char *name,
|
||||
const isc_tlsctx_cache_transport_t transport,
|
||||
const uint16_t family, isc_tlsctx_t **pctx,
|
||||
isc_tls_cert_store_t **pstore);
|
||||
isc_tlsctx_cache_find(
|
||||
isc_tlsctx_cache_t *cache, const char *name,
|
||||
const isc_tlsctx_cache_transport_t transport, const uint16_t family,
|
||||
isc_tlsctx_t **pctx, isc_tls_cert_store_t **pstore,
|
||||
isc_tlsctx_client_session_cache_t **pfound_client_sess_cache);
|
||||
/*%<
|
||||
* Look up a TLS context in the TLS context cache.
|
||||
* Look up a TLS context and its associated data in the TLS context cache.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'cache' is a valid pointer to a TLS context cache object;
|
||||
|
|
@ -376,9 +551,14 @@ isc_tlsctx_cache_find(isc_tlsctx_cache_t *cache, const char *name,
|
|||
*\li 'transport' - a valid transport identifier (currently only
|
||||
* TLS/DoT and HTTPS/DoH are supported;
|
||||
*\li 'family' - either 'AF_INET' or 'AF_INET6';
|
||||
*\li 'pctx' - a valid pointer to a non-NULL pointer.
|
||||
*\li 'pctx' - a valid pointer to a non-NULL pointer;
|
||||
*\li 'pstore' - a valid pointer to a non-NULL pointer or 'NULL'.
|
||||
*\li 'pfound_client_sess_cache' - a valid pointer to a non-NULL pointer or
|
||||
*'NULL'.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS - the context has been found;
|
||||
*\li #ISC_R_NOTFOUND - the context has not been found.
|
||||
*\li #ISC_R_NOTFOUND - the context has not been found. In such a case,
|
||||
* 'pstore' still might get initialised as there is one to many
|
||||
* relation between stores and contexts.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1424,8 +1424,9 @@ error:
|
|||
void
|
||||
isc_nm_httpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
|
||||
const char *uri, bool post, isc_nm_cb_t cb, void *cbarg,
|
||||
isc_tlsctx_t *tlsctx, unsigned int timeout,
|
||||
size_t extrahandlesize) {
|
||||
isc_tlsctx_t *tlsctx,
|
||||
isc_tlsctx_client_session_cache_t *client_sess_cache,
|
||||
unsigned int timeout, size_t extrahandlesize) {
|
||||
isc_sockaddr_t local_interface;
|
||||
isc_nmsocket_t *sock = NULL;
|
||||
|
||||
|
|
@ -1487,7 +1488,7 @@ isc_nm_httpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
|
|||
|
||||
if (tlsctx != NULL) {
|
||||
isc_nm_tlsconnect(mgr, local, peer, transport_connect_cb, sock,
|
||||
tlsctx, timeout, 0);
|
||||
tlsctx, client_sess_cache, timeout, 0);
|
||||
} else {
|
||||
isc_nm_tcpconnect(mgr, local, peer, transport_connect_cb, sock,
|
||||
timeout, 0);
|
||||
|
|
@ -1507,7 +1508,12 @@ client_send(isc_nmhandle_t *handle, const isc_region_t *region) {
|
|||
REQUIRE(region != NULL);
|
||||
REQUIRE(region->base != NULL);
|
||||
REQUIRE(region->length <= MAX_DNS_MESSAGE_SIZE);
|
||||
REQUIRE(cstream != NULL);
|
||||
|
||||
if (session->closed) {
|
||||
return (ISC_R_CANCELED);
|
||||
}
|
||||
|
||||
INSIST(cstream != NULL);
|
||||
|
||||
if (cstream->post) {
|
||||
/* POST */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -971,6 +973,8 @@ struct isc_nmsocket {
|
|||
isc_tlsctx_t **listener_tls_ctx; /*%< A context reference per
|
||||
worker */
|
||||
size_t n_listener_tls_ctx;
|
||||
isc_tlsctx_client_session_cache_t *client_sess_cache;
|
||||
bool client_session_saved;
|
||||
isc_nmsocket_t *tlslistener;
|
||||
isc_nmsocket_t *tlssocket;
|
||||
atomic_bool result_updated;
|
||||
|
|
@ -2175,3 +2179,6 @@ isc__nmsocket_writetimeout_cb(void *data, isc_result_t eresult);
|
|||
isc_error_fatal(__FILE__, __LINE__, "%s failed: %s\n", #func, \
|
||||
uv_strerror(ret)); \
|
||||
}
|
||||
|
||||
void
|
||||
isc__nmsocket_log_tls_session_reuse(isc_nmsocket_t *sock, isc_tls_t *tls);
|
||||
|
|
|
|||
|
|
@ -2077,6 +2077,10 @@ void
|
|||
isc__nmsocket_timer_restart(isc_nmsocket_t *sock) {
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
|
||||
if (uv_is_closing((uv_handle_t *)&sock->read_timer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (atomic_load(&sock->connecting)) {
|
||||
int r;
|
||||
|
||||
|
|
@ -3729,6 +3733,27 @@ isc_nm_verify_tls_peer_result_string(const isc_nmhandle_t *handle) {
|
|||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
isc__nmsocket_log_tls_session_reuse(isc_nmsocket_t *sock, isc_tls_t *tls) {
|
||||
const int log_level = ISC_LOG_DEBUG(1);
|
||||
char client_sabuf[ISC_SOCKADDR_FORMATSIZE];
|
||||
char local_sabuf[ISC_SOCKADDR_FORMATSIZE];
|
||||
|
||||
REQUIRE(tls != NULL);
|
||||
|
||||
if (!isc_log_wouldlog(isc_lctx, log_level)) {
|
||||
return;
|
||||
};
|
||||
|
||||
isc_sockaddr_format(&sock->peer, client_sabuf, sizeof(client_sabuf));
|
||||
isc_sockaddr_format(&sock->iface, local_sabuf, sizeof(local_sabuf));
|
||||
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR,
|
||||
log_level, "TLS %s session %s for %s on %s",
|
||||
SSL_is_server(tls) ? "server" : "client",
|
||||
SSL_session_reused(tls) ? "resumed" : "created",
|
||||
client_sabuf, local_sabuf);
|
||||
}
|
||||
|
||||
#ifdef NETMGR_TRACE
|
||||
/*
|
||||
* Dump all active sockets in netmgr. We output to stderr
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,6 +86,12 @@ tls_cleanup_listener_tlsctx(isc_nmsocket_t *listener);
|
|||
static isc_tlsctx_t *
|
||||
tls_get_listener_tlsctx(isc_nmsocket_t *listener, const int tid);
|
||||
|
||||
static void
|
||||
tls_keep_client_tls_session(isc_nmsocket_t *sock);
|
||||
|
||||
static void
|
||||
tls_try_shutdown(isc_tls_t *tls, const bool quite);
|
||||
|
||||
/*
|
||||
* The socket is closing, outerhandle has been detached, listener is
|
||||
* inactive, or the netmgr is closing: any operation on it should abort
|
||||
|
|
@ -128,6 +134,10 @@ tls_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
|
|||
tlssock = send_req->tlssock;
|
||||
send_req->tlssock = NULL;
|
||||
|
||||
if (finish) {
|
||||
tls_try_shutdown(tlssock->tlsstream.tls, true);
|
||||
}
|
||||
|
||||
if (send_req->cb != NULL) {
|
||||
INSIST(VALID_NMHANDLE(tlssock->statichandle));
|
||||
send_req->cb(send_req->handle, eresult, send_req->cbarg);
|
||||
|
|
@ -241,10 +251,9 @@ tls_send_outgoing(isc_nmsocket_t *sock, bool finish, isc_nmhandle_t *tlshandle,
|
|||
return (0);
|
||||
}
|
||||
|
||||
if (finish && (SSL_get_shutdown(sock->tlsstream.tls) &
|
||||
SSL_SENT_SHUTDOWN) != SSL_SENT_SHUTDOWN)
|
||||
{
|
||||
(void)SSL_shutdown(sock->tlsstream.tls);
|
||||
if (finish) {
|
||||
tls_try_shutdown(sock->tlsstream.tls, false);
|
||||
tls_keep_client_tls_session(sock);
|
||||
}
|
||||
|
||||
pending = BIO_pending(sock->tlsstream.bio_out);
|
||||
|
|
@ -293,22 +302,21 @@ tls_process_outgoing(isc_nmsocket_t *sock, bool finish,
|
|||
isc__nm_uvreq_t *send_data) {
|
||||
int pending;
|
||||
|
||||
bool received_shutdown = ((SSL_get_shutdown(sock->tlsstream.tls) &
|
||||
SSL_RECEIVED_SHUTDOWN) != 0);
|
||||
bool sent_shutdown = ((SSL_get_shutdown(sock->tlsstream.tls) &
|
||||
SSL_SENT_SHUTDOWN) != 0);
|
||||
|
||||
if (received_shutdown && !sent_shutdown) {
|
||||
finish = true;
|
||||
}
|
||||
|
||||
/* Data from TLS to network */
|
||||
if (send_data != NULL) {
|
||||
pending = tls_send_outgoing(sock, finish, send_data->handle,
|
||||
send_data->cb.send,
|
||||
send_data->cbarg);
|
||||
} else {
|
||||
bool received_shutdown =
|
||||
((SSL_get_shutdown(sock->tlsstream.tls) &
|
||||
SSL_RECEIVED_SHUTDOWN) != 0);
|
||||
bool sent_shutdown = ((SSL_get_shutdown(sock->tlsstream.tls) &
|
||||
SSL_SENT_SHUTDOWN) != 0);
|
||||
|
||||
if (received_shutdown && !sent_shutdown) {
|
||||
finish = true;
|
||||
(void)SSL_shutdown(sock->tlsstream.tls);
|
||||
}
|
||||
pending = tls_send_outgoing(sock, finish, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -331,6 +339,7 @@ tls_try_handshake(isc_nmsocket_t *sock) {
|
|||
isc_result_t result = ISC_R_SUCCESS;
|
||||
INSIST(SSL_is_init_finished(sock->tlsstream.tls) == 1);
|
||||
INSIST(sock->statichandle == NULL);
|
||||
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,
|
||||
|
|
@ -889,7 +898,8 @@ tcp_connected(isc_nmhandle_t *handle, isc_result_t result, void *cbarg);
|
|||
|
||||
void
|
||||
isc_nm_tlsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
|
||||
isc_nm_cb_t cb, void *cbarg, SSL_CTX *ctx,
|
||||
isc_nm_cb_t cb, void *cbarg, isc_tlsctx_t *ctx,
|
||||
isc_tlsctx_client_session_cache_t *client_sess_cache,
|
||||
unsigned int timeout, size_t extrahandlesize) {
|
||||
isc_nmsocket_t *nsock = NULL;
|
||||
#if defined(NETMGR_TRACE) && defined(NETMGR_TRACE_VERBOSE)
|
||||
|
|
@ -907,6 +917,13 @@ isc_nm_tlsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
|
|||
nsock->connect_cbarg = cbarg;
|
||||
nsock->connect_timeout = timeout;
|
||||
isc_tlsctx_attach(ctx, &nsock->tlsstream.ctx);
|
||||
atomic_init(&nsock->client, true);
|
||||
if (client_sess_cache != NULL) {
|
||||
INSIST(isc_tlsctx_client_session_cache_getctx(
|
||||
client_sess_cache) == ctx);
|
||||
isc_tlsctx_client_session_cache_attach(
|
||||
client_sess_cache, &nsock->tlsstream.client_sess_cache);
|
||||
}
|
||||
|
||||
isc_nm_tcpconnect(mgr, local, peer, tcp_connected, nsock,
|
||||
nsock->connect_timeout, 0);
|
||||
|
|
@ -949,6 +966,12 @@ tcp_connected(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
|||
isc_nmhandle_attach(handle, &tlssock->outerhandle);
|
||||
atomic_store(&tlssock->active, true);
|
||||
|
||||
if (tlssock->tlsstream.client_sess_cache != NULL) {
|
||||
isc_tlsctx_client_session_cache_reuse_sockaddr(
|
||||
tlssock->tlsstream.client_sess_cache, &tlssock->peer,
|
||||
tlssock->tlsstream.tls);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hold a reference to tlssock in the TCP socket: it will
|
||||
* detached in isc__nm_tls_cleanup_data().
|
||||
|
|
@ -1026,15 +1049,26 @@ isc__nm_tls_cleanup_data(isc_nmsocket_t *sock) {
|
|||
} else if (sock->type == isc_nm_tlslistener) {
|
||||
tls_cleanup_listener_tlsctx(sock);
|
||||
} else if (sock->type == isc_nm_tlssocket) {
|
||||
if (sock->tlsstream.ctx != NULL) {
|
||||
isc_tlsctx_free(&sock->tlsstream.ctx);
|
||||
}
|
||||
if (sock->tlsstream.tls != NULL) {
|
||||
/*
|
||||
* Let's shutdown 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);
|
||||
isc_tls_free(&sock->tlsstream.tls);
|
||||
/* These are destroyed when we free SSL */
|
||||
sock->tlsstream.bio_out = NULL;
|
||||
sock->tlsstream.bio_in = NULL;
|
||||
}
|
||||
if (sock->tlsstream.ctx != NULL) {
|
||||
isc_tlsctx_free(&sock->tlsstream.ctx);
|
||||
}
|
||||
if (sock->tlsstream.client_sess_cache != NULL) {
|
||||
INSIST(atomic_load(&sock->client));
|
||||
isc_tlsctx_client_session_cache_detach(
|
||||
&sock->tlsstream.client_sess_cache);
|
||||
}
|
||||
} else if (sock->type == isc_nm_tcpsocket &&
|
||||
sock->tlsstream.tlssocket != NULL) {
|
||||
/*
|
||||
|
|
@ -1164,3 +1198,30 @@ isc__nm_async_tls_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx,
|
|||
isc_tlsctx_free(&listener->tlsstream.listener_tls_ctx[tid]);
|
||||
isc_tlsctx_attach(tlsctx, &listener->tlsstream.listener_tls_ctx[tid]);
|
||||
}
|
||||
|
||||
static void
|
||||
tls_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->tlsstream.client_sess_cache != NULL &&
|
||||
sock->tlsstream.client_session_saved == false)
|
||||
{
|
||||
INSIST(atomic_load(&sock->client));
|
||||
isc_tlsctx_client_session_cache_keep_sockaddr(
|
||||
sock->tlsstream.client_sess_cache, &sock->peer,
|
||||
sock->tlsstream.tls);
|
||||
sock->tlsstream.client_session_saved = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tls_try_shutdown(isc_tls_t *tls, const bool force) {
|
||||
if (force) {
|
||||
(void)SSL_set_shutdown(tls, SSL_SENT_SHUTDOWN);
|
||||
} else if ((SSL_get_shutdown(tls) & SSL_SENT_SHUTDOWN) == 0) {
|
||||
(void)SSL_shutdown(tls);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
377
lib/isc/tls.c
377
lib/isc/tls.c
|
|
@ -43,6 +43,7 @@
|
|||
#include <isc/random.h>
|
||||
#include <isc/refcount.h>
|
||||
#include <isc/rwlock.h>
|
||||
#include <isc/sockaddr.h>
|
||||
#include <isc/thread.h>
|
||||
#include <isc/tls.h>
|
||||
#include <isc/util.h>
|
||||
|
|
@ -1074,6 +1075,10 @@ isc_tls_cert_store_free(isc_tls_cert_store_t **pstore) {
|
|||
#define TLSCTX_CACHE_MAGIC ISC_MAGIC('T', 'l', 'S', 'c')
|
||||
#define VALID_TLSCTX_CACHE(t) ISC_MAGIC_VALID(t, TLSCTX_CACHE_MAGIC)
|
||||
|
||||
#define TLSCTX_CLIENT_SESSION_CACHE_MAGIC ISC_MAGIC('T', 'l', 'C', 'c')
|
||||
#define VALID_TLSCTX_CLIENT_SESSION_CACHE(t) \
|
||||
ISC_MAGIC_VALID(t, TLSCTX_CLIENT_SESSION_CACHE_MAGIC)
|
||||
|
||||
typedef struct isc_tlsctx_cache_entry {
|
||||
/*
|
||||
* We need a TLS context entry for each transport on both IPv4 and
|
||||
|
|
@ -1081,6 +1086,8 @@ typedef struct isc_tlsctx_cache_entry {
|
|||
* session-resumption cache.
|
||||
*/
|
||||
isc_tlsctx_t *ctx[isc_tlsctx_cache_count - 1][2];
|
||||
isc_tlsctx_client_session_cache_t
|
||||
*client_sess_cache[isc_tlsctx_cache_count - 1][2];
|
||||
/*
|
||||
* One certificate store is enough for all the contexts defined
|
||||
* above. We need that for peer validation.
|
||||
|
|
@ -1133,6 +1140,11 @@ tlsctx_cache_entry_destroy(isc_mem_t *mctx, isc_tlsctx_cache_entry_t *entry) {
|
|||
if (entry->ctx[i][k] != NULL) {
|
||||
isc_tlsctx_free(&entry->ctx[i][k]);
|
||||
}
|
||||
|
||||
if (entry->client_sess_cache[i][k] != NULL) {
|
||||
isc_tlsctx_client_session_cache_detach(
|
||||
&entry->client_sess_cache[i][k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entry->ca_store != NULL) {
|
||||
|
|
@ -1182,17 +1194,21 @@ isc_tlsctx_cache_detach(isc_tlsctx_cache_t **cachep) {
|
|||
}
|
||||
|
||||
isc_result_t
|
||||
isc_tlsctx_cache_add(isc_tlsctx_cache_t *cache, const char *name,
|
||||
const isc_tlsctx_cache_transport_t transport,
|
||||
const uint16_t family, isc_tlsctx_t *ctx,
|
||||
isc_tls_cert_store_t *store, isc_tlsctx_t **pfound,
|
||||
isc_tls_cert_store_t **pfound_store) {
|
||||
isc_tlsctx_cache_add(
|
||||
isc_tlsctx_cache_t *cache, const char *name,
|
||||
const isc_tlsctx_cache_transport_t transport, const uint16_t family,
|
||||
isc_tlsctx_t *ctx, isc_tls_cert_store_t *store,
|
||||
isc_tlsctx_client_session_cache_t *client_sess_cache,
|
||||
isc_tlsctx_t **pfound, isc_tls_cert_store_t **pfound_store,
|
||||
isc_tlsctx_client_session_cache_t **pfound_client_sess_cache) {
|
||||
isc_result_t result = ISC_R_FAILURE;
|
||||
size_t name_len, tr_offset;
|
||||
isc_tlsctx_cache_entry_t *entry = NULL;
|
||||
bool ipv6;
|
||||
|
||||
REQUIRE(VALID_TLSCTX_CACHE(cache));
|
||||
REQUIRE(client_sess_cache == NULL ||
|
||||
VALID_TLSCTX_CLIENT_SESSION_CACHE(client_sess_cache));
|
||||
REQUIRE(name != NULL && *name != '\0');
|
||||
REQUIRE(transport > isc_tlsctx_cache_none &&
|
||||
transport < isc_tlsctx_cache_count);
|
||||
|
|
@ -1208,6 +1224,7 @@ isc_tlsctx_cache_add(isc_tlsctx_cache_t *cache, const char *name,
|
|||
result = isc_ht_find(cache->data, (const uint8_t *)name, name_len,
|
||||
(void **)&entry);
|
||||
if (result == ISC_R_SUCCESS && entry->ctx[tr_offset][ipv6] != NULL) {
|
||||
isc_tlsctx_client_session_cache_t *found_client_sess_cache;
|
||||
/* The entry exists. */
|
||||
if (pfound != NULL) {
|
||||
INSIST(*pfound == NULL);
|
||||
|
|
@ -1218,6 +1235,14 @@ isc_tlsctx_cache_add(isc_tlsctx_cache_t *cache, const char *name,
|
|||
INSIST(*pfound_store == NULL);
|
||||
*pfound_store = entry->ca_store;
|
||||
}
|
||||
|
||||
found_client_sess_cache =
|
||||
entry->client_sess_cache[tr_offset][ipv6];
|
||||
if (pfound_client_sess_cache != NULL &&
|
||||
found_client_sess_cache != NULL) {
|
||||
INSIST(*pfound_client_sess_cache == NULL);
|
||||
*pfound_client_sess_cache = found_client_sess_cache;
|
||||
}
|
||||
result = ISC_R_EXISTS;
|
||||
} else if (result == ISC_R_SUCCESS &&
|
||||
entry->ctx[tr_offset][ipv6] == NULL) {
|
||||
|
|
@ -1226,10 +1251,11 @@ isc_tlsctx_cache_add(isc_tlsctx_cache_t *cache, const char *name,
|
|||
* particular transport/IP type combination.
|
||||
*/
|
||||
entry->ctx[tr_offset][ipv6] = ctx;
|
||||
entry->client_sess_cache[tr_offset][ipv6] = client_sess_cache;
|
||||
/*
|
||||
* As the passed certificates store object is supposed to be
|
||||
* internally managed by the cache object anyway, we might
|
||||
* destroy the unneeded store object right now.
|
||||
* As the passed certificates store object is supposed
|
||||
* to be internally managed by the cache object anyway,
|
||||
* we might destroy the unneeded store object right now.
|
||||
*/
|
||||
if (store != NULL && store != entry->ca_store) {
|
||||
isc_tls_cert_store_free(&store);
|
||||
|
|
@ -1244,6 +1270,7 @@ isc_tlsctx_cache_add(isc_tlsctx_cache_t *cache, const char *name,
|
|||
/* Oracle/Red Hat Linux, GCC bug #53119 */
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
entry->ctx[tr_offset][ipv6] = ctx;
|
||||
entry->client_sess_cache[tr_offset][ipv6] = client_sess_cache;
|
||||
entry->ca_store = store;
|
||||
RUNTIME_CHECK(isc_ht_add(cache->data, (const uint8_t *)name,
|
||||
name_len,
|
||||
|
|
@ -1257,10 +1284,11 @@ isc_tlsctx_cache_add(isc_tlsctx_cache_t *cache, const char *name,
|
|||
}
|
||||
|
||||
isc_result_t
|
||||
isc_tlsctx_cache_find(isc_tlsctx_cache_t *cache, const char *name,
|
||||
const isc_tlsctx_cache_transport_t transport,
|
||||
const uint16_t family, isc_tlsctx_t **pctx,
|
||||
isc_tls_cert_store_t **pstore) {
|
||||
isc_tlsctx_cache_find(
|
||||
isc_tlsctx_cache_t *cache, const char *name,
|
||||
const isc_tlsctx_cache_transport_t transport, const uint16_t family,
|
||||
isc_tlsctx_t **pctx, isc_tls_cert_store_t **pstore,
|
||||
isc_tlsctx_client_session_cache_t **pfound_client_sess_cache) {
|
||||
isc_result_t result = ISC_R_FAILURE;
|
||||
size_t tr_offset;
|
||||
isc_tlsctx_cache_entry_t *entry = NULL;
|
||||
|
|
@ -1287,7 +1315,16 @@ isc_tlsctx_cache_find(isc_tlsctx_cache_t *cache, const char *name,
|
|||
}
|
||||
|
||||
if (result == ISC_R_SUCCESS && entry->ctx[tr_offset][ipv6] != NULL) {
|
||||
isc_tlsctx_client_session_cache_t *found_client_sess_cache =
|
||||
entry->client_sess_cache[tr_offset][ipv6];
|
||||
|
||||
*pctx = entry->ctx[tr_offset][ipv6];
|
||||
|
||||
if (pfound_client_sess_cache != NULL &&
|
||||
found_client_sess_cache != NULL) {
|
||||
INSIST(*pfound_client_sess_cache == NULL);
|
||||
*pfound_client_sess_cache = found_client_sess_cache;
|
||||
}
|
||||
} else if (result == ISC_R_SUCCESS &&
|
||||
entry->ctx[tr_offset][ipv6] == NULL) {
|
||||
result = ISC_R_NOTFOUND;
|
||||
|
|
@ -1299,3 +1336,319 @@ isc_tlsctx_cache_find(isc_tlsctx_cache_t *cache, const char *name,
|
|||
|
||||
return (result);
|
||||
}
|
||||
|
||||
typedef struct client_session_cache_entry client_session_cache_entry_t;
|
||||
|
||||
typedef struct client_session_cache_bucket {
|
||||
char *bucket_key;
|
||||
size_t bucket_key_len;
|
||||
/* Cache entries within the bucket (from the oldest to the newest). */
|
||||
ISC_LIST(client_session_cache_entry_t) entries;
|
||||
} client_session_cache_bucket_t;
|
||||
|
||||
struct client_session_cache_entry {
|
||||
SSL_SESSION *session;
|
||||
client_session_cache_bucket_t *bucket; /* "Parent" bucket pointer. */
|
||||
ISC_LINK(client_session_cache_entry_t) bucket_link;
|
||||
ISC_LINK(client_session_cache_entry_t) cache_link;
|
||||
};
|
||||
|
||||
struct isc_tlsctx_client_session_cache {
|
||||
uint32_t magic;
|
||||
isc_refcount_t references;
|
||||
isc_mem_t *mctx;
|
||||
|
||||
/*
|
||||
* We need to keep a reference to the related TLS context in order
|
||||
* to ensure that it remains valid while the TLS client sessions
|
||||
* cache object is valid, as every TLS session object
|
||||
* (SSL_SESSION) is "tied" to a particular context.
|
||||
*/
|
||||
isc_tlsctx_t *ctx;
|
||||
|
||||
/*
|
||||
* The idea is to have one bucket per remote server. Each bucket,
|
||||
* can maintain multiple TLS sessions to that server, as BIND
|
||||
* might want to establish multiple TLS connections to the remote
|
||||
* server at once.
|
||||
*/
|
||||
isc_ht_t *buckets;
|
||||
|
||||
/*
|
||||
* The list of all current entries within the cache maintained in
|
||||
* LRU-manner, so that the oldest entry might be efficiently
|
||||
* removed.
|
||||
*/
|
||||
ISC_LIST(client_session_cache_entry_t) lru_entries;
|
||||
/* Number of the entries within the cache. */
|
||||
size_t nentries;
|
||||
/* Maximum number of the entries within the cache. */
|
||||
size_t max_entries;
|
||||
|
||||
isc_mutex_t lock;
|
||||
};
|
||||
|
||||
isc_tlsctx_client_session_cache_t *
|
||||
isc_tlsctx_client_session_cache_new(isc_mem_t *mctx, isc_tlsctx_t *ctx,
|
||||
const size_t max_entries) {
|
||||
isc_tlsctx_client_session_cache_t *nc;
|
||||
|
||||
REQUIRE(ctx != NULL);
|
||||
REQUIRE(max_entries > 0);
|
||||
|
||||
nc = isc_mem_get(mctx, sizeof(*nc));
|
||||
|
||||
*nc = (isc_tlsctx_client_session_cache_t){ .max_entries = max_entries };
|
||||
isc_refcount_init(&nc->references, 1);
|
||||
isc_mem_attach(mctx, &nc->mctx);
|
||||
isc_tlsctx_attach(ctx, &nc->ctx);
|
||||
|
||||
isc_ht_init(&nc->buckets, mctx, 5);
|
||||
ISC_LIST_INIT(nc->lru_entries);
|
||||
isc_mutex_init(&nc->lock);
|
||||
|
||||
nc->magic = TLSCTX_CLIENT_SESSION_CACHE_MAGIC;
|
||||
|
||||
return (nc);
|
||||
}
|
||||
|
||||
void
|
||||
isc_tlsctx_client_session_cache_attach(
|
||||
isc_tlsctx_client_session_cache_t *source,
|
||||
isc_tlsctx_client_session_cache_t **targetp) {
|
||||
REQUIRE(VALID_TLSCTX_CLIENT_SESSION_CACHE(source));
|
||||
REQUIRE(targetp != NULL && *targetp == NULL);
|
||||
|
||||
isc_refcount_increment(&source->references);
|
||||
|
||||
*targetp = source;
|
||||
}
|
||||
|
||||
static void
|
||||
client_cache_entry_delete(isc_tlsctx_client_session_cache_t *restrict cache,
|
||||
client_session_cache_entry_t *restrict entry) {
|
||||
client_session_cache_bucket_t *restrict bucket = entry->bucket;
|
||||
|
||||
/* Unlink and free the cache entry */
|
||||
ISC_LIST_UNLINK(bucket->entries, entry, bucket_link);
|
||||
ISC_LIST_UNLINK(cache->lru_entries, entry, cache_link);
|
||||
cache->nentries--;
|
||||
(void)SSL_SESSION_free(entry->session);
|
||||
isc_mem_put(cache->mctx, entry, sizeof(*entry));
|
||||
|
||||
/* The bucket is empty - let's remove it */
|
||||
if (ISC_LIST_EMPTY(bucket->entries)) {
|
||||
RUNTIME_CHECK(isc_ht_delete(cache->buckets,
|
||||
(const uint8_t *)bucket->bucket_key,
|
||||
bucket->bucket_key_len) ==
|
||||
ISC_R_SUCCESS);
|
||||
|
||||
isc_mem_free(cache->mctx, bucket->bucket_key);
|
||||
isc_mem_put(cache->mctx, bucket, sizeof(*bucket));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
isc_tlsctx_client_session_cache_detach(
|
||||
isc_tlsctx_client_session_cache_t **cachep) {
|
||||
isc_tlsctx_client_session_cache_t *cache = NULL;
|
||||
client_session_cache_entry_t *entry = NULL, *next = NULL;
|
||||
|
||||
REQUIRE(cachep != NULL);
|
||||
|
||||
cache = *cachep;
|
||||
*cachep = NULL;
|
||||
|
||||
REQUIRE(VALID_TLSCTX_CLIENT_SESSION_CACHE(cache));
|
||||
|
||||
if (isc_refcount_decrement(&cache->references) != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
cache->magic = 0;
|
||||
|
||||
isc_refcount_destroy(&cache->references);
|
||||
|
||||
entry = ISC_LIST_HEAD(cache->lru_entries);
|
||||
while (entry != NULL) {
|
||||
next = ISC_LIST_NEXT(entry, cache_link);
|
||||
client_cache_entry_delete(cache, entry);
|
||||
entry = next;
|
||||
}
|
||||
|
||||
RUNTIME_CHECK(isc_ht_count(cache->buckets) == 0);
|
||||
isc_ht_destroy(&cache->buckets);
|
||||
|
||||
isc_mutex_destroy(&cache->lock);
|
||||
isc_tlsctx_free(&cache->ctx);
|
||||
isc_mem_putanddetach(&cache->mctx, cache, sizeof(*cache));
|
||||
}
|
||||
|
||||
static bool
|
||||
ssl_session_seems_resumable(const SSL_SESSION *sess) {
|
||||
#ifdef HAVE_SSL_SESSION_IS_RESUMABLE
|
||||
/*
|
||||
* If SSL_SESSION_is_resumable() is available, let's use that. It
|
||||
* is expected to be available on OpenSSL >= 1.1.1 and its modern
|
||||
* siblings.
|
||||
*/
|
||||
return (SSL_SESSION_is_resumable(sess) != 0);
|
||||
#elif (OPENSSL_VERSION_NUMBER >= 0x10100000L)
|
||||
/*
|
||||
* Taking into consideration that OpenSSL 1.1.0 uses opaque
|
||||
* pointers for SSL_SESSION, we cannot implement a replacement for
|
||||
* SSL_SESSION_is_resumable() manually. Let's use a sensible
|
||||
* approximation for that, then: if there is an associated session
|
||||
* ticket or session ID, then, most likely, the session is
|
||||
* resumable.
|
||||
*/
|
||||
unsigned int session_id_len = 0;
|
||||
(void)SSL_SESSION_get_id(sess, &session_id_len);
|
||||
return (SSL_SESSION_has_ticket(sess) || session_id_len > 0);
|
||||
#else
|
||||
return (!sess->not_resumable &&
|
||||
(sess->session_id_length > 0 || sess->tlsext_ticklen > 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
isc_tlsctx_client_session_cache_keep(isc_tlsctx_client_session_cache_t *cache,
|
||||
char *remote_peer_name, isc_tls_t *tls) {
|
||||
size_t name_len;
|
||||
isc_result_t result;
|
||||
SSL_SESSION *sess;
|
||||
client_session_cache_bucket_t *restrict bucket = NULL;
|
||||
client_session_cache_entry_t *restrict entry = NULL;
|
||||
|
||||
REQUIRE(VALID_TLSCTX_CLIENT_SESSION_CACHE(cache));
|
||||
REQUIRE(remote_peer_name != NULL && *remote_peer_name != '\0');
|
||||
REQUIRE(tls != NULL);
|
||||
|
||||
sess = SSL_get1_session(tls);
|
||||
if (sess == NULL) {
|
||||
return;
|
||||
} else if (!ssl_session_seems_resumable(sess)) {
|
||||
SSL_SESSION_free(sess);
|
||||
return;
|
||||
}
|
||||
|
||||
isc_mutex_lock(&cache->lock);
|
||||
|
||||
name_len = strlen(remote_peer_name);
|
||||
result = isc_ht_find(cache->buckets, (const uint8_t *)remote_peer_name,
|
||||
name_len, (void **)&bucket);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
/* Let's create a new bucket */
|
||||
INSIST(bucket == NULL);
|
||||
bucket = isc_mem_get(cache->mctx, sizeof(*bucket));
|
||||
*bucket = (client_session_cache_bucket_t){
|
||||
.bucket_key = isc_mem_strdup(cache->mctx,
|
||||
remote_peer_name),
|
||||
.bucket_key_len = name_len
|
||||
};
|
||||
ISC_LIST_INIT(bucket->entries);
|
||||
RUNTIME_CHECK(isc_ht_add(cache->buckets,
|
||||
(const uint8_t *)remote_peer_name,
|
||||
name_len,
|
||||
(void *)bucket) == ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
/* Let's add a new cache entry to the new/found bucket */
|
||||
entry = isc_mem_get(cache->mctx, sizeof(*entry));
|
||||
*entry = (client_session_cache_entry_t){ .session = sess,
|
||||
.bucket = bucket };
|
||||
ISC_LINK_INIT(entry, bucket_link);
|
||||
ISC_LINK_INIT(entry, cache_link);
|
||||
|
||||
ISC_LIST_APPEND(bucket->entries, entry, bucket_link);
|
||||
|
||||
ISC_LIST_APPEND(cache->lru_entries, entry, cache_link);
|
||||
cache->nentries++;
|
||||
|
||||
if (cache->nentries > cache->max_entries) {
|
||||
/*
|
||||
* Cache overrun. We need to remove the oldest entry from the
|
||||
* cache
|
||||
*/
|
||||
client_session_cache_entry_t *restrict oldest;
|
||||
INSIST((cache->nentries - 1) == cache->max_entries);
|
||||
|
||||
oldest = ISC_LIST_HEAD(cache->lru_entries);
|
||||
client_cache_entry_delete(cache, oldest);
|
||||
}
|
||||
|
||||
isc_mutex_unlock(&cache->lock);
|
||||
}
|
||||
|
||||
void
|
||||
isc_tlsctx_client_session_cache_reuse(isc_tlsctx_client_session_cache_t *cache,
|
||||
char *remote_peer_name, isc_tls_t *tls) {
|
||||
client_session_cache_bucket_t *restrict bucket = NULL;
|
||||
client_session_cache_entry_t *restrict entry;
|
||||
size_t name_len;
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(VALID_TLSCTX_CLIENT_SESSION_CACHE(cache));
|
||||
REQUIRE(remote_peer_name != NULL && *remote_peer_name != '\0');
|
||||
REQUIRE(tls != NULL);
|
||||
|
||||
isc_mutex_lock(&cache->lock);
|
||||
|
||||
/* Let's find the bucket */
|
||||
name_len = strlen(remote_peer_name);
|
||||
result = isc_ht_find(cache->buckets, (const uint8_t *)remote_peer_name,
|
||||
name_len, (void **)&bucket);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
INSIST(bucket != NULL);
|
||||
|
||||
/*
|
||||
* If the bucket has been found, let's use the newest session from
|
||||
* the bucket, as it has the highest chance to be successfully
|
||||
* resumed.
|
||||
*/
|
||||
INSIST(!ISC_LIST_EMPTY(bucket->entries));
|
||||
entry = ISC_LIST_TAIL(bucket->entries);
|
||||
RUNTIME_CHECK(SSL_set_session(tls, entry->session) == 1);
|
||||
client_cache_entry_delete(cache, entry);
|
||||
|
||||
exit:
|
||||
isc_mutex_unlock(&cache->lock);
|
||||
}
|
||||
|
||||
void
|
||||
isc_tlsctx_client_session_cache_keep_sockaddr(
|
||||
isc_tlsctx_client_session_cache_t *cache, isc_sockaddr_t *remote_peer,
|
||||
isc_tls_t *tls) {
|
||||
char peername[ISC_SOCKADDR_FORMATSIZE] = { 0 };
|
||||
|
||||
REQUIRE(remote_peer != NULL);
|
||||
|
||||
isc_sockaddr_format(remote_peer, peername, sizeof(peername));
|
||||
|
||||
isc_tlsctx_client_session_cache_keep(cache, peername, tls);
|
||||
}
|
||||
|
||||
void
|
||||
isc_tlsctx_client_session_cache_reuse_sockaddr(
|
||||
isc_tlsctx_client_session_cache_t *cache, isc_sockaddr_t *remote_peer,
|
||||
isc_tls_t *tls) {
|
||||
char peername[ISC_SOCKADDR_FORMATSIZE] = { 0 };
|
||||
|
||||
REQUIRE(remote_peer != NULL);
|
||||
|
||||
isc_sockaddr_format(remote_peer, peername, sizeof(peername));
|
||||
|
||||
isc_tlsctx_client_session_cache_reuse(cache, peername, tls);
|
||||
}
|
||||
|
||||
const isc_tlsctx_t *
|
||||
isc_tlsctx_client_session_cache_getctx(
|
||||
isc_tlsctx_client_session_cache_t *cache) {
|
||||
REQUIRE(VALID_TLSCTX_CLIENT_SESSION_CACHE(cache));
|
||||
return (cache->ctx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
|
|||
*/
|
||||
result = isc_tlsctx_cache_find(tlsctx_cache, tls_params->name,
|
||||
transport, family, &sslctx,
|
||||
&found_store);
|
||||
&found_store, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
/*
|
||||
* The lookup failed, let's try to create a new context
|
||||
|
|
@ -150,7 +150,8 @@ listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
|
|||
RUNTIME_CHECK(isc_tlsctx_cache_add(
|
||||
tlsctx_cache, tls_params->name,
|
||||
transport, family, sslctx, store,
|
||||
NULL, NULL) == ISC_R_SUCCESS);
|
||||
NULL, NULL, NULL,
|
||||
NULL) == ISC_R_SUCCESS);
|
||||
} else {
|
||||
INSIST(sslctx != NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ static atomic_bool slowdown = false;
|
|||
static atomic_bool use_TLS = false;
|
||||
static isc_tlsctx_t *server_tlsctx = NULL;
|
||||
static isc_tlsctx_t *client_tlsctx = NULL;
|
||||
static isc_tlsctx_client_session_cache_t *client_sess_cache = NULL;
|
||||
|
||||
static isc_quota_t listener_quota;
|
||||
static atomic_bool check_listener_quota = false;
|
||||
|
|
@ -176,7 +177,8 @@ connect_send_request(isc_nm_t *mgr, const char *uri, bool post,
|
|||
}
|
||||
|
||||
isc_nm_httpconnect(mgr, NULL, &tcp_listen_addr, uri, post,
|
||||
connect_send_cb, data, ctx, timeout, 0);
|
||||
connect_send_cb, data, ctx, client_sess_cache,
|
||||
timeout, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -321,6 +323,9 @@ setup_test(void **state) {
|
|||
client_tlsctx = NULL;
|
||||
isc_tlsctx_createclient(&client_tlsctx);
|
||||
isc_tlsctx_enable_http2client_alpn(client_tlsctx);
|
||||
client_sess_cache = isc_tlsctx_client_session_cache_new(
|
||||
mctx, client_tlsctx,
|
||||
ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE);
|
||||
|
||||
isc_quota_init(&listener_quota, 0);
|
||||
atomic_store(&check_listener_quota, false);
|
||||
|
|
@ -350,6 +355,8 @@ teardown_test(void **state) {
|
|||
isc_tlsctx_free(&client_tlsctx);
|
||||
}
|
||||
|
||||
isc_tlsctx_client_session_cache_detach(&client_sess_cache);
|
||||
|
||||
isc_quota_destroy(&listener_quota);
|
||||
|
||||
isc_nm_http_endpoints_detach(&endpoints);
|
||||
|
|
@ -644,7 +651,7 @@ doh_timeout_recovery(void **state) {
|
|||
ISC_NM_HTTP_DEFAULT_PATH);
|
||||
isc_nm_httpconnect(connect_nm, NULL, &tcp_listen_addr, req_url,
|
||||
atomic_load(&POST), timeout_request_cb, NULL, ctx,
|
||||
T_SOFT, 0);
|
||||
client_sess_cache, T_SOFT, 0);
|
||||
|
||||
/*
|
||||
* Sleep until sends reaches 5.
|
||||
|
|
@ -932,7 +939,7 @@ doh_recv_two(void **state) {
|
|||
|
||||
isc_nm_httpconnect(connect_nm, NULL, &tcp_listen_addr, req_url,
|
||||
atomic_load(&POST), doh_connect_send_two_requests_cb,
|
||||
NULL, ctx, 5000, 0);
|
||||
NULL, ctx, client_sess_cache, 5000, 0);
|
||||
|
||||
while (atomic_load(&nsends) > 0) {
|
||||
if (atomic_load(&was_error)) {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <isc/refcount.h>
|
||||
#include <isc/sockaddr.h>
|
||||
#include <isc/thread.h>
|
||||
#include <isc/tls.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include "uv_wrap.h"
|
||||
|
|
@ -62,6 +63,7 @@ static isc_sockaddr_t tcp_listen_addr;
|
|||
static isc_sockaddr_t tcp_connect_addr;
|
||||
static isc_tlsctx_t *tcp_listen_tlsctx = NULL;
|
||||
static isc_tlsctx_t *tcp_connect_tlsctx = NULL;
|
||||
static isc_tlsctx_client_session_cache_t *tcp_tlsctx_client_sess_cache = NULL;
|
||||
|
||||
static uint64_t send_magic = 0;
|
||||
static uint64_t stop_magic = 0;
|
||||
|
|
@ -333,6 +335,10 @@ setup_test(void **state __attribute__((unused))) {
|
|||
|
||||
isc_tlsctx_enable_dot_client_alpn(tcp_connect_tlsctx);
|
||||
|
||||
tcp_tlsctx_client_sess_cache = isc_tlsctx_client_session_cache_new(
|
||||
mctx, tcp_connect_tlsctx,
|
||||
ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
@ -361,6 +367,8 @@ teardown_test(void **state __attribute__((unused))) {
|
|||
isc_refcount_destroy(&active_ssends);
|
||||
isc_refcount_destroy(&active_sreads);
|
||||
|
||||
isc_tlsctx_client_session_cache_detach(&tcp_tlsctx_client_sess_cache);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
@ -1156,7 +1164,8 @@ stream_connect(isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
|
|||
if (stream_use_TLS) {
|
||||
isc_nm_tlsconnect(connect_nm, &tcp_connect_addr,
|
||||
&tcp_listen_addr, cb, cbarg,
|
||||
tcp_connect_tlsctx, timeout, extrahandlesize);
|
||||
tcp_connect_tlsctx,
|
||||
tcp_tlsctx_client_sess_cache, timeout, 0);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -2059,7 +2068,7 @@ static void
|
|||
tls_connect(isc_nm_t *nm) {
|
||||
isc_nm_tlsconnect(nm, &tcp_connect_addr, &tcp_listen_addr,
|
||||
connect_connect_cb, NULL, tcp_connect_tlsctx,
|
||||
T_CONNECT, 0);
|
||||
tcp_tlsctx_client_sess_cache, T_CONNECT, 0);
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(tls_noop) {
|
||||
|
|
@ -2220,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) {
|
||||
|
|
@ -2240,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);
|
||||
|
||||
|
|
@ -2267,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);
|
||||
|
|
@ -2321,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);
|
||||
|
|
@ -2352,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);
|
||||
|
|
@ -2394,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);
|
||||
|
||||
|
|
@ -2664,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);
|
||||
|
||||
|
|
@ -2730,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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue