* \li 'handle' is a valid netmgr handle object.
*/
+const char *
+isc_nm_verify_tls_peer_result_string(const isc_nmhandle_t *handle);
+/*%<
+ * Returns user-readable message describing TLS peer's certificate
+ * validation result. Returns 'NULL' for the transport handles for
+ * which peer verification was not performed.
+ *
+ * Requires:
+ * \li 'handle' is a valid netmgr handle object.
+ */
+
void
isc_nm_task_enqueue(isc_nm_t *mgr, isc_task_t *task, int tid);
/*%<
ISC_R_DEFAULT, /*%< default */
ISC_R_IPV4PREFIX, /*%< IPv4 prefix */
ISC_R_TLSERROR, /*%< TLS error */
- ISC_R_HTTP2ALPNERROR, /*%< ALPN for HTTP/2 failed */
+ ISC_R_TLSBADPEERCERT, /*%< TLS peer certificate verification failed */
+ ISC_R_HTTP2ALPNERROR, /*%< ALPN for HTTP/2 failed */
DNS_R_LABELTOOLONG = 1 << 16,
DNS_R_BADESCAPE,
INSIST(http_sock->h2.connect.uri != NULL);
http_sock->tid = transp_sock->tid;
+ http_sock->h2.connect.tls_peer_verify_string =
+ isc_nm_verify_tls_peer_result_string(handle);
if (result != ISC_R_SUCCESS) {
goto error;
}
return (isc_nm_socket_type(session->handle) == isc_nm_tlssocket);
}
+const char *
+isc__nm_http_verify_tls_peer_result_string(const isc_nmhandle_t *handle) {
+ isc_nmsocket_t *sock = NULL;
+ isc_nm_http_session_t *session;
+
+ REQUIRE(VALID_NMHANDLE(handle));
+ REQUIRE(VALID_NMSOCK(handle->sock));
+ REQUIRE(handle->sock->type == isc_nm_httpsocket);
+
+ sock = handle->sock;
+ session = sock->h2.session;
+
+ /*
+ * In the case of a low-level error the session->handle is not
+ * attached nor session object is created.
+ */
+ if (session == NULL && sock->h2.connect.tls_peer_verify_string != NULL)
+ {
+ return (sock->h2.connect.tls_peer_verify_string);
+ }
+
+ if (session == NULL) {
+ return (NULL);
+ }
+
+ INSIST(VALID_HTTP2_SESSION(session));
+
+ return (isc_nm_verify_tls_peer_result_string(session->handle));
+}
+
static const bool base64url_validation_table[256] = {
false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false,
isc_tlsctx_t *tlsctx;
isc_sockaddr_t local_interface;
void *cstream;
+ const char *tls_peer_verify_string;
} connect;
} isc_nmsocket_h2_t;
#endif /* HAVE_LIBNGHTTP2 */
* Stop reading on a connected TLSDNS handle.
*/
+const char *
+isc__nm_tlsdns_verify_tls_peer_result_string(const isc_nmhandle_t *handle);
+
void
isc__nm_async_tlsdnscycle(isc__networker_t *worker, isc__netievent_t *ev0);
void
* around.
*/
+const char *
+isc__nm_tls_verify_tls_peer_result_string(const isc_nmhandle_t *handle);
+
void
isc__nmhandle_tls_keepalive(isc_nmhandle_t *handle, bool value);
/*%<
void
isc__nm_http_set_maxage(isc_nmhandle_t *handle, const uint32_t ttl);
+const char *
+isc__nm_http_verify_tls_peer_result_string(const isc_nmhandle_t *handle);
+
void
isc__nm_async_httpsend(isc__networker_t *worker, isc__netievent_t *ev0);
return (netmgr->nworkers);
}
+const char *
+isc_nm_verify_tls_peer_result_string(const isc_nmhandle_t *handle) {
+ isc_nmsocket_t *sock;
+
+ REQUIRE(VALID_NMHANDLE(handle));
+ REQUIRE(VALID_NMSOCK(handle->sock));
+
+ sock = handle->sock;
+ switch (sock->type) {
+ case isc_nm_tlsdnssocket:
+ return (isc__nm_tlsdns_verify_tls_peer_result_string(handle));
+ break;
+#if HAVE_LIBNGHTTP2
+ case isc_nm_tlssocket:
+ return (isc__nm_tls_verify_tls_peer_result_string(handle));
+ break;
+ case isc_nm_httpsocket:
+ return (isc__nm_http_verify_tls_peer_result_string(handle));
+ break;
+#endif /* HAVE_LIBNGHTTP2 */
+ default:
+ break;
+ }
+
+ return (NULL);
+}
+
#ifdef NETMGR_TRACE
/*
* Dump all active sockets in netmgr. We output to stderr
static isc_result_t
tls_cycle(isc_nmsocket_t *sock);
+static bool
+peer_verification_has_failed(isc_nmsocket_t *sock) {
+ if (sock->tls.tls != NULL && sock->tls.state == TLS_STATE_HANDSHAKE &&
+ SSL_get_verify_result(sock->tls.tls) != X509_V_OK)
+ {
+ return (true);
+ }
+
+ return (false);
+}
+
static bool
can_log_tlsdns_quota(void) {
isc_stdtime_t now, last;
isc__nm_stop_reading(sock);
if (sock->tls.pending_req != NULL) {
+ isc_result_t failure_result = ISC_R_CANCELED;
isc__nm_uvreq_t *req = sock->tls.pending_req;
sock->tls.pending_req = NULL;
- isc__nm_failed_connect_cb(sock, req, ISC_R_CANCELED, async);
+
+ if (peer_verification_has_failed(sock)) {
+ failure_result = ISC_R_TLSBADPEERCERT;
+ }
+ isc__nm_failed_connect_cb(sock, req, failure_result, async);
}
if (!sock->recv_read) {
* TLS handshake to complete
*/
if (sock->tls.pending_req != NULL) {
+ isc_result_t result = ISC_R_CANCELED;
isc__nm_uvreq_t *req = sock->tls.pending_req;
sock->tls.pending_req = NULL;
- isc__nm_failed_connect_cb(sock, req, ISC_R_CANCELED,
- false);
+ if (peer_verification_has_failed(sock)) {
+ result = ISC_R_TLSBADPEERCERT;
+ }
+ isc__nm_failed_connect_cb(sock, req, result, false);
return;
}
return (sock->tls.alpn_negotiated);
}
+
+const char *
+isc__nm_tlsdns_verify_tls_peer_result_string(const isc_nmhandle_t *handle) {
+ isc_nmsocket_t *sock = NULL;
+
+ REQUIRE(VALID_NMHANDLE(handle));
+ REQUIRE(VALID_NMSOCK(handle->sock));
+ REQUIRE(handle->sock->type == isc_nm_tlsdnssocket);
+
+ sock = handle->sock;
+ if (sock->tls.tls == NULL) {
+ return (NULL);
+ }
+
+ return (isc_tls_verify_peer_result_string(sock->tls.tls));
+}
#define TLS_BUF_SIZE (UINT16_MAX)
static isc_result_t
-tls_error_to_result(int tls_err) {
+tls_error_to_result(const int tls_err, const int tls_state, isc_tls_t *tls) {
switch (tls_err) {
case SSL_ERROR_ZERO_RETURN:
return (ISC_R_EOF);
case SSL_ERROR_SSL:
+ if (tls != NULL && tls_state < TLS_IO &&
+ SSL_get_verify_result(tls) != X509_V_OK)
+ {
+ return (ISC_R_TLSBADPEERCERT);
+ }
return (ISC_R_TLSERROR);
default:
return (ISC_R_UNEXPECTED);
rv = SSL_do_handshake(sock->tlsstream.tls);
if (rv == 1) {
+ isc_result_t result = ISC_R_SUCCESS;
INSIST(SSL_is_init_finished(sock->tlsstream.tls) == 1);
INSIST(sock->statichandle == NULL);
tlshandle = isc__nmhandle_get(sock, &sock->peer, &sock->iface);
if (sock->tlsstream.server) {
- sock->listener->accept_cb(tlshandle, ISC_R_SUCCESS,
+ sock->listener->accept_cb(tlshandle, result,
sock->listener->accept_cbarg);
} else {
- tls_call_connect_cb(sock, tlshandle, ISC_R_SUCCESS);
+ tls_call_connect_cb(sock, tlshandle, result);
}
isc_nmhandle_detach(&tlshandle);
sock->tlsstream.state = TLS_IO;
}
return;
default:
- result = tls_error_to_result(tls_status);
+ result = tls_error_to_result(tls_status, sock->tlsstream.state,
+ sock->tlsstream.tls);
break;
}
isc_nmhandle_keepalive(sock->outerhandle, value);
}
}
+
+const char *
+isc__nm_tls_verify_tls_peer_result_string(const isc_nmhandle_t *handle) {
+ 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->tlsstream.tls == NULL) {
+ return (NULL);
+ }
+
+ return (isc_tls_verify_peer_result_string(sock->tlsstream.tls));
+}
[ISC_R_DEFAULT] = "default",
[ISC_R_IPV4PREFIX] = "IPv4 prefix",
[ISC_R_TLSERROR] = "TLS error",
+ [ISC_R_TLSBADPEERCERT] = "TLS peer certificate verification failed",
[ISC_R_HTTP2ALPNERROR] = "ALPN for HTTP/2 failed",
[DNS_R_LABELTOOLONG] = "label too long",
[ISC_R_DEFAULT] = "ISC_R_DEFAULT",
[ISC_R_IPV4PREFIX] = "ISC_R_IPV4PREFIX",
[ISC_R_TLSERROR] = "ISC_R_TLSERROR",
+ [ISC_R_TLSBADPEERCERT] = "ISC_R_TLSBADPEERCERT",
[ISC_R_HTTP2ALPNERROR] = "ISC_R_HTTP2ALPNERROR",
[DNS_R_LABELTOOLONG] = "DNS_R_LABELTOOLONG",
[DNS_R_BADESCAPE] = "DNS_R_BADESCAPE",