From patchwork Tue Apr 17 05:51:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Jason A. Donenfeld" X-Patchwork-Id: 303 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director8.mail.ord1d.rsapps.net ([172.27.255.53]) by backend30.mail.ord1d.rsapps.net (Dovecot) with LMTP id TP9dDZoe1lo/VQAAIUCqbw for ; Tue, 17 Apr 2018 12:19:38 -0400 Received: from proxy10.mail.iad3a.rsapps.net ([172.27.255.53]) by director8.mail.ord1d.rsapps.net (Dovecot) with LMTP id G2Z2Gpoe1lrPdQAAfY0hYg ; Tue, 17 Apr 2018 12:19:38 -0400 Received: from smtp30.gate.iad3a ([172.27.255.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy10.mail.iad3a.rsapps.net with LMTP id WKGnGJoe1lptbgAAnQ/bqA ; Tue, 17 Apr 2018 12:19:38 -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: 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; dkim=fail (signature verification failed) header.d=zx2c4.com; dmarc=fail (p=none; dis=none) header.from=zx2c4.com X-Suspicious-Flag: YES X-Classification-ID: 1f517024-425b-11e8-85ac-525400089674-1-1 Received: from [216.105.38.7] ([216.105.38.7:38031] helo=lists.sourceforge.net) by smtp30.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.1.56364 r(Core:4.2.1.14)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 73/98-21249-99E16DA5; Tue, 17 Apr 2018 12:19:38 -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 1f8TJd-0004Gq-7N; Tue, 17 Apr 2018 16:18:45 +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 1f8TJb-0004Gh-I2 for openvpn-devel@lists.sourceforge.net; Tue, 17 Apr 2018 16:18:43 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Type:MIME-Version:Message-ID:Subject:Cc:To: From:Date:Sender:Reply-To: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=at7vtZKwjML/XQ0XfoeMWJYFEGmIablrAwVsvGmbQlM=; b=fDPM49doSNFrBvzqXiqjEv+NBo 0UgHD28gSttCRpR6Shb2wgvae22/sRUhUaQHcReiu6U7ouXbLQgxron1kz3YVE4poGh5WymYXg1Q2 6PaswDARiN/pBW4e4uXhwQmOtghiKXTHxqdh5M6vUdIOtScDiNehJ2JMIVOjhzoRtHBw=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Type:MIME-Version:Message-ID:Subject:Cc:To:From:Date:Sender: Reply-To: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=at7vtZKwjML/XQ0XfoeMWJYFEGmIablrAwVsvGmbQlM=; b=H kLauV3m/nIoyrwvEm+X8yx4r7X8uz5mc9vD3R/iOzhy4xmYfEOY1lAiFtnGCgQLUHWJsK1AZPjQNS WvGSs+drxn0/UjoqXZRvpH4AUAIxS0I0+Z4ahZxO0NWgogxUlguv1ZRXrZX0NpMFw1WtlCt8N6O3w DEUWTuLNz6zxUOWg=; Received: from frisell.zx2c4.com ([192.95.5.64]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) id 1f8TJY-00HM4F-Ee for openvpn-devel@lists.sourceforge.net; Tue, 17 Apr 2018 16:18:43 +0000 Received: by frisell.zx2c4.com (ZX2C4 Mail Server) with ESMTP id af66e72c; Tue, 17 Apr 2018 15:28:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=zx2c4.com; h=date:from:to :cc:subject:message-id:mime-version:content-type; s=mail; bh=I3X TyRoHvvmNxKLjZc8QZGQZ5Tw=; b=zaNDkWez+USQm8XGJQ+2tqSZGeB0DYeY43x kWPx7IxCKV5yGfgHgc0cYYzC0MqGHLo0Mby/rv380SdBV0c5sDQ9aOjhop5ln8Z+ 3NE18R1kmmgKmXDuG4EgWGDtKSHG3VPxrvclb4WKKPBWbC8D+O2dR10f0i56iqsB eA22wKyvrPCPVlbZBTAxB6a7E6O9v0tMwNmouEyLfZT3SImJeB4Qa6jYpswZgud5 +KEKfqoaooLqoGd+aaBsNO25sGZk1wNKVs/KFGSU7M/tbg2UDvDfR2TeQe5AdRcF Xq6RUKKZLlgA6ThgjiD9PWkL4rwqUhM/ukGGgj2ijA+DYqeRSSg== Received: by frisell.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 6420e7cf (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256:NO); Tue, 17 Apr 2018 15:28:22 +0000 (UTC) Date: Tue, 17 Apr 2018 17:51:51 +0200 From: "Jason A. Donenfeld" To: openvpn-devel@lists.sourceforge.net Message-ID: <20180417155149.GA20143@zx2c4.com> MIME-Version: 1.0 Content-Disposition: inline X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [192.95.5.64 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-Headers-End: 1f8TJY-00HM4F-Ee Subject: [Openvpn-devel] Fingerprint-based Auth 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: , Cc: Rogier.Spoor@surfnet.nl Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox Hello list, OpenVPN traditionally works around CAs. However many TLS-based protocols also allow an alternative simpler mode in which rather than verify certificates against CAs, the certificate itself is hashed and compared against a pre-known set of acceptable hashes. This is usually referred to as "fingerprint verification". It's popular across SMTP servers, IRC servers, XMPP servers, and even in the context of HTTP with pinning. So, I'd like to propose an extremely simple and non-invasive way of supporting this in OpenVPN, by re-using several features that already basically support it. Namely, what I propose is: * Allow specifying 'none' to the --ca parameter, to specify that certificates should not be checked against a CA. Note that 'none' is already used in other similar options as a special placeholder. * When '--ca none' is in use, --verify-hash checks all depths instead of just level 1. With these very simple changes, fingerprint authentication is easily achieved via the --tls-verify script on the server and via --verify-hash on the client. I wrote an extremely crufty patch for this -- which I'm sure you'll want to rewrite -- that I thought might provide some lens as to how simple of a change this is. I've also included some instructions on how to use all of this. I'm busy with WireGuard and won't have time to fully develop this feature, but the CC'd parties are very interested in having it, so hopefully someone will step up to bring this sketch to fruition. Regards, Jason Server side: ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ============ Make self-signed cert: $ openssl req -x509 -newkey ec:<(openssl ecparam -name secp384r1) -keyout key.pem -out cert.pem -nodes -sha256 -days 3650 -subj '/CN=server' Record our fingerprint in an environment variable for the client to use later: $ server_fingerprint="$(openssl x509 -in cert.pem -noout -sha256 -fingerprint | sed 's/.*=//;s/\(.*\)/\L\1/')" Start openvpn with tls verify script: $ sudo openvpn --server 10.66.0.0 255.255.255.0 --dev tun --dh none --ca none --cert cert.pem --key key.pem --tls-verify $(readlink -f tls-verify.sh) --script-security 2 TLS Verify Script: ================== #!/bin/sh [ -n "$tls_digest_sha256_0" -a -e "/tmp/allowed-openvpn-fingerprints/$tls_digest_sha256_0" ] Client side: ============ Make self-signed cert: $ openssl req -x509 -newkey ec:<(openssl ecparam -name secp384r1) -keyout key.pem -out cert.pem -nodes -sha256 -days 3650 -subj '/CN=client' "Tell" the server about our fingerprint: $ mkdir -p /tmp/allowed-openvpn-fingerprints; touch "/tmp/allowed-openvpn-fingerprints/$(openssl x509 -in cert.pem -noout -sha256 -fingerprint | sed 's/.*=//;s/\(.*\)/\L\1/')" Start openvpn with server fingerprint verification: $ sudo openvpn --client --remote 127.0.0.1 --dev tun --ca none --cert cert.pem --key key.pem --verify-hash "$server_fingerprint" SHA256 --nobind Crufty patch: ============= diff -ru openvpn-2.4.5/src/openvpn/init.c openvpn-2.4.5-modified/src/openvpn/init.c --- openvpn-2.4.5/src/openvpn/init.c 2018-03-01 08:22:19.000000000 +0100 +++ openvpn-2.4.5-modified/src/openvpn/init.c 2018-04-17 17:15:09.388690819 +0200 @@ -2749,6 +2749,7 @@ to.remote_cert_eku = options->remote_cert_eku; to.verify_hash = options->verify_hash; to.verify_hash_algo = options->verify_hash_algo; + to.ca_file_none = options->ca_file_none; #ifdef ENABLE_X509ALTUSERNAME to.x509_username_field = (char *) options->x509_username_field; #else diff -ru openvpn-2.4.5/src/openvpn/options.c openvpn-2.4.5-modified/src/openvpn/options.c --- openvpn-2.4.5/src/openvpn/options.c 2018-03-01 08:22:19.000000000 +0100 +++ openvpn-2.4.5-modified/src/openvpn/options.c 2018-04-17 16:54:11.523414012 +0200 @@ -3290,7 +3290,10 @@ #ifdef ENABLE_CRYPTO /* ** SSL/TLS/crypto related files ** */ errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE, options->dh_file, R_OK, "--dh"); - errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE, options->ca_file, R_OK, "--ca"); + if (!options->ca_file_none) + { + errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE, options->ca_file, R_OK, "--ca"); + } errs |= check_file_access_chroot(options->chroot_dir, CHKACC_FILE, options->ca_path, R_OK, "--capath"); errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE, options->cert_file, R_OK, "--cert"); errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE, options->extra_certs_file, R_OK, @@ -7700,6 +7703,10 @@ { options->ca_file_inline = p[2]; } + else if (streq(p[1], "none")) + { + options->ca_file_none = true; + } } #ifndef ENABLE_CRYPTO_MBEDTLS else if (streq(p[0], "capath") && p[1] && !p[2]) diff -ru openvpn-2.4.5/src/openvpn/options.h openvpn-2.4.5-modified/src/openvpn/options.h --- openvpn-2.4.5/src/openvpn/options.h 2018-03-01 08:22:19.000000000 +0100 +++ openvpn-2.4.5-modified/src/openvpn/options.h 2018-04-17 16:51:00.962640290 +0200 @@ -495,6 +495,7 @@ /* TLS (control channel) parms */ bool tls_server; bool tls_client; + bool ca_file_none; const char *ca_file; const char *ca_path; const char *dh_file; diff -ru openvpn-2.4.5/src/openvpn/ssl.c openvpn-2.4.5-modified/src/openvpn/ssl.c --- openvpn-2.4.5/src/openvpn/ssl.c 2018-03-01 08:22:19.000000000 +0100 +++ openvpn-2.4.5-modified/src/openvpn/ssl.c 2018-04-17 17:14:00.563153748 +0200 @@ -695,7 +695,7 @@ } } - if (options->ca_file || options->ca_path) + if ((!options->ca_file_none && options->ca_file) || options->ca_path) { tls_ctx_load_ca(new_ctx, options->ca_file, options->ca_file_inline, options->ca_path, options->tls_server); diff -ru openvpn-2.4.5/src/openvpn/ssl_common.h openvpn-2.4.5-modified/src/openvpn/ssl_common.h --- openvpn-2.4.5/src/openvpn/ssl_common.h 2018-03-01 08:22:19.000000000 +0100 +++ openvpn-2.4.5-modified/src/openvpn/ssl_common.h 2018-04-17 17:14:41.447285597 +0200 @@ -272,6 +272,7 @@ uint8_t *verify_hash; hash_algo_type verify_hash_algo; char *x509_username_field; + bool ca_file_none; /* allow openvpn config info to be * passed over control channel */ diff -ru openvpn-2.4.5/src/openvpn/ssl_verify.c openvpn-2.4.5-modified/src/openvpn/ssl_verify.c --- openvpn-2.4.5/src/openvpn/ssl_verify.c 2018-03-01 08:22:19.000000000 +0100 +++ openvpn-2.4.5-modified/src/openvpn/ssl_verify.c 2018-04-17 17:17:55.230139543 +0200 @@ -719,7 +719,7 @@ } /* verify level 1 cert, i.e. the CA that signed our leaf cert */ - if (cert_depth == 1 && opt->verify_hash) + if ((opt->ca_file_none || cert_depth == 1) && opt->verify_hash) { struct buffer ca_hash = {0}; diff -ru openvpn-2.4.5/src/openvpn/ssl_verify_openssl.c openvpn-2.4.5-modified/src/openvpn/ssl_verify_openssl.c --- openvpn-2.4.5/src/openvpn/ssl_verify_openssl.c 2018-03-01 08:22:19.000000000 +0100 +++ openvpn-2.4.5-modified/src/openvpn/ssl_verify_openssl.c 2018-04-17 17:17:30.001681856 +0200 @@ -66,7 +66,7 @@ cert_hash_remember(session, X509_STORE_CTX_get_error_depth(ctx), &cert_hash); /* did peer present cert which was signed by our root cert? */ - if (!preverify_ok) + if (!preverify_ok && !session->opt->ca_file_none) { /* get the X509 name */ char *subject = x509_get_subject(current_cert, &gc);