summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib/vtls/nss.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/vtls/nss.c')
-rw-r--r--Utilities/cmcurl/lib/vtls/nss.c168
1 files changed, 128 insertions, 40 deletions
diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c
index 89a16d3..cd01389 100644
--- a/Utilities/cmcurl/lib/vtls/nss.c
+++ b/Utilities/cmcurl/lib/vtls/nss.c
@@ -81,10 +81,17 @@
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;
+/* type used to wrap pointers as list nodes */
+struct ptr_list_wrap {
+ void *ptr;
+ struct curl_llist_element node;
+};
+
typedef struct {
const char *name;
int num;
@@ -201,7 +208,10 @@ static const cipher_s cipherlist[] = {
};
static const char *pem_library = "libnsspem.so";
-static SECMODModule *mod = NULL;
+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;
@@ -371,6 +381,18 @@ static PK11SlotInfo* nss_find_slot_by_name(const char *slot_name)
return slot;
}
+/* wrap 'ptr' as list node and tail-insert into 'list' */
+static CURLcode insert_wrapped_ptr(struct curl_llist *list, void *ptr)
+{
+ struct ptr_list_wrap *wrap = malloc(sizeof *wrap);
+ if(!wrap)
+ return CURLE_OUT_OF_MEMORY;
+
+ wrap->ptr = ptr;
+ Curl_llist_insert_next(list, list->tail, wrap, &wrap->node);
+ return CURLE_OK;
+}
+
/* Call PK11_CreateGenericObject() with the given obj_class and filename. If
* the call succeeds, append the object handle to the list of objects so that
* the object can be destroyed in Curl_nss_close(). */
@@ -413,7 +435,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl,
if(!obj)
return result;
- if(!Curl_llist_insert_next(&ssl->obj_list, ssl->obj_list.tail, obj)) {
+ if(insert_wrapped_ptr(&ssl->obj_list, obj) != CURLE_OK) {
PK11_DestroyGenericObject(obj);
return CURLE_OUT_OF_MEMORY;
}
@@ -430,17 +452,21 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl,
* NSS objects in Curl_nss_close() */
static void nss_destroy_object(void *user, void *ptr)
{
- PK11GenericObject *obj = (PK11GenericObject *)ptr;
+ struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr;
+ PK11GenericObject *obj = (PK11GenericObject *) wrap->ptr;
(void) user;
PK11_DestroyGenericObject(obj);
+ free(wrap);
}
/* same as nss_destroy_object() but for CRL items */
static void nss_destroy_crl_item(void *user, void *ptr)
{
- SECItem *crl_der = (SECItem *)ptr;
+ struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr;
+ SECItem *crl_der = (SECItem *) wrap->ptr;
(void) user;
SECITEM_FreeItem(crl_der, PR_TRUE);
+ free(wrap);
}
static CURLcode nss_load_cert(struct ssl_connect_data *ssl,
@@ -496,7 +522,7 @@ static CURLcode nss_cache_crl(SECItem *crl_der)
PR_Lock(nss_crllock);
/* store the CRL item so that we can free it in Curl_nss_cleanup() */
- if(!Curl_llist_insert_next(&nss_crl_list, nss_crl_list.tail, crl_der)) {
+ if(insert_wrapped_ptr(&nss_crl_list, crl_der) != CURLE_OK) {
SECITEM_FreeItem(crl_der, PR_TRUE);
PR_Unlock(nss_crllock);
return CURLE_OUT_OF_MEMORY;
@@ -581,7 +607,7 @@ fail:
static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
char *key_file)
{
- PK11SlotInfo *slot;
+ PK11SlotInfo *slot, *tmp;
SECStatus status;
CURLcode result;
struct ssl_connect_data *ssl = conn->ssl;
@@ -600,7 +626,9 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
return CURLE_SSL_CERTPROBLEM;
/* This will force the token to be seen as re-inserted */
- SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
+ tmp = SECMOD_WaitForAnyTokenEvent(pem_module, 0, 0);
+ if(tmp)
+ PK11_FreeSlot(tmp);
PK11_IsPresent(slot);
status = PK11_Authenticate(slot, PR_TRUE, SSL_SET_OPTION(key_passwd));
@@ -1178,6 +1206,50 @@ static PRStatus nspr_io_close(PRFileDesc *fd)
return close_fn(fd);
}
+/* load a PKCS #11 module */
+static CURLcode nss_load_module(SECMODModule **pmod, const char *library,
+ const char *name)
+{
+ char *config_string;
+ SECMODModule *module = *pmod;
+ if(module)
+ /* already loaded */
+ return CURLE_OK;
+
+ config_string = aprintf("library=%s name=%s", library, name);
+ if(!config_string)
+ return CURLE_OUT_OF_MEMORY;
+
+ module = SECMOD_LoadUserModule(config_string, NULL, PR_FALSE);
+ free(config_string);
+
+ if(module && module->loaded) {
+ /* loaded successfully */
+ *pmod = module;
+ return CURLE_OK;
+ }
+
+ if(module)
+ SECMOD_DestroyModule(module);
+ return CURLE_FAILED_INIT;
+}
+
+/* unload a PKCS #11 module */
+static void nss_unload_module(SECMODModule **pmod)
+{
+ SECMODModule *module = *pmod;
+ if(!module)
+ /* not loaded */
+ return;
+
+ if(SECMOD_UnloadUserModule(module) != SECSuccess)
+ /* unload failed */
+ return;
+
+ SECMOD_DestroyModule(module);
+ *pmod = NULL;
+}
+
/* data might be NULL */
static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
{
@@ -1287,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 */
@@ -1325,10 +1398,8 @@ void Curl_nss_cleanup(void)
* the certificates. */
SSL_ClearSessionCache();
- if(mod && SECSuccess == SECMOD_UnloadUserModule(mod)) {
- SECMOD_DestroyModule(mod);
- mod = NULL;
- }
+ nss_unload_module(&pem_module);
+ nss_unload_module(&trust_module);
NSS_ShutdownContext(nss_context);
nss_context = NULL;
}
@@ -1341,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;
@@ -1462,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;
@@ -1501,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;
}
@@ -1683,29 +1783,17 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
goto error;
}
- result = CURLE_SSL_CONNECT_ERROR;
-
- if(!mod) {
- char *configstring = aprintf("library=%s name=PEM", pem_library);
- if(!configstring) {
- PR_Unlock(nss_initlock);
- goto error;
- }
- mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
- free(configstring);
-
- if(!mod || !mod->loaded) {
- if(mod) {
- SECMOD_DestroyModule(mod);
- mod = NULL;
- }
- infof(data, "WARNING: failed to load NSS PEM library %s. Using "
- "OpenSSL PEM certificates will not work.\n", pem_library);
- }
- }
-
PK11_SetPasswordFunc(nss_get_password);
+
+ result = nss_load_module(&pem_module, pem_library, "PEM");
PR_Unlock(nss_initlock);
+ if(result == CURLE_FAILED_INIT)
+ infof(data, "WARNING: failed to load NSS PEM library %s. Using "
+ "OpenSSL PEM certificates will not work.\n", pem_library);
+ else if(result)
+ goto error;
+
+ result = CURLE_SSL_CONNECT_ERROR;
model = PR_NewTCPSocket();
if(!model)