From 673adb0a7a21ca3a877ee03dc9e197d5be15a9d3 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 2 Dec 2019 10:45:55 +0100 Subject: [PATCH 1/3] openssl: set X509_V_FLAG_PARTIAL_CHAIN Have intermediate certificates in the trust store be treated as trust-anchors, in the same way as self-signed root CA certificates are. This allows users to verify servers using the intermediate cert only, instead of needing the whole chain. Other TLS backends already accept partial chains. Reported-by: Jeffrey Walton Bug: https://curl.haxx.se/mail/lib-2019-11/0094.html Upstream-commit: 94f1f771586913addf5c68f9219e176036c50115 Signed-off-by: Kamil Dudka --- lib/vtls/openssl.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index d8bcc4f..8e791b9 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -2551,19 +2551,27 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) infof(data, " CRLfile: %s\n", ssl_crlfile); } - /* Try building a chain using issuers in the trusted store first to avoid - problems with server-sent legacy intermediates. - Newer versions of OpenSSL do alternate chain checking by default which - gives us the same fix without as much of a performance hit (slight), so we - prefer that if available. - https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest - */ -#if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS) if(verifypeer) { + /* Try building a chain using issuers in the trusted store first to avoid + problems with server-sent legacy intermediates. Newer versions of + OpenSSL do alternate chain checking by default which gives us the same + fix without as much of a performance hit (slight), so we prefer that if + available. + https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest + */ +#if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS) X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), X509_V_FLAG_TRUSTED_FIRST); - } #endif +#ifdef X509_V_FLAG_PARTIAL_CHAIN + /* Have intermediate certificates in the trust store be treated as + trust-anchors, in the same way as self-signed root CA certificates + are. This allows users to verify servers using the intermediate cert + only, instead of needing the whole chain. */ + X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), + X509_V_FLAG_PARTIAL_CHAIN); +#endif + } /* SSL always tries to verify the peer, this only says whether it should * fail to connect if the verification fails, or if it should continue -- 2.26.2 From b2e6e39b60e1722aecf250ff79a69867df5d3aa8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 2 Dec 2019 10:55:33 +0100 Subject: [PATCH 2/3] openssl: CURLSSLOPT_NO_PARTIALCHAIN can disable partial cert chains Closes #4655 Upstream-commit: 564d88a8bd190a21b362d6da535fccf74d33394d Signed-off-by: Kamil Dudka --- docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3 | 40 +++++++++++++------------ docs/libcurl/symbols-in-versions | 1 + include/curl/curl.h | 4 +++ lib/setopt.c | 1 + lib/urldata.h | 1 + lib/vtls/openssl.c | 14 +++++---- 6 files changed, 36 insertions(+), 25 deletions(-) diff --git a/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3 b/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3 index d781434..6286a64 100644 --- a/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3 +++ b/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3 @@ -29,25 +29,27 @@ CURLOPT_SSL_OPTIONS \- set SSL behavior options CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_OPTIONS, long bitmask); .SH DESCRIPTION -Pass a long with a bitmask to tell libcurl about specific SSL behaviors. - -\fICURLSSLOPT_ALLOW_BEAST\fP tells libcurl to not attempt to use any -workarounds for a security flaw in the SSL3 and TLS1.0 protocols. If this -option isn't used or this bit is set to 0, the SSL layer libcurl uses may use a -work-around for this flaw although it might cause interoperability problems -with some (older) SSL implementations. WARNING: avoiding this work-around -lessens the security, and by setting this option to 1 you ask for exactly that. -This option is only supported for DarwinSSL, NSS and OpenSSL. - -Added in 7.44.0: - -\fICURLSSLOPT_NO_REVOKE\fP tells libcurl to disable certificate revocation -checks for those SSL backends where such behavior is present. \fBCurrently this -option is only supported for WinSSL (the native Windows SSL library), with an -exception in the case of Windows' Untrusted Publishers blacklist which it seems -can't be bypassed.\fP This option may have broader support to accommodate other -SSL backends in the future. -https://curl.haxx.se/docs/ssl-compared.html +Pass a long with a bitmask to tell libcurl about specific SSL +behaviors. Available bits: +.IP CURLSSLOPT_ALLOW_BEAST +Tells libcurl to not attempt to use any workarounds for a security flaw in the +SSL3 and TLS1.0 protocols. If this option isn't used or this bit is set to 0, +the SSL layer libcurl uses may use a work-around for this flaw although it +might cause interoperability problems with some (older) SSL +implementations. WARNING: avoiding this work-around lessens the security, and +by setting this option to 1 you ask for exactly that. This option is only +supported for DarwinSSL, NSS and OpenSSL. +.IP CURLSSLOPT_NO_REVOKE +Tells libcurl to disable certificate revocation checks for those SSL backends +where such behavior is present. This option is only supported for Schannel +(the native Windows SSL library), with an exception in the case of Windows' +Untrusted Publishers blacklist which it seems can't be bypassed. (Added in +7.44.0) +.IP CURLSSLOPT_NO_PARTIALCHAIN +Tells libcurl to not accept "partial" certificate chains, which it otherwise +does by default. This option is only supported for OpenSSL and will fail the +certificate verification if the chain ends with an intermediate certificate +and not with a root cert. (Added in 7.68.0) .SH DEFAULT 0 .SH PROTOCOLS diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index 3b3861f..54923d0 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -713,6 +713,7 @@ CURLSSLBACKEND_QSOSSL 7.34.0 - 7.38.1 CURLSSLBACKEND_SCHANNEL 7.34.0 CURLSSLBACKEND_WOLFSSL 7.49.0 CURLSSLOPT_ALLOW_BEAST 7.25.0 +CURLSSLOPT_NO_PARTIALCHAIN 7.68.0 CURLSSLOPT_NO_REVOKE 7.44.0 CURLSSLSET_NO_BACKENDS 7.56.0 CURLSSLSET_OK 7.56.0 diff --git a/include/curl/curl.h b/include/curl/curl.h index 8f473e2..75f9384 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -795,6 +795,10 @@ typedef enum { SSL backends where such behavior is present. */ #define CURLSSLOPT_NO_REVOKE (1<<1) +/* - NO_PARTIALCHAIN tells libcurl to *NOT* accept a partial certificate chain + if possible. The OpenSSL backend has this ability. */ +#define CURLSSLOPT_NO_PARTIALCHAIN (1<<2) + /* The default connection attempt delay in milliseconds for happy eyeballs. CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document this value, keep them in sync. */ diff --git a/lib/setopt.c b/lib/setopt.c index 5c5f4b3..4f04962 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -2046,6 +2046,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, arg = va_arg(param, long); data->set.ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE; data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); + data->set.ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN); break; case CURLOPT_PROXY_SSL_OPTIONS: diff --git a/lib/urldata.h b/lib/urldata.h index 4b70cc5..c70290a 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -235,6 +235,7 @@ struct ssl_config_data { bool enable_beast; /* especially allow this flaw for interoperability's sake*/ bool no_revoke; /* disable SSL certificate revocation checks */ + bool no_partialchain; /* don't accept partial certificate chains */ long certverifyresult; /* result from the certificate verification */ char *CRLfile; /* CRL to check certificate revocation */ char *issuercert;/* optional issuer certificate filename */ diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 8e791b9..87f6c4c 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -2564,12 +2564,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) X509_V_FLAG_TRUSTED_FIRST); #endif #ifdef X509_V_FLAG_PARTIAL_CHAIN - /* Have intermediate certificates in the trust store be treated as - trust-anchors, in the same way as self-signed root CA certificates - are. This allows users to verify servers using the intermediate cert - only, instead of needing the whole chain. */ - X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), - X509_V_FLAG_PARTIAL_CHAIN); + if(!SSL_SET_OPTION(no_partialchain)) { + /* Have intermediate certificates in the trust store be treated as + trust-anchors, in the same way as self-signed root CA certificates + are. This allows users to verify servers using the intermediate cert + only, instead of needing the whole chain. */ + X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), + X509_V_FLAG_PARTIAL_CHAIN); + } #endif } -- 2.26.2 From d149ba12f302e5275b408d82ffb349eac16b9226 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 11 May 2020 23:00:31 +0200 Subject: [PATCH 3/3] OpenSSL: have CURLOPT_CRLFILE imply CURLSSLOPT_NO_PARTIALCHAIN ... to avoid an OpenSSL bug that otherwise makes the CRL check to fail. Reported-by: Michael Kaufmann Fixes #5374 Closes #5376 Upstream-commit: 81a54b12c631e8126e3eb484c74040b991e78f0c Signed-off-by: Kamil Dudka --- docs/libcurl/opts/CURLOPT_CRLFILE.3 | 13 ++++++++----- lib/vtls/openssl.c | 8 ++++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/libcurl/opts/CURLOPT_CRLFILE.3 b/docs/libcurl/opts/CURLOPT_CRLFILE.3 index 080caa7..f111585 100644 --- a/docs/libcurl/opts/CURLOPT_CRLFILE.3 +++ b/docs/libcurl/opts/CURLOPT_CRLFILE.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -34,10 +34,13 @@ concatenation of CRL (in PEM format) to use in the certificate validation that occurs during the SSL exchange. When curl is built to use NSS or GnuTLS, there is no way to influence the use -of CRL passed to help in the verification process. When libcurl is built with -OpenSSL support, X509_V_FLAG_CRL_CHECK and X509_V_FLAG_CRL_CHECK_ALL are both -set, requiring CRL check against all the elements of the certificate chain if -a CRL file is passed. +of CRL passed to help in the verification process. + +When libcurl is built with OpenSSL support, X509_V_FLAG_CRL_CHECK and +X509_V_FLAG_CRL_CHECK_ALL are both set, requiring CRL check against all the +elements of the certificate chain if a CRL file is passed. Also note that +\fICURLOPT_CRLFILE(3)\fP will imply \fBCURLSSLOPT_NO_PARTIALCHAIN\fP (see +\fICURLOPT_SSL_OPTIONS(3)\fP) since curl 7.71.0 due to an OpenSSL bug. This option makes sense only when used in combination with the \fICURLOPT_SSL_VERIFYPEER(3)\fP option. diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 87f6c4c..9476773 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -2564,11 +2564,15 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) X509_V_FLAG_TRUSTED_FIRST); #endif #ifdef X509_V_FLAG_PARTIAL_CHAIN - if(!SSL_SET_OPTION(no_partialchain)) { + if(!SSL_SET_OPTION(no_partialchain) && !ssl_crlfile) { /* Have intermediate certificates in the trust store be treated as trust-anchors, in the same way as self-signed root CA certificates are. This allows users to verify servers using the intermediate cert - only, instead of needing the whole chain. */ + only, instead of needing the whole chain. + + Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we + cannot do partial chains with CRL check. + */ X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), X509_V_FLAG_PARTIAL_CHAIN); } -- 2.26.2