On Thu, 25 Oct 2012, Mark Tully wrote:
Yes, I agree with this and I believe it could be an acceptable way forward.
I don't think 1 is used on purpose very much so it wouldn't hurt a lot.
FWIW I think this is a sensible compromise.
It struck me that there's a good argument why not allow 1 at all:
If we allow 1 or 2 having the same effect in upcoming releases, which would be
sead simple, it would of course lead to programs using 1 or TRUE to get this
effect. When running that program on an older libcurl, it will run unsecurely.
So instead of fixing the problem, we risk actually expanding the problem if
people write code that runs on multiple libcurl versions - something which is
known to happen quite a lot.
I thus suggest we simply ban 1 as a value in an upcoming release. This will
fource users to use 2 instead and when copying such code back to older
libcurl-using code that will improve the code running there as well!
See my attached patch that does exactly this. As this *will* cause one or two
legitimate users get an error I'm very interested in further feedback.
The PHP guys discussed doing the change in there end, in this discussion:
http://thread.gmane.org/gmane.comp.php.devel/76531/focus=76546
... but I saw nobody agreeing to that.
Are there any other options where TRUE / 1 are bad values? Perhaps there are
similar fixes to be pre-emptively made elsewhere?
I can't think of any obvious ones, no...
--
/ daniel.haxx.se
From 5df1793f540723b9faac539cbd7025d21cfa4751 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <[email protected]>
Date: Sat, 27 Oct 2012 12:31:39 +0200
Subject: [PATCH] CURLOPT_SSL_VERIFYHOST: stop supporting the 1 value
After a research team wrote a document[1] that found several live source
codes out there in the wild that misused the CURLOPT_SSL_VERIFYHOST
option thinking it was a boolean, this change now bans 1 as a value and
will make libcurl return error for it.
1 was never a sensible value to use in production but was introduced
back in the days to help debugging. It was always documented clearly
this way.
1 was never supported by all SSL backends in libcurl, so this cleanup
makes the treatment of it unified.
The report's list of mistakes for this option were all PHP code and
while there's a binding layer between libcurl and PHP, the PHP team has
decided that they have an as thin layer as possible on top of libcurl so
they will not alter or specifically filter a 'TRUE' value for this
particular option. I sympathize with that position.
[1] = http://daniel.haxx.se/blog/2012/10/25/libcurl-claimed-to-be-dangerous/
---
docs/libcurl/curl_easy_setopt.3 | 5 +++--
lib/curl_schannel.c | 7 ++-----
lib/gtls.c | 2 +-
lib/nss.c | 2 --
lib/ssluse.c | 11 +++--------
lib/url.c | 20 ++++++++++++++++----
lib/urldata.h | 11 +++++------
7 files changed, 30 insertions(+), 28 deletions(-)
diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3
index 3b0dc6c..a388c22 100644
--- a/docs/libcurl/curl_easy_setopt.3
+++ b/docs/libcurl/curl_easy_setopt.3
@@ -2323,8 +2323,9 @@ Curl considers the server the intended one when the Common Name field or a
Subject Alternate Name field in the certificate matches the host name in the
URL to which you told Curl to connect.
-When the value is 1, the certificate must contain a Common Name field, but it
-doesn't matter what name it says. (This is not ordinarily a useful setting).
+When the value is 1, libcurl will return a failure. It was previously (in
+7.28.0 and earlier) a debug option of some sorts, but it is no longer
+supported due to frequently leading to programmer mistakes.
When the value is 0, the connection succeeds regardless of the names in the
certificate.
diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 75fa071..ef6b1ad 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -160,7 +160,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
#ifdef ENABLE_IPV6
Curl_inet_pton(AF_INET6, conn->host.name, &addr6) ||
#endif
- data->set.ssl.verifyhost < 2) {
+ !data->set.ssl.verifyhost) {
schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
infof(data, "schannel: using IP address, disable SNI servername "
"check\n");
@@ -1238,10 +1238,7 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
}
if(result == CURLE_OK) {
- if(data->set.ssl.verifyhost == 1) {
- infof(data, "warning: ignoring unsupported value (1) ssl.verifyhost\n");
- }
- else if(data->set.ssl.verifyhost == 2) {
+ if(data->set.ssl.verifyhost) {
TCHAR cert_hostname_buff[128];
xcharp_u hostname;
xcharp_u cert_hostname;
diff --git a/lib/gtls.c b/lib/gtls.c
index f5f95ae..09c68f6 100644
--- a/lib/gtls.c
+++ b/lib/gtls.c
@@ -661,7 +661,7 @@ gtls_connect_step3(struct connectdata *conn,
rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);
if(!rc) {
- if(data->set.ssl.verifyhost > 1) {
+ if(data->set.ssl.verifyhost) {
failf(data, "SSL: certificate subject name (%s) does not match "
"target host name '%s'", certbuf, conn->host.dispname);
gnutls_x509_crt_deinit(x509_cert);
diff --git a/lib/nss.c b/lib/nss.c
index 56290f4..22b53bf 100644
--- a/lib/nss.c
+++ b/lib/nss.c
@@ -1316,8 +1316,6 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
if(!data->set.ssl.verifypeer && data->set.ssl.verifyhost)
infof(data, "warning: ignoring value of ssl.verifyhost\n");
- else if(data->set.ssl.verifyhost == 1)
- infof(data, "warning: ignoring unsupported value (1) of ssl.verifyhost\n");
/* bypass the default SSL_AuthCertificate() hook in case we do not want to
* verify peer */
diff --git a/lib/ssluse.c b/lib/ssluse.c
index a701131..745fc88 100644
--- a/lib/ssluse.c
+++ b/lib/ssluse.c
@@ -1292,14 +1292,9 @@ static CURLcode verifyhost(struct connectdata *conn,
res = CURLE_PEER_FAILED_VERIFICATION;
}
else if(!cert_hostcheck((const char *)peer_CN, conn->host.name)) {
- if(data->set.ssl.verifyhost > 1) {
- failf(data, "SSL: certificate subject name '%s' does not match "
- "target host name '%s'", peer_CN, conn->host.dispname);
- res = CURLE_PEER_FAILED_VERIFICATION;
- }
- else
- infof(data, "\t common name: %s (does not match '%s')\n",
- peer_CN, conn->host.dispname);
+ failf(data, "SSL: certificate subject name '%s' does not match "
+ "target host name '%s'", peer_CN, conn->host.dispname);
+ res = CURLE_PEER_FAILED_VERIFICATION;
}
else {
infof(data, "\t common name: %s (matched)\n", peer_CN);
diff --git a/lib/url.c b/lib/url.c
index b30a4fa..5ffaa73 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -708,7 +708,7 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
* switched off unless wanted.
*/
set->ssl.verifypeer = TRUE;
- set->ssl.verifyhost = 2;
+ set->ssl.verifyhost = TRUE;
#ifdef USE_TLS_SRP
set->ssl.authtype = CURL_TLSAUTH_NONE;
#endif
@@ -2049,13 +2049,25 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* Enable peer SSL verifying.
*/
- data->set.ssl.verifypeer = va_arg(param, long);
+ data->set.ssl.verifypeer = (0 != va_arg(param, long))?TRUE:FALSE;
break;
case CURLOPT_SSL_VERIFYHOST:
/*
- * Enable verification of the CN contained in the peer certificate
+ * Enable verification of the host name in the peer certificate
*/
- data->set.ssl.verifyhost = va_arg(param, long);
+ arg = va_arg(param, long);
+
+ /* Obviously people are not reading documentation and too many thought
+ this argument took a boolean when it wasn't and misused it. We thus ban
+ 1 as a sensible input and we warn about its use. Then we only have the
+ 2 action internally stored as TRUE. */
+
+ if(1 == arg) {
+ failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+
+ data->set.ssl.verifyhost = (0 != arg)?TRUE:FALSE;
break;
#ifdef USE_SSLEAY
/* since these two options are only possible to use on an OpenSSL-
diff --git a/lib/urldata.h b/lib/urldata.h
index 5f893c9..4116c34 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -332,10 +332,9 @@ struct ssl_connect_data {
struct ssl_config_data {
long version; /* what version the client wants to use */
long certverifyresult; /* result from the certificate verification */
- long verifypeer; /* set TRUE if this is desired */
- long verifyhost; /* 0: no verify
- 1: check that CN exists
- 2: CN must match hostname */
+
+ bool verifypeer; /* set TRUE if this is desired */
+ bool verifyhost; /* set TRUE if CN/SAN must match hostname */
char *CApath; /* certificate dir (doesn't work on windows) */
char *CAfile; /* certificate to verify peer against */
const char *CRLfile; /* CRL to check certificate revocation */
@@ -994,8 +993,8 @@ struct connectdata {
int socks5_gssapi_enctype;
#endif
- long verifypeer;
- long verifyhost;
+ bool verifypeer;
+ bool verifyhost;
/* When this connection is created, store the conditions for the local end
bind. This is stored before the actual bind and before any connection is
--
1.7.10.4
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html