]> granicus.if.org Git - curl/commitdiff
nss: load libnssckbi.so if no other trust is specified
authorKamil Dudka <kdudka@redhat.com>
Mon, 10 Apr 2017 15:40:30 +0000 (17:40 +0200)
committerKamil Dudka <kdudka@redhat.com>
Tue, 25 Apr 2017 11:24:24 +0000 (13:24 +0200)
The module contains a more comprehensive set of trust information than
supported by nss-pem, because libnssckbi.so also includes information
about distrusted certificates.

Reviewed-by: Kai Engert
Closes #1414

docs/libcurl/opts/CURLOPT_CAINFO.3
lib/vtls/nss.c

index 127b904436ff63a5dc356d764de7d96b39e9a323..43a4901f0f2527529375386f72f69706d3b8be93 100644 (file)
@@ -40,6 +40,11 @@ is assumed to be stored, as established at build time.
 
 If curl is built against the NSS SSL library, the NSS PEM PKCS#11 module
 (libnsspem.so) needs to be available for this option to work properly.
+Starting with curl-7.55.0, if both \fICURLOPT_CAINFO(3)\fP and
+\fICURLOPT_CAPATH(3)\fP are unset, NSS-linked libcurl tries to load
+libnssckbi.so, which contains a more comprehensive set of trust information
+than supported by nss-pem, because libnssckbi.so also includes information
+about distrusted certificates.
 
 (iOS and macOS only) If curl is built against Secure Transport, then this
 option is supported for backward compatibility with other SSL engines, but it
index 78bb98da026b01c766a53763aaf86a277653587e..cd0138930997dbd0fcb9c70c3ed9f477f22893c0 100644 (file)
@@ -81,6 +81,7 @@
 static PRLock *nss_initlock = NULL;
 static PRLock *nss_crllock = NULL;
 static PRLock *nss_findslot_lock = NULL;
+static PRLock *nss_trustload_lock = NULL;
 static struct curl_llist nss_crl_list;
 static NSSInitContext *nss_context = NULL;
 static volatile int initialized = 0;
@@ -209,6 +210,9 @@ static const cipher_s cipherlist[] = {
 static const char *pem_library = "libnsspem.so";
 static SECMODModule *pem_module = NULL;
 
+static const char *trust_library = "libnssckbi.so";
+static SECMODModule *trust_module = NULL;
+
 /* NSPR I/O layer we use to detect blocking direction during SSL handshake */
 static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER;
 static PRIOMethods nspr_io_methods;
@@ -1355,6 +1359,7 @@ int Curl_nss_init(void)
     nss_initlock = PR_NewLock();
     nss_crllock = PR_NewLock();
     nss_findslot_lock = PR_NewLock();
+    nss_trustload_lock = PR_NewLock();
   }
 
   /* We will actually initialize NSS later */
@@ -1394,6 +1399,7 @@ void Curl_nss_cleanup(void)
     SSL_ClearSessionCache();
 
     nss_unload_module(&pem_module);
+    nss_unload_module(&trust_module);
     NSS_ShutdownContext(nss_context);
     nss_context = NULL;
   }
@@ -1406,6 +1412,7 @@ void Curl_nss_cleanup(void)
   PR_DestroyLock(nss_initlock);
   PR_DestroyLock(nss_crllock);
   PR_DestroyLock(nss_findslot_lock);
+  PR_DestroyLock(nss_trustload_lock);
   nss_initlock = NULL;
 
   initialized = 0;
@@ -1527,12 +1534,44 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
   struct Curl_easy *data = conn->data;
   const char *cafile = SSL_CONN_CONFIG(CAfile);
   const char *capath = SSL_CONN_CONFIG(CApath);
+  bool use_trust_module;
+  CURLcode result = CURLE_OK;
 
-  if(cafile) {
-    CURLcode result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
-    if(result)
-      return result;
+  /* treat empty string as unset */
+  if(cafile && !cafile[0])
+    cafile = NULL;
+  if(capath && !capath[0])
+    capath = NULL;
+
+  infof(data, "  CAfile: %s\n  CApath: %s\n",
+      cafile ? cafile : "none",
+      capath ? capath : "none");
+
+  /* load libnssckbi.so if no other trust roots were specified */
+  use_trust_module = !cafile && !capath;
+
+  PR_Lock(nss_trustload_lock);
+  if(use_trust_module && !trust_module) {
+    /* libnssckbi.so needed but not yet loaded --> load it! */
+    result = nss_load_module(&trust_module, trust_library, "trust");
+    infof(data, "%s %s\n", (result) ? "failed to load" : "loaded",
+          trust_library);
+    if(result == CURLE_FAILED_INIT)
+      /* make the error non-fatal if we are not going to verify peer */
+      result = CURLE_SSL_CACERT_BADFILE;
   }
+  else if(!use_trust_module && trust_module) {
+    /* libnssckbi.so not needed but already loaded --> unload it! */
+    infof(data, "unloading %s\n", trust_library);
+    nss_unload_module(&trust_module);
+  }
+  PR_Unlock(nss_trustload_lock);
+
+  if(cafile)
+    result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
+
+  if(result)
+    return result;
 
   if(capath) {
     struct_stat st;
@@ -1566,10 +1605,6 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
       infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath);
   }
 
-  infof(data, "  CAfile: %s\n  CApath: %s\n",
-      cafile ? cafile : "none",
-      capath ? capath : "none");
-
   return CURLE_OK;
 }