From patchwork Fri Apr 14 05:40:49 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steffan Karger X-Patchwork-Id: 56 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director3.mail.ord1d.rsapps.net ([172.30.191.6]) by backend31.mail.ord1d.rsapps.net (Dovecot) with LMTP id xpgLALHLBVrdfwAAgoeIoA for ; Fri, 10 Nov 2017 10:54:25 -0500 Received: from proxy20.mail.ord1d.rsapps.net ([172.30.191.6]) by director3.mail.ord1d.rsapps.net (Dovecot) with LMTP id Y+loB7HLBVqvFgAAkXNnRw ; Fri, 10 Nov 2017 10:54:25 -0500 Received: from smtp47.gate.ord1c ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy20.mail.ord1d.rsapps.net (Dovecot) with LMTP id OKpDB7HLBVoJBwAAsk8m8w ; Fri, 10 Nov 2017 10:54:25 -0500 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO Authentication-Results: smtp47.gate.ord1c.rsapps.net x-tls.subject="/C=XX/ST=Some-state/L=Some-city/O=Some-org/CN=chekov.greenie.muc.de"; auth=fail (cipher=DHE-RSA-AES256-GCM-SHA384) X-Virus-Scanned: OK X-Orig-To: patchwork@openvpn.net X-Originating-Ip: [193.149.48.178] Authentication-Results: smtp47.gate.ord1c.rsapps.net; iprev=pass policy.iprev="193.149.48.178"; spf=neutral smtp.mailfrom="gert@chekov.greenie.muc.de" smtp.helo="chekov.greenie.muc.de"; dkim=none (message not signed) header.d=none; dmarc=none (p=nil; dis=none) header.from=fox-it.com X-Classification-ID: 6b008e9a-c62f-11e7-a56f-b8ca3a5dcc5c-1-1 Received: from [193.149.48.178] ([193.149.48.178:56246] helo=chekov.greenie.muc.de) by smtp47.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 subject="/C=XX/ST=Some-state/L=Some-city/O=Some-org/CN=chekov.greenie.muc.de") id 3A/70-12979-FABC50A5; Fri, 10 Nov 2017 10:54:24 -0500 Received: from chekov.greenie.muc.de (localhost [127.0.0.1]) by chekov.greenie.muc.de (8.15.2/8.15.2) with ESMTPS id vAAFsLSP086224 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Fri, 10 Nov 2017 16:54:21 +0100 (CET) (envelope-from gert@chekov.greenie.muc.de) Received: (from gert@localhost) by chekov.greenie.muc.de (8.15.2/8.15.2/Submit) id vAAFsLEp086223 for patchwork@openvpn.net; Fri, 10 Nov 2017 16:54:21 +0100 (CET) (envelope-from gert) Resent-From: Gert Doering Resent-Date: Fri, 10 Nov 2017 16:54:21 +0100 Resent-Message-ID: <20171110155421.GV958@greenie.muc.de> Resent-To: patchwork@openvpn.net X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on chekov.greenie.muc.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=7.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.1 Received: from delta2.greenie.net (root@delta2.greenie.net [IPv6:2001:608:0:1007:a00:20ff:fefe:4bd2]) by chekov.greenie.muc.de (8.15.2/8.15.2) with ESMTPS id v3EFhg9l042667 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Fri, 14 Apr 2017 17:43:42 +0200 (CEST) (envelope-from openvpn-devel-bounces@lists.sourceforge.net) Received: from lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) by delta2.greenie.net (8.14.9/8.12.11) with ESMTP id v3EFheUw020180 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Fri, 14 Apr 2017 17:43:41 +0200 (CEST) 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.76) (envelope-from ) id 1cz3LX-0005Po-GO; Fri, 14 Apr 2017 15:41:15 +0000 Received: from sog-mx-3.v43.ch3.sourceforge.com ([172.29.43.193] helo=mx.sourceforge.net) by sfs-ml-2.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1cz3LW-0005Pi-4A for openvpn-devel@lists.sourceforge.net; Fri, 14 Apr 2017 15:41:14 +0000 Received-SPF: pass (sog-mx-3.v43.ch3.sourceforge.com: domain of fox-it.com designates 178.250.144.131 as permitted sender) client-ip=178.250.144.131; envelope-from=steffan.karger@fox-it.com; helo=ns2.fox-it.com; Received: from ns2.fox-it.com ([178.250.144.131]) by sog-mx-3.v43.ch3.sourceforge.com with esmtps (TLSv1:AES256-SHA:256) (Exim 4.76) id 1cz3LT-0008BI-LE for openvpn-devel@lists.sourceforge.net; Fri, 14 Apr 2017 15:41:14 +0000 Received: from FOXDFT52.FOX.local (unknown [10.0.0.129]) by ns2.fox-it.com (Postfix) with ESMTPS id 5A91C1C2A84 for ; Fri, 14 Apr 2017 17:41:05 +0200 (CEST) Received: from steffan-fox.fox.local (10.0.3.209) by FOXDFT52.FOX.local (10.0.0.129) with Microsoft SMTP Server (TLS) id 15.0.1263.5; Fri, 14 Apr 2017 17:41:05 +0200 From: Steffan Karger To: Date: Fri, 14 Apr 2017 17:40:49 +0200 Message-ID: <1492184450-11994-1-git-send-email-steffan.karger@fox-it.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <3275c6bd-8194-2e23-2e64-3d3fd5d2f090@sf.lists.topphemmelig.net> References: <3275c6bd-8194-2e23-2e64-3d3fd5d2f090@sf.lists.topphemmelig.net> MIME-Version: 1.0 X-ClientProxiedBy: FOXDFT52.FOX.local (10.0.0.129) To FOXDFT52.FOX.local (10.0.0.129) X-Headers-End: 1cz3LT-0008BI-LE Subject: [Openvpn-devel] [PATCH v3] Add --tls-cert-profile option for mbedtls builds X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.4.3 (delta2.greenie.net [194.97.144.211]); Fri, 14 Apr 2017 17:43:41 +0200 (CEST) X-Virus-Status: Clean X-getmail-retrieved-from-mailbox: Inbox This allows the user to specify what certificate crypto algorithms to support. The supported profiles are 'preferred' (default), 'legacy' 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. Signed-off-by: Steffan Karger Tested-by: Gert Doering --- 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). Changes.rst | 19 +++++++++++++++++- doc/openvpn.8 | 19 ++++++++++++++++++ src/openvpn/options.c | 14 ++++++++++++- 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, 122 insertions(+), 2 deletions(-) diff --git a/Changes.rst b/Changes.rst index 2a94990..4b4360a 100644 --- a/Changes.rst +++ b/Changes.rst @@ -1,6 +1,15 @@ -Overview of changes in 2.4 +Overview of changes in 2.5 ========================== +User-visible Changes +-------------------- +- (For mbed TLS buils) The default certificate profile is now "preferred", + which means that only SHA2+, RSA-2048+ and EC certs are accepted. Legacy + crypto can be re-enabled by setting ``--tls-cert-profile legacy``. + + +Overview of changes in 2.4 +========================== New features ------------ @@ -318,3 +327,11 @@ Version 2.4.1 ``--remote-cert-tls`` uses the far more common keyUsage and extendedKeyUsage extension instead. Make sure your certificates carry these to be able to use ``--remote-cert-tls``. + +Version 2.4.2 +============= +- 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. diff --git a/doc/openvpn.8 b/doc/openvpn.8 index a9f5db7..fd821c7 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4879,6 +4879,25 @@ when using PolarSSL 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 +(default): SHA2 and newer, RSA 2048-bit+, any elliptic curve. + +.B legacy +: 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. +.\"********************************************************* +.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 9fef394..74536fb 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" @@ -873,6 +875,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 = "preferred"; o->ecdh_curve = NULL; #ifdef ENABLE_X509ALTUSERNAME o->x509_username_field = X509_USERNAME_FIELD_DEFAULT; @@ -1752,6 +1755,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); @@ -2734,6 +2738,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); @@ -4090,7 +4095,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, @@ -7813,6 +7818,13 @@ add_option(struct options *options, VERIFY_PERMISSION(OPT_P_GENERAL); options->cipher_list = p[1]; } +#ifdef ENABLE_CRYPTO_MBEDTLS + else if (streq(p[0], "tls-cert-profile") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->tls_cert_profile = p[1]; + } +#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 b3ab029..9085413 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -500,6 +500,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 1033e58..72dbec3 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -702,6 +702,9 @@ init_ssl(const struct options *options, struct tls_root_ctx *new_ctx) /* Allowable ciphers */ 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); + #ifdef ENABLE_CRYPTO_MBEDTLS /* Personalise the random by mixing in the certificate */ tls_ctx_personalise_random(new_ctx); diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h index 206400f..3c4cf34 100644 --- a/src/openvpn/ssl_backend.h +++ b/src/openvpn/ssl_backend.h @@ -178,6 +178,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, * since we compare against the system time, which might be incorrect. diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index ba8dadf..6e27a83 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -63,6 +63,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() { @@ -252,6 +280,27 @@ 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) +{ + 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) { ASSERT(ctx); @@ -918,6 +967,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 d8f717c..0a4ad17 100644 --- a/src/openvpn/ssl_mbedtls.h +++ b/src/openvpn/ssl_mbedtls.h @@ -83,6 +83,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 d7cc2ba..5af0e4f 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -384,6 +384,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) { int ret;