From patchwork Thu Apr 8 04:02:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 1728 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director15.mail.ord1d.rsapps.net ([172.31.255.6]) by backend30.mail.ord1d.rsapps.net with LMTP id cEkHNT8Nb2B0ZgAAIUCqbw (envelope-from ) for ; Thu, 08 Apr 2021 10:03:43 -0400 Received: from proxy19.mail.iad3b.rsapps.net ([172.31.255.6]) by director15.mail.ord1d.rsapps.net with LMTP id MKTJND8Nb2ABFgAAIcMcQg (envelope-from ) for ; Thu, 08 Apr 2021 10:03:43 -0400 Received: from smtp31.gate.iad3b ([172.31.255.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy19.mail.iad3b.rsapps.net with LMTPS id qK/ZLT8Nb2CobAAAIG4riQ (envelope-from ) for ; Thu, 08 Apr 2021 10:03:43 -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.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: 39bf0d06-9873-11eb-bd5f-52540005277f-1-1 Received: from [216.105.38.7] ([216.105.38.7:40272] helo=lists.sourceforge.net) by smtp31.gate.iad3b.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id C4/1C-29892-E3D0F606; Thu, 08 Apr 2021 10:03:43 -0400 Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1lUVFM-0005um-WF; Thu, 08 Apr 2021 14:03:01 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lUVFK-0005uC-6b for openvpn-devel@lists.sourceforge.net; Thu, 08 Apr 2021 14:02:58 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=References:In-Reply-To:Message-Id:Date:Subject:To: From:Sender:Reply-To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding: 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=pkEg2eBe1Rhd1zZvr0pTgYP3fP/OH3tAVLLTrWvQC/0=; b=EaVhFl0hZU9KNn8SQ3SDfLUW0P LH/C9EFHccdd0pOEvAkF+IO92Nck9jfLeG4BRtdDRwVGwT9gU8rL517tSD4auvwMXmyF/+0xdlDKg ciKaNYMC1t17mwGF6wBlhLRn5qrgtV9XgXF/eIgtdkCbuUeJj2ppoxLhrP9qUdkWDQqo=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=References:In-Reply-To:Message-Id:Date:Subject:To:From:Sender:Reply-To:Cc :MIME-Version:Content-Type:Content-Transfer-Encoding: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=pkEg2eBe1Rhd1zZvr0pTgYP3fP/OH3tAVLLTrWvQC/0=; b=OgawMXHygD/UKkgRrwWleFLrX1 zXSBNQF+5rkjt8u2O/Kt3ca0yqcq2rBj4s5pXlWiwBmavJRPTh+VgbZdjZpA1KBByl1mn3/dG+Pj2 CzVSFjnOQLplPWEkwiMsHRXzkfhWfY1TzkfDQKXyOdFoVbOZfOF+Ck2tFwvv8d3XpzTY=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.3) id 1lUVF4-0002nW-RB for openvpn-devel@lists.sourceforge.net; Thu, 08 Apr 2021 14:02:57 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.94 (FreeBSD)) (envelope-from ) id 1lUVEr-000DZD-9z for openvpn-devel@lists.sourceforge.net; Thu, 08 Apr 2021 16:02:29 +0200 Received: (nullmailer pid 31872 invoked by uid 10006); Thu, 08 Apr 2021 14:02:29 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Thu, 8 Apr 2021 16:02:26 +0200 Message-Id: <20210408140229.31824-2-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210408140229.31824-1-arne@rfc2549.org> References: <20210408140229.31824-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 TIME_LIMIT_EXCEEDED Exceeded time limit / deadline X-Headers-End: 1lUVF4-0002nW-RB Subject: [Openvpn-devel] [PATCH 1/3] Change options->data_channel_use_ekm to flags 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: , MIME-Version: 1.0 Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox Instead maintaining two different representation of the data channel options in struct options and struct tls_options, use the same flags variable that tls_options uses. Signed-off-by: Arne Schwabe Acked-by: Antonio Quartulli --- src/openvpn/multi.c | 5 ++++- src/openvpn/options.c | 4 ++-- src/openvpn/options.h | 4 ++-- src/openvpn/push.c | 2 +- src/openvpn/ssl.c | 6 ++---- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index d5f34c349..e6eb34bfb 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1783,7 +1783,10 @@ multi_client_set_protocol_options(struct context *c) } #ifdef HAVE_EXPORT_KEYING_MATERIAL - o->data_channel_use_ekm = (proto & IV_PROTO_TLS_KEY_EXPORT); + if (proto & IV_PROTO_TLS_KEY_EXPORT) + { + o->data_channel_crypto_flags |= CO_USE_TLS_KEY_MATERIAL_EXPORT; + } #endif /* Select cipher if client supports Negotiable Crypto Parameters */ diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 9e61b1e05..24d722fd5 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -3651,7 +3651,7 @@ pre_pull_restore(struct options *o, struct gc_arena *gc) o->push_continuation = 0; o->push_option_types_found = 0; - o->data_channel_use_ekm = false; + o->data_channel_crypto_flags = 0; } /** @@ -7949,7 +7949,7 @@ add_option(struct options *options, #ifdef HAVE_EXPORT_KEYING_MATERIAL if (streq(p[1], "tls-ekm")) { - options->data_channel_use_ekm = true; + options->data_channel_crypto_flags |= CO_USE_TLS_KEY_MATERIAL_EXPORT; } else #endif diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 65e5ffccf..b80cd3d1b 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -651,8 +651,8 @@ struct options * to the routing tables that would move packets into the tunnel. */ bool allow_recursive_routing; - /* Use RFC5705 key export to generate data channel keys */ - bool data_channel_use_ekm; + /* data channel crypto flags set by push/pull. Reuses the CO_* crypto_flags */ + unsigned int data_channel_crypto_flags; }; #define streq(x, y) (!strcmp((x), (y))) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 15a9141ee..2e92d8ee2 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -595,7 +595,7 @@ prepare_push_reply(struct context *c, struct gc_arena *gc, { push_option_fmt(gc, push_list, M_USAGE, "cipher %s", o->ciphername); } - if (o->data_channel_use_ekm) + if (o->data_channel_crypto_flags & CO_USE_TLS_KEY_MATERIAL_EXPORT) { push_option_fmt(gc, push_list, M_USAGE, "key-derivation tls-ekm"); } diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index d8662d000..5d65c3da5 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1860,10 +1860,8 @@ tls_session_update_crypto_params(struct tls_session *session, return false; } - if (options->data_channel_use_ekm) - { - session->opt->crypto_flags |= CO_USE_TLS_KEY_MATERIAL_EXPORT; - } + /* Import crypto settings that might be set by pull/push */ + session->opt->crypto_flags |= options->data_channel_crypto_flags; if (strcmp(options->ciphername, session->opt->config_ciphername)) { From patchwork Thu Apr 8 04:02:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 1731 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director12.mail.ord1d.rsapps.net ([172.27.255.9]) by backend30.mail.ord1d.rsapps.net with LMTP id eGW3LsMTb2CNCAAAIUCqbw (envelope-from ) for ; Thu, 08 Apr 2021 10:31:31 -0400 Received: from proxy14.mail.iad3a.rsapps.net ([172.27.255.9]) by director12.mail.ord1d.rsapps.net with LMTP id qMDrLcMTb2CcNAAAIasKDg (envelope-from ) for ; Thu, 08 Apr 2021 10:31:31 -0400 Received: from smtp23.gate.iad3a ([172.27.255.9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy14.mail.iad3a.rsapps.net with LMTPS id wHYhIMUTb2CzegAA1+b4IQ (envelope-from ) for ; Thu, 08 Apr 2021 10:31:33 -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: smtp23.gate.iad3a.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: 1b868a86-9877-11eb-af1f-52540033eb40-1-1 Received: from [216.105.38.7] ([216.105.38.7:36882] helo=lists.sourceforge.net) by smtp23.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 78/FB-27819-2C31F606; Thu, 08 Apr 2021 10:31:30 -0400 Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1lUVfy-0002i8-RN; Thu, 08 Apr 2021 14:30:30 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lUVfu-0002hO-Pf for openvpn-devel@lists.sourceforge.net; Thu, 08 Apr 2021 14:30:26 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=References:In-Reply-To:Message-Id:Date:Subject:To: From:Sender:Reply-To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding: 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=AEgSvrJ5HT5029uui9BucwlvfUvtDh6qHr0zL3cZsb0=; b=VEZwNwtPpPgxs92EDYBkNT8kGB isqacr6Gt1H7mtmAVjYv4OujXJ89u/wWonsqWfJsZL2u9DKPznjxQFokvVA/OZLnh/UWh54UzFZ4t EobuBBD/pMtgDGS/dIkoYOhWD2gWpgVqHS1rQfCqnZ8NW9yzRu1vd+AZjaVzw9A5GygY=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=References:In-Reply-To:Message-Id:Date:Subject:To:From:Sender:Reply-To:Cc :MIME-Version:Content-Type:Content-Transfer-Encoding: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=AEgSvrJ5HT5029uui9BucwlvfUvtDh6qHr0zL3cZsb0=; b=QDvNuMVZLPm/sHLzbQEEdHUSEm Mx3Pky4tyomuCAymtZuXLI/BpcLGpyw94OWGJtXqXixg+X9NHasIPsBiL7mIf3ljIOhaqtRZPQEcy wSGCNDpdGRiIr2sStkaoJ3cCW9u/tYT8vwpZJ8JUJ1nDfEmPzvNOftx/lhjwRNj/ppCc=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.3) id 1lUVfd-0003mV-Vd for openvpn-devel@lists.sourceforge.net; Thu, 08 Apr 2021 14:30:25 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.94 (FreeBSD)) (envelope-from ) id 1lUVEr-000DZH-CW for openvpn-devel@lists.sourceforge.net; Thu, 08 Apr 2021 16:02:29 +0200 Received: (nullmailer pid 31875 invoked by uid 10006); Thu, 08 Apr 2021 14:02:29 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Thu, 8 Apr 2021 16:02:27 +0200 Message-Id: <20210408140229.31824-3-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210408140229.31824-1-arne@rfc2549.org> References: <20210408140229.31824-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 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 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 TIME_LIMIT_EXCEEDED Exceeded time limit / deadline X-Headers-End: 1lUVfd-0003mV-Vd Subject: [Openvpn-devel] [PATCH 2/3] Remove --ncp-disable option 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: , MIME-Version: 1.0 Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox NCP has proven to be stable and apart from the one VPN Provider doing hacky things with homebrewed NCP we have not had any reports about ncp-disable being required. Remove ncp-disable to simplify code paths. Note: This patch breaks client without --pull. The follow up patch for P2P NCP will restore that. But to avoid all the NCP/non-NCP special cases to be implemented in P2P. P2P will directly switch from always non-NCP to always NCP. Signed-off-by: Arne Schwabe --- Changes.rst | 4 +++ doc/man-sections/protocol-options.rst | 8 ++---- src/openvpn/init.c | 17 ++++--------- src/openvpn/multi.c | 4 --- src/openvpn/options.c | 36 +++------------------------ src/openvpn/options.h | 1 - src/openvpn/ssl.c | 3 +-- src/openvpn/ssl_common.h | 1 - src/openvpn/ssl_ncp.c | 4 --- 9 files changed, 16 insertions(+), 62 deletions(-) diff --git a/Changes.rst b/Changes.rst index 457dfc07e..d6ccc1c92 100644 --- a/Changes.rst +++ b/Changes.rst @@ -47,6 +47,10 @@ Deprecated features is considered "too complicated", using ``--peer-fingerprint`` makes TLS mode about as easy as using ``--secret``. +``ncp-disable`` has been removed + This option mainly served a role as debug option when NCP was first + introduced. It should now no longer be necessary. + Overview of changes in 2.5 ========================== diff --git a/doc/man-sections/protocol-options.rst b/doc/man-sections/protocol-options.rst index 4b6928c68..fe8ca8fd1 100644 --- a/doc/man-sections/protocol-options.rst +++ b/doc/man-sections/protocol-options.rst @@ -65,8 +65,8 @@ configured in a compatible way between both the local and remote side. The default is :code:`BF-CBC`, an abbreviation for Blowfish in Cipher Block Chaining mode. When cipher negotiation (NCP) is allowed, OpenVPN 2.4 and newer on both client and server side will automatically - upgrade to :code:`AES-256-GCM`. See ``--data-ciphers`` and - ``--ncp-disable`` for more details on NCP. + upgrade to :code:`AES-256-GCM`. See ``--data-ciphers`` for more details + on NCP. Using :code:`BF-CBC` is no longer recommended, because of its 64-bit block size. This small block size allows attacks based on collisions, as @@ -230,10 +230,6 @@ configured in a compatible way between both the local and remote side. have been configured with `--enable-small` (typically used on routers or other embedded devices). ---ncp-disable - **DEPRECATED** Disable "Negotiable Crypto Parameters". This completely - disables cipher negotiation. - --secret args **DEPRECATED** Enable Static Key encryption mode (non-TLS). Use pre-shared secret ``file`` which was generated with ``--genkey``. diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 28d183aa0..4a6b84914 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2226,18 +2226,14 @@ pull_permission_mask(const struct context *c) | OPT_P_EXPLICIT_NOTIFY | OPT_P_ECHO | OPT_P_PULL_MODE - | OPT_P_PEER_ID; + | OPT_P_PEER_ID + | OPT_P_NCP; if (!c->options.route_nopull) { flags |= (OPT_P_ROUTE | OPT_P_IPWIN32); } - if (c->options.ncp_enabled) - { - flags |= OPT_P_NCP; - } - return flags; } @@ -2734,8 +2730,6 @@ do_init_crypto_tls_c1(struct context *c) * * Therefore, the key structure has to be initialized when: * - any non-BF-CBC cipher was selected; or - * - BF-CBC is selected and NCP is disabled (explicit request to - * use the BF-CBC cipher); or * - BF-CBC is selected, NCP is enabled and fallback is enabled * (BF-CBC will be the fallback). * - BF-CBC is in data-ciphers and we negotiate to use BF-CBC: @@ -2745,12 +2739,12 @@ do_init_crypto_tls_c1(struct context *c) * Note that BF-CBC will still be part of the OCC string to retain * backwards compatibility with older clients. */ - if (!streq(options->ciphername, "BF-CBC") || !options->ncp_enabled - || (options->ncp_enabled && tls_item_in_cipher_list("BF-CBC", options->ncp_ciphers)) + if (!streq(options->ciphername, "BF-CBC") + || tls_item_in_cipher_list("BF-CBC", options->ncp_ciphers) || options->enable_ncp_fallback) { /* Do not warn if the if the cipher is used only in OCC */ - bool warn = !options->ncp_enabled || options->enable_ncp_fallback; + bool warn = options->enable_ncp_fallback; init_key_type(&c->c1.ks.key_type, options->ciphername, options->authname, true, warn); } @@ -2847,7 +2841,6 @@ do_init_crypto_tls(struct context *c, const unsigned int flags) to.tcp_mode = link_socket_proto_connection_oriented(options->ce.proto); to.config_ciphername = c->options.ciphername; to.config_ncp_ciphers = c->options.ncp_ciphers; - to.ncp_enabled = options->ncp_enabled; to.transition_window = options->transition_window; to.handshake_window = options->handshake_window; to.packet_timeout = options->tls_timeout; diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index e6eb34bfb..1dd7c8983 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1790,10 +1790,6 @@ multi_client_set_protocol_options(struct context *c) #endif /* Select cipher if client supports Negotiable Crypto Parameters */ - if (!o->ncp_enabled) - { - return true; - } /* if we have already created our key, we cannot *change* our own * cipher -> so log the fact and push the "what we have now" cipher diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 24d722fd5..e2759a1ac 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -526,7 +526,6 @@ static const char usage_message[] = " (default=%s).\n" " Set alg=none to disable encryption.\n" "--data-ciphers list : List of ciphers that are allowed to be negotiated.\n" - "--ncp-disable : (DEPRECATED) Disable cipher negotiation.\n" "--prng alg [nsl] : For PRNG, use digest algorithm alg, and\n" " nonce_secret_len=nsl. Set alg=none to disable PRNG.\n" #ifndef ENABLE_CRYPTO_MBEDTLS @@ -843,7 +842,6 @@ init_options(struct options *o, const bool init_gc) o->stale_routes_check_interval = 0; o->ifconfig_pool_persist_refresh_freq = 600; o->scheduled_exit_interval = 5; - o->ncp_enabled = true; o->ncp_ciphers = "AES-256-GCM:AES-128-GCM"; o->authname = "SHA1"; o->prng_hash = "SHA1"; @@ -1715,7 +1713,6 @@ show_settings(const struct options *o) SHOW_STR_INLINE(shared_secret_file); SHOW_PARM(key_direction, keydirection2ascii(o->key_direction, false, true), "%s"); SHOW_STR(ciphername); - SHOW_BOOL(ncp_enabled); SHOW_STR(ncp_ciphers); SHOW_STR(authname); SHOW_STR(prng_hash); @@ -3061,7 +3058,6 @@ options_postprocess_cipher(struct options *o) if (!o->pull && !(o->mode == MODE_SERVER)) { /* we are in the classic P2P mode */ - o->ncp_enabled = false; msg( M_WARN, "Cipher negotiation is disabled since neither " "P2MP client nor server mode is enabled"); @@ -3078,18 +3074,6 @@ options_postprocess_cipher(struct options *o) /* pull or P2MP mode */ if (!o->ciphername) { - if (!o->ncp_enabled) - { - msg(M_USAGE, "--ncp-disable needs an explicit --cipher or " - "--data-ciphers-fallback config option"); - } - - msg(M_WARN, "--cipher is not set. Previous OpenVPN version defaulted to " - "BF-CBC as fallback when cipher negotiation failed in this case. " - "If you need this fallback please add '--data-ciphers-fallback " - "BF-CBC' to your configuration and/or add BF-CBC to " - "--data-ciphers."); - /* We still need to set the ciphername to BF-CBC since various other * parts of OpenVPN assert that the ciphername is set */ o->ciphername = "BF-CBC"; @@ -3131,13 +3115,10 @@ options_postprocess_mutate(struct options *o) options_postprocess_cipher(o); options_postprocess_mutate_invariant(o); - if (o->ncp_enabled) + o->ncp_ciphers = mutate_ncp_cipher_list(o->ncp_ciphers, &o->gc); + if (o->ncp_ciphers == NULL) { - o->ncp_ciphers = mutate_ncp_cipher_list(o->ncp_ciphers, &o->gc); - if (o->ncp_ciphers == NULL) - { - msg(M_USAGE, "NCP cipher list contains unsupported ciphers or is too long."); - } + msg(M_USAGE, "NCP cipher list contains unsupported ciphers or is too long."); } if (o->remote_list && !o->connection_list) @@ -3879,8 +3860,7 @@ options_string(const struct options *o, } /* Only announce the cipher to our peer if we are willing to * support it */ - if (p2p_nopull || !o->ncp_enabled - || tls_item_in_cipher_list(ciphername, o->ncp_ciphers)) + if (p2p_nopull || tls_item_in_cipher_list(ciphername, o->ncp_ciphers)) { buf_printf(&out, ",cipher %s", ciphername); } @@ -7957,14 +7937,6 @@ add_option(struct options *options, msg(msglevel, "Unknown key-derivation method %s", p[1]); } } - else if (streq(p[0], "ncp-disable") && !p[1]) - { - VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_INSTANCE); - options->ncp_enabled = false; - msg(M_WARN, "DEPRECATED OPTION: ncp-disable. Disabling " - "cipher negotiation is a deprecated debug feature that " - "will be removed in OpenVPN 2.6"); - } else if (streq(p[0], "prng") && p[1] && !p[3]) { VERIFY_PERMISSION(OPT_P_GENERAL); diff --git a/src/openvpn/options.h b/src/openvpn/options.h index b80cd3d1b..17f21103d 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -506,7 +506,6 @@ struct options const char *ciphername; bool enable_ncp_fallback; /**< If defined fall back to * ciphername if NCP fails */ - bool ncp_enabled; const char *ncp_ciphers; const char *authname; const char *prng_hash; diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 5d65c3da5..068b66616 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2149,8 +2149,7 @@ push_peer_info(struct buffer *buf, struct tls_session *session) } /* support for Negotiable Crypto Parameters */ - if (session->opt->ncp_enabled - && (session->opt->mode == MODE_SERVER || session->opt->pull)) + if (session->opt->mode == MODE_SERVER || session->opt->pull) { if (tls_item_in_cipher_list("AES-128-GCM", session->opt->config_ncp_ciphers) && tls_item_in_cipher_list("AES-256-GCM", session->opt->config_ncp_ciphers)) diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 5b24623d4..3f8dd0178 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -308,7 +308,6 @@ struct tls_options const char *config_ciphername; const char *config_ncp_ciphers; - bool ncp_enabled; bool tls_crypt_v2; const char *tls_crypt_v2_verify_script; diff --git a/src/openvpn/ssl_ncp.c b/src/openvpn/ssl_ncp.c index f02a3103c..722256b42 100644 --- a/src/openvpn/ssl_ncp.c +++ b/src/openvpn/ssl_ncp.c @@ -289,10 +289,6 @@ check_pull_client_ncp(struct context *c, const int found) return true; } - if (!c->options.ncp_enabled) - { - return true; - } /* If the server did not push a --cipher, we will switch to the * remote cipher if it is in our ncp-ciphers list */ if(tls_poor_mans_ncp(&c->options, c->c2.tls_multi->remote_ciphername)) From patchwork Thu Apr 8 04:02:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 1730 X-Patchwork-Delegate: a@unstable.cc Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director9.mail.ord1d.rsapps.net ([172.31.255.6]) by backend30.mail.ord1d.rsapps.net with LMTP id YP6jB0cNb2ByZgAAIUCqbw (envelope-from ) for ; Thu, 08 Apr 2021 10:03:51 -0400 Received: from proxy2.mail.iad3b.rsapps.net ([172.31.255.6]) by director9.mail.ord1d.rsapps.net with LMTP id YNNCB0cNb2A3MwAAalYnBA (envelope-from ) for ; Thu, 08 Apr 2021 10:03:51 -0400 Received: from smtp10.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 8FmmAEcNb2BBYgAAvAZTew (envelope-from ) for ; Thu, 08 Apr 2021 10:03:51 -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: smtp10.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: 3dd04608-9873-11eb-94fb-52540055034d-1-1 Received: from [216.105.38.7] ([216.105.38.7:59516] helo=lists.sourceforge.net) by smtp10.gate.iad3b.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 76/73-26872-54D0F606; Thu, 08 Apr 2021 10:03:50 -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.90_1) (envelope-from ) id 1lUVFQ-0005En-Mr; Thu, 08 Apr 2021 14:03:04 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lUVFO-0005EV-BZ for openvpn-devel@lists.sourceforge.net; Thu, 08 Apr 2021 14:03:02 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=References:In-Reply-To:Message-Id:Date:Subject:To: From:Sender:Reply-To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding: 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=ZcYTSfKAC37wEVSRGSNPfebKzSxg5FG+UaxO3hrN4R8=; b=U3eA6TAjq9iTpzocfTPpkeCwoX M7LNlqWLGfcwz9fQjkT4FuEY3AmK48o6wHWamBC2/mR8Unb5xnItTH/27466Th1KptyEN0UrOVglx +uCy+QogBrVJslUtuNt+/1ROeJWpC/lUxE7V5tlK8SNtVTSVOePZ/7M+THmZMERUAlnQ=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=References:In-Reply-To:Message-Id:Date:Subject:To:From:Sender:Reply-To:Cc :MIME-Version:Content-Type:Content-Transfer-Encoding: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=ZcYTSfKAC37wEVSRGSNPfebKzSxg5FG+UaxO3hrN4R8=; b=eA4ADqsZBkk7y8x7iPncf1FKwi LMCSAAF6/FRdJkUgceM9AYqagBO2v9pGXzMzK1ye+Z5WU0vB+jEgqeR0xoII25428Qlelx38R+0s4 a2Hqe9XqKzqOJYYAf+y850PK/oh99if5VFW6ilpE5ZgNnjkM2S4PllZlHkgaWOXVFeYk=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1lUVEy-004oUF-Hg for openvpn-devel@lists.sourceforge.net; Thu, 08 Apr 2021 14:03:02 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.94 (FreeBSD)) (envelope-from ) id 1lUVEr-000DZK-F5 for openvpn-devel@lists.sourceforge.net; Thu, 08 Apr 2021 16:02:29 +0200 Received: (nullmailer pid 31878 invoked by uid 10006); Thu, 08 Apr 2021 14:02:29 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Thu, 8 Apr 2021 16:02:28 +0200 Message-Id: <20210408140229.31824-4-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210408140229.31824-1-arne@rfc2549.org> References: <20210408140229.31824-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 TIME_LIMIT_EXCEEDED Exceeded time limit / deadline X-Headers-End: 1lUVEy-004oUF-Hg Subject: [Openvpn-devel] [PATCH 3/3] Support NCP in pure P2P VPN setups 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: , MIME-Version: 1.0 Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox Currently P2P mode of OpenVPN is on of the few places that cannot negotiate modern OpenVPN features. This becomes more and more problematic since P2P and P2MP code diverge more and more and also the lack of switching to more advanced features like Data v2 currently blocks P2P mode from working together with the upcoming ovpn-dco support. This NCP support is a lot simpler and works in the following way: - P2P peer announce an extremely limited IV_ variable set (IV_PROTO and IV_CIPHERS) - Both peers check if the IV_PROTO_NCP_P2P bit is present in IV_PROTO - if yes both sides deterministically determine according to IV_PROTO and IV_CIPHER what options can be used and start using these There are no poor man's NCP or other compatibility workaround like in the normal NCP, making this NCP leanear and more deterministic. Signed-off-by: Arne Schwabe --- src/openvpn/init.c | 100 ++++++++++++++--- src/openvpn/options.c | 8 +- src/openvpn/ssl.c | 168 +++++++++++++++++++--------- src/openvpn/ssl.h | 5 + src/openvpn/ssl_backend.h | 1 + src/openvpn/ssl_common.h | 10 ++ src/openvpn/ssl_ncp.c | 145 ++++++++++++++++++++++++ src/openvpn/ssl_ncp.h | 25 +++++ tests/unit_tests/openvpn/test_ncp.c | 11 ++ 9 files changed, 403 insertions(+), 70 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 4a6b84914..11ac8b776 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -68,6 +68,7 @@ static const char *saved_pid_file_name; /* GLOBAL */ #define CF_INIT_TLS_AUTH_STANDALONE (1<<2) static void do_init_first_time(struct context *c); +static bool do_deferred_p2p_ncp(struct context *c); void context_clear(struct context *c) @@ -2151,6 +2152,14 @@ do_up(struct context *c, bool pulled_options, unsigned int option_types_found) return false; } } + else if (c->mode == MODE_POINT_TO_POINT) + { + if (!do_deferred_p2p_ncp(c)) + { + msg(D_TLS_ERRORS, "ERROR: Failed to apply P2P negotiated protocol options"); + return false; + } + } /* if --up-delay specified, open tun, do ifconfig, and run up script now */ if (c->options.up_delay || PULL_DEFINED(&c->options)) @@ -2237,6 +2246,72 @@ pull_permission_mask(const struct context *c) return flags; } +static +void adjust_mtu_peerid(struct context *c) +{ + frame_add_to_extra_frame(&c->c2.frame, +3); /* peer-id overhead */ + if (!c->options.ce.link_mtu_defined) + { + frame_add_to_link_mtu(&c->c2.frame, +3); + msg(D_PUSH, "OPTIONS IMPORT: adjusting link_mtu to %d", + EXPANDED_SIZE(&c->c2.frame)); + } + else + { + msg(M_WARN, "OPTIONS IMPORT: WARNING: peer-id set, but link-mtu" + " fixed by config - reducing tun-mtu to %d, expect" + " MTU problems", TUN_MTU_SIZE(&c->c2.frame) ); + } +} + +static bool +do_deferred_p2p_ncp(struct context *c) +{ + + if (!c->c2.tls_multi) + { + return true; + } + + if (c->c2.tls_multi->use_peer_id) + { + adjust_mtu_peerid(c); + } + + struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; + + const char *ncp_cipher = get_p2p_ncp_cipher(session, c->c2.tls_multi->peer_info, + &c->options.gc); + + if (ncp_cipher) + { + c->options.ciphername = ncp_cipher; + } + else if (!c->options.enable_ncp_fallback) + { + msg(D_TLS_ERRORS, "ERROR: failed to negotiate cipher with peer and " + "--data-ciphers-fallback not enabled. No useable " + "data channel cipher"); + return false; + } + + struct frame *frame_fragment = NULL; +#ifdef ENABLE_FRAGMENT + if (c->options.ce.fragment) + { + frame_fragment = &c->c2.frame_fragment; + } +#endif + + if (!tls_session_update_crypto_params(session, &c->options, &c->c2.frame, + frame_fragment)) + { + msg(D_TLS_ERRORS, "ERROR: failed to set crypto cipher"); + return false; + } + return true; +} + /* * Handle non-tun-related pulled options. */ @@ -2324,19 +2399,7 @@ do_deferred_options(struct context *c, const unsigned int found) msg(D_PUSH, "OPTIONS IMPORT: peer-id set"); c->c2.tls_multi->use_peer_id = true; c->c2.tls_multi->peer_id = c->options.peer_id; - frame_add_to_extra_frame(&c->c2.frame, +3); /* peer-id overhead */ - if (!c->options.ce.link_mtu_defined) - { - frame_add_to_link_mtu(&c->c2.frame, +3); - msg(D_PUSH, "OPTIONS IMPORT: adjusting link_mtu to %d", - EXPANDED_SIZE(&c->c2.frame)); - } - else - { - msg(M_WARN, "OPTIONS IMPORT: WARNING: peer-id set, but link-mtu" - " fixed by config - reducing tun-mtu to %d, expect" - " MTU problems", TUN_MTU_SIZE(&c->c2.frame) ); - } + adjust_mtu_peerid(c); } /* process (potentially pushed) crypto options */ @@ -2865,16 +2928,21 @@ do_init_crypto_tls(struct context *c, const unsigned int flags) to.pull = options->pull; if (options->push_peer_info) /* all there is */ { - to.push_peer_info_detail = 2; + to.push_peer_info_detail = 3; } else if (options->pull) /* pull clients send some details */ { - to.push_peer_info_detail = 1; + to.push_peer_info_detail = 2; } - else /* default: no peer-info at all */ + else if (options->mode == MODE_SERVER) /* server: no peer info at all */ { to.push_peer_info_detail = 0; } + else /* default: minimal info to allow NCP in P2P mode */ + { + to.push_peer_info_detail = 1; + } + /* should we not xmit any packets until we get an initial * response from client? */ diff --git a/src/openvpn/options.c b/src/openvpn/options.c index e2759a1ac..26489becb 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -3057,10 +3057,6 @@ options_postprocess_cipher(struct options *o) { if (!o->pull && !(o->mode == MODE_SERVER)) { - /* we are in the classic P2P mode */ - msg( M_WARN, "Cipher negotiation is disabled since neither " - "P2MP client nor server mode is enabled"); - /* If the cipher is not set, use the old default of BF-CBC. We will * warn that this is deprecated on cipher initialisation, no need * to warn here as well */ @@ -3068,6 +3064,10 @@ options_postprocess_cipher(struct options *o) { o->ciphername = "BF-CBC"; } + else + { + o->enable_ncp_fallback = true; + } return; } diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 068b66616..20acf65ea 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1836,33 +1836,18 @@ cleanup: return ret; } + bool -tls_session_update_crypto_params(struct tls_session *session, - struct options *options, struct frame *frame, +tls_session_update_crypto_params_do_work(struct tls_session *session, + struct options* options, struct frame *frame, struct frame *frame_fragment) { if (session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized) { /* keys already generated, nothing to do */ return true; - } - - bool cipher_allowed_as_fallback = options->enable_ncp_fallback - && streq(options->ciphername, session->opt->config_ciphername); - if (!session->opt->server && !cipher_allowed_as_fallback - && !tls_item_in_cipher_list(options->ciphername, options->ncp_ciphers)) - { - msg(D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s", - options->ciphername, options->ncp_ciphers); - /* undo cipher push, abort connection setup */ - options->ciphername = session->opt->config_ciphername; - return false; } - - /* Import crypto settings that might be set by pull/push */ - session->opt->crypto_flags |= options->data_channel_crypto_flags; - if (strcmp(options->ciphername, session->opt->config_ciphername)) { msg(D_HANDSHAKE, "Data Channel: using negotiated cipher '%s'", @@ -1914,6 +1899,32 @@ tls_session_update_crypto_params(struct tls_session *session, return tls_session_generate_data_channel_keys(session); } +bool +tls_session_update_crypto_params(struct tls_session *session, + struct options *options, struct frame *frame, + struct frame *frame_fragment) +{ + + bool cipher_allowed_as_fallback = options->enable_ncp_fallback + && streq(options->ciphername, session->opt->config_ciphername); + + if (!session->opt->server && !cipher_allowed_as_fallback + && !tls_item_in_cipher_list(options->ciphername, options->ncp_ciphers)) + { + msg(D_TLS_ERRORS, "Error: negotiated cipher not allowed - %s not in %s", + options->ciphername, options->ncp_ciphers); + /* undo cipher push, abort connection setup */ + options->ciphername = session->opt->config_ciphername; + return false; + } + + /* Import crypto settings that might be set by pull/push */ + session->opt->crypto_flags |= options->data_channel_crypto_flags; + + return tls_session_update_crypto_params_do_work(session, options, frame, frame_fragment); +} + + static bool random_bytes_to_buf(struct buffer *buf, uint8_t *out, @@ -2107,12 +2118,10 @@ push_peer_info(struct buffer *buf, struct tls_session *session) { struct gc_arena gc = gc_new(); bool ret = false; + struct buffer out = alloc_buf_gc(512 * 3, &gc); - if (session->opt->push_peer_info_detail > 0) + if (session->opt->push_peer_info_detail > 1) { - struct env_set *es = session->opt->es; - struct buffer out = alloc_buf_gc(512*3, &gc); - /* push version */ buf_printf(&out, "IV_VER=%s\n", PACKAGE_VERSION); @@ -2134,7 +2143,11 @@ push_peer_info(struct buffer *buf, struct tls_session *session) #elif defined(_WIN32) buf_printf(&out, "IV_PLAT=win\n"); #endif + } + /* These are the IV variable that are sent to peers in p2p mode */ + if (session->opt->push_peer_info_detail > 0) + { /* support for P_DATA_V2 */ int iv_proto = IV_PROTO_DATA_V2; @@ -2157,19 +2170,28 @@ push_peer_info(struct buffer *buf, struct tls_session *session) buf_printf(&out, "IV_NCP=2\n"); } - buf_printf(&out, "IV_CIPHERS=%s\n", session->opt->config_ncp_ciphers); + } + else + { + /* We are not using pull or p2mp server, instead do P2P NCP */ + iv_proto |= IV_PROTO_NCP_P2P; + } + + buf_printf(&out, "IV_CIPHERS=%s\n", session->opt->config_ncp_ciphers); #ifdef HAVE_EXPORT_KEYING_MATERIAL - iv_proto |= IV_PROTO_TLS_KEY_EXPORT; + iv_proto |= IV_PROTO_TLS_KEY_EXPORT; #endif - } buf_printf(&out, "IV_PROTO=%d\n", iv_proto); - /* push compression status */ + if (session->opt->push_peer_info_detail > 1) + { + /* push compression status */ #ifdef USE_COMP - comp_generate_peer_info_string(&session->opt->comp_options, &out); + comp_generate_peer_info_string(&session->opt->comp_options, &out); #endif + } if (session->opt->push_peer_info_detail >= 2) { @@ -2186,24 +2208,29 @@ push_peer_info(struct buffer *buf, struct tls_session *session) #endif } - /* push env vars that begin with UV_, IV_PLAT_VER and IV_GUI_VER */ - for (struct env_item *e = es->list; e != NULL; e = e->next) + if (session->opt->push_peer_info_detail > 1) { - if (e->string) + struct env_set *es = session->opt->es; + /* push env vars that begin with UV_, IV_PLAT_VER and IV_GUI_VER */ + for (struct env_item *e = es->list; e != NULL; e = e->next) { - if ((((strncmp(e->string, "UV_", 3)==0 - || strncmp(e->string, "IV_PLAT_VER=", sizeof("IV_PLAT_VER=")-1)==0) - && session->opt->push_peer_info_detail >= 2) - || (strncmp(e->string,"IV_GUI_VER=",sizeof("IV_GUI_VER=")-1)==0) - || (strncmp(e->string,"IV_SSO=",sizeof("IV_SSO=")-1)==0) - ) - && buf_safe(&out, strlen(e->string)+1)) + if (e->string) { - buf_printf(&out, "%s\n", e->string); + if ((((strncmp(e->string, "UV_", 3) == 0 + || strncmp(e->string, "IV_PLAT_VER=", sizeof("IV_PLAT_VER=") - 1) == 0) + && session->opt->push_peer_info_detail >= 2) + || (strncmp(e->string, "IV_GUI_VER=", sizeof("IV_GUI_VER=") - 1) == 0) + || (strncmp(e->string, "IV_SSO=", sizeof("IV_SSO=") - 1) == 0) + ) + && buf_safe(&out, strlen(e->string) + 1)) + { + buf_printf(&out, "%s\n", e->string); + } } } } + if (!write_string(buf, BSTR(&out), -1)) { goto error; @@ -2342,19 +2369,47 @@ key_method_2_write(struct buffer *buf, struct tls_multi *multi, struct tls_sessi goto error; } - /* Generate tunnel keys if we're a TLS server. + /* + * Generate tunnel keys if we're a TLS server. + * * If we're a p2mp server and IV_NCP >= 2 is negotiated, the first key * generation is postponed until after the pull/push, so we can process pushed * cipher directives. + * + * Generate tunnel keys if are not using NCP as TLS server. + * + * If we're a p2mp server to allow NCP, the first key + * generation is postponed until after the connect script finished and the + * NCP options can be processed. Since that always happens at after connect + * script options are available the CAS_SUCCEEDED status is identical to + * NCP options are processed and we have no extra state for NCP finished. + * + * As P2P TLS server we also postpone the key generation just long enough + * until the TLS session is fully established. */ - if (session->opt->server && !(session->opt->mode == MODE_SERVER && ks->key_id <= 0)) + if (session->opt->server) { - if (ks->authenticated > KS_AUTH_FALSE) + if(session->opt->mode != MODE_SERVER && ks->key_id == 0) { - if (!tls_session_generate_data_channel_keys(session)) + /* tls-server option set and not P2MP server, so we + * are a P2P client running in tls-server mode */ + p2p_mode_ncp(multi, session); + } + else if ((session->opt->mode == MODE_SERVER && multi->multi_state == CAS_SUCCEEDED) + || ks->key_id > 0) + { + /* if key_id >= 1, is a renegotiation, so we use the already established + * parameters and do not need to delay anything. */ + + /* key-id == 0 and context_auth == CAS_SUCCEEDED is a special case of + * the server reusing the session of a reconnecting client. */ + if (ks->authenticated > KS_AUTH_FALSE) { - msg(D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed"); - goto error; + if (!tls_session_generate_data_channel_keys(session)) + { + msg(D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed"); + goto error; + } } } } @@ -2561,15 +2616,28 @@ key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_sessio /* * Generate tunnel keys if we're a client. - * If --pull is enabled, the first key generation is postponed until after the - * pull/push, so we can process pushed cipher directives. + * If NCP is enabled, the first key generation is postponed until the TLS + * handshake has completed or even further delayed or after the pull + * response so we initialise the cipher after it is negotiated. + * */ - if (!session->opt->server && (!session->opt->pull || ks->key_id > 0)) + if (!session->opt->server) { - if (!tls_session_generate_data_channel_keys(session)) + if (!session->opt->pull && ks->key_id == 0) { - msg(D_TLS_ERRORS, "TLS Error: client generate_key_expansion failed"); - goto error; + /* We are a p2p tls-client without pull with NCP, enable common + * protocol options */ + p2p_mode_ncp(multi, session); + } + else if (ks->key_id > 0) + { + /* if key_id >= 1, is a renogiation, so we use the channel + * paramter and do not need to delay anything */ + if (!tls_session_generate_data_channel_keys(session)) + { + msg(D_TLS_ERRORS, "TLS Error: client generate_key_expansion failed"); + goto error; + } } } diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index 300a70d35..f39d9d788 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -122,6 +122,11 @@ /** Supports signaling keywords with AUTH_PENDING, e.g. timeout=xy */ #define IV_PROTO_AUTH_PENDING_KW (1<<4) +/** Support doing NCP in P2P mode. This mode works by both peers looking at + * each other's IV_ variables and deterministically deciding both on the same + * result. */ +#define IV_PROTO_NCP_P2P (1<<5) + /* Default field in X509 to be username */ #define X509_USERNAME_FIELD_DEFAULT "CN" diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h index c3d12e5be..d228c70d8 100644 --- a/src/openvpn/ssl_backend.h +++ b/src/openvpn/ssl_backend.h @@ -390,6 +390,7 @@ void backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, bool crl_inline); #define EXPORT_KEY_DATA_LABEL "EXPORTER-OpenVPN-datakeys" +#define EXPORT_P2P_PEERID_LABEL "EXPORTER-OpenVPN-p2p-peerid" /** * Keying Material Exporters [RFC 5705] allows additional keying material to be * derived from existing TLS channel. This exported keying material can then be diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 3f8dd0178..9404be939 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -271,6 +271,16 @@ struct tls_options bool disable_occ; int mode; bool pull; + /** + * The detail of info we push in peer info + * + * 0 - nothing at all, P2MP server only + * 1 - only the most basic information to negotiate cipher and features + * for P2P NCP + * 2 - normal setting for clients + * 3 - full information including "sensitive data" like IV_HWADDR + * enabled by --push-peer-info + */ int push_peer_info_detail; int transition_window; int handshake_window; diff --git a/src/openvpn/ssl_ncp.c b/src/openvpn/ssl_ncp.c index 722256b42..8850ba237 100644 --- a/src/openvpn/ssl_ncp.c +++ b/src/openvpn/ssl_ncp.c @@ -324,3 +324,148 @@ check_pull_client_ncp(struct context *c, const int found) return false; } } + +const char* +get_p2p_ncp_cipher(struct tls_session *session, const char *peer_info, + struct gc_arena *gc) +{ + /* we use a local gc arena to keep the temporary strings needed by strsep */ + struct gc_arena gc_local = gc_new(); + const char *peer_ciphers = extract_var_peer_info(peer_info, "IV_CIPHERS=", &gc_local); + + if (!peer_ciphers) + { + gc_free(&gc_local); + return NULL; + } + + const char* server_ciphers; + const char* client_ciphers; + + if (session->opt->server) + { + server_ciphers = session->opt->config_ncp_ciphers; + client_ciphers = peer_ciphers; + } + else + { + client_ciphers = session->opt->config_ncp_ciphers; + server_ciphers = peer_ciphers; + } + + /* Find the first common cipher from TLS server and TLS client. We + * use the preference of the server here to make it deterministic */ + char *tmp_ciphers = string_alloc(server_ciphers, &gc_local); + + const char *token; + while ((token = strsep(&tmp_ciphers, ":"))) + { + if (tls_item_in_cipher_list(token, client_ciphers)) + { + break; + } + } + + const char *ret = NULL; + if (token != NULL) + { + const char *chosen_cipher = string_alloc(token, gc); + ret = chosen_cipher; + } + gc_free(&gc_local); + + return ret; +} + +static void +p2p_ncp_set_options(struct tls_multi *multi, struct tls_session *session) +{ + /* will return 0 if peer_info is null */ + const unsigned int iv_proto_peer = extract_iv_proto(multi->peer_info); + + /* The other peer does not support P2P NCP */ + if (!(iv_proto_peer & IV_PROTO_NCP_P2P)) + { + return; + } + + if (iv_proto_peer & IV_PROTO_DATA_V2) + { + multi->use_peer_id = true; + multi->peer_id = 0x76706e; // 'v' 'p' 'n' + + } + +#if defined(HAVE_EXPORT_KEYING_MATERIAL) + if (iv_proto_peer & IV_PROTO_TLS_KEY_EXPORT) + { + session->opt->crypto_flags |= CO_USE_TLS_KEY_MATERIAL_EXPORT; + + if (multi->use_peer_id) + { + /* Using a non hardcoded peer-id makes a tiny bit harder to + * fingerprint packets and also gives each connection a unique + * peer-id that can be useful for NAT tracking etc. */ + + uint8_t peerid[3]; + if (!key_state_export_keying_material(session, EXPORT_P2P_PEERID_LABEL, + strlen(EXPORT_P2P_PEERID_LABEL), + &peerid, 3)) + { + /* Non DCO setup might still work but also this should never + * happen or very likely the TLS encryption key exporter will + * also fail */ + msg(M_NONFATAL, "TLS key export for P2P peer id failed. " + "Continuing anyway, expect problems"); + } + else + { + multi->peer_id = (peerid[0] << 16) + (peerid[1] << 8) + peerid[2]; + } + + } + } +#endif +} + +void +p2p_mode_ncp(struct tls_multi *multi, struct tls_session *session) +{ + /* Set the common options */ + p2p_ncp_set_options(multi, session); + + struct gc_arena gc = gc_new(); + + /* Query the common cipher here to log it as part of our message. + * We postpone switching the cipher to do_up */ + const char* common_cipher = get_p2p_ncp_cipher(session, multi->peer_info, &gc); + + if (!common_cipher) + { + struct buffer out = alloc_buf_gc(128, &gc); + struct key_state *ks = get_key_scan(multi, KS_PRIMARY); + + const cipher_ctx_t *ctx = ks->crypto_options.key_ctx_bi.encrypt.cipher; + const cipher_kt_t *cipher = cipher_ctx_get_cipher_kt(ctx); + const char *fallback_name = cipher_kt_name(cipher); + + if (!cipher) + { + /* at this point we do not really know if our fallback is + * not enabled or if we use 'none' cipher as fallback, so + * keep this ambiguity here and print fallback-cipher: none + */ + fallback_name = "none"; + } + + buf_printf(&out, "(not negotiated, fallback-cipher: %s)", fallback_name); + common_cipher = BSTR(&out); + } + + msg(D_TLS_DEBUG_LOW, "P2P mode NCP negotiation result: " + "TLS_export=%d, DATA_v2=%d, peer-id %d, cipher=%s", + (bool)(session->opt->crypto_flags & CO_USE_TLS_KEY_MATERIAL_EXPORT), + multi->use_peer_id, multi->peer_id, common_cipher); + + gc_free(&gc); +} \ No newline at end of file diff --git a/src/openvpn/ssl_ncp.h b/src/openvpn/ssl_ncp.h index 39158a568..c02be6939 100644 --- a/src/openvpn/ssl_ncp.h +++ b/src/openvpn/ssl_ncp.h @@ -32,6 +32,7 @@ #include "buffer.h" #include "options.h" +#include "ssl_common.h" /** * Returns whether the client supports NCP either by @@ -115,4 +116,28 @@ bool tls_item_in_cipher_list(const char *item, const char *list); */ #define MAX_NCP_CIPHERS_LENGTH 127 +/** + * Determines if there is common cipher of both peer by looking at the + * IV_CIPHER peer info. In contrast of the server mode NCP that tries to + * accomandate all kind of corner cases in P2P mode NCP only takes IV_CIPHER + * into account and falls back to previous behaviour if this fails. + */ +void p2p_mode_ncp(struct tls_multi *multi, struct tls_session *session); + +/** + * Determines the best common cipher from both peers IV_CIPHER lists. The + * first cipher from the tls-server that is also in the tls-client IV_CIPHER + * list will be returned. If no common cipher can be found, both peer + * will continue to use whatever cipher is their default and NULL will be + * returned. + * + * @param session tls_session + * @param peer_info peer info of the peer + * @param gc gc arena that will be used to allocate the returned cipher + * @return common cipher if one exist. + */ +const char * +get_p2p_ncp_cipher(struct tls_session *session, const char *peer_info, + struct gc_arena *gc); + #endif /* ifndef OPENVPN_SSL_NCP_H */ diff --git a/tests/unit_tests/openvpn/test_ncp.c b/tests/unit_tests/openvpn/test_ncp.c index 4077be5e8..9dcd6f0a7 100644 --- a/tests/unit_tests/openvpn/test_ncp.c +++ b/tests/unit_tests/openvpn/test_ncp.c @@ -44,6 +44,17 @@ const char *bf_chacha = "BF-CBC:CHACHA20-POLY1305"; const char *aes_ciphers = "AES-256-GCM:AES-128-GCM"; + +/* Define this function here as dummy since including the ssl_*.c files + * leads to having to include even more unrelated code */ +bool +key_state_export_keying_material(struct tls_session *session, + const char* label, size_t label_size, + void *ekm, size_t ekm_size) +{ + ASSERT(0); +} + static void test_check_ncp_ciphers_list(void **state) { From patchwork Thu Apr 8 04:02:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 1729 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director12.mail.ord1d.rsapps.net ([172.31.255.6]) by backend30.mail.ord1d.rsapps.net with LMTP id eGjqG0YNb2BkHAAAIUCqbw (envelope-from ) for ; Thu, 08 Apr 2021 10:03:50 -0400 Received: from proxy11.mail.iad3b.rsapps.net ([172.31.255.6]) by director12.mail.ord1d.rsapps.net with LMTP id WCSVG0YNb2CXLAAAIasKDg (envelope-from ) for ; Thu, 08 Apr 2021 10:03:50 -0400 Received: from smtp37.gate.iad3b ([172.31.255.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy11.mail.iad3b.rsapps.net with LMTPS id IC8lE0YNb2BiAQAARNREpw (envelope-from ) for ; Thu, 08 Apr 2021 10:03:50 -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: smtp37.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: 3c4e4b0e-9873-11eb-82d5-5254002ca64a-1-1 Received: from [216.105.38.7] ([216.105.38.7:53748] helo=lists.sourceforge.net) by smtp37.gate.iad3b.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 37/22-09035-34D0F606; Thu, 08 Apr 2021 10:03:48 -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.92.3) (envelope-from ) id 1lUVFU-0005Kz-M3; Thu, 08 Apr 2021 14:03:08 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.3) (envelope-from ) id 1lUVFR-0005KJ-Hv for openvpn-devel@lists.sourceforge.net; Thu, 08 Apr 2021 14:03:05 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=References:In-Reply-To:Message-Id:Date:Subject:To: From:Sender:Reply-To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding: 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=w4zj9GckfHZ2XGZYag3gH+jM6KF3CBmdsxqIwL/uqrA=; b=keB2VvXN2J2om66LAOcHNC8RXt v8tSHz5w0scpt2xhIlogvXKHDKBXd/0hvXvTmZ4hB+Pz92OabxOCyOP2F2nYFaiPd3m+xzrtxyC+V pDD/FH9gDykiAzf8dSioZXxyugb7ozazcDiwh8pnGKC5Jzjd0gKe+SM7fomdY835vWMg=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=References:In-Reply-To:Message-Id:Date:Subject:To:From:Sender:Reply-To:Cc :MIME-Version:Content-Type:Content-Transfer-Encoding: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=w4zj9GckfHZ2XGZYag3gH+jM6KF3CBmdsxqIwL/uqrA=; b=Ca43+dtwZeCyG1Is8ikOop/7hz Y6uNB8CGBl8YiYxuF2IH2ZQeI4aDfng5Fb3mjfGuK9sdR2lb2ewWKgyElcAEn6yEugRFetTAOaTq9 HAG+SKVrzPjft5uitSj4kLsaVh8oZ2bv9fohYTEDJjBrclOmQEZxDwn/BmeieahCOhEo=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.3) id 1lUVF4-0002nY-Qw for openvpn-devel@lists.sourceforge.net; Thu, 08 Apr 2021 14:03:05 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.94 (FreeBSD)) (envelope-from ) id 1lUVEr-000DZN-HP for openvpn-devel@lists.sourceforge.net; Thu, 08 Apr 2021 16:02:29 +0200 Received: (nullmailer pid 31883 invoked by uid 10006); Thu, 08 Apr 2021 14:02:29 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Thu, 8 Apr 2021 16:02:29 +0200 Message-Id: <20210408140229.31824-5-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210408140229.31824-1-arne@rfc2549.org> References: <20210408140229.31824-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 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 0.0 TIME_LIMIT_EXCEEDED Exceeded time limit / deadline X-Headers-End: 1lUVF4-0002nY-Qw Subject: [Openvpn-devel] [PATCH 4/4] Implement deferred auth for scripts 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: , MIME-Version: 1.0 Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox This patch also refactors the if condition that checks the result of the authentication since that has become quite unreadable. It renames s1/s2 and extracts some parts of the condition into individual variables to make the condition better understandle Patch v2: add refactoring of the if condition Patch v4: fix documentation not mentioning method as 2nd line Patch v5: fix deferred auth used by both plugin and script not working Patch v6: Add missing async inotify for script deferred auth Signed-off-by: Arne Schwabe --- Changes.rst | 10 +++ doc/man-sections/script-options.rst | 14 +++- src/openvpn/multi.c | 6 ++ src/openvpn/ssl.c | 1 + src/openvpn/ssl_common.h | 1 + src/openvpn/ssl_verify.c | 105 ++++++++++++++++++++-------- 6 files changed, 106 insertions(+), 31 deletions(-) diff --git a/Changes.rst b/Changes.rst index d6ccc1c92..e7ae6abed 100644 --- a/Changes.rst +++ b/Changes.rst @@ -30,6 +30,16 @@ TLS mode with self-signed certificates become optional. This allows for small OpenVPN setups without setting up a PKI with Easy-RSA or similar software. +Deferred auth support for scripts + The ``--auth-user-pass-verify`` script supports now deferred authentication. + +Pending auth support for plugins and scripts + Both auth plugin and script can now signal pending authentication to + the client when using deferred authentication. The new ``client-crresponse`` + script option and ``OPENVPN_PLUGIN_CLIENT_CRRESPONSE`` plugin function can + be used to parse a client response to a ``CR_TEXT`` two factor challenge. + + See ``sample/sample-scripts/totpauth.py`` for an example. Deprecated features ------------------- diff --git a/doc/man-sections/script-options.rst b/doc/man-sections/script-options.rst index 03b3dd77b..22990f4f4 100644 --- a/doc/man-sections/script-options.rst +++ b/doc/man-sections/script-options.rst @@ -90,7 +90,19 @@ SCRIPT HOOKS The script should examine the username and password, returning a success exit code (:code:`0`) if the client's authentication request is to be - accepted, or a failure code (:code:`1`) to reject the client. + accepted, a failure code (:code:`1`) to reject the client, or a that + the authentication is deferred (:code:`2`). If the authentication is + deferred, the script must fork/start a background or another non-blocking + operation to continue the authentication in the background. When finshing + the authentication, a :code:`1` or :code:`0` must be written to the + file specified by the :code:`auth_control_file`. + + When deferred authentication is in use, the script can also request + pending authentication by writing to the file specified by the + :code:`auth_pending_file`. The first line must be the timeout in + seconds, the required method on the second line (e.g. crtext) and + third line must be the EXTRA as documented in the + ``client-pending-auth`` section of `doc/management.txt`. This directive is designed to enable a plugin-style interface for extending OpenVPN's authentication capabilities. diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index ee3ee6ced..eba80ee59 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -2989,6 +2989,12 @@ multi_process_post(struct multi_context *m, struct multi_instance *mi, const uns add_inotify_file_watch(m, mi, m->top.c2.inotify_fd, ks->plugin_auth.auth_control_file); } + if (ks && ks->script_auth.auth_control_file && was_unauthenticated + && (ks->authenticated == KS_AUTH_DEFERRED)) + { + add_inotify_file_watch(m, mi, m->top.c2.inotify_fd, + ks->script_auth.auth_control_file); + } #endif if (!IS_SIG(&mi->context)) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index c28818b6e..6e53a3be4 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -994,6 +994,7 @@ key_state_free(struct key_state *ks, bool clear) packet_id_free(&ks->crypto_options.packet_id); key_state_rm_auth_control_files(&ks->plugin_auth); + key_state_rm_auth_control_files(&ks->script_auth); if (clear) { diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 824dac310..f85131ee7 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -222,6 +222,7 @@ struct key_state time_t acf_last_mod; struct auth_deferred_status plugin_auth; + struct auth_deferred_status script_auth; }; /** Control channel wrapping (--tls-auth/--tls-crypt) context */ diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index 7608155cd..7c02d46ce 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -1102,20 +1102,25 @@ tls_authentication_status(struct tls_multi *multi, const int latency) } else { - unsigned int s1 = ACF_DISABLED; - unsigned int s2 = ACF_DISABLED; - s1 = key_state_test_auth_control_file(&ks->plugin_auth); + unsigned int auth_plugin = ACF_DISABLED; + unsigned int auth_script = ACF_DISABLED; + unsigned int auth_man = ACF_DISABLED; + auth_plugin = key_state_test_auth_control_file(&ks->plugin_auth); + auth_script = key_state_test_auth_control_file(&ks->script_auth); #ifdef ENABLE_MANAGEMENT - s2 = man_def_auth_test(ks); + auth_man = man_def_auth_test(ks); #endif - ASSERT(s1 < 4 && s2 < 4); + ASSERT(auth_plugin < 4 && auth_script < 4 && auth_man < 4); - if (s1 == ACF_FAILED || s2 == ACF_FAILED) + if (auth_plugin == ACF_FAILED || auth_script == ACF_FAILED + || auth_man == ACF_FAILED) { ks->authenticated = KS_AUTH_FALSE; failed_auth = true; } - else if (s1 == ACF_UNDEFINED || s2 == ACF_UNDEFINED) + else if (auth_plugin == ACF_UNDEFINED + || auth_script == ACF_UNDEFINED + || auth_man == ACF_UNDEFINED) { if (now < ks->auth_deferred_expire) { @@ -1124,7 +1129,7 @@ tls_authentication_status(struct tls_multi *multi, const int latency) } else { - /* s1 and s2 are either ACF_DISABLED or ACF_SUCCEDED */ + /* auth_plugin and auth_man are either ACF_DISABLED or ACF_SUCCEDED */ success = true; ks->authenticated = KS_AUTH_TRUE; } @@ -1204,14 +1209,15 @@ tls_authenticate_key(struct tls_multi *multi, const unsigned int mda_key_id, con /* * Verify the user name and password using a script */ -static bool +static int verify_user_pass_script(struct tls_session *session, struct tls_multi *multi, const struct user_pass *up) { struct gc_arena gc = gc_new(); struct argv argv = argv_new(); const char *tmp_file = ""; - bool ret = false; + int retval = OPENVPN_PLUGIN_FUNC_ERROR; + struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ /* Set environmental variables prior to calling script */ setenv_str(session->opt->es, "script_type", "user-pass-verify"); @@ -1239,25 +1245,58 @@ verify_user_pass_script(struct tls_session *session, struct tls_multi *multi, /* pass temp file name to script */ argv_printf_cat(&argv, "%s", tmp_file); } - else - { - msg(D_TLS_ERRORS, "TLS Auth Error: could not create write " - "username/password to temp file"); - } } else { + setenv_str(session->opt->es, "username", up->username); setenv_str(session->opt->es, "password", up->password); } + /* generate filename for deferred auth control file */ + if (!key_state_gen_auth_control_files(&ks->script_auth, session->opt)) + { + msg(D_TLS_ERRORS, "TLS Auth Error (%s): " + "could not create deferred auth control file", __func__); + return OPENVPN_PLUGIN_FUNC_ERROR; + } + /* call command */ - ret = openvpn_run_script(&argv, session->opt->es, 0, - "--auth-user-pass-verify"); + int script_ret = openvpn_run_script(&argv, session->opt->es, S_EXITCODE, + "--auth-user-pass-verify"); + switch (script_ret) + { + case 0: + retval = OPENVPN_PLUGIN_FUNC_SUCCESS; + break; + case 2: + retval = OPENVPN_PLUGIN_FUNC_DEFERRED; + break; + default: + retval = OPENVPN_PLUGIN_FUNC_ERROR; + break; + } + if (retval == OPENVPN_PLUGIN_FUNC_DEFERRED) + { + /* Check if we the plugin has written the pending auth control + * file and send the pending auth to the client */ + if(!key_state_check_auth_pending_file(&ks->script_auth, + multi)) + { + retval = OPENVPN_PLUGIN_FUNC_ERROR; + key_state_rm_auth_control_files(&ks->script_auth); + } + } + else + { + /* purge auth control filename (and file itself) for non-deferred returns */ + key_state_rm_auth_control_files(&ks->script_auth); + } if (!session->opt->auth_user_pass_verify_script_via_file) { setenv_del(session->opt->es, "password"); } + done: if (tmp_file && strlen(tmp_file) > 0) { @@ -1266,7 +1305,7 @@ done: argv_free(&argv); gc_free(&gc); - return ret; + return retval; } /* @@ -1387,8 +1426,6 @@ void verify_user_pass(struct user_pass *up, struct tls_multi *multi, struct tls_session *session) { - int s1 = OPENVPN_PLUGIN_FUNC_SUCCESS; - bool s2 = true; struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ #ifdef ENABLE_MANAGEMENT @@ -1448,30 +1485,32 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, } } + int plugin_status = OPENVPN_PLUGIN_FUNC_SUCCESS; + int script_status = OPENVPN_PLUGIN_FUNC_SUCCESS; /* Set the environment variables used by all auth variants */ if (!set_verify_user_pass_env(up, multi, session)) { skip_auth = true; - s1 = OPENVPN_PLUGIN_FUNC_ERROR; + plugin_status = OPENVPN_PLUGIN_FUNC_ERROR; } /* call plugin(s) and/or script */ if (!skip_auth) { #ifdef ENABLE_MANAGEMENT - if (man_def_auth==KMDA_DEF) + if (man_def_auth == KMDA_DEF) { man_def_auth = verify_user_pass_management(session, multi, up); } #endif if (plugin_defined(session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)) { - s1 = verify_user_pass_plugin(session, multi, up); + plugin_status = verify_user_pass_plugin(session, multi, up); } if (session->opt->auth_user_pass_verify_script) { - s2 = verify_user_pass_script(session, multi, up); + script_status = verify_user_pass_script(session, multi, up); } } @@ -1482,19 +1521,25 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, msg(D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_USERNAME_LEN); - s1 = OPENVPN_PLUGIN_FUNC_ERROR; + plugin_status = OPENVPN_PLUGIN_FUNC_ERROR; + script_status = OPENVPN_PLUGIN_FUNC_ERROR; } /* auth succeeded? */ - if ((s1 == OPENVPN_PLUGIN_FUNC_SUCCESS - || s1 == OPENVPN_PLUGIN_FUNC_DEFERRED - ) && s2 + bool plugin_ok = plugin_status == OPENVPN_PLUGIN_FUNC_SUCCESS + || plugin_status == OPENVPN_PLUGIN_FUNC_DEFERRED; + + bool script_ok = script_status == OPENVPN_PLUGIN_FUNC_SUCCESS + || script_status == OPENVPN_PLUGIN_FUNC_DEFERRED; + + if (script_ok && plugin_ok && tls_lock_username(multi, up->username) #ifdef ENABLE_MANAGEMENT && man_def_auth != KMDA_ERROR #endif - && tls_lock_username(multi, up->username)) + ) { ks->authenticated = KS_AUTH_TRUE; - if (s1 == OPENVPN_PLUGIN_FUNC_DEFERRED) + if (plugin_status == OPENVPN_PLUGIN_FUNC_DEFERRED + || script_status == OPENVPN_PLUGIN_FUNC_DEFERRED) { ks->authenticated = KS_AUTH_DEFERRED; }