From patchwork Fri Apr 22 04:29:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 2409 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director8.mail.ord1d.rsapps.net ([172.31.255.6]) by backend41.mail.ord1d.rsapps.net with LMTP id SNC1Nk/KYmKMOAAAqwncew (envelope-from ) for ; Fri, 22 Apr 2022 11:31:27 -0400 Received: from proxy2.mail.iad3b.rsapps.net ([172.31.255.6]) by director8.mail.ord1d.rsapps.net with LMTP id MN/uBlDKYmKbKwAAfY0hYg (envelope-from ) for ; Fri, 22 Apr 2022 11:31:28 -0400 Received: from smtp24.gate.iad3b ([172.31.255.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy2.mail.iad3b.rsapps.net with LMTPS id GCk3AFDKYmJ/CAAAvAZTew (envelope-from ) for ; Fri, 22 Apr 2022 11:31:28 -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: smtp24.gate.iad3b.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: 463ae786-c251-11ec-9973-525400892b35-1-1 Received: from [216.105.38.7] ([216.105.38.7:41066] helo=lists.sourceforge.net) by smtp24.gate.iad3b.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 6C/1D-25362-F4AC2626; Fri, 22 Apr 2022 11:31:27 -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 1nhvEh-0006H8-LD; Fri, 22 Apr 2022 15:30:20 +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 1nhvEg-0006H2-81 for openvpn-devel@lists.sourceforge.net; Fri, 22 Apr 2022 15: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=3Wpu/2kNx/d1VMUR/svyvD+b7+xDv2cLfOD092Zi7ks=; b=HAuWNmU7ckinhs0KWltxlHUZyx 4PWHiqcl/JmpwRwn56a/Gerg+/kr4ryKpkppRKjyj+LosO17x1C+upfX8Op8XUZs1LMWqMU6sJapG A/gF/XkFTUypxds0fNy3G7LbwVl7xGkskSmmfT132zc6EVd98ZXqwefH0/wCrVdjUaGU=; 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=3Wpu/2kNx/d1VMUR/svyvD+b7+xDv2cLfOD092Zi7ks=; b=iBeJ3WvWuMHYxxU/o5ePjpxooK wKkmmwCDDlUiVueo3uBaYdnHTiqpcW4lwLSNdGKWMLgItfCKqqVYK8HPav2d/SxtbobH6dJ3vM4Ss 0FWrwkdGsH53mlDVaUDVPh1gjMRYUF+gICSN98nmmgdyGUTjq57jju286Rz9h8RmTkWg=; 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 1nhvEf-0000Bh-Tu for openvpn-devel@lists.sourceforge.net; Fri, 22 Apr 2022 15:30:18 +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-00096f-Pc for openvpn-devel@lists.sourceforge.net; Fri, 22 Apr 2022 16:29:53 +0200 Received: (nullmailer pid 3805432 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:42 +0200 Message-Id: <20220422142953.3805364-8-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 implement creating a reset packet without needing to setup a full control session. --- src/openvpn/packet_id.h | 15 ++++++ src/openvpn/ssl.h | 6 --- src/openvpn/ssl_pkt.c | 34 +++++++++++- src/op [...] 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: 1nhvEf-0000Bh-Tu Subject: [Openvpn-devel] [PATCH 17/28] Implement constructing a control channel reset client as standalone fucntion 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 implement creating a reset packet without needing to setup a full control session. --- src/openvpn/packet_id.h | 15 ++++++ src/openvpn/ssl.h | 6 --- src/openvpn/ssl_pkt.c | 34 +++++++++++- src/openvpn/ssl_pkt.h | 19 +++++++ tests/unit_tests/openvpn/test_pkt.c | 84 ++++++++++++++++++++++++++++- 5 files changed, 149 insertions(+), 9 deletions(-) diff --git a/src/openvpn/packet_id.h b/src/openvpn/packet_id.h index 410071e26..e5ffd485c 100644 --- a/src/openvpn/packet_id.h +++ b/src/openvpn/packet_id.h @@ -289,6 +289,21 @@ packet_id_persist_save_obj(struct packet_id_persist *p, const struct packet_id * } } +/** + * Reset the current send packet id to its initial state. + * Use very carefully only as (e.g. in the standalone reset packet context) + * to avoid sending more than one packet with the same packet id (that is not + * also a resend like the reset packet) + * + * @param p the packet structure to modify + */ +static inline void +reset_packet_id_send(struct packet_id_send *p) +{ + p->time = 0; + p->id = 0; +} + const char *packet_id_net_print(const struct packet_id_net *pin, bool print_timestamp, struct gc_arena *gc); static inline int diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index d718aa27b..3a65bad6a 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -53,12 +53,6 @@ */ #define CONTROL_SEND_ACK_MAX 4 -/* - * Define number of buffers for send and receive in the reliability layer. - */ -#define TLS_RELIABLE_N_SEND_BUFFERS 4 /* also window size for reliability layer */ -#define TLS_RELIABLE_N_REC_BUFFERS 8 - /* * Various timeouts */ diff --git a/src/openvpn/ssl_pkt.c b/src/openvpn/ssl_pkt.c index 86c1f0e29..927ee35aa 100644 --- a/src/openvpn/ssl_pkt.c +++ b/src/openvpn/ssl_pkt.c @@ -397,4 +397,36 @@ error: tls_clear_error(); gc_free(&gc); return VERDICT_INVALID; -} \ No newline at end of file +} + +struct buffer +tls_reset_standalone(struct tls_auth_standalone *tas, + struct session_id *own_sid, + struct session_id *remote_sid, + uint8_t header) +{ + struct buffer buf = alloc_buf(tas->frame.buf.payload_size); + ASSERT(buf_init(&buf, tas->frame.buf.headroom)); + + /* Reliable ACK structure */ + /* Length of the ACK structure - 1 ACK */ + buf_write_u8(&buf, 1); + + /* ACKed packet - first packet's id is always 0 */ + buf_write_u32(&buf, 0); + + /* Remote session id */ + buf_write(&buf, remote_sid->id, SID_SIZE); + + /* Packet ID of our own packet: Our reset packet is always using + * packet id 0 since it is the first packet */ + packet_id_type net_pid = htonpid(0); + + ASSERT(buf_write(&buf, &net_pid, sizeof(net_pid))); + + /* Add tls-auth/tls-crypt wrapping, this might replace buf */ + tls_wrap_control(&tas->tls_wrap, header, &buf, own_sid); + + return buf; +} + diff --git a/src/openvpn/ssl_pkt.h b/src/openvpn/ssl_pkt.h index b7a8d9c35..1a327eba6 100644 --- a/src/openvpn/ssl_pkt.h +++ b/src/openvpn/ssl_pkt.h @@ -60,6 +60,12 @@ #define P_FIRST_OPCODE 3 #define P_LAST_OPCODE 10 +/* + * Define number of buffers for send and receive in the reliability layer. + */ +#define TLS_RELIABLE_N_SEND_BUFFERS 4 /* also window size for reliability layer */ +#define TLS_RELIABLE_N_REC_BUFFERS 8 + /* * Used in --mode server mode to check tls-auth signature on initial * packets received from new clients. @@ -157,6 +163,19 @@ read_control_auth(struct buffer *buf, const struct link_socket_actual *from, const struct tls_options *opt); + +/** + * This function creates a reset packet using the information + * from the tls pre decrypt state. + * + * The returned buf need to be free with \c free_buf + */ +struct buffer +tls_reset_standalone(struct tls_auth_standalone *tas, + struct session_id *own_sid, + struct session_id *remote_sid, + uint8_t header); + static inline const char * packet_opcode_name(int op) { diff --git a/tests/unit_tests/openvpn/test_pkt.c b/tests/unit_tests/openvpn/test_pkt.c index 022e15d3e..95ff13b5a 100644 --- a/tests/unit_tests/openvpn/test_pkt.c +++ b/tests/unit_tests/openvpn/test_pkt.c @@ -156,7 +156,7 @@ struct tls_auth_standalone init_tas_auth(int key_direction) tas.tls_wrap.mode = TLS_WRAP_AUTH; /* we ignore packet ids on for the first packet check */ - tas.tls_wrap.opt.flags |= CO_IGNORE_PACKET_ID; + tas.tls_wrap.opt.flags |= (CO_IGNORE_PACKET_ID|CO_PACKET_ID_LONG_FORM); struct key_type tls_crypt_kt; init_key_type(&tls_crypt_kt, "none", "SHA1", true, false); @@ -171,7 +171,7 @@ struct tls_auth_standalone init_tas_crypt(bool server) { struct tls_auth_standalone tas = { 0 }; tas.tls_wrap.mode = TLS_WRAP_CRYPT; - tas.tls_wrap.opt.flags |= CO_IGNORE_PACKET_ID; + tas.tls_wrap.opt.flags |= (CO_IGNORE_PACKET_ID|CO_PACKET_ID_LONG_FORM); tls_crypt_init_key(&tas.tls_wrap.opt.key_ctx_bi, static_key, true, server); @@ -324,6 +324,84 @@ test_tls_decrypt_lite_none(void **ut_state) free_buf(&buf); } +static void +test_generate_reset_packet_plain(void **ut_state) +{ + struct link_socket_actual from = { 0 }; + struct tls_auth_standalone tas = { 0 }; + struct tls_pre_decrypt_state state = { 0 }; + + struct session_id client_id = {{0, 1, 2, 3, 4, 5, 6, 7}}; + struct session_id server_id = {{8, 9, 0, 9, 8, 7, 6, 2}}; + + enum first_packet_verdict verdict; + + tas.tls_wrap.mode = TLS_WRAP_NONE; + struct frame frame = { {.headroom = 200, .payload_size = 1400}, 0}; + tas.frame = frame; + + uint8_t header = 0 | (P_CONTROL_HARD_RESET_CLIENT_V2 << P_OPCODE_SHIFT); + + struct buffer buf = tls_reset_standalone(&tas, &client_id, &server_id, header); + + + verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf); + assert_int_equal(verdict, VERDICT_VALID_RESET); + + /* Assure repeated generation of reset is deterministic/stateless*/ + assert_memory_equal(state.peer_session_id.id, client_id.id, SID_SIZE); + struct buffer buf2 = tls_reset_standalone(&tas, &client_id, &server_id, header); + assert_int_equal(BLEN(&buf), BLEN(&buf2)); + assert_memory_equal(BPTR(&buf), BPTR(&buf2), BLEN(&buf)); + free_buf(&buf2); + + free_tls_pre_decrypt_state(&state); + free_buf(&buf); +} + +static void +test_generate_reset_packet_tls_auth(void **ut_state) +{ + struct link_socket_actual from = { 0 }; + struct tls_pre_decrypt_state state = { 0 }; + + struct tls_auth_standalone tas_server = init_tas_auth(KEY_DIRECTION_NORMAL); + struct tls_auth_standalone tas_client = init_tas_auth(KEY_DIRECTION_INVERSE); + + packet_id_init(&tas_client.tls_wrap.opt.packet_id, 5, 5, "UNITTEST", 0); + + struct session_id client_id = {{0xab, 1, 2, 3, 4, 5, 6, 0xcd}}; + struct session_id server_id = {{8, 9, 0xa, 0xc, 8, 7, 6, 2}}; + + uint8_t header = 0 | (P_CONTROL_HARD_RESET_CLIENT_V2 << P_OPCODE_SHIFT); + + now = 0x22446688; + reset_packet_id_send(&tas_client.tls_wrap.opt.packet_id.send); + struct buffer buf = tls_reset_standalone(&tas_client, &client_id, &server_id, header); + + enum first_packet_verdict verdict = tls_pre_decrypt_lite(&tas_server, &state, &from, &buf); + assert_int_equal(verdict, VERDICT_VALID_RESET); + + assert_memory_equal(state.peer_session_id.id, client_id.id, SID_SIZE); + + /* Assure repeated generation of reset is deterministic/stateless*/ + reset_packet_id_send(&tas_client.tls_wrap.opt.packet_id.send); + struct buffer buf2 = tls_reset_standalone(&tas_client, &client_id, &server_id, header); + assert_int_equal(BLEN(&buf), BLEN(&buf2)); + assert_memory_equal(BPTR(&buf), BPTR(&buf2), BLEN(&buf)); + free_buf(&buf2); + + + free_tls_pre_decrypt_state(&state); + + packet_id_free(&tas_client.tls_wrap.opt.packet_id); + + free_buf(&buf); + free_key_ctx_bi(&tas_server.tls_wrap.opt.key_ctx_bi); + free_key_ctx_bi(&tas_client.tls_wrap.opt.key_ctx_bi); + +} + int main(void) { @@ -331,6 +409,8 @@ main(void) cmocka_unit_test(test_tls_decrypt_lite_none), cmocka_unit_test(test_tls_decrypt_lite_auth), cmocka_unit_test(test_tls_decrypt_lite_crypt), + cmocka_unit_test(test_generate_reset_packet_plain), + cmocka_unit_test(test_generate_reset_packet_tls_auth), }; #if defined(ENABLE_CRYPTO_OPENSSL)