From: Grigorii Demidov Date: Mon, 9 Jul 2018 12:42:51 +0000 (+0200) Subject: daemon/tls: properly process TLS rehandshake X-Git-Tag: v2.4.1~9^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a909f8b6689c032d6e23ff72da760f4c20ebcba7;p=thirdparty%2Fknot-resolver.git daemon/tls: properly process TLS rehandshake --- diff --git a/daemon/io.c b/daemon/io.c index b59e3d879..e6ee4a260 100644 --- a/daemon/io.c +++ b/daemon/io.c @@ -309,7 +309,7 @@ static void _tcp_accept(uv_stream_t *master, int status, bool tls) uint64_t timeout = KR_CONN_RTT_MAX / 2; session->has_tls = tls; if (tls) { - timeout += KR_CONN_RTT_MAX * 3; + timeout += TLS_MAX_HANDSHAKE_TIME; if (!session->tls_ctx) { session->tls_ctx = tls_new(master->loop->data); if (!session->tls_ctx) { diff --git a/daemon/tls.c b/daemon/tls.c index 3036a7f94..5424cfc59 100644 --- a/daemon/tls.c +++ b/daemon/tls.c @@ -307,11 +307,22 @@ int tls_process(struct worker_ctx *worker, uv_stream_t *handle, const uint8_t *b } int submitted = 0; + bool is_retrying = false; + uint64_t retrying_start = 0; while (true) { ssize_t count = gnutls_record_recv(tls_p->tls_session, tls_p->recv_buf, sizeof(tls_p->recv_buf)); if (count == GNUTLS_E_AGAIN) { break; /* No data available */ - } else if (count == GNUTLS_E_INTERRUPTED) { + } else if (count == GNUTLS_E_INTERRUPTED || + count == GNUTLS_E_REHANDSHAKE) { + if (!is_retrying) { + is_retrying = true; + retrying_start = kr_now(); + } + uint64_t elapsed = kr_now() - retrying_start; + if (elapsed > TLS_MAX_HANDSHAKE_TIME) { + return kr_error(EIO); + } continue; /* Try reading again */ } else if (count < 0) { kr_log_verbose("[%s] gnutls_record_recv failed: %s (%zd)\n", diff --git a/daemon/tls.h b/daemon/tls.h index 724463ecc..c5c01c787 100644 --- a/daemon/tls.h +++ b/daemon/tls.h @@ -26,6 +26,22 @@ #define MAX_TLS_PADDING KR_EDNS_PAYLOAD #define TLS_MAX_UNCORK_RETRIES 100 +/* rfc 5476, 7.3 - handshake Protocol overview + * https://tools.ietf.org/html/rfc5246#page-33 + * Message flow for a full handshake (only mandatory messages) + * ClientHello --------> + ServerHello + <-------- ServerHelloDone + ClientKeyExchange + Finished --------> + <-------- Finished + * + * See also https://blog.cloudflare.com/keyless-ssl-the-nitty-gritty-technical-details/ + * So it takes 2 RTT. + * As we use session tickets, there are additional messages, add one RTT mode. + */ + #define TLS_MAX_HANDSHAKE_TIME (KR_CONN_RTT_MAX * 3) + struct tls_ctx_t; struct tls_client_ctx_t; struct tls_credentials {