aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Dudka <kdudka@redhat.com>2011-03-15 14:52:26 +0100
committerKamil Dudka <kdudka@redhat.com>2011-03-15 15:48:24 +0100
commit806dbb022b8a595405a740131a30fa0cf4523645 (patch)
tree2e8b7c861c078903d57acb67c1d08c33b73920fe
parent5a433a033ffc8b489a8edc14c4505d0c47a63df6 (diff)
nss: do not ignore value of CURLOPT_SSL_VERIFYPEER
When NSS-powered libcurl connected to a SSL server with CURLOPT_SSL_VERIFYPEER equal to zero, NSS remembered that the peer certificate was accepted by libcurl and did not ask the second time when connecting to the same server with CURLOPT_SSL_VERIFYPEER equal to one. This patch turns off the SSL session cache for the particular SSL socket if peer verification is disabled. In order to avoid any performance impact, the peer verification is completely skipped in that case, which makes it even faster than before. Bug: https://bugzilla.redhat.com/678580
-rw-r--r--RELEASE-NOTES1
-rw-r--r--docs/libcurl/curl_easy_setopt.35
-rw-r--r--lib/nss.c50
3 files changed, 37 insertions, 19 deletions
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 480603f0a..223f5ea11 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -35,6 +35,7 @@ This release includes the following bugfixes:
o Fixed detection of recvfrom arguments on Android/bionic
o GSS: handle reuse fix
o transfer: avoid insane conversion of time_t
+ o nss: do not ignore value of CURLOPT_SSL_VERIFYPEER in certain cases
This release includes the following known bugs:
diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3
index 56a54a9db..2dd536cf5 100644
--- a/docs/libcurl/curl_easy_setopt.3
+++ b/docs/libcurl/curl_easy_setopt.3
@@ -2007,7 +2007,10 @@ The default value for this option is 2.
This option controls checking the server's certificate's claimed identity.
The server could be lying. To control lying, see
-\fICURLOPT_SSL_VERIFYPEER\fP.
+\fICURLOPT_SSL_VERIFYPEER\fP. If libcurl is built against NSS and
+\fICURLOPT_SSL_VERIFYPEER\fP is zero, \fICURLOPT_SSL_VERIFYHOST\fP
+is ignored.
+
.IP CURLOPT_CERTINFO
Pass a long set to 1 to enable libcurl's certificate chain info gatherer. With
this enabled, libcurl (if built with OpenSSL) will extract lots of information
diff --git a/lib/nss.c b/lib/nss.c
index be26253c4..a3bd77cfb 100644
--- a/lib/nss.c
+++ b/lib/nss.c
@@ -622,17 +622,28 @@ static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg)
return (char *)PORT_Strdup((char *)arg);
}
+/* bypass the default SSL_AuthCertificate() hook in case we do not want to
+ * verify peer */
+static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
+ PRBool isServer)
+{
+ struct connectdata *conn = (struct connectdata *)arg;
+ if(!conn->data->set.ssl.verifypeer) {
+ infof(conn->data, "skipping SSL peer certificate verification\n");
+ return SECSuccess;
+ }
+
+ return SSL_AuthCertificate(arg, fd, checksig, isServer);
+}
+
static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
{
- SECStatus success = SECSuccess;
+ SECStatus result = SECFailure;
struct connectdata *conn = (struct connectdata *)arg;
PRErrorCode err = PR_GetError();
CERTCertificate *cert = NULL;
char *subject, *subject_cn, *issuer;
- if(conn->data->set.ssl.certverifyresult!=0)
- return success;
-
conn->data->set.ssl.certverifyresult=err;
cert = SSL_PeerCertificate(sock);
subject = CERT_NameToAscii(&cert->subject);
@@ -643,12 +654,8 @@ static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
switch(err) {
case SEC_ERROR_CA_CERT_INVALID:
infof(conn->data, "Issuer certificate is invalid: '%s'\n", issuer);
- if(conn->data->set.ssl.verifypeer)
- success = SECFailure;
break;
case SEC_ERROR_UNTRUSTED_ISSUER:
- if(conn->data->set.ssl.verifypeer)
- success = SECFailure;
infof(conn->data, "Certificate is signed by an untrusted issuer: '%s'\n",
issuer);
break;
@@ -656,37 +663,31 @@ static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
if(conn->data->set.ssl.verifyhost) {
failf(conn->data, "SSL: certificate subject name '%s' does not match "
"target host name '%s'", subject_cn, conn->host.dispname);
- success = SECFailure;
} else {
+ result = SECSuccess;
infof(conn->data, "warning: SSL: certificate subject name '%s' does not "
"match target host name '%s'\n", subject_cn, conn->host.dispname);
}
break;
case SEC_ERROR_EXPIRED_CERTIFICATE:
- if(conn->data->set.ssl.verifypeer)
- success = SECFailure;
infof(conn->data, "Remote Certificate has expired.\n");
break;
case SEC_ERROR_UNKNOWN_ISSUER:
- if(conn->data->set.ssl.verifypeer)
- success = SECFailure;
infof(conn->data, "Peer's certificate issuer is not recognized: '%s'\n",
issuer);
break;
default:
- if(conn->data->set.ssl.verifypeer)
- success = SECFailure;
infof(conn->data, "Bad certificate received. Subject = '%s', "
"Issuer = '%s'\n", subject, issuer);
break;
}
- if(success == SECSuccess)
+ if(result == SECSuccess)
infof(conn->data, "SSL certificate verify ok.\n");
PR_Free(subject);
PR_Free(subject_cn);
PR_Free(issuer);
- return success;
+ return result;
}
/**
@@ -1154,6 +1155,7 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
PRBool ssl2 = PR_FALSE;
PRBool ssl3 = PR_FALSE;
PRBool tlsv1 = PR_FALSE;
+ PRBool ssl_no_cache;
struct SessionHandle *data = conn->data;
curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
@@ -1227,6 +1229,11 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
goto error;
+ /* do not use SSL cache if we are not going to verify peer */
+ ssl_no_cache = (data->set.ssl.verifypeer) ? PR_FALSE : PR_TRUE;
+ if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
+ goto error;
+
switch (data->set.ssl.version) {
default:
case CURL_SSLVERSION_DEFAULT:
@@ -1277,9 +1284,16 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
}
}
- if(data->set.ssl.verifyhost == 1)
+ 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 */
+ if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess)
+ goto error;
+
data->set.ssl.certverifyresult=0; /* not checked yet */
if(SSL_BadCertHook(model, (SSLBadCertHandler) BadCertHandler, conn)
!= SECSuccess) {