]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
daemon/tls: properly process TLS rehandshake
authorGrigorii Demidov <grigorii.demidov@nic.cz>
Mon, 9 Jul 2018 12:42:51 +0000 (14:42 +0200)
committerPetr Špaček <petr.spacek@nic.cz>
Mon, 23 Jul 2018 14:15:48 +0000 (14:15 +0000)
daemon/io.c
daemon/tls.c
daemon/tls.h

index b59e3d879240557331fd77393dc905ea8eeb239a..e6ee4a26022f84a4d63416713221aac4fc058251 100644 (file)
@@ -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) {
index 3036a7f94921edb2558e7da5e0271c93a9c4d090..5424cfc59f6419b4f114b3f222c69978a97bd3b7 100644 (file)
@@ -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",
index 724463ecc4f6b8bf84545342eeeae33309202f31..c5c01c787520741a2dd8f0b278fe599aaad52081 100644 (file)
 #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 {