From patchwork Fri Apr 22 03:40:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 2386 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director8.mail.ord1d.rsapps.net ([172.28.255.1]) by backend41.mail.ord1d.rsapps.net with LMTP id SNzSHBq7YmKSOwAAqwncew (envelope-from ) for ; Fri, 22 Apr 2022 10:26:34 -0400 Received: from proxy1.mail.ord1c.rsapps.net ([172.28.255.1]) by director8.mail.ord1d.rsapps.net with LMTP id yB2ZMBq7YmK6FwAAfY0hYg (envelope-from ) for ; Fri, 22 Apr 2022 10:26:34 -0400 Received: from smtp14.gate.ord1c ([172.28.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy1.mail.ord1c.rsapps.net with LMTPS id 4DF9NBu7YmKHOgAA2VeTtA (envelope-from ) for ; Fri, 22 Apr 2022 10:26:35 -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: smtp14.gate.ord1c.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: 35d900f2-c248-11ec-8347-bc305bf032e0-1-1 Received: from [216.105.38.7] ([216.105.38.7:57470] helo=lists.sourceforge.net) by smtp14.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 08/A4-30613-A1BB2626; Fri, 22 Apr 2022 10:26:34 -0400 Received: from [127.0.0.1] (helo=sfs-ml-2.v29.lw.sourceforge.com) by sfs-ml-2.v29.lw.sourceforge.com with esmtp (Exim 4.94.2) (envelope-from ) id 1nhuEC-0003yv-3k; Fri, 22 Apr 2022 14:25:45 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1nhuEA-0003yg-KL for openvpn-devel@lists.sourceforge.net; Fri, 22 Apr 2022 14:25:43 +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=uzKnz1MqeM53jxRjiTHQ7Y+ZjC19UgOGoDSftsanFr0=; b=fRvrj/cXmTGbioPWqAJuyf1tZa rgW05Ed8+7wyB+7mUvz4hJ/OLiaBHHX0beOxnfLjmdbLhrqVL/KogF5HyYyi6t4jdietOG1+zKHYO 5DGAx7/XWerRayNbvQsYDIhRA1yTMo9eWZQXkgN9xknSh0C4ukj623+XL3/6DVjLz+1c=; 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=uzKnz1MqeM53jxRjiTHQ7Y+ZjC19UgOGoDSftsanFr0=; b=QZaDPp/f/BMjKk0bCuG5Dp/zRJ z16YW9EqWIvuAFinsXeiqwapUuwmhhS2khEL+Vd6a4MciUlUXPyGxywB5KmX+FfU6wM7Krr2+82KH ufZ8Qdkig1KDUdu2jzVof7+EJZG6mLyzY/bL9p5Rv8RAWDVsS6J4HOMZ2j/kCPUED7JM=; 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 1nhuEA-0005KF-Ed for openvpn-devel@lists.sourceforge.net; Fri, 22 Apr 2022 14:25:43 +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 1nhtWY-0008sR-Od for openvpn-devel@lists.sourceforge.net; Fri, 22 Apr 2022 15:40:38 +0200 Received: (nullmailer pid 3801300 invoked by uid 10006); Fri, 22 Apr 2022 13:40:38 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Fri, 22 Apr 2022 15:40:34 +0200 Message-Id: <20220422134038.3801239-6-arne@rfc2549.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220422134038.3801239-1-arne@rfc2549.org> References: <20220422134038.3801239-1-arne@rfc2549.org> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-1.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 allows us to keep the temporary data for a little bit longer so we can use this to make further checks and ultimatively use the state to craft the HMAC based RESET reply. For now we do not use the extra information and keep behaviour identical. Content analysis details: (0.3 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: 1nhuEA-0005KF-Ed Subject: [Openvpn-devel] [PATCH 05/28] Extend tls_pre_decrypt_lite to return type of packet and keep state 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 allows us to keep the temporary data for a little bit longer so we can use this to make further checks and ultimatively use the state to craft the HMAC based RESET reply. For now we do not use the extra information and keep behaviour identical. Signed-off-by: Arne Schwabe Acked-by: Gert Doering --- src/openvpn/mudp.c | 11 ++++++- src/openvpn/ssl.c | 76 +++++++++++++++++++++++++++++++++------------- src/openvpn/ssl.h | 37 ++++++++++++++++++++-- 3 files changed, 99 insertions(+), 25 deletions(-) diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index 910268333..6dd026701 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -46,7 +46,16 @@ do_pre_decrypt_check(struct multi_context *m) { return false; } - if (!tls_pre_decrypt_lite(m->top.c2.tls_auth_standalone, &m->top.c2.from, &m->top.c2.buf)) + + enum first_packet_verdict verdict; + struct tls_pre_decrypt_state state = {0}; + + verdict = tls_pre_decrypt_lite(m->top.c2.tls_auth_standalone, &state, + &m->top.c2.from, &m->top.c2.buf); + + free_tls_pre_decrypt_state(&state); + + if (verdict == VERDICT_INVALID || verdict == VERDICT_VALID_CONTROL_V1) { return false; } diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index f58f3b727..452433ebb 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1367,7 +1367,6 @@ tls_multi_free(struct tls_multi *multi, bool clear) - /* * Dependent on hmac size, opcode size, and session_id size. * Will assert if too small. @@ -1380,10 +1379,10 @@ tls_multi_free(struct tls_multi *multi, bool clear) * * Turning the on wire format that starts with the opcode to a format * that starts with the hmac - * e.g. "onwire" [opcode + packet id] [hmac] [remainder of packed] * + * "onwire" [opcode, peer session id] [hmac, packet id] [remainder of packed] * - * "internal" [hmac] [opcode + packet id] [remainer of packet] + * "internal" [hmac, packet id] [opcode, peer session id] [remainder of packet] * * @param buf the buffer the swap operation is executed on * @param incoming determines the direction of the swap @@ -1404,7 +1403,7 @@ swap_hmac(struct buffer *buf, const struct crypto_options *co, bool incoming) /* hmac + packet_id (8 bytes) */ const int hmac_size = hmac_ctx_size(ctx->hmac) + packet_id_size(true); - /* opcode + session_id */ + /* opcode (1 byte) + session_id (8 bytes) */ const int osid_size = 1 + SID_SIZE; int e1, e2; @@ -3755,6 +3754,17 @@ error: goto done; } +void +free_tls_pre_decrypt_state(struct tls_pre_decrypt_state *state) +{ + free_buf(&state->newbuf); + free_buf(&state->tls_wrap_tmp.tls_crypt_v2_metadata); + if (state->tls_wrap_tmp.cleanup_key_ctx) + { + free_key_ctx_bi(&state->tls_wrap_tmp.opt.key_ctx_bi); + } +} + /* * This function is similar to tls_pre_decrypt, except it is called * when we are in server mode and receive an initial incoming @@ -3766,17 +3776,21 @@ error: * This function is essentially the first-line HMAC firewall * on the UDP port listener in --mode server mode. */ -bool +enum first_packet_verdict tls_pre_decrypt_lite(const struct tls_auth_standalone *tas, + struct tls_pre_decrypt_state *state, const struct link_socket_actual *from, const struct buffer *buf) - { - if (buf->len <= 0) + struct gc_arena gc = gc_new(); + /* A packet needs to have at least an opcode and session id */ + if (buf->len < (1 + SID_SIZE)) { - return false; + dmsg(D_TLS_STATE_ERRORS, + "TLS State Error: Too short packet (length %d) received from %s", + buf->len, print_link_socket_actual(from, &gc)); + goto error; } - struct gc_arena gc = gc_new(); /* get opcode and key ID */ uint8_t pkt_firstbyte = *BPTR(buf); @@ -3786,8 +3800,10 @@ tls_pre_decrypt_lite(const struct tls_auth_standalone *tas, /* this packet is from an as-yet untrusted source, so * scrutinize carefully */ + /* Allow only the reset packet or the first packet of the actual handshake. */ if (op != P_CONTROL_HARD_RESET_CLIENT_V2 - && op != P_CONTROL_HARD_RESET_CLIENT_V3) + && op != P_CONTROL_HARD_RESET_CLIENT_V3 + && op != P_CONTROL_V1) { /* * This can occur due to bogus data or DoS packets. @@ -3808,17 +3824,28 @@ tls_pre_decrypt_lite(const struct tls_auth_standalone *tas, goto error; } - struct buffer newbuf = clone_buf(buf); - struct tls_wrap_ctx tls_wrap_tmp = tas->tls_wrap; - - /* HMAC test, if --tls-auth was specified */ - bool status = read_control_auth(&newbuf, &tls_wrap_tmp, from, NULL); - free_buf(&newbuf); - free_buf(&tls_wrap_tmp.tls_crypt_v2_metadata); - if (tls_wrap_tmp.cleanup_key_ctx) + /* read peer session id, we do this at this point since + * read_control_auth will skip over it */ + struct buffer tmp = *buf; + buf_advance(&tmp, 1); + if (!session_id_read(&state->peer_session_id, &tmp) + || !session_id_defined(&state->peer_session_id)) { - free_key_ctx_bi(&tls_wrap_tmp.opt.key_ctx_bi); + msg(D_TLS_ERRORS, + "TLS Error: session-id not found in packet from %s", + print_link_socket_actual(from, &gc)); + goto error; } + + state->newbuf = clone_buf(buf); + state->tls_wrap_tmp = tas->tls_wrap; + + /* HMAC test and unwrapping the encrypted part of the control message + * into newbuf or just setting newbuf to point to the start of control + * message */ + bool status = read_control_auth(&state->newbuf, &state->tls_wrap_tmp, + from, NULL); + if (!status) { goto error; @@ -3840,12 +3867,19 @@ tls_pre_decrypt_lite(const struct tls_auth_standalone *tas, * of authentication solely up to TLS. */ gc_free(&gc); - return true; + if (op == P_CONTROL_V1) + { + return VERDICT_VALID_CONTROL_V1; + } + else + { + return VERDICT_VALID_RESET; + } error: tls_clear_error(); gc_free(&gc); - return false; + return VERDICT_INVALID; } struct key_state * diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index 5b9232006..d72bf3c50 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -323,6 +323,33 @@ bool tls_pre_decrypt(struct tls_multi *multi, /** @name Functions for managing security parameter state for data channel packets * @{ */ + +enum first_packet_verdict { + /** This packet is a valid reset packet from the peer */ + VERDICT_VALID_RESET, + /** This packet is a valid control packet from the peer, + * i.e. it has a valid session id hmac in it */ + VERDICT_VALID_CONTROL_V1, + /** the packet failed on of the various checks */ + VERDICT_INVALID +}; + +/** + * struct that stores the temporary data for the tls lite decrypt + * functions + */ +struct tls_pre_decrypt_state { + struct tls_wrap_ctx tls_wrap_tmp; + struct buffer newbuf; + struct session_id peer_session_id; +}; + +/** + * + * @param state + */ +void free_tls_pre_decrypt_state(struct tls_pre_decrypt_state *state); + /** * Inspect an incoming packet for which no VPN tunnel is active, and * determine whether a new VPN tunnel should be created. @@ -343,6 +370,8 @@ bool tls_pre_decrypt(struct tls_multi *multi, * whether a new VPN tunnel should be created. If so, that new VPN tunnel * instance will handle processing of the packet. * + * This function is only used in the UDP p2mp server code path + * * @param tas - The standalone TLS authentication setting structure for * this process. * @param from - The source address of the packet. @@ -354,9 +383,11 @@ bool tls_pre_decrypt(struct tls_multi *multi, * @li False if the packet is not valid, did not pass the HMAC firewall * test, or some other error occurred. */ -bool tls_pre_decrypt_lite(const struct tls_auth_standalone *tas, - const struct link_socket_actual *from, - const struct buffer *buf); +enum first_packet_verdict +tls_pre_decrypt_lite(const struct tls_auth_standalone *tas, + struct tls_pre_decrypt_state *state, + const struct link_socket_actual *from, + const struct buffer *buf); /**