9549974
From 50582c5be1a613ee1d212855a8945b4c8ef8950f Mon Sep 17 00:00:00 2001
9549974
From: Kamil Dudka <kdudka@redhat.com>
9549974
Date: Mon, 10 Apr 2017 17:05:05 +0200
9549974
Subject: [PATCH 1/2] nss: factorize out nss_{un,}load_module to separate fncs
9549974
9549974
No change of behavior is intended by this commit.
9549974
9549974
Upstream-commit: fab3d1ec650e17fd15cf8b6d4ffa5bfd523501dc
9549974
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
9549974
---
9549974
 lib/vtls/nss.c | 83 +++++++++++++++++++++++++++++++++++++++-------------------
9549974
 1 file changed, 56 insertions(+), 27 deletions(-)
9549974
9549974
diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
9549974
index 099f364..6b8f8c0 100644
9549974
--- a/lib/vtls/nss.c
9549974
+++ b/lib/vtls/nss.c
9549974
@@ -201,7 +201,7 @@ static const cipher_s cipherlist[] = {
9549974
 };
9549974
 
9549974
 static const char *pem_library = "libnsspem.so";
9549974
-static SECMODModule *mod = NULL;
9549974
+static SECMODModule *pem_module = NULL;
9549974
 
9549974
 /* NSPR I/O layer we use to detect blocking direction during SSL handshake */
9549974
 static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER;
9549974
@@ -600,7 +600,7 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
9549974
     return CURLE_SSL_CERTPROBLEM;
9549974
 
9549974
   /* This will force the token to be seen as re-inserted */
9549974
-  tmp = SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
9549974
+  tmp = SECMOD_WaitForAnyTokenEvent(pem_module, 0, 0);
9549974
   if(tmp)
9549974
     PK11_FreeSlot(tmp);
9549974
   PK11_IsPresent(slot);
9549974
@@ -1180,6 +1180,50 @@ static PRStatus nspr_io_close(PRFileDesc *fd)
9549974
   return close_fn(fd);
9549974
 }
9549974
 
9549974
+/* load a PKCS #11 module */
9549974
+static CURLcode nss_load_module(SECMODModule **pmod, const char *library,
9549974
+                                const char *name)
9549974
+{
9549974
+  char *config_string;
9549974
+  SECMODModule *module = *pmod;
9549974
+  if(module)
9549974
+    /* already loaded */
9549974
+    return CURLE_OK;
9549974
+
9549974
+  config_string = aprintf("library=%s name=%s", library, name);
9549974
+  if(!config_string)
9549974
+    return CURLE_OUT_OF_MEMORY;
9549974
+
9549974
+  module = SECMOD_LoadUserModule(config_string, NULL, PR_FALSE);
9549974
+  free(config_string);
9549974
+
9549974
+  if(module && module->loaded) {
9549974
+    /* loaded successfully */
9549974
+    *pmod = module;
9549974
+    return CURLE_OK;
9549974
+  }
9549974
+
9549974
+  if(module)
9549974
+    SECMOD_DestroyModule(module);
9549974
+  return CURLE_FAILED_INIT;
9549974
+}
9549974
+
9549974
+/* unload a PKCS #11 module */
9549974
+static void nss_unload_module(SECMODModule **pmod)
9549974
+{
9549974
+  SECMODModule *module = *pmod;
9549974
+  if(!module)
9549974
+    /* not loaded */
9549974
+    return;
9549974
+
9549974
+  if(SECMOD_UnloadUserModule(module) != SECSuccess)
9549974
+    /* unload failed */
9549974
+    return;
9549974
+
9549974
+  SECMOD_DestroyModule(module);
9549974
+  *pmod = NULL;
9549974
+}
9549974
+
9549974
 /* data might be NULL */
9549974
 static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
9549974
 {
9549974
@@ -1327,10 +1371,7 @@ void Curl_nss_cleanup(void)
9549974
      * the certificates. */
9549974
     SSL_ClearSessionCache();
9549974
 
9549974
-    if(mod && SECSuccess == SECMOD_UnloadUserModule(mod)) {
9549974
-      SECMOD_DestroyModule(mod);
9549974
-      mod = NULL;
9549974
-    }
9549974
+    nss_unload_module(&pem_module);
9549974
     NSS_ShutdownContext(nss_context);
9549974
     nss_context = NULL;
9549974
   }
9549974
@@ -1685,29 +1726,17 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
9549974
     goto error;
9549974
   }
9549974
 
