From patchwork Sun Nov 17 07:12:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 924 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director11.mail.ord1d.rsapps.net ([172.31.255.6]) by backend30.mail.ord1d.rsapps.net with LMTP id 6FRaDviN0V3jcgAAIUCqbw for ; Sun, 17 Nov 2019 13:14:16 -0500 Received: from proxy10.mail.iad3b.rsapps.net ([172.31.255.6]) by director11.mail.ord1d.rsapps.net with LMTP id CCHVC/iN0V3OXAAAvGGmqA ; Sun, 17 Nov 2019 13:14:16 -0500 Received: from smtp24.gate.iad3b ([172.31.255.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy10.mail.iad3b.rsapps.net with LMTP id KEi7BviN0V1bKAAA/F5p9A ; Sun, 17 Nov 2019 13:14:16 -0500 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: 101c1a9a-0966-11ea-ac7a-525400892b35-1-1 Received: from [216.105.38.7] ([216.105.38.7:34222] 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 83/D3-05782-7FD81DD5; Sun, 17 Nov 2019 13:14:15 -0500 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 1iWP2t-0006xM-4M; Sun, 17 Nov 2019 18:13:11 +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 1iWP2n-0006wW-FI for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 18:13:05 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=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:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=tuEsuKiGRePh6d9UfSyKdJmGhOq4ujQDeqUClIx4bZE=; b=e7gZX+CMB4VdfEz6dAInXNGxU7 zRnyRbTgFQxtoqLziFnUNAVuMD1TnXV0SYeVrC7RUuivx6qyGVjkZ1fiGBYxG7rMxVAKgW7LXtksl 3+z0nRaCGyiw/3qtF6MXM2j4UWSFeuFU1d3bNhaNSgqXGKyYRI+LVVjEgANNllAfs8hc=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=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: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=tuEsuKiGRePh6d9UfSyKdJmGhOq4ujQDeqUClIx4bZE=; b=MOrzK9k2bjTikf4OeIyze/s++n ouLBBKEwWMRgs6isAfmqYve9Q7+4AGX4dghgE9ISzLlyt0w5LUwivFq7LjJSPhbL1msiE4QMN8meX N6VRPpdEIXmHvFhNE9zeuPmzd3/jnSIES7sxJ5Kq11m5UgPH3BSUGW5xqFbMqHadeKAk=; Received: from [192.26.174.232] (helo=mail.blinkt.de) by sfi-mx-3.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1iWP2j-003csw-48 for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 18:13:05 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.92.3 (FreeBSD)) (envelope-from ) id 1iWP2R-000Aeq-Ud for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 19:12:43 +0100 Received: (nullmailer pid 28964 invoked by uid 10006); Sun, 17 Nov 2019 18:12:43 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Sun, 17 Nov 2019 19:12:40 +0100 Message-Id: <20191117181243.28919-1-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.0 URIBL_BLOCKED ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [URIs: rfc2549.org] 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 1.0 RDNS_NONE Delivered to internal network by a host with no rDNS -0.2 AWL AWL: Adjusted score from AWL reputation of From: address X-Headers-End: 1iWP2j-003csw-48 Subject: [Openvpn-devel] [PATCH 1/4] Only announce IV_NCP=2 when we are willing to support these ciphers 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 We currently always announce IV_NCP=2 when we support these ciphers even when we do not accept them. This lead to a server pushing a AES-GCM-128 cipher to clients and the client then rejecting it. Signed-off-by: Arne Schwabe --- doc/openvpn.8 | 2 ++ src/openvpn/init.c | 4 ++++ src/openvpn/openvpn.h | 1 + src/openvpn/ssl.c | 4 +++- src/openvpn/ssl_common.h | 1 + 5 files changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 457c2667..ae24b6c0 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4392,6 +4392,8 @@ NCP server (v2.4+) with "\-\-cipher BF\-CBC" and "\-\-ncp\-ciphers AES\-256\-GCM:AES\-256\-CBC" set can either specify "\-\-cipher BF\-CBC" or "\-\-cipher AES\-256\-CBC" and both will work. +Note, for using NCP with a OpenVPN 2.4 server this list must include +the AES\-256\-GCM and AES\-128\-GCM ciphers. .\"********************************************************* .TP .B \-\-ncp\-disable diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 0bdb0a9c..8f142311 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -623,6 +623,7 @@ save_ncp_options(struct context *c) c->c1.ciphername = c->options.ciphername; c->c1.authname = c->options.authname; c->c1.keysize = c->options.keysize; + c->c1.ncp_ciphers = c->options.ncp_ciphers; } /* Restores NCP-negotiable options to original values */ @@ -632,6 +633,7 @@ restore_ncp_options(struct context *c) c->options.ciphername = c->c1.ciphername; c->options.authname = c->c1.authname; c->options.keysize = c->c1.keysize; + c->options.ncp_ciphers = c->c1.ncp_ciphers; } void @@ -2827,6 +2829,7 @@ 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->c1.ciphername; to.config_authname = c->c1.authname; + to.config_ncp_ciphers = c->c1.ncp_ciphers; to.ncp_enabled = options->ncp_enabled; to.transition_window = options->transition_window; to.handshake_window = options->handshake_window; @@ -4532,6 +4535,7 @@ inherit_context_child(struct context *dest, dest->c1.ciphername = src->c1.ciphername; dest->c1.authname = src->c1.authname; dest->c1.keysize = src->c1.keysize; + dest->c1.ncp_ciphers = src->c1.ncp_ciphers; /* inherit auth-token */ dest->c1.ks.auth_token_key = src->c1.ks.auth_token_key; diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 900db7e1..9e46ad6c 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -209,6 +209,7 @@ struct context_1 const char *ciphername; /**< Data channel cipher from config file */ const char *authname; /**< Data channel auth from config file */ + const char *ncp_ciphers; /**< NCP Ciphers */ int keysize; /**< Data channel keysize from config file */ #endif }; diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 4455ebb8..6ca5c79a 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2322,7 +2322,9 @@ 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)) + && (session->opt->mode == MODE_SERVER || session->opt->pull) + && 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)) { buf_printf(&out, "IV_NCP=2\n"); } diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 8dd08862..fb82f610 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -290,6 +290,7 @@ struct tls_options const char *config_ciphername; const char *config_authname; + const char *config_ncp_ciphers; bool ncp_enabled; bool tls_crypt_v2; From patchwork Sun Nov 17 07:12:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 925 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 8IdnJfyN0V3JXAAAIUCqbw for ; Sun, 17 Nov 2019 13:14:20 -0500 Received: from proxy20.mail.iad3b.rsapps.net ([172.31.255.6]) by director9.mail.ord1d.rsapps.net with LMTP id OAfLIvyN0V0bZgAAalYnBA ; Sun, 17 Nov 2019 13:14:20 -0500 Received: from smtp35.gate.iad3b ([172.31.255.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy20.mail.iad3b.rsapps.net with LMTP id OLGpHPyN0V3uYAAAcDxLoQ ; Sun, 17 Nov 2019 13:14:20 -0500 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: smtp35.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: 12ca527a-0966-11ea-a5af-525400503131-1-1 Received: from [216.105.38.7] ([216.105.38.7:51916] helo=lists.sourceforge.net) by smtp35.gate.iad3b.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 6A/BC-16448-CFD81DD5; Sun, 17 Nov 2019 13:14:20 -0500 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 1iWP2w-0005SS-Fe; Sun, 17 Nov 2019 18:13:14 +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 1iWP2n-0005Qn-JJ for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 18:13: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=0g4xcHE2rKvSSWRRZPmXJQr3xSXRlboObVD4RZ+kR7c=; b=X2xrg8QVqsrpPTgKjyQyhHnXyE vyF5ioVMR1BrfoM88BNwW29L7skChbucvv07E8zxFhG8OewGSy+PAYgSqwnhE+m/5I4x6oGI+ax2B sNQ33hOhiJC8OZ7HutgD+O7CE3awglj1NBxvTYtIdldBHThG3pT1/IH6/C6rvS8NjZ4o=; 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=0g4xcHE2rKvSSWRRZPmXJQr3xSXRlboObVD4RZ+kR7c=; b=Qaxox92oP8IcsNM753Aa6O8My7 JegjWs8P69AsliP2qEFOoe/GOnRmXh2vVkAs4o/mK6TdAD8BAL0jpn/14PWIUIXH/F0gd0YsLdFt/ 5CUMeSbOgmGWll8SwPj4E3Wp/sz+/hAxcPU1I1WS5esl1Ovx2GvvEtIVOQSh8eYcs61Q=; Received: from [192.26.174.232] (helo=mail.blinkt.de) by sfi-mx-3.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1iWP2j-003csv-3H for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 18:13:05 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.92.3 (FreeBSD)) (envelope-from ) id 1iWP2S-000Aet-0y for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 19:12:44 +0100 Received: (nullmailer pid 28967 invoked by uid 10006); Sun, 17 Nov 2019 18:12:43 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Sun, 17 Nov 2019 19:12:41 +0100 Message-Id: <20191117181243.28919-2-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191117181243.28919-1-arne@rfc2549.org> References: <20191117181243.28919-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.0 URIBL_BLOCKED ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [URIs: rfc2549.org] 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 1.0 RDNS_NONE Delivered to internal network by a host with no rDNS -0.1 AWL AWL: Adjusted score from AWL reputation of From: address X-Headers-End: 1iWP2j-003csv-3H Subject: [Openvpn-devel] [PATCH 2/4] Implement dynamic NCP negotiation 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 Our current NCP version is flawed in the way that it can only indicate support for AES-256-GCM and AES-128-GCM. While configuring client and server with different ncp-cipher configuration directive works, the server will blindly push the first cipher of that list to the client if the client sends IV_NCP=2. This patches introduces IV_CIPHER sent from the client to the server that contains the full list of cipers that the client is willing to support (*). The server will then pick the first ciphr of its own ncp-cipher list that the client indicates support for. We choose a textual representation of the ciphers instead of a binary sinc a binary would mean that we would need to have a central place to maintain a mapping between binary and the actual cipher name. Also the normal ncp-cipher list is quite short, so this should not be problem. It also provides the freedom to negioate new ciphers from SSL libraries without the need to upgrade OpenVPN/its binary cipher table. * the client/server will also accpt the cipher specifid in --cipher but eventually we want to get rid of --ciper. So this patch keeps a reasonable backwards compatbility (especially poor man's NCP) but does not encourage to use --cipher for negotiation in documentation or warning messages. Signed-off-by: Arne Schwabe --- doc/openvpn.8 | 10 +++- src/openvpn/init.c | 1 - src/openvpn/options.c | 1 + src/openvpn/push.c | 32 +++++++---- src/openvpn/ssl.c | 111 +++++++++++++++++++++++++++++++++++++-- src/openvpn/ssl.h | 34 ++++++++++++ src/openvpn/ssl_common.h | 1 - 7 files changed, 172 insertions(+), 18 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index ae24b6c0..4f0df786 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -3111,6 +3111,11 @@ IV_NCP=2 \-\- negotiable ciphers, client supports pushed by the server, a value of 2 or greater indicates client supports AES\-GCM\-128 and AES\-GCM\-256. +IV_CIPHERS= \-\- the client pushes the list of configured +ciphers with the +\.B -\-\ncp\-ciphers +option to the server. + IV_GUI_VER= \-\- the UI version of a UI if one is running, for example "de.blinkt.openvpn 0.5.47" for the Android app. @@ -4368,7 +4373,8 @@ is a colon\-separated list of ciphers, and defaults to For servers, the first cipher from .B cipher_list -will be pushed to clients that support cipher negotiation. +that is also supported by the client will be pushed to clients +that support cipher negotiation. Cipher negotiation is enabled in client\-server mode only. I.e. if .B \-\-mode @@ -4392,7 +4398,7 @@ NCP server (v2.4+) with "\-\-cipher BF\-CBC" and "\-\-ncp\-ciphers AES\-256\-GCM:AES\-256\-CBC" set can either specify "\-\-cipher BF\-CBC" or "\-\-cipher AES\-256\-CBC" and both will work. -Note, for using NCP with a OpenVPN 2.4 server this list must include +Note, for using NCP with a OpenVPN 2.4 peer this list must include the AES\-256\-GCM and AES\-128\-GCM ciphers. .\"********************************************************* .TP diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 8f142311..5058b300 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2828,7 +2828,6 @@ do_init_crypto_tls(struct context *c, const unsigned int flags) to.replay_time = options->replay_time; to.tcp_mode = link_socket_proto_connection_oriented(options->ce.proto); to.config_ciphername = c->c1.ciphername; - to.config_authname = c->c1.authname; to.config_ncp_ciphers = c->c1.ncp_ciphers; to.ncp_enabled = options->ncp_enabled; to.transition_window = options->transition_window; diff --git a/src/openvpn/options.c b/src/openvpn/options.c index c282b582..9be5a826 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -45,6 +45,7 @@ #include "shaper.h" #include "crypto.h" #include "ssl.h" +#include "ssl_ncp.h" #include "options.h" #include "misc.h" #include "socket.h" diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 368b6920..1f1e1f0d 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -429,7 +429,7 @@ prepare_push_reply(struct context *c, struct gc_arena *gc, prepare_auth_token_push_reply(tls_multi, gc, push_list); /* Push cipher if client supports Negotiable Crypto Parameters */ - if (tls_peer_info_ncp_ver(peer_info) >= 2 && o->ncp_enabled) + if (o->ncp_enabled) { /* 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 @@ -445,17 +445,31 @@ prepare_push_reply(struct context *c, struct gc_arena *gc, } else { - /* Push the first cipher from --ncp-ciphers to the client. - * TODO: actual negotiation, instead of server dictatorship. */ - char *push_cipher = string_alloc(o->ncp_ciphers, &o->gc); - o->ciphername = strtok(push_cipher, ":"); + /* + * Push the first cipher from --ncp-ciphers to the client that + * the client announces to be supporting. + */ + char *push_cipher = ncp_get_best_cipher(o->ncp_ciphers, o->ciphername, + peer_info, + tls_multi->remote_ciphername, + &o->gc); + + if (push_cipher) + { + o->ciphername = push_cipher; + } + else + { + char *peer_ciphers = tls_peer_ncp_list(peer_info); + msg(M_INFO, "PUSH: No common cipher between server and client." + "Expect this connection not to work. " + "Server ncp-ciphers: '%s', client supported ciphers '%s'", + o->ncp_ciphers, peer_ciphers); + free(peer_ciphers); + } } push_option_fmt(gc, push_list, M_USAGE, "cipher %s", o->ciphername); } - else if (o->ncp_enabled) - { - tls_poor_mans_ncp(o, tls_multi->remote_ciphername); - } return true; } diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 6ca5c79a..61b29330 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1934,6 +1934,81 @@ tls_item_in_cipher_list(const char *item, const char *list) return token != NULL; } +char * +tls_peer_ncp_list(const char *peer_info) +{ + /* Check if the peer sends the IV_CIPHERS list */ + const char *ncp_ciphers_start; + if (peer_info && (ncp_ciphers_start = strstr(peer_info, "IV_CIPHERS="))) + { + ncp_ciphers_start += strlen("IV_CIPHERS="); + const char *ncp_ciphers_end = strstr(ncp_ciphers_start, "\n"); + if (!ncp_ciphers_end) + { + /* IV_CIPHERS is at end of the peer_info list and no '\n' + * follows */ + ncp_ciphers_end = ncp_ciphers_start + strlen(ncp_ciphers_start); + } + + char *ncp_ciphers_peer = string_alloc(ncp_ciphers_start, NULL); + /* NULL terminate the copy at the right position */ + ncp_ciphers_peer[ncp_ciphers_end - ncp_ciphers_start] = '\0'; + return ncp_ciphers_peer; + + } + else if (tls_peer_info_ncp_ver(peer_info)>=2) + { + /* If the peer announces IV_NCP=2 then it supports the AES GCM + * ciphers */ + return strdup("AES-256-GCM:AES-128-GCM"); + } + else + { + return strdup(""); + } +} + +char * +ncp_get_best_cipher(const char *server_list, const char *server_cipher, + const char *peer_info, const char *remote_cipher, + struct gc_arena *gc) +{ + char *peer_ncp_list = tls_peer_ncp_list(peer_info); + + char *tmp_ciphers = string_alloc(server_list, NULL); + char *tmp_ciphers_orig = tmp_ciphers; + + const char *token = strsep(&tmp_ciphers, ":"); + while (token) + { + if (tls_item_in_cipher_list(token, peer_ncp_list) + || streq(token, remote_cipher)) + { + break; + } + token = strsep(&tmp_ciphers, ":"); + } + /* We have not found a common cipher, as a last resort check if the + * server cipher can be used + */ + if (token == NULL + && (tls_item_in_cipher_list(server_cipher, peer_ncp_list) + || streq(server_cipher, remote_cipher))) + { + token = server_cipher; + } + + char *ret = NULL; + if (token != NULL) + { + ret = string_alloc(token, gc); + } + + free(tmp_ciphers_orig); + free(peer_ncp_list); + return ret; +} + void tls_poor_mans_ncp(struct options *o, const char *remote_ciphername) { @@ -2322,11 +2397,15 @@ 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) - && 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)) + && (session->opt->mode == MODE_SERVER || session->opt->pull)) { - buf_printf(&out, "IV_NCP=2\n"); + 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)) + { + + buf_printf(&out, "IV_NCP=2\n"); + } + buf_printf(&out, "IV_CIPHERS=%s\n", session->opt->config_ncp_ciphers); } /* push compression status */ @@ -2561,6 +2640,28 @@ error: return false; } +/** + * Returns whether the client supports NCP either by + * announcing IV_NCP>=2 or the IV_CIPHERS list + */ +static bool +tls_peer_supports_ncp(const char *peer_info) +{ + if (!peer_info) + { + return false; + } + else if (tls_peer_info_ncp_ver(peer_info) >= 2 + || strstr(peer_info, "IV_CIPHERS=")) + { + return true; + } + else + { + return false; + } +} + static bool key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_session *session) { @@ -2633,7 +2734,7 @@ key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_sessio multi->remote_ciphername = options_string_extract_option(options, "cipher", NULL); - if (tls_peer_info_ncp_ver(multi->peer_info) < 2) + if (!tls_peer_supports_ncp(multi->peer_info)) { /* Peer does not support NCP, but leave NCP enabled if the local and * remote cipher do not match to attempt 'poor-man's NCP'. diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index a944ca3a..ad3b46d7 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -512,6 +512,40 @@ tls_get_peer_info(const struct tls_multi *multi) */ int tls_peer_info_ncp_ver(const char *peer_info); +/** + * Iterates through the ciphers in server_list and return the first + * cipher that is also supported by the peer according to the IV_NCP + * and IV_CIPHER values in peer_info. + * + * We also accept a cipher that is the remote cipher of the client for + * "Poor man's NCP": Use peer cipher if it is an allowed (NCP) cipher. + * Allows non-NCP peers to upgrade their cipher individually. + * + * Make sure to call tls_session_update_crypto_params() after calling this + * function. + * + * @param gc gc arena that is ONLY used to allocate the returned string + * + * @returns NULL if no common cipher is available, otherwise the best common + * cipher + */ +char * +ncp_get_best_cipher(const char *server_list, const char *server_cipher, + const char *peer_info, const char *remote_cipher, + struct gc_arena *gc); + + +/** + * Returns the support cipher list from the peer according to the IV_NCP + * and IV_CIPHER values in peer_info. + * + * @returns Either a string containing the ncp list that needs to be + * free()ed after use. If no information is available an empty string + * ("") is returned. + */ +char * +tls_peer_ncp_list(const char *peer_info); + /** * Check whether the ciphers in the supplied list are supported. * diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index fb82f610..998ea3c4 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -289,7 +289,6 @@ struct tls_options bool tcp_mode; const char *config_ciphername; - const char *config_authname; const char *config_ncp_ciphers; bool ncp_enabled; From patchwork Sun Nov 17 07:12:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 923 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director10.mail.ord1d.rsapps.net ([172.31.255.6]) by backend30.mail.ord1d.rsapps.net with LMTP id uFDNEPeN0V3jcgAAIUCqbw for ; Sun, 17 Nov 2019 13:14:15 -0500 Received: from proxy2.mail.iad3b.rsapps.net ([172.31.255.6]) by director10.mail.ord1d.rsapps.net with LMTP id eCpyDveN0V1tYAAApN4f7A ; Sun, 17 Nov 2019 13:14:15 -0500 Received: from smtp8.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 LMTP id eLVkCfeN0V1BKgAAvAZTew ; Sun, 17 Nov 2019 13:14:15 -0500 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: smtp8.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: 0f89cfbe-0966-11ea-a8da-5254005eee35-1-1 Received: from [216.105.38.7] ([216.105.38.7:56044] helo=lists.sourceforge.net) by smtp8.gate.iad3b.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id C1/BD-19699-6FD81DD5; Sun, 17 Nov 2019 13:14:14 -0500 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.90_1) (envelope-from ) id 1iWP2v-0002d5-SS; Sun, 17 Nov 2019 18:13:13 +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.90_1) (envelope-from ) id 1iWP2o-0002ce-2d for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 18:13:06 +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=DktERwyPx7H+IStz9jkyN66HRcJUhsKQIScAafIpSrk=; b=U4GLZzv+znHQjwTzO+16wDUYra SncaRa1QURrIE99pwquS6/k8PUNRhB+bE1nNWr/8fQsFN+2utQ6bvi7NA1TKji06RBaAAjcRvP0rn adS5nx1oIuiSx/4Ez8OSSqQPPv7uzBVEw1GlrUuFhO2Xb7MN1NfK6VZsAcNDSinFLINs=; 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=DktERwyPx7H+IStz9jkyN66HRcJUhsKQIScAafIpSrk=; b=mJ365UGbuoQpNIpSG1jU8M9d9v aXE3IOikuTVYUeQalaYIr/ZCVyUa/DTQ4IIWS6CIzRVBPkqe2pWTLxhR6BNfc/42oFwm3aEPad+We vZplN9yG+sirukrvqu3voWbRNRkhvHWp4XtFnXxkJTZIx6i7qOUeBhJa6FiMJoYT2ZIo=; 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 1iWP2i-009KHm-RS for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 18:13:04 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.92.3 (FreeBSD)) (envelope-from ) id 1iWP2S-000Aey-5B for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 19:12:44 +0100 Received: (nullmailer pid 28972 invoked by uid 10006); Sun, 17 Nov 2019 18:12:44 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Sun, 17 Nov 2019 19:12:42 +0100 Message-Id: <20191117181243.28919-3-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191117181243.28919-1-arne@rfc2549.org> References: <20191117181243.28919-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.0 URIBL_BLOCKED ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [URIs: rfc2549.org] 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.5 AWL AWL: Adjusted score from AWL reputation of From: address X-Headers-End: 1iWP2i-009KHm-RS Subject: [Openvpn-devel] [PATCH 3/4] Move NCP related function into a seperate file and add unit tests 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 allows unit test the NCP functions. The ssl.c file has too many dependencies to make unit testing of it viable. Signed-off-by: Arne Schwabe --- src/openvpn/Makefile.am | 1 + src/openvpn/init.c | 1 + src/openvpn/multi.c | 1 + src/openvpn/push.c | 1 + src/openvpn/ssl.c | 172 +------------------- src/openvpn/ssl.h | 65 -------- src/openvpn/ssl_ncp.c | 225 +++++++++++++++++++++++++++ src/openvpn/ssl_ncp.h | 101 ++++++++++++ tests/unit_tests/openvpn/Makefile.am | 20 ++- tests/unit_tests/openvpn/test_ncp.c | 182 ++++++++++++++++++++++ 10 files changed, 533 insertions(+), 236 deletions(-) create mode 100644 src/openvpn/ssl_ncp.c create mode 100644 src/openvpn/ssl_ncp.h create mode 100644 tests/unit_tests/openvpn/test_ncp.c diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index a091ffc2..e0357997 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -116,6 +116,7 @@ openvpn_SOURCES = \ ssl.c ssl.h ssl_backend.h \ ssl_openssl.c ssl_openssl.h \ ssl_mbedtls.c ssl_mbedtls.h \ + ssl_ncp.c ssl_ncp.h \ ssl_common.h \ ssl_verify.c ssl_verify.h ssl_verify_backend.h \ ssl_verify_openssl.c ssl_verify_openssl.h \ diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 5058b300..13d05f65 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -49,6 +49,7 @@ #include "ping.h" #include "mstats.h" #include "ssl_verify.h" +#include "ssl_ncp.h" #include "tls_crypt.h" #include "forward.h" #include "auth_token.h" diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index d594dd25..b82c68c4 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -45,6 +45,7 @@ #include "gremlin.h" #include "mstats.h" #include "ssl_verify.h" +#include "ssl_ncp.h" #include "vlan.h" #include diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 1f1e1f0d..38069cb5 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -33,6 +33,7 @@ #include "options.h" #include "ssl.h" #include "ssl_verify.h" +#include "ssl_ncp.h" #include "manage.h" #include "memdbg.h" diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 61b29330..86a347c7 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -59,6 +59,7 @@ #include "ssl.h" #include "ssl_verify.h" #include "ssl_backend.h" +#include "ssl_ncp.h" #include "auth_token.h" #include "memdbg.h" @@ -67,6 +68,7 @@ static const char ssl_default_options_string[] = "V0 UNDEF"; #endif + static inline const char * local_options_string(const struct tls_session *session) { @@ -1914,115 +1916,6 @@ key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len) } } -bool -tls_item_in_cipher_list(const char *item, const char *list) -{ - char *tmp_ciphers = string_alloc(list, NULL); - char *tmp_ciphers_orig = tmp_ciphers; - - const char *token = strtok(tmp_ciphers, ":"); - while (token) - { - if (0 == strcmp(token, item)) - { - break; - } - token = strtok(NULL, ":"); - } - free(tmp_ciphers_orig); - - return token != NULL; -} - -char * -tls_peer_ncp_list(const char *peer_info) -{ - /* Check if the peer sends the IV_CIPHERS list */ - const char *ncp_ciphers_start; - if (peer_info && (ncp_ciphers_start = strstr(peer_info, "IV_CIPHERS="))) - { - ncp_ciphers_start += strlen("IV_CIPHERS="); - const char *ncp_ciphers_end = strstr(ncp_ciphers_start, "\n"); - if (!ncp_ciphers_end) - { - /* IV_CIPHERS is at end of the peer_info list and no '\n' - * follows */ - ncp_ciphers_end = ncp_ciphers_start + strlen(ncp_ciphers_start); - } - - char *ncp_ciphers_peer = string_alloc(ncp_ciphers_start, NULL); - /* NULL terminate the copy at the right position */ - ncp_ciphers_peer[ncp_ciphers_end - ncp_ciphers_start] = '\0'; - return ncp_ciphers_peer; - - } - else if (tls_peer_info_ncp_ver(peer_info)>=2) - { - /* If the peer announces IV_NCP=2 then it supports the AES GCM - * ciphers */ - return strdup("AES-256-GCM:AES-128-GCM"); - } - else - { - return strdup(""); - } -} - -char * -ncp_get_best_cipher(const char *server_list, const char *server_cipher, - const char *peer_info, const char *remote_cipher, - struct gc_arena *gc) -{ - char *peer_ncp_list = tls_peer_ncp_list(peer_info); - - char *tmp_ciphers = string_alloc(server_list, NULL); - char *tmp_ciphers_orig = tmp_ciphers; - - const char *token = strsep(&tmp_ciphers, ":"); - while (token) - { - if (tls_item_in_cipher_list(token, peer_ncp_list) - || streq(token, remote_cipher)) - { - break; - } - token = strsep(&tmp_ciphers, ":"); - } - /* We have not found a common cipher, as a last resort check if the - * server cipher can be used - */ - if (token == NULL - && (tls_item_in_cipher_list(server_cipher, peer_ncp_list) - || streq(server_cipher, remote_cipher))) - { - token = server_cipher; - } - - char *ret = NULL; - if (token != NULL) - { - ret = string_alloc(token, gc); - } - - free(tmp_ciphers_orig); - free(peer_ncp_list); - return ret; -} - -void -tls_poor_mans_ncp(struct options *o, const char *remote_ciphername) -{ - if (o->ncp_enabled && remote_ciphername - && 0 != strcmp(o->ciphername, remote_ciphername)) - { - if (tls_item_in_cipher_list(remote_ciphername, o->ncp_ciphers)) - { - o->ciphername = string_alloc(remote_ciphername, &o->gc); - msg(D_TLS_DEBUG_LOW, "Using peer cipher '%s'", o->ciphername); - } - } -} - /** * Generate data channel keys for the supplied TLS session. * @@ -2640,28 +2533,6 @@ error: return false; } -/** - * Returns whether the client supports NCP either by - * announcing IV_NCP>=2 or the IV_CIPHERS list - */ -static bool -tls_peer_supports_ncp(const char *peer_info) -{ - if (!peer_info) - { - return false; - } - else if (tls_peer_info_ncp_ver(peer_info) >= 2 - || strstr(peer_info, "IV_CIPHERS=")) - { - return true; - } - else - { - return false; - } -} - static bool key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_session *session) { @@ -4251,45 +4122,6 @@ tls_update_remote_addr(struct tls_multi *multi, const struct link_socket_actual gc_free(&gc); } -int -tls_peer_info_ncp_ver(const char *peer_info) -{ - const char *ncpstr = peer_info ? strstr(peer_info, "IV_NCP=") : NULL; - if (ncpstr) - { - int ncp = 0; - int r = sscanf(ncpstr, "IV_NCP=%d", &ncp); - if (r == 1) - { - return ncp; - } - } - return 0; -} - -bool -tls_check_ncp_cipher_list(const char *list) -{ - bool unsupported_cipher_found = false; - - ASSERT(list); - - char *const tmp_ciphers = string_alloc(list, NULL); - const char *token = strtok(tmp_ciphers, ":"); - while (token) - { - if (!cipher_kt_get(translate_cipher_name_from_openvpn(token))) - { - msg(M_WARN, "Unsupported cipher in --ncp-ciphers: %s", token); - unsupported_cipher_found = true; - } - token = strtok(NULL, ":"); - } - free(tmp_ciphers); - - return 0 < strlen(list) && !unsupported_cipher_found; -} - void show_available_tls_ciphers(const char *cipher_list, const char *cipher_list_tls13, diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index ad3b46d7..3449d91e 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -489,15 +489,6 @@ bool tls_session_update_crypto_params(struct tls_session *session, struct frame *frame, struct frame *frame_fragment); -/** - * "Poor man's NCP": Use peer cipher if it is an allowed (NCP) cipher. - * Allows non-NCP peers to upgrade their cipher individually. - * - * Make sure to call tls_session_update_crypto_params() after calling this - * function. - */ -void tls_poor_mans_ncp(struct options *o, const char *remote_ciphername); - #ifdef MANAGEMENT_DEF_AUTH static inline char * tls_get_peer_info(const struct tls_multi *multi) @@ -506,62 +497,6 @@ tls_get_peer_info(const struct tls_multi *multi) } #endif -/** - * Return the Negotiable Crypto Parameters version advertised in the peer info - * string, or 0 if none specified. - */ -int tls_peer_info_ncp_ver(const char *peer_info); - -/** - * Iterates through the ciphers in server_list and return the first - * cipher that is also supported by the peer according to the IV_NCP - * and IV_CIPHER values in peer_info. - * - * We also accept a cipher that is the remote cipher of the client for - * "Poor man's NCP": Use peer cipher if it is an allowed (NCP) cipher. - * Allows non-NCP peers to upgrade their cipher individually. - * - * Make sure to call tls_session_update_crypto_params() after calling this - * function. - * - * @param gc gc arena that is ONLY used to allocate the returned string - * - * @returns NULL if no common cipher is available, otherwise the best common - * cipher - */ -char * -ncp_get_best_cipher(const char *server_list, const char *server_cipher, - const char *peer_info, const char *remote_cipher, - struct gc_arena *gc); - - -/** - * Returns the support cipher list from the peer according to the IV_NCP - * and IV_CIPHER values in peer_info. - * - * @returns Either a string containing the ncp list that needs to be - * free()ed after use. If no information is available an empty string - * ("") is returned. - */ -char * -tls_peer_ncp_list(const char *peer_info); - -/** - * Check whether the ciphers in the supplied list are supported. - * - * @param list Colon-separated list of ciphers - * - * @returns true iff all ciphers in list are supported. - */ -bool tls_check_ncp_cipher_list(const char *list); - -/** - * Return true iff item is present in the colon-separated zero-terminated - * cipher list. - */ -bool tls_item_in_cipher_list(const char *item, const char *list); - - /* * inline functions */ diff --git a/src/openvpn/ssl_ncp.c b/src/openvpn/ssl_ncp.c new file mode 100644 index 00000000..029ac1d5 --- /dev/null +++ b/src/openvpn/ssl_ncp.c @@ -0,0 +1,225 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2018 OpenVPN Inc + * Copyright (C) 2010-2018 Fox Crypto B.V. + * Copyright (C) 2008-2013 David Sommerseth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** + * @file Control Channel SSL/Data dynamic negotion Module + * This file is split from ssl.c to be able to unit test it. + */ + +/* + * The routines in this file deal with dynamically negotiating + * the data channel HMAC and cipher keys through a TLS session. + * + * Both the TLS session and the data channel are multiplexed + * over the same TCP/UDP port. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#include "syshead.h" +#include "win32.h" + +#include "error.h" +#include "common.h" + +#include "ssl_ncp.h" + +/** + * Return the Negotiable Crypto Parameters version advertised in the peer info + * string, or 0 if none specified. + */ +static int +tls_peer_info_ncp_ver(const char *peer_info) +{ + const char *ncpstr = peer_info ? strstr(peer_info, "IV_NCP=") : NULL; + if (ncpstr) + { + int ncp = 0; + int r = sscanf(ncpstr, "IV_NCP=%d", &ncp); + if (r == 1) + { + return ncp; + } + } + return 0; +} + +/** + * Returns whether the client supports NCP either by + * announcing IV_NCP>=2 or the IV_CIPHERS list + */ +bool +tls_peer_supports_ncp(const char *peer_info) +{ + if (!peer_info) + { + return false; + } + else if (tls_peer_info_ncp_ver(peer_info) >= 2 + || strstr(peer_info, "IV_CIPHERS=")) + { + return true; + } + else + { + return false; + } +} + +bool +tls_check_ncp_cipher_list(const char *list) +{ + bool unsupported_cipher_found = false; + + ASSERT(list); + + char *const tmp_ciphers = string_alloc(list, NULL); + const char *token = strtok(tmp_ciphers, ":"); + while (token) + { + if (!cipher_kt_get(translate_cipher_name_from_openvpn(token))) + { + msg(M_WARN, "Unsupported cipher in --ncp-ciphers: %s", token); + unsupported_cipher_found = true; + } + token = strtok(NULL, ":"); + } + free(tmp_ciphers); + + return 0 < strlen(list) && !unsupported_cipher_found; +} + +bool +tls_item_in_cipher_list(const char *item, const char *list) +{ + char *tmp_ciphers = string_alloc(list, NULL); + char *tmp_ciphers_orig = tmp_ciphers; + + const char *token = strtok(tmp_ciphers, ":"); + while (token) + { + if (0 == strcmp(token, item)) + { + break; + } + token = strtok(NULL, ":"); + } + free(tmp_ciphers_orig); + + return token != NULL; +} + +char * +tls_peer_ncp_list(const char *peer_info) +{ + /* Check if the peer sends the IV_CIPHERS list */ + const char *ncp_ciphers_start; + if (peer_info && (ncp_ciphers_start = strstr(peer_info, "IV_CIPHERS="))) + { + ncp_ciphers_start += strlen("IV_CIPHERS="); + const char *ncp_ciphers_end = strstr(ncp_ciphers_start, "\n"); + if (!ncp_ciphers_end) + { + /* IV_CIPHERS is at end of the peer_info list and no '\n' + * follows */ + ncp_ciphers_end = ncp_ciphers_start + strlen(ncp_ciphers_start); + } + + char *ncp_ciphers_peer = string_alloc(ncp_ciphers_start, NULL); + /* NULL terminate the copy at the right position */ + ncp_ciphers_peer[ncp_ciphers_end - ncp_ciphers_start] = '\0'; + return ncp_ciphers_peer; + + } + else if (tls_peer_info_ncp_ver(peer_info)>=2) + { + /* If the peer announces IV_NCP=2 then it supports the AES GCM + * ciphers */ + return strdup("AES-256-GCM:AES-128-GCM"); + } + else + { + return strdup(""); + } +} + +char * +ncp_get_best_cipher(const char *server_list, const char *server_cipher, + const char *peer_info, const char *remote_cipher, + struct gc_arena *gc) +{ + char *peer_ncp_list = tls_peer_ncp_list(peer_info); + + char *tmp_ciphers = string_alloc(server_list, NULL); + char *tmp_ciphers_orig = tmp_ciphers; + + const char *token = strsep(&tmp_ciphers, ":"); + while (token) + { + if (tls_item_in_cipher_list(token, peer_ncp_list) + || streq(token, remote_cipher)) + { + break; + } + token = strsep(&tmp_ciphers, ":"); + } + /* We have not found a common cipher, as a last resort check if the + * server cipher can be used + */ + if (token == NULL + && (tls_item_in_cipher_list(server_cipher, peer_ncp_list) + || streq(server_cipher, remote_cipher))) + { + token = server_cipher; + } + + char *ret = NULL; + if (token != NULL) + { + ret = string_alloc(token, gc); + return ret; + } + + free(tmp_ciphers_orig); + free(peer_ncp_list); + return ret; +} + +void +tls_poor_mans_ncp(struct options *o, const char *remote_ciphername) +{ + if (o->ncp_enabled && remote_ciphername + && 0 != strcmp(o->ciphername, remote_ciphername)) + { + if (tls_item_in_cipher_list(remote_ciphername, o->ncp_ciphers)) + { + o->ciphername = string_alloc(remote_ciphername, &o->gc); + msg(D_TLS_DEBUG_LOW, "Using peer cipher '%s'", o->ciphername); + } + } +} diff --git a/src/openvpn/ssl_ncp.h b/src/openvpn/ssl_ncp.h new file mode 100644 index 00000000..82d008d8 --- /dev/null +++ b/src/openvpn/ssl_ncp.h @@ -0,0 +1,101 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2018 OpenVPN Inc + * Copyright (C) 2010-2018 Fox Crypto B.V. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** + * @file Control Channel SSL/Data dynamic negotion Module + * This file is split from ssl.h to be able to unit test it. + */ + +#ifndef OPENVPN_SSL_NCP_H +#define OPENVPN_SSL_NCP_H + +#include "buffer.h" +#include "options.h" + +/** + * Returns whether the client supports NCP either by + * announcing IV_NCP>=2 or the IV_CIPHERS list + */ +bool +tls_peer_supports_ncp(const char *peer_info); + +/** + * "Poor man's NCP": Use peer cipher if it is an allowed (NCP) cipher. + * Allows non-NCP peers to upgrade their cipher individually. + * + * Make sure to call tls_session_update_crypto_params() after calling this + * function. + */ +void tls_poor_mans_ncp(struct options *o, const char *remote_ciphername); + +/** + * Iterates through the ciphers in server_list and return the first + * cipher that is also supported by the peer according to the IV_NCP + * and IV_CIPHER values in peer_info. + * + * We also accept a cipher that is the remote cipher of the client for + * "Poor man's NCP": Use peer cipher if it is an allowed (NCP) cipher. + * Allows non-NCP peers to upgrade their cipher individually. + * + * Make sure to call tls_session_update_crypto_params() after calling this + * function. + * + * @param gc gc arena that is ONLY used to allocate the returned string + * + * @returns NULL if no common cipher is available, otherwise the best common + * cipher + */ +char * +ncp_get_best_cipher(const char *server_list, const char *server_cipher, + const char *peer_info, const char *remote_cipher, + struct gc_arena *gc); + + +/** + * Returns the support cipher list from the peer according to the IV_NCP + * and IV_CIPHER values in peer_info. + * + * @returns Either a string containing the ncp list that needs to be + * free()ed after use. If no information is available an empty string + * ("") is returned. + */ +char * +tls_peer_ncp_list(const char *peer_info); + +/** + * Check whether the ciphers in the supplied list are supported. + * + * @param list Colon-separated list of ciphers + * + * @returns true iff all ciphers in list are supported. + */ +bool tls_check_ncp_cipher_list(const char *list); + +/** + * Return true iff item is present in the colon-separated zero-terminated + * cipher list. + */ +bool tls_item_in_cipher_list(const char *item, const char *list); + +#endif /* ifndef OPENVPN_SSL_NCP_H */ diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am index 60e84639..789a9455 100644 --- a/tests/unit_tests/openvpn/Makefile.am +++ b/tests/unit_tests/openvpn/Makefile.am @@ -6,7 +6,7 @@ if HAVE_LD_WRAP_SUPPORT test_binaries += argv_testdriver buffer_testdriver endif -test_binaries += crypto_testdriver packet_id_testdriver auth_token_testdriver +test_binaries += crypto_testdriver packet_id_testdriver auth_token_testdriver ncp_testdriver if HAVE_LD_WRAP_SUPPORT test_binaries += tls_crypt_testdriver endif @@ -110,3 +110,21 @@ auth_token_testdriver_SOURCES = test_auth_token.c mock_msg.c \ $(openvpn_srcdir)/packet_id.c \ $(openvpn_srcdir)/platform.c \ $(openvpn_srcdir)/base64.c + + +ncp_testdriver_CFLAGS = @TEST_CFLAGS@ \ + -I$(openvpn_includedir) -I$(compat_srcdir) -I$(openvpn_srcdir) \ + $(OPTIONAL_CRYPTO_CFLAGS) +ncp_testdriver_LDFLAGS = @TEST_LDFLAGS@ \ + $(OPTIONAL_CRYPTO_LIBS) + +ncp_testdriver_SOURCES = test_ncp.c mock_msg.c \ + $(openvpn_srcdir)/buffer.c \ + $(openvpn_srcdir)/crypto.c \ + $(openvpn_srcdir)/crypto_mbedtls.c \ + $(openvpn_srcdir)/crypto_openssl.c \ + $(openvpn_srcdir)/otime.c \ + $(openvpn_srcdir)/packet_id.c \ + $(openvpn_srcdir)/platform.c + + diff --git a/tests/unit_tests/openvpn/test_ncp.c b/tests/unit_tests/openvpn/test_ncp.c new file mode 100644 index 00000000..e71f4825 --- /dev/null +++ b/tests/unit_tests/openvpn/test_ncp.c @@ -0,0 +1,182 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2019 Arne Schwabe + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#include "syshead.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "ssl_ncp.c" + +/* Defines for use in the tests and the mock parse_line() */ + +const char *bf_chacha = "BF-CBC:CHACHA20-POLY1305"; +const char *aes_ciphers = "AES-256-GCM:AES-128-GCM"; + +static void +test_check_ncp_ciphers_list(void **state) +{ + assert_true(tls_check_ncp_cipher_list(aes_ciphers)); + assert_true(tls_check_ncp_cipher_list(bf_chacha)); + assert_false(tls_check_ncp_cipher_list("vollbit")); + assert_false(tls_check_ncp_cipher_list("AES-256-GCM:vollbit")); +} + +static void +test_extract_client_ciphers(void **state) +{ + const char *client_peer_info; + char *peer_list; + + client_peer_info = "foo=bar\nIV_foo=y\nIV_NCP=2"; + peer_list = tls_peer_ncp_list(client_peer_info); + assert_string_equal(aes_ciphers,peer_list); + assert_true(tls_peer_supports_ncp(client_peer_info)); + free(peer_list); + + client_peer_info = "foo=bar\nIV_foo=y\nIV_NCP=2\nIV_CIPHERS=BF-CBC"; + peer_list = tls_peer_ncp_list(client_peer_info); + assert_string_equal("BF-CBC", peer_list); + assert_true(tls_peer_supports_ncp(client_peer_info)); + free(peer_list); + + client_peer_info = "IV_NCP=2\nIV_CIPHERS=BF-CBC:FOO-BAR\nIV_BAR=7"; + peer_list = tls_peer_ncp_list(client_peer_info); + assert_string_equal("BF-CBC:FOO-BAR", peer_list); + assert_true(tls_peer_supports_ncp(client_peer_info)); + free(peer_list); + + client_peer_info = "IV_CIPHERS=BF-CBC:FOO-BAR\nIV_BAR=7"; + peer_list = tls_peer_ncp_list(client_peer_info); + assert_string_equal("BF-CBC:FOO-BAR", peer_list); + assert_true(tls_peer_supports_ncp(client_peer_info)); + free(peer_list); + + client_peer_info = "IV_YOLO=NO\nIV_BAR=7"; + peer_list = tls_peer_ncp_list(client_peer_info); + assert_string_equal("", peer_list); + assert_false(tls_peer_supports_ncp(client_peer_info)); + free(peer_list); + + peer_list = tls_peer_ncp_list(NULL); + assert_string_equal("", peer_list); + assert_false(tls_peer_supports_ncp(client_peer_info)); + free(peer_list); +} + +static void +test_poor_man(void **state) +{ + struct gc_arena gc = gc_new(); + char *best_cipher; + + const char *serverlist="CHACHA20_POLY1305:AES-128-GCM"; + + best_cipher = ncp_get_best_cipher(serverlist, "BF-CBC", + "IV_YOLO=NO\nIV_BAR=7", + "BF-CBC", &gc); + + assert_string_equal(best_cipher, "BF-CBC"); + + best_cipher = ncp_get_best_cipher(serverlist, "BF-CBC", + "IV_NCP=1\nIV_BAR=7", + "AES-128-GCM", &gc); + + assert_string_equal(best_cipher, "AES-128-GCM"); + + best_cipher = ncp_get_best_cipher(serverlist, "BF-CBC", + NULL, + "AES-128-GCM", &gc); + + assert_string_equal(best_cipher, "AES-128-GCM"); + + gc_free(&gc); +} + + +static void +test_ncp_best(void **state) +{ + struct gc_arena gc = gc_new(); + char *best_cipher; + + const char *serverlist="CHACHA20_POLY1305:AES-128-GCM:AES-256-GCM"; + + best_cipher = ncp_get_best_cipher(serverlist, "BF-CBC", + "IV_YOLO=NO\nIV_NCP=2\nIV_BAR=7", + "BF-CBC", &gc); + + assert_string_equal(best_cipher, "AES-128-GCM"); + + /* Best cipher is in --cipher of client */ + best_cipher = ncp_get_best_cipher(serverlist, "BF-CBC", + "IV_NCP=2\nIV_BAR=7", + "CHACHA20_POLY1305", &gc); + + assert_string_equal(best_cipher, "CHACHA20_POLY1305"); + + /* Best cipher is in --cipher of client */ + best_cipher = ncp_get_best_cipher(serverlist, "BF-CBC", + "IV_CIPHERS=AES-128-GCM", + "AES-256-CBC", &gc); + + + assert_string_equal(best_cipher, "AES-128-GCM"); + + /* IV_NCP=2 should be ignored if IV_CIPHERS is sent */ + best_cipher = ncp_get_best_cipher(serverlist, "BF-CBC", + "IV_FOO=7\nIV_CIPHERS=AES-256-GCM\nIV_NCP=2", + "AES-256-CBC", &gc); + + assert_string_equal(best_cipher, "AES-256-GCM"); + + + gc_free(&gc); +} + + + + +const struct CMUnitTest ncp_tests[] = { + cmocka_unit_test(test_check_ncp_ciphers_list), + cmocka_unit_test(test_extract_client_ciphers), + cmocka_unit_test(test_poor_man), + cmocka_unit_test(test_ncp_best) +}; + + +int main(void) +{ + return cmocka_run_group_tests(ncp_tests, NULL, NULL); +} From patchwork Sun Nov 17 07:12:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 922 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director11.mail.ord1d.rsapps.net ([172.31.255.6]) by backend30.mail.ord1d.rsapps.net with LMTP id OM1RHPON0V0qYAAAIUCqbw for ; Sun, 17 Nov 2019 13:14:11 -0500 Received: from proxy19.mail.iad3b.rsapps.net ([172.31.255.6]) by director11.mail.ord1d.rsapps.net with LMTP id wHOKGfON0V1BXAAAvGGmqA ; Sun, 17 Nov 2019 13:14:11 -0500 Received: from smtp22.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 LMTP id oFsiFPON0V2TfwAAIG4riQ ; Sun, 17 Nov 2019 13:14:11 -0500 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: smtp22.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: 0c9863c4-0966-11ea-8c17-52540041dff8-1-1 Received: from [216.105.38.7] ([216.105.38.7:51874] helo=lists.sourceforge.net) by smtp22.gate.iad3b.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id CA/6E-16510-1FD81DD5; Sun, 17 Nov 2019 13:14:10 -0500 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 1iWP2w-0005SG-9i; Sun, 17 Nov 2019 18:13:14 +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 1iWP2n-0005Qh-1t for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 18:13: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=or0SF4sTqOBBhnHjBE3c4Kx5Ge9un5mEiCRg4tvFn6o=; b=TjX3oNDIRCIcMMLzndfZD4c5vc UFW/Yi+7gWmxU+C2spOGC0u7XYkRrYCgQJ3idNRLxGwWJxmhScq3r3A3Aie2rQBYWFgkr7D6UZjpc 87Y6mqvjJLDxYCd3EZQxF/Q84CiwBrcxftdyQaS6Fcs0t4joWYxYEGuDy3b71WRFS/Ho=; 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=or0SF4sTqOBBhnHjBE3c4Kx5Ge9un5mEiCRg4tvFn6o=; b=CEaEuHJ5Dnx02YkSBhGB8NBbbs Mki5WdXPu93dhwZ7okP8BY/DMQdcup4PhAIUYElmHeQ5WMcTBI8rJRamyjMxa8L6n2TH3zr/zr1o1 vpguHaooq7W1m8MufnC8T0txzeMcKsio76ePa4DwOfwmTo+mTKKIhgSXwr0lVpVe+1yo=; Received: from [192.26.174.232] (helo=mail.blinkt.de) by sfi-mx-3.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1iWP2j-003csx-Ar for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 18:13:05 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.92.3 (FreeBSD)) (envelope-from ) id 1iWP2S-000Af2-8q for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 19:12:44 +0100 Received: (nullmailer pid 28975 invoked by uid 10006); Sun, 17 Nov 2019 18:12:44 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Sun, 17 Nov 2019 19:12:43 +0100 Message-Id: <20191117181243.28919-4-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191117181243.28919-1-arne@rfc2549.org> References: <20191117181243.28919-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.0 URIBL_BLOCKED ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [URIs: rfc2549.org] 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 1.0 RDNS_NONE Delivered to internal network by a host with no rDNS -0.2 AWL AWL: Adjusted score from AWL reputation of From: address X-Headers-End: 1iWP2j-003csx-Ar Subject: [Openvpn-devel] [PATCH 4/4] Normalise ncp-ciphers option and restrict it to 127 bytes 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 In scenarios of mbed TLS vs OpenSSL we already normalise the ciphers that are send via the wire protocol via OCC to not have a mismatch warning between server and client. This is done by translate_cipher_name_from_openvpn. The same applies also to the ncp-ciphers list. Specifying non normalised names in ncp-ciphers will cause negotation not to succeed if ciphers are not in the same form. Therefore we will normalise the ciphers in options_postmutate. The alternative and a lot less user friendly alternative would be to bail if on of the ciphers in ncp-ciphers is not in its normalised form. Also restrict the ncp-ciphers list to 127. This is somewhat arbitrary but should prevent too large IV_CIPHER messages and problems sending those. The server will accept also large IV_CIPHER values from clients. Signed-off-by: Arne Schwabe --- doc/openvpn.8 | 3 ++ src/openvpn/options.c | 14 +++++--- src/openvpn/ssl_ncp.c | 55 +++++++++++++++++++++++++---- src/openvpn/ssl_ncp.h | 19 ++++++++-- tests/unit_tests/openvpn/test_ncp.c | 40 ++++++++++++++------- 5 files changed, 104 insertions(+), 27 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 4f0df786..a71b1c14 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4400,6 +4400,9 @@ AES\-256\-GCM:AES\-256\-CBC" set can either specify "\-\-cipher BF\-CBC" or Note, for using NCP with a OpenVPN 2.4 peer this list must include the AES\-256\-GCM and AES\-128\-GCM ciphers. + +This list is restricted to be 127 chars long after conversion to OpenVPN +ciphers. .\"********************************************************* .TP .B \-\-ncp\-disable diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 9be5a826..fd069c75 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2500,11 +2500,6 @@ options_postprocess_verify_ce(const struct options *options, const struct connec } #endif /* P2MP_SERVER */ - if (options->ncp_enabled && !tls_check_ncp_cipher_list(options->ncp_ciphers)) - { - msg(M_USAGE, "NCP cipher list contains unsupported ciphers."); - } - if (options->keysize) { msg(M_WARN, "WARNING: --keysize is DEPRECATED and will be removed in OpenVPN 2.6"); @@ -3079,6 +3074,15 @@ options_postprocess_mutate(struct options *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) + { + msg(M_USAGE, "NCP cipher list contains unsupported ciphers or is too long."); + } + } + if (o->remote_list && !o->connection_list) { /* diff --git a/src/openvpn/ssl_ncp.c b/src/openvpn/ssl_ncp.c index 029ac1d5..ee3c2cb7 100644 --- a/src/openvpn/ssl_ncp.c +++ b/src/openvpn/ssl_ncp.c @@ -91,27 +91,68 @@ tls_peer_supports_ncp(const char *peer_info) } } -bool -tls_check_ncp_cipher_list(const char *list) +char * +mutate_ncp_cipher_list(const char *list, struct gc_arena *gc) { - bool unsupported_cipher_found = false; + bool error_found = false; - ASSERT(list); + struct buffer new_list = alloc_buf(MAX_NCP_CIPHERS_LENGTH); char *const tmp_ciphers = string_alloc(list, NULL); const char *token = strtok(tmp_ciphers, ":"); while (token) { - if (!cipher_kt_get(translate_cipher_name_from_openvpn(token))) + /* translate_cipher_name_from_openvpn also normalises the cipher name, + * e.g. replacing AeS-128-gCm with AES-128-GCM + */ + const char *cipher_name = translate_cipher_name_from_openvpn(token); + const cipher_kt_t *ktc = cipher_kt_get(cipher_name); + if (!ktc) { msg(M_WARN, "Unsupported cipher in --ncp-ciphers: %s", token); - unsupported_cipher_found = true; + error_found = true; + } + else + { + const char *ovpn_cipher_name = + translate_cipher_name_to_openvpn(cipher_kt_name(ktc)); + + if (buf_len(&new_list)> 0) + { + /* The next if condition ensure there is always space for + * a : + */ + buf_puts(&new_list, ":"); + } + + /* Ensure buffer has capacity for cipher name + : + \0 */ + if (!(buf_forward_capacity(&new_list) > + strlen(ovpn_cipher_name) + 2)) + { + msg(M_WARN, "Length of --ncp-ciphers is over the" + "limit of 127 chars"); + error_found = true; + } + else + { + buf_puts(&new_list, ovpn_cipher_name); + } } token = strtok(NULL, ":"); } + + + + char *ret = NULL; + if (!error_found && buf_len(&new_list) > 0) + { + buf_null_terminate(&new_list); + ret = string_alloc(buf_str(&new_list), gc); + } free(tmp_ciphers); + free_buf(&new_list); - return 0 < strlen(list) && !unsupported_cipher_found; + return ret; } bool diff --git a/src/openvpn/ssl_ncp.h b/src/openvpn/ssl_ncp.h index 82d008d8..62822e89 100644 --- a/src/openvpn/ssl_ncp.h +++ b/src/openvpn/ssl_ncp.h @@ -87,10 +87,17 @@ tls_peer_ncp_list(const char *peer_info); * Check whether the ciphers in the supplied list are supported. * * @param list Colon-separated list of ciphers + * @parms gc gc_arena to allocate the returned string * - * @returns true iff all ciphers in list are supported. + * @returns colon separated string of normalised (via + * translate_cipher_name_from_openvpn) and + * zero terminated string iff all ciphers + * in list are supported and the total length + * is short than MAX_NCP_CIPHERS_LENGTH. NULL + * otherwise. */ -bool tls_check_ncp_cipher_list(const char *list); +char * +mutate_ncp_cipher_list(const char *list, struct gc_arena *gc); /** * Return true iff item is present in the colon-separated zero-terminated @@ -98,4 +105,12 @@ bool tls_check_ncp_cipher_list(const char *list); */ bool tls_item_in_cipher_list(const char *item, const char *list); +/** + * The maximum length of a ncp-cipher string that is accepted. + * + * Since this list needs to be pushed as IV_CIPHERS, we are conservative + * about its length. + */ +#define MAX_NCP_CIPHERS_LENGTH 127 + #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 e71f4825..7684eed4 100644 --- a/tests/unit_tests/openvpn/test_ncp.c +++ b/tests/unit_tests/openvpn/test_ncp.c @@ -47,10 +47,24 @@ const char *aes_ciphers = "AES-256-GCM:AES-128-GCM"; static void test_check_ncp_ciphers_list(void **state) { - assert_true(tls_check_ncp_cipher_list(aes_ciphers)); - assert_true(tls_check_ncp_cipher_list(bf_chacha)); - assert_false(tls_check_ncp_cipher_list("vollbit")); - assert_false(tls_check_ncp_cipher_list("AES-256-GCM:vollbit")); + struct gc_arena gc = gc_new(); + + assert_string_equal(mutate_ncp_cipher_list(aes_ciphers, &gc), aes_ciphers); + + assert_string_equal(mutate_ncp_cipher_list(bf_chacha, &gc), bf_chacha); + + assert_string_equal(mutate_ncp_cipher_list("BF-cbc:ChaCha20-Poly1305", &gc), + bf_chacha); + + + assert_ptr_equal(mutate_ncp_cipher_list("vollbit", &gc), NULL); + assert_ptr_equal(mutate_ncp_cipher_list("AES-256-GCM:vollbit", &gc), NULL); + assert_ptr_equal(mutate_ncp_cipher_list("", &gc), NULL); + + assert_ptr_equal(mutate_ncp_cipher_list( + "ChaCha20-Poly1305:ChaCha20-Poly1305:ChaCha20-Poly1305:" + "ChaCha20-Poly1305:ChaCha20-Poly1305:ChaCha20-Poly1305:" + "ChaCha20-Poly1305", &gc), NULL); } static void @@ -64,7 +78,7 @@ test_extract_client_ciphers(void **state) assert_string_equal(aes_ciphers,peer_list); assert_true(tls_peer_supports_ncp(client_peer_info)); free(peer_list); - + client_peer_info = "foo=bar\nIV_foo=y\nIV_NCP=2\nIV_CIPHERS=BF-CBC"; peer_list = tls_peer_ncp_list(client_peer_info); assert_string_equal("BF-CBC", peer_list); @@ -101,8 +115,8 @@ test_poor_man(void **state) struct gc_arena gc = gc_new(); char *best_cipher; - const char *serverlist="CHACHA20_POLY1305:AES-128-GCM"; - + const char *serverlist = "CHACHA20_POLY1305:AES-128-GCM"; + best_cipher = ncp_get_best_cipher(serverlist, "BF-CBC", "IV_YOLO=NO\nIV_BAR=7", "BF-CBC", &gc); @@ -131,8 +145,8 @@ test_ncp_best(void **state) struct gc_arena gc = gc_new(); char *best_cipher; - const char *serverlist="CHACHA20_POLY1305:AES-128-GCM:AES-256-GCM"; - + const char *serverlist = "CHACHA20_POLY1305:AES-128-GCM:AES-256-GCM"; + best_cipher = ncp_get_best_cipher(serverlist, "BF-CBC", "IV_YOLO=NO\nIV_NCP=2\nIV_BAR=7", "BF-CBC", &gc); @@ -150,7 +164,7 @@ test_ncp_best(void **state) best_cipher = ncp_get_best_cipher(serverlist, "BF-CBC", "IV_CIPHERS=AES-128-GCM", "AES-256-CBC", &gc); - + assert_string_equal(best_cipher, "AES-128-GCM"); @@ -167,16 +181,16 @@ test_ncp_best(void **state) - const struct CMUnitTest ncp_tests[] = { cmocka_unit_test(test_check_ncp_ciphers_list), - cmocka_unit_test(test_extract_client_ciphers), + cmocka_unit_test(test_extract_client_ciphers), cmocka_unit_test(test_poor_man), cmocka_unit_test(test_ncp_best) }; -int main(void) +int +main(void) { return cmocka_run_group_tests(ncp_tests, NULL, NULL); } From patchwork Sun Nov 17 10:23:17 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 926 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director7.mail.ord1d.rsapps.net ([172.27.255.54]) by backend30.mail.ord1d.rsapps.net with LMTP id oM0aJ5e60V0OLQAAIUCqbw for ; Sun, 17 Nov 2019 16:24:39 -0500 Received: from proxy4.mail.iad3a.rsapps.net ([172.27.255.54]) by director7.mail.ord1d.rsapps.net with LMTP id ALdCJJe60V0LFwAAovjBpQ ; Sun, 17 Nov 2019 16:24:39 -0500 Received: from smtp30.gate.iad3a ([172.27.255.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy4.mail.iad3a.rsapps.net with LMTP id 4EIZHpe60V3lAQAA8Zvu4w ; Sun, 17 Nov 2019 16:24:39 -0500 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: smtp30.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: a9185104-0980-11ea-9743-525400089674-1-1 Received: from [216.105.38.7] ([216.105.38.7:39824] helo=lists.sourceforge.net) by smtp30.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 4F/CC-09234-79AB1DD5; Sun, 17 Nov 2019 16:24:39 -0500 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 1iWS17-00054J-Uw; Sun, 17 Nov 2019 21:23:33 +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 1iWS16-000548-Up for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 21:23:32 +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=aJHMW2W7JK6JeppGHbfKEvKaSZ/FNpkLpe+mZ+XcMYo=; b=BDfxb6uC1N5D7i83TyaJWR3GVe 2Ps6WQ8oRx229edJ5lbhLUY5GEBWjHiMiaX0q1Dy1yNvbWhfFElazNEW+eOO/d89CZkyFL7P4gQRu Az72v+qTPwb4MbYpuyQxUOK9GyeBGS4Oq0aHeccFqORx+S5fFx56SgK1mekSk4KXFNTo=; 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=aJHMW2W7JK6JeppGHbfKEvKaSZ/FNpkLpe+mZ+XcMYo=; b=nVH/Ea2ptZCsadfXdaWx4HYl1L 381RR9OlwPktqI9xnRYEO5AHFhwtfcZ3aibnMsvCcl85UDRcv7dFMrWA8bp06Lh61Kk0bojoUy8Q6 A902kycH+DZs5T8ImSpcr8/H5/GpxslBHLLC1c5N3SWvDY78aUgkZGGGWN2OsGXZokEg=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-3.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1iWS13-003pVb-Lm for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 21:23:32 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.92.3 (FreeBSD)) (envelope-from ) id 1iWS0s-000BSW-Kx for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 22:23:18 +0100 Received: (nullmailer pid 13473 invoked by uid 10006); Sun, 17 Nov 2019 21:23:18 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Sun, 17 Nov 2019 22:23:17 +0100 Message-Id: <20191117212318.13428-1-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191117181243.28919-1-arne@rfc2549.org> References: <20191117181243.28919-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.0 URIBL_BLOCKED ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [URIs: rfc2549.org] 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.3 AWL AWL: Adjusted score from AWL reputation of From: address X-Headers-End: 1iWS13-003pVb-Lm Subject: [Openvpn-devel] [PATCH 5/4] Add ncp files to Visual studio print 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 Signed-off-by: Arne Schwabe --- src/openvpn/openvpn.vcxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj index 7446d97d..b3d35ba2 100644 --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -191,6 +191,7 @@ + @@ -276,6 +277,7 @@ + From patchwork Sun Nov 17 10:23:18 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 927 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director11.mail.ord1d.rsapps.net ([172.27.255.54]) by backend30.mail.ord1d.rsapps.net with LMTP id yPauI5i60V3AFgAAIUCqbw for ; Sun, 17 Nov 2019 16:24:40 -0500 Received: from proxy5.mail.iad3a.rsapps.net ([172.27.255.54]) by director11.mail.ord1d.rsapps.net with LMTP id wA/EIJi60V1BXAAAvGGmqA ; Sun, 17 Nov 2019 16:24:40 -0500 Received: from smtp32.gate.iad3a ([172.27.255.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy5.mail.iad3a.rsapps.net with LMTP id QLAxGpi60V2SFQAAhn5joQ ; Sun, 17 Nov 2019 16:24:40 -0500 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: smtp32.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: a90c6560-0980-11ea-a09c-5254001741cc-1-1 Received: from [216.105.38.7] ([216.105.38.7:47340] helo=lists.sourceforge.net) by smtp32.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 03/C2-01252-79AB1DD5; Sun, 17 Nov 2019 16:24:39 -0500 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.90_1) (envelope-from ) id 1iWS15-0002JP-CC; Sun, 17 Nov 2019 21:23:31 +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.90_1) (envelope-from ) id 1iWS14-0002J0-2y for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 21:23:30 +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=DhMUZdpS524ppl+5535V3yvt04e8Bsh6XHyaOjI0gJk=; b=A35ibI+uj7R77xNJc85iJVntBG 3d3AXLJRWNqd0+9jEn3H/26WZufkD1L3HDUxvcN50OCSzwx7PsWpBgz+xKmoC93O/pS7sRv7DxJ9m SqTrZ4qZYlS8TOZW2YvEatp8KzUC6axYxKQJ3ZP+IntkDDsHwiMP5CyhLhwIb6aOpc9I=; 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=DhMUZdpS524ppl+5535V3yvt04e8Bsh6XHyaOjI0gJk=; b=lI/9MFyIraRgjuVwKuz57c+dBf g45qinSFUz+TEOi22L/s/ROVhKBZyOf094QV7upKtgvQeHRsd1VNHYWxDAP+KIcim1ri3ZAH44Bcg /4OYrOllXp8E60FRrfpNiHAedrps5Tk1kcptkVIplh31dtG2nxpc0AiypEVxF8pbw6WQ=; 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 1iWS10-009aSq-7W for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 21:23:30 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.92.3 (FreeBSD)) (envelope-from ) id 1iWS0s-000BSZ-Nx for openvpn-devel@lists.sourceforge.net; Sun, 17 Nov 2019 22:23:18 +0100 Received: (nullmailer pid 13476 invoked by uid 10006); Sun, 17 Nov 2019 21:23:18 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Sun, 17 Nov 2019 22:23:18 +0100 Message-Id: <20191117212318.13428-2-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191117212318.13428-1-arne@rfc2549.org> References: <20191117181243.28919-1-arne@rfc2549.org> <20191117212318.13428-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.0 URIBL_BLOCKED ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [URIs: makefile.am] 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.4 AWL AWL: Adjusted score from AWL reputation of From: address X-Headers-End: 1iWS10-009aSq-7W Subject: [Openvpn-devel] [PATCH 6/4] Add strsep compat function X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox Some operating system do not have the strsep function. Since this API is more "modern" (4.4BSD) than strtok, add it as compat function. At least Windows is missing strsep. FreeBSD, Linux, macOS and OpenSolaris should not need the compat function. Signed-off-by: Arne Schwabe --- configure.ac | 2 +- src/compat/Makefile.am | 1 + src/compat/compat-strsep.c | 61 ++++++++++++++++++++++++++++++++++++++ src/compat/compat.h | 4 +++ src/compat/compat.vcxproj | 3 +- 5 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 src/compat/compat-strsep.c diff --git a/configure.ac b/configure.ac index 807804e5..a9fd8e77 100644 --- a/configure.ac +++ b/configure.ac @@ -655,7 +655,7 @@ AC_CHECK_FUNCS([ \ ctime memset vsnprintf strdup \ setsid chdir putenv getpeername unlink \ chsize ftruncate execve getpeereid umask basename dirname access \ - epoll_create \ + epoll_create strsep \ ]) AC_CHECK_LIB( diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am index b51f661e..2e94e943 100644 --- a/src/compat/Makefile.am +++ b/src/compat/Makefile.am @@ -30,4 +30,5 @@ libcompat_la_SOURCES = \ compat-inet_ntop.c \ compat-inet_pton.c \ compat-lz4.c compat-lz4.h \ + compat-strsep.c \ compat-versionhelpers.h diff --git a/src/compat/compat-strsep.c b/src/compat/compat-strsep.c new file mode 100644 index 00000000..42ff6414 --- /dev/null +++ b/src/compat/compat-strsep.c @@ -0,0 +1,61 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2019 Arne Schwabe + * Copyright (C) 1992-2019 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#ifndef HAVE_STRSEP +#include + +/* + * Modified version based on the glibc + */ +char * +strsep(char **stringp, const char *delim) +{ + char *begin, *end; + begin = *stringp; + if (begin == NULL) + { + return NULL; + } + /* Find the end of the token. */ + end = begin + strcspn(begin, delim); + if (*end) + { + /* Terminate the token and set *STRINGP past NUL character. */ + *end++ = '\0'; + *stringp = end; + } + else + { + /* No more delimiters; this is the last token. */ + *stringp = NULL; + } + return begin; +} +#endif diff --git a/src/compat/compat.h b/src/compat/compat.h index d5228989..592881df 100644 --- a/src/compat/compat.h +++ b/src/compat/compat.h @@ -70,4 +70,8 @@ int inet_pton(int af, const char *src, void *dst); #endif +#ifndef HAVE_STRSEP +char* strsep(char **stringp, const char *delim); +#endif + #endif /* COMPAT_H */ diff --git a/src/compat/compat.vcxproj b/src/compat/compat.vcxproj index e388008a..0c4c7b0f 100644 --- a/src/compat/compat.vcxproj +++ b/src/compat/compat.vcxproj @@ -102,6 +102,7 @@ + @@ -115,4 +116,4 @@ - \ No newline at end of file +