}
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;
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)
{
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) {
}
#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 (store != NULL && store != found_store) {
isc_tls_cert_store_free(&store);
}
+ if (sess_cache != NULL && sess_cache != found_sess_cache) {
+ isc_tlsctx_client_session_cache_detach(&sess_cache);
+ }
return (NULL);
}
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);
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;
}
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;
}
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_client_session_cache_t *sess_cache = NULL,
+ *found_sess_cache = NULL;
(void)isc_refcount_increment0(&xfr->connects);
dns_xfrin_attach(xfr, &connect_xfr);
* 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 = isc_tlsctx_cache_find(
+ xfr->tlsctx_cache, tlsname, isc_tlsctx_cache_tls,
+ family, &tlsctx, &found_store, &found_sess_cache);
if (result != ISC_R_SUCCESS) {
const char *hostname =
dns_transport_get_remote_hostname(
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,
- &found, &found_store);
+ sess_cache, &found, &found_store,
+ &found_sess_cache);
if (result == ISC_R_EXISTS) {
/*
* It seems the entry has just been created
INSIST(found != NULL);
isc_tlsctx_free(&tlsctx);
isc_tls_cert_store_free(&store);
+ isc_tlsctx_client_session_cache_detach(
+ &sess_cache);
tlsctx = found;
+ sess_cache = found_sess_cache;
} else {
INSIST(result == ISC_R_SUCCESS);
}
if (store != NULL && store != found_store) {
isc_tls_cert_store_free(&store);
}
+
+ if (sess_cache != NULL && sess_cache != found_sess_cache) {
+ isc_tlsctx_client_session_cache_detach(&sess_cache);
+ }
+
isc_refcount_decrement0(&xfr->connects);
dns_xfrin_detach(&connect_xfr);
return (result);
*
* 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 '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.
*/
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 using a
+ * 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'
+ *\li 'remote_peer' is a valid, non-'NULL', pointer to an 'isc_sockaddr_t'
*object.
*/
* 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.
+ *\li 'tls' is a valid, non-'NULL' pointer to a TLS connection state object.
*/
void
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;
/*%<
*/
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;
*/
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;
*\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;
* 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.
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) {
}
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);
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);
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) {
* 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);
/* 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,
}
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;
}
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;
*/
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
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);
}