9549974
-  result = CURLE_SSL_CONNECT_ERROR;
9549974
-
9549974
-  if(!mod) {
9549974
-    char *configstring = aprintf("library=%s name=PEM", pem_library);
9549974
-    if(!configstring) {
9549974
-      PR_Unlock(nss_initlock);
9549974
-      goto error;
9549974
-    }
9549974
-    mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
9549974
-    free(configstring);
9549974
-
9549974
-    if(!mod || !mod->loaded) {
9549974
-      if(mod) {
9549974
-        SECMOD_DestroyModule(mod);
9549974
-        mod = NULL;
9549974
-      }
9549974
-      infof(data, "WARNING: failed to load NSS PEM library %s. Using "
9549974
-                  "OpenSSL PEM certificates will not work.\n", pem_library);
9549974
-    }
9549974
-  }
9549974
-
9549974
   PK11_SetPasswordFunc(nss_get_password);
9549974
+
9549974
+  result = nss_load_module(&pem_module, pem_library, "PEM");
9549974
   PR_Unlock(nss_initlock);
9549974
+  if(result == CURLE_FAILED_INIT)
9549974
+    infof(data, "WARNING: failed to load NSS PEM library %s. Using "
9549974
+                "OpenSSL PEM certificates will not work.\n", pem_library);
9549974
+  else if(result)
9549974
+    goto error;
9549974
+
9549974
+  result = CURLE_SSL_CONNECT_ERROR;
9549974
 
9549974
   model = PR_NewTCPSocket();
9549974
   if(!model)
9549974
-- 
9549974
2.9.3
9549974
9549974
9549974
From cf6f9017f0e144ad510fd5913b44b22a2146dd4b Mon Sep 17 00:00:00 2001
9549974
From: Kamil Dudka <kdudka@redhat.com>
9549974
Date: Mon, 10 Apr 2017 17:40:30 +0200
9549974
Subject: [PATCH 2/2] nss: load libnssckbi.so if no other trust is specified
9549974
9549974
The module contains a more comprehensive set of trust information than
9549974
supported by nss-pem, because libnssckbi.so also includes information
9549974
about distrusted certificates.
9549974
9549974
Reviewed-by: Kai Engert
9549974
Closes #1414
9549974
9549974
Upstream-commit: e3e8d0204b72509cfd63d97a159d1ac3fdea703b
9549974
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
9549974
---
9549974
 docs/libcurl/opts/CURLOPT_CAINFO.3 |  5 ++++
9549974
 lib/vtls/nss.c                     | 51 ++++++++++++++++++++++++++++++++------
9549974
 2 files changed, 48 insertions(+), 8 deletions(-)
9549974
9549974
diff --git a/docs/libcurl/opts/CURLOPT_CAINFO.3 b/docs/libcurl/opts/CURLOPT_CAINFO.3
9549974
index 91b7e23..85436c3 100644
9549974
--- a/docs/libcurl/opts/CURLOPT_CAINFO.3
9549974
+++ b/docs/libcurl/opts/CURLOPT_CAINFO.3
9549974
@@ -41,6 +41,11 @@ is assumed to be stored, as established at build time.
9549974
 
9549974
 If curl is built against the NSS SSL library, the NSS PEM PKCS#11 module
9549974
 (libnsspem.so) needs to be available for this option to work properly.
9549974
+Starting with curl-7.55.0, if both \fICURLOPT_CAINFO(3)\fP and
9549974
+\fICURLOPT_CAPATH(3)\fP are unset, NSS-linked libcurl tries to load
9549974
+libnssckbi.so, which contains a more comprehensive set of trust information
9549974
+than supported by nss-pem, because libnssckbi.so also includes information
9549974
+about distrusted certificates.
9549974
 
9549974
 (iOS and macOS only) If curl is built against Secure Transport, then this
9549974
 option is supported for backward compatibility with other SSL engines, but it
9549974
diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
9549974
index 6b8f8c0..62665e7 100644
9549974
--- a/lib/vtls/nss.c
9549974
+++ b/lib/vtls/nss.c
9549974
@@ -81,6 +81,7 @@
9549974
 static PRLock *nss_initlock = NULL;
9549974
 static PRLock *nss_crllock = NULL;
9549974
 static PRLock *nss_findslot_lock = NULL;
9549974
+static PRLock *nss_trustload_lock = NULL;
9549974
 static struct curl_llist nss_crl_list;
9549974
 static NSSInitContext *nss_context = NULL;
