From patchwork Fri Apr 22 04:29:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 2396 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director12.mail.ord1d.rsapps.net ([172.30.191.6]) by backend41.mail.ord1d.rsapps.net with LMTP id mEc2CEK8YmJcRAAAqwncew (envelope-from ) for ; Fri, 22 Apr 2022 10:31:30 -0400 Received: from proxy14.mail.ord1d.rsapps.net ([172.30.191.6]) by director12.mail.ord1d.rsapps.net with LMTP id EPkjHkK8YmLTNQAAIasKDg (envelope-from ) for ; Fri, 22 Apr 2022 10:31:30 -0400 Received: from smtp31.gate.ord1d ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy14.mail.ord1d.rsapps.net with LMTPS id SBUZL0S8YmKONQAAtEH5vw (envelope-from ) for ; Fri, 22 Apr 2022 10:31:32 -0400 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: smtp31.gate.ord1d.rsapps.net; iprev=pass policy.iprev="216.105.38.7"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dmarc=none (p=nil; dis=none) header.from=rfc2549.org X-Suspicious-Flag: YES X-Classification-ID: e5c2baa8-c248-11ec-87ce-525400b3ac8c-1-1 Received: from [216.105.38.7] ([216.105.38.7:38402] helo=lists.sourceforge.net) by smtp31.gate.ord1d.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id AE/97-02341-14CB2626; Fri, 22 Apr 2022 10:31:29 -0400 Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.94.2) (envelope-from ) id 1nhuIg-0000eQ-0d; Fri, 22 Apr 2022 14:30:20 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1nhuIe-0000e6-Hs for openvpn-devel@lists.sourceforge.net; Fri, 22 Apr 2022 14:30:19 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=PukVmC1gvSgsAh6sj8vF50S4tbpBokmnjhRDmj62j+c=; b=cHeZ2Q0amha9Ds673lQ5CGVomg DD0pAzUVyuDDasbWfyxpW5HbMlM1DM0/Q+7zdR3JrOA35TCRxUMmc+UbZTOay0uAMrAMKh2uIyzP8 Ki0VDwdKEvDVRub/TsWZG6Z4XUK0XQye47pK1zV7RVds0i/NKzfaFkLfeoMbrNSa6SUs=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=PukVmC1gvSgsAh6sj8vF50S4tbpBokmnjhRDmj62j+c=; b=YuwPem/qY5SJ5zt3Fvf+0ehszO lx33XPSJ6lq9kWPeYh9/0XZk4tztasizFqCcQHdeOZ4st+yXBErCerNsl+RD3UunQeuuOXIv5o4hT 2eTmTD4CA6jkRwurB1Ju1c+Z8YoLxF58NWM0sTTiiJmI0Nxr9JOPpD40wLbqW4HdyLIY=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.94.2) id 1nhuIL-0005df-Ja for openvpn-devel@lists.sourceforge.net; Fri, 22 Apr 2022 14:30:02 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.95 (FreeBSD)) (envelope-from ) id 1nhuID-00096W-I0 for openvpn-devel@lists.sourceforge.net; Fri, 22 Apr 2022 16:29:53 +0200 Received: (nullmailer pid 3805423 invoked by uid 10006); Fri, 22 Apr 2022 14:29:53 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Fri, 22 Apr 2022 16:29:39 +0200 Message-Id: <20220422142953.3805364-5-arne@rfc2549.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220422142953.3805364-1-arne@rfc2549.org> References: <20220422134038.3801239-1-arne@rfc2549.org> <20220422142953.3805364-1-arne@rfc2549.org> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-2.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: This function does most of the state transitions in the TLS state machine. Moving it into its own function removes an intention area and makes tls_process function easier to understand as the loop is [...] Content analysis details: (0.2 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_NONE SPF: sender does not publish an SPF Record X-Headers-End: 1nhuIL-0005df-Ja Subject: [Openvpn-devel] [PATCH 14/28] Move tls_process_state into its own function X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox This function does most of the state transitions in the TLS state machine. Moving it into its own function removes an intention area and makes tls_process function easier to understand as the loop is more obvious. This is largely just a code move with small expection. bool active is no longer directly set but inferred from to_link->len Acked-By: Frank Lichtenheld (small issues mentioned below) --- src/openvpn/ssl.c | 444 ++++++++++++++++++++++++---------------------- 1 file changed, 228 insertions(+), 216 deletions(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 4ca093243..15af58949 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2433,7 +2433,7 @@ session_move_pre_start(const struct tls_session *session, /** * Moves the key to state to S_ACTIVE and also advances the multi_state state - * machine if this is the initial connection. + * machine if this is the initial connection. */ static void session_move_active(struct tls_multi *multi, struct tls_session *session, @@ -2478,6 +2478,217 @@ session_move_active(struct tls_multi *multi, struct tls_session *session, show_tls_performance_stats(); #endif } + + +static bool +tls_process_state(struct tls_multi *multi, + struct tls_session *session, + struct buffer *to_link, + struct link_socket_actual **to_link_addr, + struct link_socket_info *to_link_socket_info, + interval_t *wakeup) +{ + bool state_change = false; + struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + + /* Initial handshake */ + if (ks->state == S_INITIAL) + { + state_change = session_move_pre_start(session, ks); + } + + /* Are we timed out on receive? */ + if (now >= ks->must_negotiate && ks->state < S_ACTIVE) + { + msg(D_TLS_ERRORS, + "TLS Error: TLS key negotiation failed to occur within %d seconds (check your network connectivity)", + session->opt->handshake_window); + goto error; + } + + /* Wait for Initial Handshake ACK */ + if (ks->state == S_PRE_START && no_pending_reliable_packets(ks)) + { + ks->state = S_START; + state_change = true; + + /* + * Attempt CRL reload before TLS negotiation. Won't be performed if + * the file was not modified since the last reload + */ + if (session->opt->crl_file + && !(session->opt->ssl_flags & SSLF_CRL_VERIFY_DIR)) + { + tls_ctx_reload_crl(&session->opt->ssl_ctx, + session->opt->crl_file, session->opt->crl_file_inline); + } + + /* New connection, remove any old X509 env variables */ + tls_x509_clear_env(session->opt->es); + + dmsg(D_TLS_DEBUG_MED, "STATE S_START"); + } + + /* Wait for ACK */ + if (((ks->state == S_GOT_KEY && !session->opt->server) + || (ks->state == S_SENT_KEY && session->opt->server)) + && no_pending_reliable_packets(ks)) + { + session_move_active(multi, session, to_link_socket_info, ks); + state_change = true; + } + + /* Reliable buffer to outgoing TCP/UDP (send up to CONTROL_SEND_ACK_MAX ACKs + * for previously received packets) */ + if (!to_link->len && reliable_can_send(ks->send_reliable)) + { + int opcode; + + struct buffer *buf = reliable_send(ks->send_reliable, &opcode); + ASSERT(buf); + struct buffer b = *buf; + INCR_SENT; + + write_control_auth(session, ks, &b, to_link_addr, opcode, + CONTROL_SEND_ACK_MAX, true); + *to_link = b; + dmsg(D_TLS_DEBUG, "Reliable -> TCP/UDP"); + return true; + } + + /* Write incoming ciphertext to TLS object */ + struct buffer *buf = reliable_get_buf_sequenced(ks->rec_reliable); + if (buf) + { + int status = 0; + if (buf->len) + { + status = key_state_write_ciphertext(&ks->ks_ssl, buf); + if (status == -1) + { + msg(D_TLS_ERRORS, + "TLS Error: Incoming Ciphertext -> TLS object write error"); + goto error; + } + } + else + { + status = 1; + } + if (status == 1) + { + reliable_mark_deleted(ks->rec_reliable, buf); + state_change = true; + dmsg(D_TLS_DEBUG, "Incoming Ciphertext -> TLS"); + } + } + + /* Read incoming plaintext from TLS object */ + buf = &ks->plaintext_read_buf; + if (!buf->len) + { + int status; + + ASSERT(buf_init(buf, 0)); + status = key_state_read_plaintext(&ks->ks_ssl, buf, TLS_CHANNEL_BUF_SIZE); + update_time(); + if (status == -1) + { + msg(D_TLS_ERRORS, "TLS Error: TLS object -> incoming plaintext read error"); + goto error; + } + if (status == 1) + { + state_change = true; + dmsg(D_TLS_DEBUG, "TLS -> Incoming Plaintext"); + + /* More data may be available, wake up again asap to check. */ + *wakeup = 0; + } + } + + /* Send Key */ + buf = &ks->plaintext_write_buf; + if (!buf->len && ((ks->state == S_START && !session->opt->server) + || (ks->state == S_GOT_KEY && session->opt->server))) + { + if (!key_method_2_write(buf, multi, session)) + { + goto error; + } + + state_change = true; + dmsg(D_TLS_DEBUG_MED, "STATE S_SENT_KEY"); + ks->state = S_SENT_KEY; + } + + /* Receive Key */ + buf = &ks->plaintext_read_buf; + if (buf->len + && ((ks->state == S_SENT_KEY && !session->opt->server) + || (ks->state == S_START && session->opt->server))) + { + if (!key_method_2_read(buf, multi, session)) + { + goto error; + } + + state_change = true; + dmsg(D_TLS_DEBUG_MED, "STATE S_GOT_KEY"); + ks->state = S_GOT_KEY; + } + + /* Write outgoing plaintext to TLS object */ + buf = &ks->plaintext_write_buf; + if (buf->len) + { + int status = key_state_write_plaintext(&ks->ks_ssl, buf); + if (status == -1) + { + msg(D_TLS_ERRORS, + "TLS ERROR: Outgoing Plaintext -> TLS object write error"); + goto error; + } + if (status == 1) + { + state_change = true; + dmsg(D_TLS_DEBUG, "Outgoing Plaintext -> TLS"); + } + } + + /* Outgoing Ciphertext to reliable buffer */ + if (ks->state >= S_START) + { + buf = reliable_get_buf_output_sequenced(ks->send_reliable); + if (buf) + { + int status = key_state_read_ciphertext(&ks->ks_ssl, buf, multi->opt.frame.tun_mtu); + + if (status == -1) + { + msg(D_TLS_ERRORS, + "TLS Error: Ciphertext -> reliable TCP/UDP transport read error"); + goto error; + } + if (status == 1) + { + reliable_mark_active_outgoing(ks->send_reliable, buf, P_CONTROL_V1); + INCR_GENERATED; + state_change = true; + dmsg(D_TLS_DEBUG, "Outgoing Ciphertext -> Reliable"); + } + } + } + + return state_change; +error: + tls_clear_error(); + ks->state = S_ERROR; + msg(D_TLS_ERRORS, "TLS Error: TLS handshake failed"); + INCR_ERROR; + return false; + +} /* * This is the primary routine for processing TLS stuff inside the * the main event loop. When this routine exits @@ -2495,9 +2706,6 @@ tls_process(struct tls_multi *multi, struct link_socket_info *to_link_socket_info, interval_t *wakeup) { - struct gc_arena gc = gc_new(); - bool state_change = false; - bool active = false; struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */ @@ -2531,7 +2739,8 @@ tls_process(struct tls_multi *multi, msg(D_TLS_DEBUG_LOW, "TLS: tls_process: killed expiring key"); } - do + bool state_change = true; + while(state_change) { update_time(); @@ -2541,209 +2750,15 @@ tls_process(struct tls_multi *multi, state_name(ks_lame->state), to_link->len, *wakeup); + state_change = tls_process_state(multi, session, to_link, to_link_addr, + to_link_socket_info, wakeup); - state_change = false; - - /* - * TLS activity is finished once we get to S_ACTIVE, - * though we will still process acknowledgements. - * - * CHANGED with 2.0 -> now we may send tunnel configuration - * info over the control channel. - */ - - /* Initial handshake */ - if (ks->state == S_INITIAL) - { - state_change = session_move_pre_start(session, ks); - } - - /* Are we timed out on receive? */ - if (now >= ks->must_negotiate && ks->state < S_ACTIVE) - { - msg(D_TLS_ERRORS, - "TLS Error: TLS key negotiation failed to occur within %d seconds (check your network connectivity)", - session->opt->handshake_window); - goto error; - } - - /* Wait for Initial Handshake ACK */ - if (ks->state == S_PRE_START && no_pending_reliable_packets(ks)) - { - ks->state = S_START; - state_change = true; - - /* - * Attempt CRL reload before TLS negotiation. Won't be performed if - * the file was not modified since the last reload - */ - if (session->opt->crl_file - && !(session->opt->ssl_flags & SSLF_CRL_VERIFY_DIR)) - { - tls_ctx_reload_crl(&session->opt->ssl_ctx, - session->opt->crl_file, session->opt->crl_file_inline); - } - - /* New connection, remove any old X509 env variables */ - tls_x509_clear_env(session->opt->es); - - dmsg(D_TLS_DEBUG_MED, "STATE S_START"); - } - - /* Wait for ACK */ - if (((ks->state == S_GOT_KEY && !session->opt->server) - || (ks->state == S_SENT_KEY && session->opt->server)) - && no_pending_reliable_packets(ks)) + if (ks->state == S_ERROR) { - session_move_active(multi, session, to_link_socket_info, ks); - state_change = true; - } - - /* Reliable buffer to outgoing TCP/UDP (send up to CONTROL_SEND_ACK_MAX ACKs - * for previously received packets) */ - if (!to_link->len && reliable_can_send(ks->send_reliable)) - { - int opcode; - - struct buffer *buf = reliable_send(ks->send_reliable, &opcode); - ASSERT(buf); - struct buffer b = *buf; - INCR_SENT; - - write_control_auth(session, ks, &b, to_link_addr, opcode, - CONTROL_SEND_ACK_MAX, true); - *to_link = b; - active = true; - state_change = true; - dmsg(D_TLS_DEBUG, "Reliable -> TCP/UDP"); - break; - } - - /* Write incoming ciphertext to TLS object */ - struct buffer *buf = reliable_get_buf_sequenced(ks->rec_reliable); - if (buf) - { - int status = 0; - if (buf->len) - { - status = key_state_write_ciphertext(&ks->ks_ssl, buf); - if (status == -1) - { - msg(D_TLS_ERRORS, - "TLS Error: Incoming Ciphertext -> TLS object write error"); - goto error; - } - } - else - { - status = 1; - } - if (status == 1) - { - reliable_mark_deleted(ks->rec_reliable, buf); - state_change = true; - dmsg(D_TLS_DEBUG, "Incoming Ciphertext -> TLS"); - } - } - - /* Read incoming plaintext from TLS object */ - buf = &ks->plaintext_read_buf; - if (!buf->len) - { - int status; - - ASSERT(buf_init(buf, 0)); - status = key_state_read_plaintext(&ks->ks_ssl, buf, TLS_CHANNEL_BUF_SIZE); - update_time(); - if (status == -1) - { - msg(D_TLS_ERRORS, "TLS Error: TLS object -> incoming plaintext read error"); - goto error; - } - if (status == 1) - { - state_change = true; - dmsg(D_TLS_DEBUG, "TLS -> Incoming Plaintext"); - - /* More data may be available, wake up again asap to check. */ - *wakeup = 0; - } - } - - /* Send Key */ - buf = &ks->plaintext_write_buf; - if (!buf->len && ((ks->state == S_START && !session->opt->server) - || (ks->state == S_GOT_KEY && session->opt->server))) - { - if (!key_method_2_write(buf, multi, session)) - { - goto error; - } - - state_change = true; - dmsg(D_TLS_DEBUG_MED, "STATE S_SENT_KEY"); - ks->state = S_SENT_KEY; - } - - /* Receive Key */ - buf = &ks->plaintext_read_buf; - if (buf->len - && ((ks->state == S_SENT_KEY && !session->opt->server) - || (ks->state == S_START && session->opt->server))) - { - if (!key_method_2_read(buf, multi, session)) - { - goto error; - } - - state_change = true; - dmsg(D_TLS_DEBUG_MED, "STATE S_GOT_KEY"); - ks->state = S_GOT_KEY; - } - - /* Write outgoing plaintext to TLS object */ - buf = &ks->plaintext_write_buf; - if (buf->len) - { - int status = key_state_write_plaintext(&ks->ks_ssl, buf); - if (status == -1) - { - msg(D_TLS_ERRORS, - "TLS ERROR: Outgoing Plaintext -> TLS object write error"); - goto error; - } - if (status == 1) - { - state_change = true; - dmsg(D_TLS_DEBUG, "Outgoing Plaintext -> TLS"); - } + return false; } - /* Outgoing Ciphertext to reliable buffer */ - if (ks->state >= S_START) - { - buf = reliable_get_buf_output_sequenced(ks->send_reliable); - if (buf) - { - int status = key_state_read_ciphertext(&ks->ks_ssl, buf, multi->opt.frame.tun_mtu); - - if (status == -1) - { - msg(D_TLS_ERRORS, - "TLS Error: Ciphertext -> reliable TCP/UDP transport read error"); - goto error; - } - if (status == 1) - { - reliable_mark_active_outgoing(ks->send_reliable, buf, P_CONTROL_V1); - INCR_GENERATED; - state_change = true; - dmsg(D_TLS_DEBUG, "Outgoing Ciphertext -> Reliable"); - } - } - } } - while (state_change); update_time(); @@ -2755,7 +2770,6 @@ tls_process(struct tls_multi *multi, write_control_auth(session, ks, &buf, to_link_addr, P_ACK_V1, RELIABLE_ACK_SIZE, false); *to_link = buf; - active = true; dmsg(D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP"); } @@ -2778,6 +2792,8 @@ tls_process(struct tls_multi *multi, ks->established + session->opt->renegotiate_seconds - now); } + dmsg(D_TLS_DEBUG, "TLS: tls_process: timeout set to %d", *wakeup); + /* prevent event-loop spinning by setting minimum wakeup of 1 second */ if (*wakeup <= 0) { @@ -2785,22 +2801,18 @@ tls_process(struct tls_multi *multi, /* if we had something to send to remote, but to_link was busy, * let caller know we need to be called again soon */ - active = true; + return true; } - dmsg(D_TLS_DEBUG, "TLS: tls_process: timeout set to %d", *wakeup); + /* If any of the state changes resulted in the to_link buffer being + * set, we are also active */ + if (to_link->len) + { + return true; + } - gc_free(&gc); - return active; + return false; } - -error: - tls_clear_error(); - ks->state = S_ERROR; - msg(D_TLS_ERRORS, "TLS Error: TLS handshake failed"); - INCR_ERROR; - gc_free(&gc); - return false; } /*