Skip to content

Commit

Permalink
SSL: Add an option to disable certificate revocation checks
Browse files Browse the repository at this point in the history
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: #264
Reported-by: zenden2k <zenden2k@gmail.com>
  • Loading branch information
jay committed Jul 17, 2015
1 parent 606b29f commit 172b2be
Show file tree
Hide file tree
Showing 15 changed files with 129 additions and 23 deletions.
14 changes: 14 additions & 0 deletions docs/SSL-PROBLEMS
Expand Up @@ -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
4 changes: 4 additions & 0 deletions docs/curl.1
Expand Up @@ -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 <host[:port]>"
Use the specified SOCKS4 proxy. If the port number is not specified, it is
assumed at port 1080. (Added in 7.15.2)
Expand Down
26 changes: 19 additions & 7 deletions docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions include/curl/curl.h
Expand Up @@ -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! */

Expand Down
3 changes: 2 additions & 1 deletion lib/url.c
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions lib/urldata.h
Expand Up @@ -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) */
Expand Down
44 changes: 32 additions & 12 deletions lib/vtls/schannel.c
Expand Up @@ -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) {
Expand Down Expand Up @@ -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",
Expand All @@ -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;
}
}
Expand All @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/tool_cfgable.h
Expand Up @@ -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 */
Expand Down
6 changes: 6 additions & 0 deletions src/tool_getparam.c
Expand Up @@ -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},
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/tool_help.c
Expand Up @@ -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",
Expand Down
5 changes: 3 additions & 2 deletions src/tool_operate.c
Expand Up @@ -1328,8 +1328,9 @@ static CURLcode operate_do(struct GlobalConfig *global,
config->gssapi_delegation);

/* new in 7.25.0 */

This comment has been minimized.

Copy link
@wodin

wodin Jul 26, 2015

Comment is no longer accurate.

This comment has been minimized.

Copy link
@bagder

bagder Jul 26, 2015

Member

Thanks, fixed now!

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);
Expand Down
6 changes: 6 additions & 0 deletions src/tool_setopt.c
Expand Up @@ -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),
Expand Down
2 changes: 2 additions & 0 deletions src/tool_setopt.h
Expand Up @@ -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[];
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion tests/data/Makefile.inc
Expand Up @@ -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
33 changes: 33 additions & 0 deletions tests/data/test2043
@@ -0,0 +1,33 @@
<testcase>
<info>
<keywords>
HTTPS
HTTP GET
</keywords>
</info>

#
# Client-side
<client>
<features>
WinSSL
</features>
<server>
none
</server>
<name>
Disable certificate revocation checks
</name>
<command>
--ssl-no-revoke -I https://revoked.grc.com/
</command>
</client>

#
# Verify data after the test has been "shot"
<verify>
<errorcode>
0
</errorcode>
</verify>
</testcase>

0 comments on commit 172b2be

Please sign in to comment.