9549974
 static volatile int initialized = 0;
9549974
@@ -203,6 +204,9 @@ static const cipher_s cipherlist[] = {
9549974
 static const char *pem_library = "libnsspem.so";
9549974
 static SECMODModule *pem_module = NULL;
9549974
 
9549974
+static const char *trust_library = "libnssckbi.so";
9549974
+static SECMODModule *trust_module = NULL;
9549974
+
9549974
 /* NSPR I/O layer we use to detect blocking direction during SSL handshake */
9549974
 static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER;
9549974
 static PRIOMethods nspr_io_methods;
9549974
@@ -1333,6 +1337,7 @@ int Curl_nss_init(void)
9549974
     nss_initlock = PR_NewLock();
9549974
     nss_crllock = PR_NewLock();
9549974
     nss_findslot_lock = PR_NewLock();
9549974
+    nss_trustload_lock = PR_NewLock();
9549974
   }
9549974
 
9549974
   /* We will actually initialize NSS later */
9549974
@@ -1372,6 +1377,7 @@ void Curl_nss_cleanup(void)
9549974
     SSL_ClearSessionCache();
9549974
 
9549974
     nss_unload_module(&pem_module);
9549974
+    nss_unload_module(&trust_module);
9549974
     NSS_ShutdownContext(nss_context);
9549974
     nss_context = NULL;
9549974
   }
9549974
@@ -1384,6 +1390,7 @@ void Curl_nss_cleanup(void)
9549974
   PR_DestroyLock(nss_initlock);
9549974
   PR_DestroyLock(nss_crllock);
9549974
   PR_DestroyLock(nss_findslot_lock);
9549974
+  PR_DestroyLock(nss_trustload_lock);
9549974
   nss_initlock = NULL;
9549974
 
9549974
   initialized = 0;
9549974
@@ -1505,12 +1512,44 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
9549974
   struct Curl_easy *data = conn->data;
9549974
   const char *cafile = SSL_CONN_CONFIG(CAfile);
9549974
   const char *capath = SSL_CONN_CONFIG(CApath);
9549974
+  bool use_trust_module;
9549974
+  CURLcode result = CURLE_OK;
9549974
 
9549974
-  if(cafile) {
9549974
-    CURLcode result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
9549974
-    if(result)
9549974
-      return result;
9549974
+  /* treat empty string as unset */
9549974
+  if(cafile && !cafile[0])
9549974
+    cafile = NULL;
9549974
+  if(capath && !capath[0])
9549974
+    capath = NULL;
9549974
+
9549974
+  infof(data, "  CAfile: %s\n  CApath: %s\n",
9549974
+      cafile ? cafile : "none",
9549974
+      capath ? capath : "none");
9549974
+
9549974
+  /* load libnssckbi.so if no other trust roots were specified */
9549974
+  use_trust_module = !cafile && !capath;
9549974
+
9549974
+  PR_Lock(nss_trustload_lock);
9549974
+  if(use_trust_module && !trust_module) {
9549974
+    /* libnssckbi.so needed but not yet loaded --> load it! */
9549974
+    result = nss_load_module(&trust_module, trust_library, "trust");
9549974
+    infof(data, "%s %s\n", (result) ? "failed to load" : "loaded",
9549974
+          trust_library);
9549974
+    if(result == CURLE_FAILED_INIT)
9549974
+      /* make the error non-fatal if we are not going to verify peer */
9549974
+      result = CURLE_SSL_CACERT_BADFILE;
9549974
   }
9549974
+  else if(!use_trust_module && trust_module) {
9549974
+    /* libnssckbi.so not needed but already loaded --> unload it! */
9549974
+    infof(data, "unloading %s\n", trust_library);
9549974
+    nss_unload_module(&trust_module);
9549974
+  }
9549974
+  PR_Unlock(nss_trustload_lock);
9549974
+
9549974
+  if(cafile)
9549974
+    result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
9549974
+
9549974
+  if(result)
9549974
+    return result;
9549974
 
9549974
   if(capath) {
9549974
     struct_stat st;
9549974
@@ -1544,10 +1583,6 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
9549974
       infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath);
9549974
   }
9549974
 
9549974
-  infof(data, "  CAfile: %s\n  CApath: %s\n",
9549974
-      cafile ? cafile : "none",
9549974
-      capath ? capath : "none");
9549974
-
9549974
   return CURLE_OK;
9549974
 }
9549974
 
9549974
-- 
9549974
2.9.3
9549974