Bug 1279520 - Add support for enforcing a system-wide crypto policy, r=mt
authorElio Maldonado <emaldona@redhat.com>
Tue, 12 Jul 2016 17:38:50 -0700
changeset 12383 f0f2c22dba2239cd41d4b147e6912675ee8bc2e8
parent 12382 99067c3b8f287000d081c7ad711901a74d5dc084
child 12384 22a5d5a087a51be632dee3e1bf1d754766380470
child 12387 7c81f6fc561ad9f529c61419498b23ec6b55ef1b
push id1396
push useremaldona@redhat.com
push dateWed, 13 Jul 2016 02:51:12 +0000
reviewersmt
bugs1279520
Bug 1279520 - Add support for enforcing a system-wide crypto policy, r=mt
lib/nss/config.mk
lib/nss/nssinit.c
lib/util/utilpars.c
--- a/lib/nss/config.mk
+++ b/lib/nss/config.mk
@@ -100,8 +100,15 @@ endif
 ifeq (,$(filter-out WINNT WIN95,$(OS_TARGET)))
 ifndef NS_USE_GCC
 # Export 'mktemp' to be backward compatible with NSS 3.2.x and 3.3.x
 # but do not put it in the import library.  See bug 142575.
 DEFINES += -DWIN32_NSS3_DLL_COMPAT
 DLLFLAGS += -EXPORT:mktemp=nss_mktemp,PRIVATE
 endif
 endif
