aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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) {