From patchwork Sat Nov 11 04:36:53 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steffan Karger X-Patchwork-Id: 62 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director1.mail.ord1d.rsapps.net ([172.28.255.1]) by backend31.mail.ord1d.rsapps.net (Dovecot) with LMTP id QwjuFFQZB1qjVQAAgoeIoA for ; Sat, 11 Nov 2017 10:37:56 -0500 Received: from director4.mail.ord1c.rsapps.net ([172.28.255.1]) by director1.mail.ord1d.rsapps.net (Dovecot) with LMTP id cyiUFFQZB1quPQAANGzteQ ; Sat, 11 Nov 2017 10:37:56 -0500 Received: from smtp34.gate.ord1c ([172.28.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by director4.mail.ord1c.rsapps.net (Dovecot) with LMTP id Sj20G1QZB1ouVQAAsEL7Xg ; Sat, 11 Nov 2017 10:37:56 -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.34.181.88] Authentication-Results: smtp34.gate.ord1c.rsapps.net; iprev=pass policy.iprev="216.34.181.88"; 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=karger-me.20150623.gappssmtp.com; dmarc=none (p=nil; dis=none) header.from=karger.me X-Classification-ID: 49a230e2-c6f6-11e7-a75f-0026b93662df-1-1 Received: from [216.34.181.88] ([216.34.181.88:13260] helo=lists.sourceforge.net) by smtp34.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.1.56364 r(Core:4.2.1.14)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id B1/33-31808-359170A5; Sat, 11 Nov 2017 10:37:55 -0500 Received: from localhost ([127.0.0.1] helo=sfs-ml-2.v29.ch3.sourceforge.com) by sfs-ml-2.v29.ch3.sourceforge.com with esmtp (Exim 4.89) (envelope-from ) id 1eDXqO-0002cL-Mf; Sat, 11 Nov 2017 15:37:16 +0000 Received: from sfi-mx-1.v28.ch3.sourceforge.com ([172.29.28.191] helo=mx.sourceforge.net) by sfs-ml-2.v29.ch3.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.89) (envelope-from ) id 1eDXqN-0002cD-7G for openvpn-devel@lists.sourceforge.net; Sat, 11 Nov 2017 15:37:15 +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:Cc: To:From:Sender:Reply-To: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=lSjdeSG8DZI7qcCH1g77aBPE+KKDJ3mG5RDwpKD55Eg=; b=S7n/y+8jcOwhaMhgMF1C0vA30X luq+W4Y0lROG6vby4Qt+SLx2/JTdygE9l7vZAifcaybPDDjtstjtWtr4ZbTLDujBA7KZAMrtxA9ut K8o9F3mQpCuRp/w4JENGNDirYSHUM4NBrSLEF+tczZ4lSbl8rA2d11N+DkAce1If9B34=; 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:Cc:To:From:Sender:Reply-To :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=lSjdeSG8DZI7qcCH1g77aBPE+KKDJ3mG5RDwpKD55Eg=; b=DiuX8rKlOfjfRuIx/0qgu50cao Si+KuHD4MdRcYkdoOufcATH3GJyRiCx4jbl1y8Ic1pNaCh8As9tP7Is+EomG8t5sfPcoQCszeQYV2 6A/7I+6hOH+f8q/rCVIJQm2Bf2DLbx3uM2v/Vi4HH1YA+Efw91PC8wSjfqr+lL+HlOGs=; Received: from mail-wm0-f52.google.com ([74.125.82.52]) by sfi-mx-1.v28.ch3.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.89) id 1eDXqK-000804-NI for openvpn-devel@lists.sourceforge.net; Sat, 11 Nov 2017 15:37:15 +0000 Received: by mail-wm0-f52.google.com with SMTP id n74so8995490wmi.1 for ; Sat, 11 Nov 2017 07:37:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=karger-me.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=lSjdeSG8DZI7qcCH1g77aBPE+KKDJ3mG5RDwpKD55Eg=; b=yjNV1MSrtnNIVJhoQYe+ktgdkLuMAXpKU6N1fgLx6SoxvP5vlcoVVH/rqVFPfU0ftK QE6AIJRHBtyh/waPB03BVCcgMaDhGeZp20/dU5V7OnL92G6Ho72QkZH5Im37vXyGtDlm mbfyJplSS4GCKShwQV+k0TAZFBpRJDFY/mXfupRjKHR+g1KzNUy0pifpU6aMm/+7t1pj UUE1eT+zKaKzpgW2VWu7/au9eGZ8p/yYpiftPhLwuwZKPjTD4r7dkA+z910n9JrReXaB vtuas8fBHIuILdXiVDzlAUqMJv03/gWnwUbNbFiO2waPDq7DKf3MNDSg0/3COtFczwN2 8DrA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=lSjdeSG8DZI7qcCH1g77aBPE+KKDJ3mG5RDwpKD55Eg=; b=aE87VHW0uE7QUDsV5GFe0qAvzdCIVmvlnJYPcuBJSuDKZELC8HxXqimVX6+iufNHD4 8iCl/R40JjaUTOLfLcNv/U70Gdm4GB865QuhiEHHYj8Psn2PdrBEd0DnAiIw3pgMPGd7 ZIMv6HqVuJWrBVd3+R69a2lP+HJB9q6k4MP7FK4/tN77nLVqsf1CtKfO1xZIEHDFEJTG c76euBrrmoC9cSW1jC09x0gnoNYGYEhlZTzR0yFSHa+KgOrEf/iBW+671okmZfFqfBcl EONAafHy++r9Zw3hgmCqXZZesJEkFQjQvbaRJp4KG6X2CRcYAsxtTGfccd+K6w+EW1Dl e1gg== X-Gm-Message-State: AJaThX5ktxw9YNBS76UEs3eiqbFM/aW/sIsNs666Ip8CVoY6cvliOUol zNhYtSLUDctaMwPHmGDC2+EBSXLk9F8= X-Google-Smtp-Source: AGs4zMZkWPoqyuT/vbNM/WMikNfj/hInGR/ZIC9WojiA/USWS0d8lfswUaeSYqhK3eMqHjoaQLGdOA== X-Received: by 10.80.160.231 with SMTP id 94mr5361400edo.242.1510414626209; Sat, 11 Nov 2017 07:37:06 -0800 (PST) Received: from localhost.localdomain ([2001:985:e54:1050::1000]) by smtp.gmail.com with ESMTPSA id b17sm10218898edj.21.2017.11.11.07.37.05 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 11 Nov 2017 07:37:05 -0800 (PST) From: Steffan Karger To: openvpn-devel@lists.sourceforge.net Date: Sat, 11 Nov 2017 16:36:53 +0100 Message-Id: <20171111153653.24773-1-steffan@karger.me> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171110161131.GZ958@greenie.muc.de> References: <20171110161131.GZ958@greenie.muc.de> 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 [74.125.82.52 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 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 0.1 AWL AWL: Adjusted score from AWL reputation of From: address X-Headers-End: 1eDXqK-000804-NI Subject: [Openvpn-devel] [PATCH v4] Add --tls-cert-profile option for mbedtls builds 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 From: Steffan Karger This allows the user to specify what certificate crypto algorithms to support. The supported profiles are 'preferred', 'legacy' (default) and 'suiteb', as discussed in <84590a17-1c48-9df2-c48e-4160750b2e33@fox-it.com> (https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14214.html). This only implements the feature for mbed TLS builds, because for mbed it is both more easy to implement and the most relevant because mbed TLS 2+ is by default somewhat restrictive by requiring 2048-bit+ for RSA keys. This patch uses 'legacy' as the default profile following discussion on the openvpn-devel mailing list. This way this patch can be applied to both the release/2.4 and master branches. I'll send a follow-up patch for the master branch to change the default to 'preferred' later. Signed-off-by: Steffan Karger Tested-by: Antonio Quartulli --- v2: - add documentation (manpage, Changes.rst and --help) - no longer print a warning message on each startup for OpenSSL builds v3: - remove format changes in unrelated items (introduced in v2) - Update Changes.rst text to reflect that the default in 2.4.2 is 'legacy' and the default in 2.5 will be 'preferred' (as discussed on the ML). - This patch is for the master branch only now (due to the default). v4: - Ignore the option for OpenSSL builds, instead of rejecting the option and refusing to start. - Patch is for master and release/2.4 again. A follow-up patch will change the default for master later on. Changes.rst | 12 +++++++++++ doc/openvpn.8 | 22 ++++++++++++++++++++ src/openvpn/options.c | 16 ++++++++++++++- src/openvpn/options.h | 1 + src/openvpn/ssl.c | 3 +++ src/openvpn/ssl_backend.h | 10 ++++++++++ src/openvpn/ssl_mbedtls.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ src/openvpn/ssl_mbedtls.h | 1 + src/openvpn/ssl_openssl.c | 6 ++++++ 9 files changed, 121 insertions(+), 1 deletion(-) diff --git a/Changes.rst b/Changes.rst index db9b18b9..a6090cf5 100644 --- a/Changes.rst +++ b/Changes.rst @@ -321,6 +321,18 @@ Maintainer-visible changes i386/i686 builds on RHEL5. +Version 2.4.5 +============= + +New features +------------ +- The new option ``--tls-cert-profile`` can be used to restrict the set of + allowed crypto algorithms in TLS certificates in mbed TLS builds. The + default profile is 'legacy' for now, which allows SHA1+, RSA-1024+ and any + elliptic curve certificates. The default will be changed to the 'preferred' + profile in the future, which requires SHA2+, RSA-2048+ and any curve. + + Version 2.4.3 ============= diff --git a/doc/openvpn.8 b/doc/openvpn.8 index a4189ac2..6059c81d 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4917,6 +4917,28 @@ when using mbed TLS or OpenSSL. .\"********************************************************* .TP +.B \-\-tls\-cert\-profile profile +Set the allowed cryptographic algorithms for certificates according to +.B profile\fN. + +The following profiles are supported: + +.B preferred +: SHA2 and newer, RSA 2048-bit+, any elliptic curve. + +.B legacy +(default): SHA1 and newer, RSA 2048-bit+, any elliptic curve. + +.B suiteb +: SHA256/SHA384, ECDSA with P-256 or P-384. + +This option is only supported for mbed TLS builds. OpenSSL builds accept any +certificate that OpenSSL accepts. + +OpenVPN will migrate to 'preferred' as default in the future. Please ensure +that your keys already comply. +.\"********************************************************* +.TP .B \-\-tls\-timeout n Packet retransmit timeout on TLS control channel if no acknowledgment from remote within diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 49ed004b..23c2c02a 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -599,6 +599,8 @@ static const char usage_message[] = #endif "--tls-cipher l : A list l of allowable TLS ciphers separated by : (optional).\n" " : Use --show-tls to see a list of supported TLS ciphers.\n" + "--tls-cert-profile p : Set the allowed certificate crypto algorithm profile\n" + " (default=%s).\n" "--tls-timeout n : Packet retransmit timeout on TLS control channel\n" " if no ACK from remote within n seconds (default=%d).\n" "--reneg-bytes n : Renegotiate data chan. key after n bytes sent and recvd.\n" @@ -872,6 +874,7 @@ init_options(struct options *o, const bool init_gc) o->renegotiate_seconds = 3600; o->handshake_window = 60; o->transition_window = 3600; + o->tls_cert_profile = "legacy"; o->ecdh_curve = NULL; #ifdef ENABLE_X509ALTUSERNAME o->x509_username_field = X509_USERNAME_FIELD_DEFAULT; @@ -1750,6 +1753,7 @@ show_settings(const struct options *o) SHOW_STR(cryptoapi_cert); #endif SHOW_STR(cipher_list); + SHOW_STR(tls_cert_profile); SHOW_STR(tls_verify); SHOW_STR(tls_export_cert); SHOW_INT(verify_x509_type); @@ -2729,6 +2733,7 @@ options_postprocess_verify_ce(const struct options *options, const struct connec MUST_BE_UNDEF(pkcs12_file); #endif MUST_BE_UNDEF(cipher_list); + MUST_BE_UNDEF(tls_cert_profile); MUST_BE_UNDEF(tls_verify); MUST_BE_UNDEF(tls_export_cert); MUST_BE_UNDEF(verify_x509_name); @@ -4086,7 +4091,7 @@ usage(void) o.verbosity, o.authname, o.ciphername, o.replay_window, o.replay_time, - o.tls_timeout, o.renegotiate_seconds, + o.tls_cert_profile, o.tls_timeout, o.renegotiate_seconds, o.handshake_window, o.transition_window); #else /* ifdef ENABLE_CRYPTO */ fprintf(fp, usage_message, @@ -7831,6 +7836,15 @@ add_option(struct options *options, VERIFY_PERMISSION(OPT_P_GENERAL); options->cipher_list = p[1]; } + else if (streq(p[0], "tls-cert-profile") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); +#ifdef ENABLE_CRYPTO_MBEDTLS + options->tls_cert_profile = p[1]; +#else + msg(M_WARN, "WARNING: --tls-cert-profile is not yet implemented for OpenSSL, ignoring option."); +#endif + } else if (streq(p[0], "crl-verify") && p[1] && ((p[2] && streq(p[2], "dir")) || (p[2] && streq(p[1], INLINE_FILE_TAG) ) || !p[2]) && !p[3]) { diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 496c1143..85ff200b 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -502,6 +502,7 @@ struct options const char *priv_key_file; const char *pkcs12_file; const char *cipher_list; + const char *tls_cert_profile; const char *ecdh_curve; const char *tls_verify; int verify_x509_type; diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index cb94229a..48c1b477 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -621,6 +621,9 @@ init_ssl(const struct options *options, struct tls_root_ctx *new_ctx) * cipher restrictions before loading certificates */ tls_ctx_restrict_ciphers(new_ctx, options->cipher_list); + /* Restrict allowed certificate crypto algorithms */ + tls_ctx_set_cert_profile(new_ctx, options->tls_cert_profile); + tls_ctx_set_options(new_ctx, options->ssl_flags); if (options->pkcs12_file) diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h index aba5a4de..ddc76a97 100644 --- a/src/openvpn/ssl_backend.h +++ b/src/openvpn/ssl_backend.h @@ -176,6 +176,16 @@ void tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags); */ void tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers); +/** + * Set the TLS certificate profile. The profile defines which crypto + * algorithms may be used in the supplied certificate. + * + * @param ctx TLS context to restrict, must be valid. + * @param profile The profile name ('preferred', 'legacy' or 'suiteb'). + * Defaults to 'preferred' if NULL. + */ +void tls_ctx_set_cert_profile(struct tls_root_ctx *ctx, const char *profile); + /** * Check our certificate notBefore and notAfter fields, and warn if the cert is * either not yet valid or has expired. Note that this is a non-fatal error, diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index 861d936d..6950abfe 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -62,6 +62,34 @@ #include #include +static const mbedtls_x509_crt_profile openvpn_x509_crt_profile_legacy = +{ + /* Hashes from SHA-1 and above */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_RIPEMD160 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), + 0xFFFFFFF, /* Any PK alg */ + 0xFFFFFFF, /* Any curve */ + 1024, /* RSA-1024 and larger */ +}; + +static const mbedtls_x509_crt_profile openvpn_x509_crt_profile_preferred = +{ + /* SHA-2 and above */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), + 0xFFFFFFF, /* Any PK alg */ + 0xFFFFFFF, /* Any curve */ + 2048, /* RSA-2048 and larger */ +}; + +#define openvpn_x509_crt_profile_suiteb mbedtls_x509_crt_profile_suiteb; + void tls_init_lib(void) { @@ -250,6 +278,27 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) free(tmp_ciphers_orig); } +void +tls_ctx_set_cert_profile(struct tls_root_ctx *ctx, const char *profile) +{ + if (!profile || 0 == strcmp(profile, "preferred")) + { + ctx->cert_profile = openvpn_x509_crt_profile_preferred; + } + else if (0 == strcmp(profile, "legacy")) + { + ctx->cert_profile = openvpn_x509_crt_profile_legacy; + } + else if (0 == strcmp(profile, "suiteb")) + { + ctx->cert_profile = openvpn_x509_crt_profile_suiteb; + } + else + { + msg (M_FATAL, "ERROR: Invalid cert profile: %s", profile); + } +} + void tls_ctx_check_cert_time(const struct tls_root_ctx *ctx) { @@ -917,6 +966,8 @@ key_state_ssl_init(struct key_state_ssl *ks_ssl, mbedtls_ssl_conf_rng(&ks_ssl->ssl_config, mbedtls_ctr_drbg_random, rand_ctx_get()); + mbedtls_ssl_conf_cert_profile(&ks_ssl->ssl_config, &ssl_ctx->cert_profile); + if (ssl_ctx->allowed_ciphers) { mbedtls_ssl_conf_ciphersuites(&ks_ssl->ssl_config, ssl_ctx->allowed_ciphers); diff --git a/src/openvpn/ssl_mbedtls.h b/src/openvpn/ssl_mbedtls.h index f69b6100..341da7d4 100644 --- a/src/openvpn/ssl_mbedtls.h +++ b/src/openvpn/ssl_mbedtls.h @@ -82,6 +82,7 @@ struct tls_root_ctx { struct external_context *external_key; /**< Management external key */ #endif int *allowed_ciphers; /**< List of allowed ciphers for this connection */ + mbedtls_x509_crt_profile cert_profile; /**< Allowed certificate types */ }; struct key_state_ssl { diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 0bfb6939..aed36a26 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -383,6 +383,12 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) } } +void +tls_ctx_set_cert_profile(struct tls_root_ctx *ctx, const char *profile) +{ + /* TODO --tls-cert-profile not supported for OpenSSL builds */ +} + void tls_ctx_check_cert_time(const struct tls_root_ctx *ctx) {