+
+ifdef POLICY_FILE
+ifndef POLICY_PATH
+$(error You must define POLICY_PATH if you set POLICY_FILE)
+endif
+DEFINES += -DPOLICY_FILE=\"$(POLICY_FILE)\" -DPOLICY_PATH=\"$(POLICY_PATH)\"
+endif
--- a/lib/nss/nssinit.c
+++ b/lib/nss/nssinit.c
@@ -333,47 +333,47 @@ nss_FindExternalRoot(const char *dbpath,
 
 /*
  * see nss_Init for definitions of the various options.
  *
  * this function builds a moduleSpec string from the options and previously
  * set statics (from PKCS11_Configure, for instance), and uses it to kick off
  * the loading of the various PKCS #11 modules.
  */
-static SECStatus
+static SECMODModule *
 nss_InitModules(const char *configdir, const char *certPrefix, 
 		const char *keyPrefix, const char *secmodName, 
 		const char *updateDir, const char *updCertPrefix, 
 		const char *updKeyPrefix, const char *updateID, 
 		const char *updateName, char *configName, char *configStrings,
 		PRBool pwRequired, PRBool readOnly, PRBool noCertDB,
 		PRBool noModDB, PRBool forceOpen, PRBool optimizeSpace,
 		PRBool isContextInit)
 {
-    SECStatus rv = SECFailure;
+    SECMODModule *module = NULL;
     char *moduleSpec = NULL;
     char *flags = NULL;
     char *lconfigdir = NULL;
     char *lcertPrefix = NULL;
     char *lkeyPrefix = NULL;
     char *lsecmodName = NULL;
     char *lupdateDir = NULL;
     char *lupdCertPrefix = NULL;
     char *lupdKeyPrefix = NULL;
     char *lupdateID = NULL;
     char *lupdateName = NULL;
 
     if (NSS_InitializePRErrorTable() != SECSuccess) {
 	PORT_SetError(SEC_ERROR_NO_MEMORY);
-	return rv;
+	return NULL;
     }
 
     flags = nss_makeFlags(readOnly,noCertDB,noModDB,forceOpen,
 					pwRequired, optimizeSpace);
-    if (flags == NULL) return rv;
+    if (flags == NULL) return NULL;
 
     /*
      * configdir is double nested, and Windows uses the same character
      * for file seps as we use for escapes! (sigh).
      */
     lconfigdir = NSSUTIL_DoubleEscape(configdir, '\'', '\"');
     if (lconfigdir == NULL) {
 	goto loser;
@@ -430,24 +430,24 @@ loser:
     if (lsecmodName) PORT_Free(lsecmodName);
     if (lupdateDir) PORT_Free(lupdateDir);
     if (lupdCertPrefix) PORT_Free(lupdCertPrefix);
     if (lupdKeyPrefix) PORT_Free(lupdKeyPrefix);
     if (lupdateID) PORT_Free(lupdateID);
     if (lupdateName) PORT_Free(lupdateName);
 
     if (moduleSpec) {
-	SECMODModule *module = SECMOD_LoadModule(moduleSpec,NULL,PR_TRUE);
+	module = SECMOD_LoadModule(moduleSpec, NULL, PR_TRUE);
 	PR_smprintf_free(moduleSpec);
-	if (module) {
-	    if (module->loaded) rv=SECSuccess;
+	if (module && !module->loaded) {
 	    SECMOD_DestroyModule(module);
+	    return NULL;
 	}
     }
-    return rv;
+    return module;
 }
 
 /*
  * OK there are now lots of options here, lets go through them all:
  *
  * configdir - base directory where all the cert, key, and module datbases live.
  * certPrefix - prefix added to the beginning of the cert database example: "
  * 			"https-server1-"
@@ -515,43 +515,46 @@ nss_doLockInit(void)
 	return PR_FAILURE;
     }
     return PR_SUCCESS;
 }
 
 
 static SECStatus
 nss_Init(const char *configdir, const char *certPrefix, const char *keyPrefix,
-		 const char *secmodName, const char *updateDir, 
+		 const char *secmodName, const char *updateDir,
 		 const char *updCertPrefix, const char *updKeyPrefix,
 		 const char *updateID, const char *updateName,
 		 NSSInitContext ** initContextPtr,
 		 NSSInitParameters *initParams,
-		 PRBool readOnly, PRBool noCertDB, 
+		 PRBool readOnly, PRBool noCertDB,
 		 PRBool noModDB, PRBool forceOpen, PRBool noRootInit,
 		 PRBool optimizeSpace, PRBool noSingleThreadedModules,
 		 PRBool allowAlreadyInitializedModules,
 		 PRBool dontFinalizeModules)
 {
-    SECStatus rv = SECFailure;
+    SECMODModule *parent = NULL;
 #ifndef NSS_DISABLE_LIBPKIX
     PKIX_UInt32 actualMinorVersion = 0;
     PKIX_Error *pkixError = NULL;
 #endif /* NSS_DISABLE_LIBPKIX */
     PRBool isReallyInitted;
     char *configStrings = NULL;
     char *configName = NULL;
     PRBool passwordRequired = PR_FALSE;
+#ifdef POLICY_FILE
+    char *ignoreVar;
+#endif
 
     /* if we are trying to init with a traditional NSS_Init call, maintain
      * the traditional idempotent behavior. */
     if (!initContextPtr && nssIsInitted) {
 	return SECSuccess;
     }
-  
+
     /* make sure our lock and condition variable are initialized one and only
      * one time */ 
     if (PR_CallOnce(&nssInitOnce, nss_doLockInit) != PR_SUCCESS) {
 	return SECFailure;
     }
 
     /*
      * if we haven't done basic initialization, single thread the 
@@ -638,23 +641,23 @@ nss_Init(const char *configdir, const ch
 	configStrings = pk11_config_strings;
 	configName = pk11_config_name;
 	passwordRequired = pk11_password_required;
     }
 
     /* Skip the module init if we are already initted and we are trying
      * to init with noCertDB and noModDB */
     if (!(isReallyInitted && noCertDB && noModDB)) {
-	rv = nss_InitModules(configdir, certPrefix, keyPrefix, secmodName, 
-		updateDir, updCertPrefix, updKeyPrefix, updateID, 
+	parent = nss_InitModules(configdir, certPrefix, keyPrefix, secmodName,
+		updateDir, updCertPrefix, updKeyPrefix, updateID,
 		updateName, configName, configStrings, passwordRequired,
-		readOnly, noCertDB, noModDB, forceOpen, optimizeSpace, 
+		readOnly, noCertDB, noModDB, forceOpen, optimizeSpace,
 		(initContextPtr != NULL));
 
-	if (rv != SECSuccess) {
+	if (parent == NULL) {
 	    goto loser;
 	}
     }
 
 
     /* finish up initialization */
     if (!isReallyInitted) {
 	if (SECOID_Init() != SECSuccess) {
@@ -683,17 +686,40 @@ nss_Init(const char *configdir, const ch
 		     * path. Skip it */
 		    dbpath = NULL;
 		}
 		if (dbpath) {
 		    nss_FindExternalRoot(dbpath, secmodName);
 		}
 	    }
 	}
-
+#ifdef POLICY_FILE
+	/* Load the system crypto policy file if it exists,
+	 * unless the NSS_IGNORE_SYSTEM_POLICY environment
+	 * variable has been set to 1. */
+	ignoreVar = PR_GetEnvSecure("NSS_IGNORE_SYSTEM_POLICY");
+	if (ignoreVar == NULL || strncmp(ignoreVar, "1", sizeof("1")) != 0) {
+	    if (PR_Access(POLICY_PATH "/" POLICY_FILE, PR_ACCESS_READ_OK) == PR_SUCCESS) {
+	    SECMODModule *module = SECMOD_LoadModule(
+		"name=\"Policy File\" "
+		"parameters=\"configdir='sql:" POLICY_PATH "' "
+		"secmod='" POLICY_FILE "' "
+		"flags=readOnly,noCertDB,forceSecmodChoice,forceOpen\" "
+		"NSS=\"flags=internal,moduleDB,skipFirst,moduleDBOnly,critical\"",
+		parent, PR_TRUE);
+	    if (module) {
+		PRBool isLoaded = module->loaded;
+		SECMOD_DestroyModule(module);
+		if (!isLoaded) {
+		    goto loser;
+		}
+	    }
+	}
+    }
+#endif
 	pk11sdr_Init();
 	cert_CreateSubjectKeyIDHashTable();
 
 #ifndef NSS_DISABLE_LIBPKIX
 	pkixError = PKIX_Initialize
 	    (PKIX_FALSE, PKIX_MAJOR_VERSION, PKIX_MINOR_VERSION,
 	    PKIX_MINOR_VERSION, &actualMinorVersion, &plContext);
 
@@ -724,32 +750,38 @@ nss_Init(const char *configdir, const ch
     nssIsInInit--;
     /* now that we are inited, all waiters can move forward */
     PZ_NotifyAllCondVar(nssInitCondition);
     PZ_Unlock(nssInitLock);
 
     if (initContextPtr && configStrings) {
 	PR_smprintf_free(configStrings);
     }
+    if (parent) {
+	SECMOD_DestroyModule(parent);
+    }
 
     return SECSuccess;
 
 loser:
     if (initContextPtr && *initContextPtr) {
 	PORT_Free(*initContextPtr);
 	*initContextPtr = NULL;
 	if (configStrings) {
 	   PR_smprintf_free(configStrings);
 	}
     }
     PZ_Lock(nssInitLock);
     nssIsInInit--;
     /* We failed to init, allow one to move forward */
     PZ_NotifyCondVar(nssInitCondition);
     PZ_Unlock(nssInitLock);
+    if (parent) {
+	SECMOD_DestroyModule(parent);
+    }
     return SECFailure;
 }
 
 
 SECStatus
 NSS_Init(const char *configdir)
 {
     return nss_Init(configdir, "", "", SECMOD_DB, "", "", "", "", "", NULL,
--- a/lib/util/utilpars.c
+++ b/lib/util/utilpars.c
@@ -1145,18 +1145,19 @@ char *
 	noModDB = PR_TRUE;
 	*dbType = NSS_DB_TYPE_SQL;
 	PORT_Free(*filename);
 	*filename = NULL;
         *rw = PR_FALSE;
    }
 
    /* only use the renamed secmod for legacy databases */
-   if ((*dbType != NSS_DB_TYPE_LEGACY) && 
-	(*dbType != NSS_DB_TYPE_MULTIACCESS)) {
+   if ((*dbType != NSS_DB_TYPE_LEGACY) &&
+	(*dbType != NSS_DB_TYPE_MULTIACCESS) &&
+	  !NSSUTIL_ArgHasFlag("flags", "forceSecmodChoice", save_params)) {
 	secmodName="pkcs11.txt";
    }
 
    if (noModDB) {
 	value = NULL;
    } else if (lconfigdir && lconfigdir[0] != '\0') {
 	value = PR_smprintf("%s" NSSUTIL_PATH_SEPARATOR "%s",
 			lconfigdir,secmodName);