From 172b2beba6b89b632c09be7a88645e3a0607cfe9 Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Fri, 17 Jul 2015 02:40:16 -0400 Subject: [PATCH] SSL: Add an option to disable certificate revocation checks New tool option --ssl-no-revoke. New value CURLSSLOPT_NO_REVOKE for CURLOPT_SSL_OPTIONS. Currently this option applies only to WinSSL where we have automatic certificate revocation checking by default. According to the ssl-compared chart there are other backends that have automatic checking (NSS, wolfSSL and DarwinSSL) so we could possibly accommodate them at some later point. Bug: https://github.com/bagder/curl/issues/264 Reported-by: zenden2k --- docs/SSL-PROBLEMS | 14 ++++++++ docs/curl.1 | 4 +++ docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3 | 26 +++++++++++---- include/curl/curl.h | 4 +++ lib/url.c | 3 +- lib/urldata.h | 1 + lib/vtls/schannel.c | 44 ++++++++++++++++++------- src/tool_cfgable.h | 1 + src/tool_getparam.c | 6 ++++ src/tool_help.c | 1 + src/tool_operate.c | 5 +-- src/tool_setopt.c | 6 ++++ src/tool_setopt.h | 2 ++ tests/data/Makefile.inc | 2 +- tests/data/test2043 | 33 +++++++++++++++++++ 15 files changed, 129 insertions(+), 23 deletions(-) create mode 100644 tests/data/test2043 diff --git a/docs/SSL-PROBLEMS b/docs/SSL-PROBLEMS index 5a56d3da5..45faa241c 100644 --- a/docs/SSL-PROBLEMS +++ b/docs/SSL-PROBLEMS @@ -71,3 +71,17 @@ Allow BEAST introduced. Exactly as it sounds, it re-introduces the BEAST vulnerability but on the other hand it allows curl to connect to that kind of strange servers. + +Disabling certificate revocation checks + + Some SSL backends may do certificate revocation checks (CRL, OCSP, etc) + depending on the OS or build configuration. The --ssl-no-revoke option was + introduced in 7.44.0 to disable revocation checking but currently 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. This option may have broader support to accommodate other SSL + backends in the future. + + References: + + http://curl.haxx.se/docs/ssl-compared.html diff --git a/docs/curl.1 b/docs/curl.1 index afd4e8c35..69ab9781d 100644 --- a/docs/curl.1 +++ b/docs/curl.1 @@ -1545,6 +1545,10 @@ and TLS1.0 protocols known as BEAST. If this option isn't used, the SSL layer may use workarounds known to cause interoperability problems with some older SSL implementations. WARNING: this option loosens the SSL security, and by using this flag you ask for exactly that. (Added in 7.25.0) +.IP "--ssl-no-revoke" +(WinSSL) This option tells curl to disable certificate revocation checks. +WARNING: this option loosens the SSL security, and by using this flag you ask +for exactly that. (Added in 7.44.0) .IP "--socks4 " Use the specified SOCKS4 proxy. If the port number is not specified, it is assumed at port 1080. (Added in 7.15.2) diff --git a/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3 b/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3 index 09bcb96cf..0afd2fb6a 100644 --- a/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3 +++ b/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3 @@ -30,13 +30,25 @@ 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 is the only supported bit and by setting this the -user will tell 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. +\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. +http://curl.haxx.se/docs/ssl-compared.html + + .SH DEFAULT 0 .SH PROTOCOLS diff --git a/include/curl/curl.h b/include/curl/curl.h index eab2f6e99..64f926142 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -725,6 +725,10 @@ typedef enum { servers, a user can this way allow the vulnerability back. */ #define CURLSSLOPT_ALLOW_BEAST (1<<0) +/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those + SSL backends where such behavior is present. */ +#define CURLSSLOPT_NO_REVOKE (1<<1) + #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all the obsolete stuff removed! */ diff --git a/lib/url.c b/lib/url.c index 4e9495251..406c1f02c 100644 --- a/lib/url.c +++ b/lib/url.c @@ -2234,7 +2234,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, case CURLOPT_SSL_OPTIONS: arg = va_arg(param, long); - data->set.ssl_enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE; + data->set.ssl_enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST); + data->set.ssl_no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); break; #endif diff --git a/lib/urldata.h b/lib/urldata.h index 59c704e0d..06559229b 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1582,6 +1582,7 @@ struct UserDefined { bool connect_only; /* make connection, let application use the socket */ bool ssl_enable_beast; /* especially allow this flaw for interoperability's sake*/ + bool ssl_no_revoke; /* disable SSL certificate revocation checks */ long ssh_auth_types; /* allowed SSH auth types */ bool http_te_skip; /* pass the raw body data to the user, even when transfer-encoded (chunked, compressed) */ diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 19aff8f07..fe35a278b 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -128,16 +128,24 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE; #else - schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION | - SCH_CRED_REVOCATION_CHECK_CHAIN; + schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION; + if(data->set.ssl_no_revoke) + schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE; + else + schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN; #endif - infof(data, "schannel: checking server certificate revocation\n"); + if(data->set.ssl_no_revoke) + infof(data, "schannel: disabled server certificate revocation " + "checks\n"); + else + infof(data, "schannel: checking server certificate revocation\n"); } else { schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE; - infof(data, "schannel: disable server certificate revocation checks\n"); + infof(data, "schannel: disabled server certificate revocation checks\n"); } if(!data->set.ssl.verifyhost) { @@ -1384,7 +1392,8 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex) NULL, pCertContextServer->hCertStore, &ChainPara, - 0, + (data->set.ssl_no_revoke ? 0 : + CERT_CHAIN_REVOCATION_CHECK_CHAIN), NULL, &pChainContext)) { failf(data, "schannel: CertGetCertificateChain failed: %s", @@ -1395,21 +1404,24 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex) if(result == CURLE_OK) { CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0]; - DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED| - CERT_TRUST_REVOCATION_STATUS_UNKNOWN); + DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED); dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus; if(dwTrustErrorMask) { - if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN) + if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED) + failf(data, "schannel: CertGetCertificateChain trust error" + " CERT_TRUST_IS_REVOKED"); + else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN) failf(data, "schannel: CertGetCertificateChain trust error" " CERT_TRUST_IS_PARTIAL_CHAIN"); - if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT) + else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT) failf(data, "schannel: CertGetCertificateChain trust error" " CERT_TRUST_IS_UNTRUSTED_ROOT"); - if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID) + else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID) failf(data, "schannel: CertGetCertificateChain trust error" " CERT_TRUST_IS_NOT_TIME_VALID"); - failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x", - dwTrustErrorMask); + else + failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x", + dwTrustErrorMask); result = CURLE_PEER_FAILED_VERIFICATION; } } @@ -1425,6 +1437,14 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex) cert_hostname.const_tchar_ptr = cert_hostname_buff; hostname.tchar_ptr = Curl_convert_UTF8_to_tchar(conn->host.name); + /* TODO: Fix this for certificates with multiple alternative names. + Right now we're only asking for the first preferred alternative name. + Instead we'd need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG + (if WinCE supports that?) and run this section in a loop for each. + https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx + curl: (51) schannel: CertGetNameString() certificate hostname + (.google.com) did not match connection (google.com) + */ len = CertGetNameString(pCertContextServer, CERT_NAME_DNS_TYPE, 0, diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 048eb4ffe..c6a691447 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -199,6 +199,7 @@ struct OperationConfig { bool xattr; /* store metadata in extended attributes */ long gssapi_delegation; bool ssl_allow_beast; /* allow this SSL vulnerability */ + bool ssl_no_revoke; /* disable SSL certificate revocation checks */ bool use_metalink; /* process given URLs as metalink XML file */ metalinkfile *metalinkfile_list; /* point to the first node */ diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 339fb7b5d..4405bce87 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -221,6 +221,7 @@ static const struct LongShort aliases[]= { {"Ep", "pinnedpubkey", TRUE}, {"Eq", "cert-status", FALSE}, {"Er", "false-start", FALSE}, + {"Es", "ssl-no-revoke", FALSE}, {"f", "fail", FALSE}, {"F", "form", TRUE}, {"Fs", "form-string", TRUE}, @@ -1382,6 +1383,11 @@ ParameterError getparameter(char *flag, /* f or -long-flag */ config->falsestart = TRUE; break; + case 's': /* --ssl-no-revoke */ + if(curlinfo->features & CURL_VERSION_SSL) + config->ssl_no_revoke = TRUE; + break; + default: /* certificate file */ { char *certname, *passphrase; diff --git a/src/tool_help.c b/src/tool_help.c index e0c45954b..6ad51cb5b 100644 --- a/src/tool_help.c +++ b/src/tool_help.c @@ -214,6 +214,7 @@ static const char *const helptext[] = { " -2, --sslv2 Use SSLv2 (SSL)", " -3, --sslv3 Use SSLv3 (SSL)", " --ssl-allow-beast Allow security flaw to improve interop (SSL)", + " --ssl-no-revoke Disable cert revocation checks (WinSSL)", " --stderr FILE Where to redirect stderr (use \"-\" for stdout)", " --tcp-nodelay Use the TCP_NODELAY option", " -t, --telnet-option OPT=VAL Set telnet option", diff --git a/src/tool_operate.c b/src/tool_operate.c index 4c6ff854c..1180555fa 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1328,8 +1328,9 @@ static CURLcode operate_do(struct GlobalConfig *global, config->gssapi_delegation); /* new in 7.25.0 */ - if(config->ssl_allow_beast) - my_setopt(curl, CURLOPT_SSL_OPTIONS, (long)CURLSSLOPT_ALLOW_BEAST); + my_setopt_bitmask(curl, CURLOPT_SSL_OPTIONS, + (long)((config->ssl_allow_beast ? CURLSSLOPT_ALLOW_BEAST : 0) | + (config->ssl_no_revoke ? CURLSSLOPT_NO_REVOKE : 0))); if(config->mail_auth) my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth); diff --git a/src/tool_setopt.c b/src/tool_setopt.c index a53fdc835..7eb64b039 100644 --- a/src/tool_setopt.c +++ b/src/tool_setopt.c @@ -107,6 +107,12 @@ const NameValue setopt_nv_CURLUSESSL[] = { NVEND, }; +const NameValueUnsigned setopt_nv_CURLSSLOPT[] = { + NV(CURLSSLOPT_ALLOW_BEAST), + NV(CURLSSLOPT_NO_REVOKE), + NVEND, +}; + const NameValue setopt_nv_CURL_NETRC[] = { NV(CURL_NETRC_IGNORED), NV(CURL_NETRC_OPTIONAL), diff --git a/src/tool_setopt.h b/src/tool_setopt.h index fcba94cb2..b32adf988 100644 --- a/src/tool_setopt.h +++ b/src/tool_setopt.h @@ -52,6 +52,7 @@ extern const NameValue setopt_nv_CURL_SSLVERSION[]; extern const NameValue setopt_nv_CURL_TIMECOND[]; extern const NameValue setopt_nv_CURLFTPSSL_CCC[]; extern const NameValue setopt_nv_CURLUSESSL[]; +extern const NameValueUnsigned setopt_nv_CURLSSLOPT[]; extern const NameValue setopt_nv_CURL_NETRC[]; extern const NameValue setopt_nv_CURLPROTO[]; extern const NameValueUnsigned setopt_nv_CURLAUTH[]; @@ -63,6 +64,7 @@ extern const NameValueUnsigned setopt_nv_CURLAUTH[]; #define setopt_nv_CURLOPT_TIMECONDITION setopt_nv_CURL_TIMECOND #define setopt_nv_CURLOPT_FTP_SSL_CCC setopt_nv_CURLFTPSSL_CCC #define setopt_nv_CURLOPT_USE_SSL setopt_nv_CURLUSESSL +#define setopt_nv_CURLOPT_SSL_OPTIONS setopt_nv_CURLSSLOPT #define setopt_nv_CURLOPT_NETRC setopt_nv_CURL_NETRC #define setopt_nv_CURLOPT_PROTOCOLS setopt_nv_CURLPROTO #define setopt_nv_CURLOPT_REDIR_PROTOCOLS setopt_nv_CURLPROTO diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc index 51823fe88..f39db40da 100644 --- a/tests/data/Makefile.inc +++ b/tests/data/Makefile.inc @@ -166,4 +166,4 @@ test2008 test2009 test2010 test2011 test2012 test2013 test2014 test2015 \ test2016 test2017 test2018 test2019 test2020 test2021 test2022 test2023 \ test2024 test2025 test2026 test2027 test2028 test2029 test2030 test2031 \ test2032 test2033 test2034 test2035 test2036 test2037 test2038 test2039 \ -test2040 test2041 test2042 +test2040 test2041 test2042 test2043 diff --git a/tests/data/test2043 b/tests/data/test2043 new file mode 100644 index 000000000..7a91f5b60 --- /dev/null +++ b/tests/data/test2043 @@ -0,0 +1,33 @@ + + + +HTTPS +HTTP GET + + + +# +# Client-side + + +WinSSL + + +none + + +Disable certificate revocation checks + + +--ssl-no-revoke -I https://revoked.grc.com/ + + + +# +# Verify data after the test has been "shot" + + +0 + + +