# HG changeset patch
# Parent a4116725d048eff8480c58c19ba4abe30351b906
# Parent  2bf609fcef400204ec013dbfbb60dfe0e3668712
Perform necessary selftests in the libraaary constructors so that they get
called at library load time. Do not test non-FIPS-approved tests by default.

diff --git a/cmd/chktest/chktest.c b/cmd/chktest/chktest.c
--- a/cmd/chktest/chktest.c
+++ b/cmd/chktest/chktest.c
@@ -31,13 +31,13 @@ int main(int argc, char **argv)
     }
     rv = BL_Init();
     if (rv != SECSuccess) {
         SECU_PrintPRandOSError("");
         return -1;
     }
     RNG_SystemInfoForRNG();
 
-    good_result = BLAPI_SHVerifyFile(argv[1]);
+    good_result = BLAPI_SHVerifyFile(argv[1], NULL);
     printf("%s\n", 
       (good_result ? "SUCCESS" : "FAILURE"));
     return (good_result) ? SECSuccess : SECFailure;
 }
diff --git a/lib/freebl/blapi.h b/lib/freebl/blapi.h
--- a/lib/freebl/blapi.h
+++ b/lib/freebl/blapi.h
@@ -1554,27 +1554,27 @@ extern void PQG_DestroyVerify(PQGVerify 
 extern void BL_Cleanup(void);
 
 /* unload freebl shared library from memory */
 extern void BL_Unload(void);
 
 /**************************************************************************
  *  Verify a given Shared library signature                               *
  **************************************************************************/
-PRBool BLAPI_SHVerify(const char *name, PRFuncPtr addr);
+PRBool BLAPI_SHVerify(const char *name, PRFuncPtr addr, int *err);
 
 /**************************************************************************
  *  Verify a given filename's signature                               *
  **************************************************************************/
-PRBool BLAPI_SHVerifyFile(const char *shName);
+PRBool BLAPI_SHVerifyFile(const char *shName, int *err);
 
 /**************************************************************************
  *  Verify Are Own Shared library signature                               *
  **************************************************************************/
-PRBool BLAPI_VerifySelf(const char *name);
+PRBool BLAPI_VerifySelf(const char *name, int *err);
 
 /*********************************************************************/
 extern const SECHashObject * HASH_GetRawHashObject(HASH_HashType hashType);
 
 extern void BL_SetForkState(PRBool forked);
 
 #ifndef NSS_DISABLE_ECC
 /*
diff --git a/lib/freebl/fips-selftest.inc b/lib/freebl/fips-selftest.inc
new file mode 100644
--- /dev/null
+++ b/lib/freebl/fips-selftest.inc
@@ -0,0 +1,280 @@
+/*
+ * PKCS #11 FIPS Power-Up Self Test - common stuff.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef FIPS_INC
+#define FIPS_INC
+
+/* common functions used for FIPS selftests. Due to the modular design of NSS
+ * putting these into libfreebl would mean either amending the API represented
+ * by FREEBLVectorStr - which might cause problems with newer applications, or
+ * extending the API with another similar function set. Thus, to make things
+ * less complicated in the binaries, we mess up the source a bit. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include <prtypes.h>
+#include <prerror.h>
+
+#include <prlink.h>
+
+#include "blapi.h"
+
+#define NSS_FORCE_FIPS_ENV  "NSS_FIPS"
+#define FIPS_PROC_PATH      "/proc/sys/crypto/fips_enabled"
+ 
+#define CHECKSUM_SUFFIX     ".chk"
+
+typedef enum fips_check_status {
+    CHECK_UNCHECKED = -1,
+    CHECK_OK = 0,
+    CHECK_FAIL,
+    CHECK_FAIL_CRYPTO,
+    CHECK_MISSING
+} fips_check_status;
+
+/* initial value of FIPS state is -1 */
+static int fips_state = -1;
+
+static int fips_wanted = -1;
+
+/* debug messages are sent to stderr */
+static void
+debug(const char *fmt,...)
+{
+#ifdef DEBUG_FIPS
+    va_list args;
+
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+    fputc('\n', stderr);
+#endif
+    return;
+}
+
+/* Fatal messages ending with abort(); this function never returns */
+static void __attribute__ ((__noreturn__))
+fatal(const char *fmt,...)
+{
+    va_list args;
+
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+    fputc('\n', stderr);
+    abort();
+}
+
+/* check whether FIPS moode is mandated by the kernel */
+static int
+fips_isWantedProc(void)
+{
+    int fips_wanted = 0;
+    int fips_fd;
+    char fips_sys = 0;
+
+    struct stat dummy;
+    if (-1 == stat(FIPS_PROC_PATH, &dummy)) {
+	switch (errno) {
+	    case ENOENT:
+	    case ENOTDIR:
+		break;
+	    default:
+		fatal("Check for system-wide FIPS mode is required and %s cannot"
+		    " be accessed for reason other than non-existence - aborting"
+		    , FIPS_PROC_PATH);
+		break;
+	}
+    } else {
+	if (-1 == (fips_fd = open(FIPS_PROC_PATH, O_RDONLY))) {
+	    fatal("Check for system-wide FIPS mode is required and %s cannot"
+		" be opened for reading - aborting"
+		, FIPS_PROC_PATH);
+	}
+	if (1 > read(fips_fd, &fips_sys, 1)) {
+	    close(fips_fd);
+	    fatal("Check for system-wide FIPS mode is required and %s doesn't"
+		" return at least one character - aborting"
+		, FIPS_PROC_PATH);
+	}
+	close(fips_fd);
+	switch (fips_sys) {
+	    case '0':
+	    case '1':
+		fips_wanted = fips_sys - '0';
+		break;
+	    default:
+		fatal("Bogus character %c found in %s - aborting"
+		    , fips_sys, FIPS_PROC_PATH);
+	}
+    }
+    return fips_wanted;
+}
+
+/* "legacy" from lib/sysinit/nsssysinit.c */
+static PRBool
+getFIPSEnv(void)
+{
+    char *fipsEnv = getenv("NSS_FIPS");
+    if (!fipsEnv) {
+	return PR_FALSE;
+    }
+    if ((strcasecmp(fipsEnv,"fips") == 0) ||
+	(strcasecmp(fipsEnv,"true") == 0) ||
+	(strcasecmp(fipsEnv,"on") == 0) ||
+	(strcasecmp(fipsEnv,"1") == 0)) {
+	 return PR_TRUE;
+    }
+    return PR_FALSE;
+}
+
+static int
+fips_isWantedEnv(void)
+{
+    return getFIPSEnv() ? 1 : 0;
+}
+
+static int
+fips_isWanted(void)
+{
+    int fips_requests = 0;
+#ifdef LINUX
+    fips_requests += fips_isWantedProc();
+#endif
+    fips_requests += fips_isWantedEnv();
+    return fips_requests;
+}
+
+/* check integrity signatures (if present) */
+static fips_check_status
+fips_checkSignature(char *libName, PRFuncPtr addr)
+{
+    PRBool rv;
+    fips_check_status rv_check = CHECK_UNCHECKED;
+    int l = PATH_MAX;
+    int err = 0;
+    int err_NOENT = 0;
+    char full_lib_name[PATH_MAX+1];
+    full_lib_name[0] = '\0';
+
+    if (NULL == libName) {
+	err_NOENT = ENOENT;
+	rv = BLAPI_VerifySelf(SHLIB_PREFIX"freebl"SHLIB_VERSION"."SHLIB_SUFFIX, &err);
+    } else {
+	err_NOENT = PR_FILE_NOT_FOUND_ERROR;
+	strncat(full_lib_name, SHLIB_PREFIX, l);
+	l -= strlen(SHLIB_PREFIX);
+	strncat(full_lib_name, libName, l);
+	l -= strlen(libName);
+	strncat(full_lib_name, SHLIB_VERSION"."SHLIB_SUFFIX, l);
+	l -= strlen(SHLIB_VERSION"."SHLIB_SUFFIX);
+	rv = BLAPI_SHVerify(full_lib_name, addr, &err);
+    }
+
+    if (rv) {
+	rv_check = CHECK_OK;
+    } else {
+	if (err_NOENT == err) {
+	    rv_check = CHECK_MISSING;
+	} else {
+	    rv_check = CHECK_FAIL;
+	}
+    }
+
+    return rv_check;
+}
+
+/* decide what to do depending on the results of tests and system/required FIPS
+ * mode */
+static int
+fips_resolve(fips_check_status check, char *libName)
+{
+    int state;
+
+    if (fips_wanted) {
+	switch (check) {
+	    case CHECK_OK:
+		debug("fips - %s: mandatory checksum ok"
+		    , (libName) ? libName : "freebl");
+		break;
+	    case CHECK_FAIL:
+		fatal("fips - %s: mandatory checksum failed - aborting"
+		    , (libName) ? libName : "freebl");
+		break;
+	    case CHECK_FAIL_CRYPTO:
+		fatal("fips - %s: mandatory crypto test failed - aborting"
+		    , (libName) ? libName : "freebl");
+		break;
+	    case CHECK_MISSING:
+		fatal("fips - %s: mandatory checksum data missing - aborting"
+		    , (libName) ? libName : "freebl");
+		break;
+	    default:
+		fatal("Fatal error: internal error at %s:%u"
+		    , __FILE__, __LINE__);
+		break;
+	}
+	state = 1;
+    } else {
+	switch (check) {
+	    case CHECK_OK:
+		debug("fips - %s: checksum ok"
+		    , (libName) ? libName : "freebl");
+		break;
+	    case CHECK_FAIL:
+		fatal("fips - %s: checksum failed - aborting"
+		    , (libName) ? libName : "freebl");
+		break;
+	    case CHECK_FAIL_CRYPTO:
+		fatal("fips - %s: crypto test failed - aborting"
+		    , (libName) ? libName : "freebl");
+		break;
+	    case CHECK_MISSING:
+		debug("fips - %s: mandatory checksum data missing, but not required in non FIPS mode; continuing non-FIPS"
+		    , (libName) ? libName : "freebl");
+		break;
+	    default:
+		fatal("Fatal error: internal error at %s:%u"
+		    , __FILE__, __LINE__);
+		break;
+	}
+	state = 0;
+    }
+    return state;
+}
+
+/* generic selftest
+ * libName and addr are the name of shared object to check and a function
+ * contained therein; (NULL, NULL) performs selfcheck of freebl.
+ * crypto_check is callback that performs cryptographic algorithms checks; NULL
+ * for libraries that do not implement any cryptographic algorithms per se
+ */
+static int
+fips_initTest(char *libName, PRFuncPtr addr, fips_check_status cryptoCheck(void))
+{
+    fips_check_status check = fips_checkSignature(libName, addr);
+
+    fips_wanted = fips_isWanted();
+
+    if ((cryptoCheck) && (CHECK_OK == check)) {
+	check = cryptoCheck();
+        debug("fips - %s: crypto check %s"
+	    , (libName) ? libName : "freebl"
+	    , (CHECK_OK == check) ? "ok" : "failed");
+    }
+
+    return fips_resolve(check, libName);
+}
+
+#endif
diff --git a/lib/freebl/fips.c b/lib/freebl/fips.c
new file mode 100644
--- /dev/null
+++ b/lib/freebl/fips.c
@@ -0,0 +1,69 @@
+/*
+ * PKCS #11 FIPS Power-Up Self Test.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "fips-selftest.inc"
+
+#include "fips.h"
+
+#define RNG_DEV_FIPS0   "/dev/urandom"
+#define RNG_DEV_FIPS1   "/dev/random"
+   
+/* crypto algorithms selftest wrapper */
+static fips_check_status
+fips_checkCryptoFreebl(void)
+{
+    /* currently there are no crypto selftets in FreeBL, since it is not
+     * considered to be a stand-alone FIPS crypto module */
+    return CHECK_OK;
+}
+
+/* constructor - load-time selfchecks */
+static void __attribute__ ((constructor))
+fips_initTestFreebl(void)
+{
+    fips_state = fips_initTest(NULL, NULL, fips_checkCryptoFreebl);
+
+    debug("FIPS mode: %i\n", FIPS_mode());
+    return;
+}
+
+/* returns the FIPS mode we are running in or the one that we aspire to if the
+ * tests have not completed yet - which might happen during the crypto selftest
+ */
+int
+FIPS_mode(void)
+{
+    int fips;
+
+    /* until FIPS mode is cleared up, assume we are running in whatever is
+     * wanted by the environment */
+    fips = (-1 != fips_state) ? fips_state : fips_wanted;
+    switch (fips) {
+	case 0:
+	case 1:
+	    return fips;
+	default:
+	    fatal("Fatal error: internal error at %s:%u"
+		, __FILE__, __LINE__);
+    }
+}
+
+/* returns string specifying what system RNG file to use for seeding */
+char *
+FIPS_rngDev(void)
+{
+    switch (FIPS_mode()) {
+	case 0:
+            return RNG_DEV_FIPS0;
+	case 1:
+            return RNG_DEV_FIPS1;
+	default:
+	    fatal("Fatal error: internal error at %s:%u"
+		, __FILE__, __LINE__);
+    }
+}
+
diff --git a/lib/freebl/fips.h b/lib/freebl/fips.h
new file mode 100644
--- /dev/null
+++ b/lib/freebl/fips.h
@@ -0,0 +1,15 @@
+/*
+ * PKCS #11 FIPS Power-Up Self Test.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef FIPS_H
+#define FIPS_H
+
+int	FIPS_mode(void);
+char*	FIPS_rngDev(void);
+
+#endif
+
diff --git a/lib/freebl/loader.c b/lib/freebl/loader.c
--- a/lib/freebl/loader.c
+++ b/lib/freebl/loader.c
@@ -1217,36 +1217,36 @@ AESKeyWrap_Decrypt(AESKeyWrapContext *cx
 {
   if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
       return SECFailure;
   return vector->p_AESKeyWrap_Decrypt(cx, output, outputLen, maxOutputLen,
 		                      input, inputLen);
 }
 
 PRBool
-BLAPI_SHVerify(const char *name, PRFuncPtr addr)
+BLAPI_SHVerify(const char *name, PRFuncPtr addr, int *err)
 {
   if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
       return PR_FALSE;
-  return vector->p_BLAPI_SHVerify(name, addr);
+  return vector->p_BLAPI_SHVerify(name, addr, err);
 }
 
 /*
  * The Caller is expected to pass NULL as the name, which will
  * trigger the p_BLAPI_VerifySelf() to return 'TRUE'. Pass the real
  * name of the shared library we loaded (the static libraryName set
  * in freebl_LoadDSO) to p_BLAPI_VerifySelf.
  */
 PRBool
-BLAPI_VerifySelf(const char *name)
+BLAPI_VerifySelf(const char *name, int *err)
 {
   PORT_Assert(!name);
   if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
       return PR_FALSE;
-  return vector->p_BLAPI_VerifySelf(libraryName);
+  return vector->p_BLAPI_VerifySelf(libraryName, err);
 }
 
 /* ============== New for 3.006 =============================== */
 
 SECStatus 
 EC_NewKey(ECParams * params, ECPrivateKey ** privKey)
 {
   if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
@@ -1831,21 +1831,21 @@ void
 SHA224_Clone(SHA224Context *dest, SHA224Context *src)
 {
   if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
       return;
   (vector->p_SHA224_Clone)(dest, src);
 }
 
 PRBool
-BLAPI_SHVerifyFile(const char *name)
+BLAPI_SHVerifyFile(const char *name, int *err)
 {
   if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
       return PR_FALSE;
-  return vector->p_BLAPI_SHVerifyFile(name);
+  return vector->p_BLAPI_SHVerifyFile(name, err);
 }
 
 /* === new for DSA-2 === */
 SECStatus
 PQG_ParamGenV2( unsigned int L, unsigned int N, unsigned int seedBytes, 
                PQGParams **pParams, PQGVerify **pVfy)
 {
   if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
diff --git a/lib/freebl/loader.h b/lib/freebl/loader.h
--- a/lib/freebl/loader.h
+++ b/lib/freebl/loader.h
@@ -294,18 +294,18 @@ struct FREEBLVectorStr {
 
  SECStatus (* p_AESKeyWrap_Decrypt)(AESKeyWrapContext *cx, 
             unsigned char *output,
             unsigned int *outputLen, unsigned int maxOutputLen,
             const unsigned char *input, unsigned int inputLen);
 
   /* Version 3.004 came to here */
 
- PRBool (*p_BLAPI_SHVerify)(const char *name, PRFuncPtr addr);
- PRBool (*p_BLAPI_VerifySelf)(const char *name);
+ PRBool (*p_BLAPI_SHVerify)(const char *name, PRFuncPtr addr, int *err);
+ PRBool (*p_BLAPI_VerifySelf)(const char *name, int *err);
 
   /* Version 3.005 came to here */
 
  SECStatus (* p_EC_NewKey)(ECParams *           params, 
                            ECPrivateKey **	privKey);
 
  SECStatus (* p_EC_NewKeyFromSeed)(ECParams *   params, 
                              ECPrivateKey **	privKey,
@@ -553,17 +553,17 @@ struct FREEBLVectorStr {
  SECStatus (*p_SHA224_HashBuf)(unsigned char *dest, const unsigned char *src,
 			       PRUint32 src_length);
  SECStatus (*p_SHA224_Hash)(unsigned char *dest, const char *src);
  void (*p_SHA224_TraceState)(SHA224Context *cx);
  unsigned int (* p_SHA224_FlattenSize)(SHA224Context *cx);
  SECStatus (* p_SHA224_Flatten)(SHA224Context *cx,unsigned char *space);
  SHA224Context * (* p_SHA224_Resurrect)(unsigned char *space, void *arg);
  void (* p_SHA224_Clone)(SHA224Context *dest, SHA224Context *src);
- PRBool (*p_BLAPI_SHVerifyFile)(const char *name);
+ PRBool (*p_BLAPI_SHVerifyFile)(const char *name, int *err);
 
   /* Version 3.013 came to here */
 
  SECStatus (* p_PQG_ParamGenV2)( unsigned int L, unsigned int N,
                                 unsigned int seedBytes, 
                                 PQGParams **pParams, PQGVerify **pVfy); 
  SECStatus (*p_PRNGTEST_RunHealthTests)(void);
 
diff --git a/lib/freebl/manifest.mn b/lib/freebl/manifest.mn
--- a/lib/freebl/manifest.mn
+++ b/lib/freebl/manifest.mn
@@ -57,16 +57,17 @@ PRIVATE_EXPORTS = \
 	alghmac.h \
 	blapi.h \
 	hmacct.h \
 	secmpi.h \
 	secrng.h \
 	ec.h \
 	ecl.h \
 	ecl-curve.h \
+	fips.h \
 	$(NULL)
 
 MPI_HDRS = mpi-config.h mpi.h mpi-priv.h mplogic.h mpprime.h logtab.h mp_gf2m.h
 MPI_SRCS = mpprime.c mpmontg.c mplogic.c mpi.c mp_gf2m.c
 
 
 ECL_HDRS = ecl-exp.h ecl.h ec2.h ecp.h ecl-priv.h
 ifndef NSS_DISABLE_ECC
@@ -120,16 +121,17 @@ CSRCS = \
 	seed.c \
 	jpake.c \
 	$(MPI_SRCS) \
 	$(MPCPU_SRCS) \
 	$(ECL_SRCS) \
 	$(STUBS_SRCS) \
 	$(LOWHASH_SRCS) \
 	$(EXTRA_SRCS) \
+	fips.c \
 	$(NULL)
 
 ALL_CSRCS := $(CSRCS)
 
 ALL_HDRS =  \
 	alghmac.h \
 	blapi.h \
 	blapit.h \
@@ -139,16 +141,17 @@ ALL_HDRS =  \
 	rijndael.h \
 	camellia.h \
 	secmpi.h \
 	sha_fast.h \
 	sha256.h \
 	shsign.h \
 	vis_proto.h \
 	seed.h \
+	fips.h \
 	$(NULL)
 
 
 ifdef AES_GEN_TBL
 DEFINES += -DRIJNDAEL_GENERATE_TABLES
 else 
 ifdef AES_GEN_TBL_M
 DEFINES += -DRIJNDAEL_GENERATE_TABLES_MACRO
diff --git a/lib/freebl/nsslowhash.c b/lib/freebl/nsslowhash.c
--- a/lib/freebl/nsslowhash.c
+++ b/lib/freebl/nsslowhash.c
@@ -8,343 +8,75 @@
 #include "prtypes.h"
 #include "secerr.h"
 #include "pkcs11t.h"
 #include "blapi.h"
 #include "hasht.h"
 #include "plhash.h"
 #include "nsslowhash.h"
 
-/* FIPS preprocessor directives for message digests             */
-#define FIPS_KNOWN_HASH_MESSAGE_LENGTH          64  /* 512-bits */
-
-/* Known Hash Message (512-bits).  Used for all hashes (incl. SHA-N [N>1]). */
-static const PRUint8 known_hash_message[] = {
-  "The test message for the MD2, MD5, and SHA-1 hashing algorithms." };
-
-static CK_RV
-freebl_fips_MD2_PowerUpSelfTest( void )
-{
-    /* MD2 Known Digest Message (128-bits). */
-    static const PRUint8 md2_known_digest[]  = {
-                                   0x41,0x5a,0x12,0xb2,0x3f,0x28,0x97,0x17,
-                                   0x0c,0x71,0x4e,0xcc,0x40,0xc8,0x1d,0x1b};
-
-    /* MD2 variables. */
-    MD2Context * md2_context;
-    unsigned int md2_bytes_hashed;
-    PRUint8      md2_computed_digest[MD2_LENGTH];
-
-
-    /***********************************************/
-    /* MD2 Single-Round Known Answer Hashing Test. */
-    /***********************************************/
-
-    md2_context = MD2_NewContext();
-
-    if( md2_context == NULL )
-        return( CKR_HOST_MEMORY );
-
-    MD2_Begin( md2_context );
-
-    MD2_Update( md2_context, known_hash_message,
-                FIPS_KNOWN_HASH_MESSAGE_LENGTH );
-
-    MD2_End( md2_context, md2_computed_digest, &md2_bytes_hashed, MD2_LENGTH );
-
-    MD2_DestroyContext( md2_context , PR_TRUE );
-    
-    if( ( md2_bytes_hashed != MD2_LENGTH ) ||
-        ( PORT_Memcmp( md2_computed_digest, md2_known_digest,
-                       MD2_LENGTH ) != 0 ) )
-        return( CKR_DEVICE_ERROR );
-
-    return( CKR_OK );
-}
-
-
-
-static CK_RV
-freebl_fips_MD5_PowerUpSelfTest( void )
-{
-    /* MD5 Known Digest Message (128-bits). */
-    static const PRUint8 md5_known_digest[]  = {
-				   0x25,0xc8,0xc0,0x10,0xc5,0x6e,0x68,0x28,
-				   0x28,0xa4,0xa5,0xd2,0x98,0x9a,0xea,0x2d};
-
-    /* MD5 variables. */
-    PRUint8        md5_computed_digest[MD5_LENGTH];
-    SECStatus      md5_status;
-
-
-    /***********************************************/
-    /* MD5 Single-Round Known Answer Hashing Test. */
-    /***********************************************/
-
-    md5_status = MD5_HashBuf( md5_computed_digest, known_hash_message,
-                              FIPS_KNOWN_HASH_MESSAGE_LENGTH );
-
-    if( ( md5_status != SECSuccess ) ||
-        ( PORT_Memcmp( md5_computed_digest, md5_known_digest,
-                       MD5_LENGTH ) != 0 ) )
-        return( CKR_DEVICE_ERROR );
-
-    return( CKR_OK );
-}
-
-static CK_RV
-freebl_fips_SHA_PowerUpSelfTest( void )
-{
-    /* SHA-1 Known Digest Message (160-bits). */
-    static const PRUint8 sha1_known_digest[] = {
-			       0x0a,0x6d,0x07,0xba,0x1e,0xbd,0x8a,0x1b,
-			       0x72,0xf6,0xc7,0x22,0xf1,0x27,0x9f,0xf0,
-			       0xe0,0x68,0x47,0x7a};
-
-    /* SHA-224 Known Digest Message (224-bits). */
-    static const PRUint8 sha224_known_digest[] = {
-        0x89,0x5e,0x7f,0xfd,0x0e,0xd8,0x35,0x6f,
-        0x64,0x6d,0xf2,0xde,0x5e,0xed,0xa6,0x7f,
-        0x29,0xd1,0x12,0x73,0x42,0x84,0x95,0x4f,
-        0x8e,0x08,0xe5,0xcb};
-
-    /* SHA-256 Known Digest Message (256-bits). */
-    static const PRUint8 sha256_known_digest[] = {
-        0x38,0xa9,0xc1,0xf0,0x35,0xf6,0x5d,0x61,
-        0x11,0xd4,0x0b,0xdc,0xce,0x35,0x14,0x8d,
-        0xf2,0xdd,0xaf,0xaf,0xcf,0xb7,0x87,0xe9,
-        0x96,0xa5,0xd2,0x83,0x62,0x46,0x56,0x79};
- 
-    /* SHA-384 Known Digest Message (384-bits). */
-    static const PRUint8 sha384_known_digest[] = {
-        0x11,0xfe,0x1c,0x00,0x89,0x48,0xde,0xb3,
-        0x99,0xee,0x1c,0x18,0xb4,0x10,0xfb,0xfe,
-        0xe3,0xa8,0x2c,0xf3,0x04,0xb0,0x2f,0xc8,
-        0xa3,0xc4,0x5e,0xea,0x7e,0x60,0x48,0x7b,
-        0xce,0x2c,0x62,0xf7,0xbc,0xa7,0xe8,0xa3,
-        0xcf,0x24,0xce,0x9c,0xe2,0x8b,0x09,0x72};
-
-    /* SHA-512 Known Digest Message (512-bits). */
-    static const PRUint8 sha512_known_digest[] = {
-        0xc8,0xb3,0x27,0xf9,0x0b,0x24,0xc8,0xbf,
-        0x4c,0xba,0x33,0x54,0xf2,0x31,0xbf,0xdb,
-        0xab,0xfd,0xb3,0x15,0xd7,0xfa,0x48,0x99,
-        0x07,0x60,0x0f,0x57,0x41,0x1a,0xdd,0x28,
-        0x12,0x55,0x25,0xac,0xba,0x3a,0x99,0x12,
-        0x2c,0x7a,0x8f,0x75,0x3a,0xe1,0x06,0x6f,
-        0x30,0x31,0xc9,0x33,0xc6,0x1b,0x90,0x1a,
-        0x6c,0x98,0x9a,0x87,0xd0,0xb2,0xf8,0x07};
-
-    /* SHA-X variables. */
-    PRUint8        sha_computed_digest[HASH_LENGTH_MAX];
-    SECStatus      sha_status;
-
-    /*************************************************/
-    /* SHA-1 Single-Round Known Answer Hashing Test. */
-    /*************************************************/
-
-    sha_status = SHA1_HashBuf( sha_computed_digest, known_hash_message,
-                                FIPS_KNOWN_HASH_MESSAGE_LENGTH );
- 
-    if( ( sha_status != SECSuccess ) ||
-        ( PORT_Memcmp( sha_computed_digest, sha1_known_digest,
-                       SHA1_LENGTH ) != 0 ) )
-        return( CKR_DEVICE_ERROR );
-
-    /***************************************************/
-    /* SHA-224 Single-Round Known Answer Hashing Test. */
-    /***************************************************/
-
-    sha_status = SHA224_HashBuf( sha_computed_digest, known_hash_message,
-                                FIPS_KNOWN_HASH_MESSAGE_LENGTH );
-
-    if( ( sha_status != SECSuccess ) ||
-        ( PORT_Memcmp( sha_computed_digest, sha224_known_digest,
-                       SHA224_LENGTH ) != 0 ) )
-        return( CKR_DEVICE_ERROR );
-
-    /***************************************************/
-    /* SHA-256 Single-Round Known Answer Hashing Test. */
-    /***************************************************/
-
-    sha_status = SHA256_HashBuf( sha_computed_digest, known_hash_message,
-                                FIPS_KNOWN_HASH_MESSAGE_LENGTH );
-
-    if( ( sha_status != SECSuccess ) ||
-        ( PORT_Memcmp( sha_computed_digest, sha256_known_digest,
-                       SHA256_LENGTH ) != 0 ) )
-        return( CKR_DEVICE_ERROR );
-
-    /***************************************************/
-    /* SHA-384 Single-Round Known Answer Hashing Test. */
-    /***************************************************/
-
-    sha_status = SHA384_HashBuf( sha_computed_digest, known_hash_message,
-                                FIPS_KNOWN_HASH_MESSAGE_LENGTH );
-
-    if( ( sha_status != SECSuccess ) ||
-        ( PORT_Memcmp( sha_computed_digest, sha384_known_digest,
-                       SHA384_LENGTH ) != 0 ) )
-        return( CKR_DEVICE_ERROR );
-
-    /***************************************************/
-    /* SHA-512 Single-Round Known Answer Hashing Test. */
-    /***************************************************/
-
-    sha_status = SHA512_HashBuf( sha_computed_digest, known_hash_message,
-                                FIPS_KNOWN_HASH_MESSAGE_LENGTH );
-
-    if( ( sha_status != SECSuccess ) ||
-        ( PORT_Memcmp( sha_computed_digest, sha512_known_digest,
-                       SHA512_LENGTH ) != 0 ) )
-        return( CKR_DEVICE_ERROR );
-
-    return( CKR_OK );
-}
-
-
-static CK_RV
-freebl_fipsSoftwareIntegrityTest(void)
-{
-    CK_RV crv = CKR_OK;
-
-    /* make sure that our check file signatures are OK */
-    if (!BLAPI_VerifySelf(SHLIB_PREFIX"freebl"SHLIB_VERSION"."SHLIB_SUFFIX)) {
-	crv = CKR_DEVICE_ERROR; /* better error code? checksum error? */
-    }
-    return crv;
-}
-
+/* FIPS selftests are implemented in library constructors and abort on failure
+ * - if anybody gets to call this function it means the tests passed and this
+ * can be a successful no-op; the integrity selftest that used to be here is
+ * handled by the freebl constructor as well
+ */
 CK_RV
 freebl_fipsPowerUpSelfTest( void )
 {
-    CK_RV rv;
-
-    /* MD2 Power-Up SelfTest(s). */
-    rv = freebl_fips_MD2_PowerUpSelfTest();
-
-    if( rv != CKR_OK )
-        return rv;
-
-    /* MD5 Power-Up SelfTest(s). */
-    rv = freebl_fips_MD5_PowerUpSelfTest();
-
-    if( rv != CKR_OK )
-        return rv;
-
-    /* SHA-X Power-Up SelfTest(s). */
-    rv = freebl_fips_SHA_PowerUpSelfTest();
-
-    if( rv != CKR_OK )
-        return rv;
-
-    /* Software/Firmware Integrity Test. */
-    rv = freebl_fipsSoftwareIntegrityTest();
-
-    if( rv != CKR_OK )
-        return rv;
-
-    /* Passed Power-Up SelfTest(s). */
     return( CKR_OK );
 }
 
 struct NSSLOWInitContextStr {
    int count;
 };
 
 struct NSSLOWHASHContextStr {
     const SECHashObject *hashObj;
     void *hashCtxt;
    
 };
 
-static int nsslow_GetFIPSEnabled(void) {
-#ifdef LINUX
-    FILE *f;
-    char d;
-    size_t size;
-
-    f = fopen("/proc/sys/crypto/fips_enabled", "r");
-    if (!f)
-        return 0;
-
-    size = fread(&d, 1, 1, f);
-    fclose(f);
-    if (size != 1)
-        return 0;
-    if (d != '1')
-        return 0;
-#endif
-    return 1;
-}
-
-
-static int post = 0;
-static int post_failed = 0;
-
 static NSSLOWInitContext dummyContext = { 0 };
 
 NSSLOWInitContext *
 NSSLOW_Init(void)
 {
     SECStatus rv;
     CK_RV crv;
 #ifdef FREEBL_NO_DEPEND
     PRBool nsprAvailable = PR_FALSE;
 
 
     rv = FREEBL_InitStubs();
     nsprAvailable = (rv ==  SECSuccess ) ? PR_TRUE : PR_FALSE;
 #endif
 
-    if (post_failed) {
-	return NULL;
-    }
-	
-
-    if (!post && nsslow_GetFIPSEnabled()) {
-	crv = freebl_fipsPowerUpSelfTest();
-	if (crv != CKR_OK) {
-	    post_failed = 1;
-	    return NULL;
-	}
-    }
-    post = 1;
-
-    
     return &dummyContext;
 }
 
 void
 NSSLOW_Shutdown(NSSLOWInitContext *context)
 {
    PORT_Assert(context == &dummyContext);
    return;
 }
 
 void
 NSSLOW_Reset(NSSLOWInitContext *context)
 {
    PORT_Assert(context == &dummyContext);
-   post_failed = 0;
-   post = 0;
    return;
 }
 
 NSSLOWHASHContext *
 NSSLOWHASH_NewContext(NSSLOWInitContext *initContext, 
 			HASH_HashType hashType)
 {
    NSSLOWHASHContext *context;
 
-   if (post_failed) {
-	PORT_SetError(SEC_ERROR_PKCS11_DEVICE_ERROR);
-	return NULL;
-   }
-
    if (initContext != &dummyContext) {
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	return (NULL);
    }
 
    context = PORT_ZNew(NSSLOWHASHContext);
    if (!context) {
 	return NULL;
diff --git a/lib/freebl/shvfy.c b/lib/freebl/shvfy.c
--- a/lib/freebl/shvfy.c
+++ b/lib/freebl/shvfy.c
@@ -269,37 +269,37 @@ readItem(PRFileDesc *fd, SECItem *item)
 	item->data = NULL;
 	item->len = 0;
 	return SECFailure;
     }
     return SECSuccess;
 }
 
 PRBool
-BLAPI_SHVerify(const char *name, PRFuncPtr addr)
+BLAPI_SHVerify(const char *name, PRFuncPtr addr, int *err)
 {
     PRBool result = PR_FALSE; /* if anything goes wrong,
 			       * the signature does not verify */
     /* find our shared library name */
     char *shName = PR_GetLibraryFilePathname(name, addr);
     if (!shName) {
 	goto loser;
     }
-    result = BLAPI_SHVerifyFile(shName);
+    result = BLAPI_SHVerifyFile(shName, err);
 
 loser:
     if (shName != NULL) {
 	PR_Free(shName);
     }
 
     return result;
 }
 
 PRBool
-BLAPI_SHVerifyFile(const char *shName)
+BLAPI_SHVerifyFile(const char *shName, int *err)
 {
     char *checkName = NULL;
     PRFileDesc *checkFD = NULL;
     PRFileDesc *shFD = NULL;
     void  *hashcx = NULL;
     const SECHashObject *hashObj = NULL;
     SECItem signature = { 0, NULL, 0 };
     SECItem hash;
@@ -332,16 +332,19 @@ BLAPI_SHVerifyFile(const char *shName)
 
     /* open the check File */
     checkFD = PR_Open(checkName, PR_RDONLY, 0);
     if (checkFD == NULL) {
 #ifdef DEBUG_SHVERIFY
         fprintf(stderr, "Failed to open the check file %s: (%d, %d)\n",
                 checkName, (int)PR_GetError(), (int)PR_GetOSError());
 #endif /* DEBUG_SHVERIFY */
+        if (err) {
+            *err = PORT_GetError();
+        }
 	goto loser;
     }
 
     /* read and Verify the headerthe header */
     bytesRead = PR_Read(checkFD, buf, 12);
     if (bytesRead != 12) {
 	goto loser;
     }
@@ -490,19 +493,19 @@ loser:
     if (key.publicValue.data != NULL) {
 	PORT_Free(key.publicValue.data);
     }
 
     return result;
 }
 
 PRBool
-BLAPI_VerifySelf(const char *name)
+BLAPI_VerifySelf(const char *name,  int *err)
 {
     if (name == NULL) {
 	/*
 	 * If name is NULL, freebl is statically linked into softoken.
 	 * softoken will call BLAPI_SHVerify next to verify itself.
 	 */
 	return PR_TRUE;
     }
-    return BLAPI_SHVerify(name, (PRFuncPtr) decodeInt);
+    return BLAPI_SHVerify(name, (PRFuncPtr) decodeInt, err);
 }
diff --git a/lib/softoken/fips.c b/lib/softoken/fips.c
new file mode 100644
--- /dev/null
+++ b/lib/softoken/fips.c
@@ -0,0 +1,26 @@
+#include "../freebl/fips-selftest.inc"
+
+#include "fips.h"
+
+#include "softoken.h"
+
+/* crypto algorithms selftest wrapper */
+static fips_check_status
+fips_checkCryptoSoftoken(void)
+{
+    if (CKR_OK == FIPS_cryptoSelftestSoftoken()) {
+	return CHECK_OK;
+    } else {
+	return CHECK_FAIL_CRYPTO;
+    }
+}
+
+/* constructor - load-time selfchecks */
+static void __attribute__ ((constructor))
+fips_initTestSoftoken(void)
+{
+    fips_state = fips_initTest("softokn", (PRFuncPtr)fips_initTestSoftoken, fips_checkCryptoSoftoken);
+
+    return;
+}
+
diff --git a/lib/softoken/fips.h b/lib/softoken/fips.h
new file mode 100644
--- /dev/null
+++ b/lib/softoken/fips.h
@@ -0,0 +1,10 @@
+#ifndef FIPS_H
+#define FIPS_H
+
+#include "softoken.h"
+
+CK_RV FIPS_cryptoSelftestSoftoken(void);
+CK_RV sftk_fipsPowerUpSelfTest(void);
+
+#endif
+
diff --git a/lib/softoken/fipstest.c b/lib/softoken/fipstest.c
--- a/lib/softoken/fipstest.c
+++ b/lib/softoken/fipstest.c
@@ -77,16 +77,22 @@
 #define FIPS_DSA_SUBPRIME_LENGTH                20 /*  160-bits */
 #define FIPS_DSA_SIGNATURE_LENGTH               40 /*  320-bits */
 #define FIPS_DSA_PRIME_LENGTH                  128 /* 1024-bits */
 #define FIPS_DSA_BASE_LENGTH                   128 /* 1024-bits */
 
 /* FIPS preprocessor directives for RNG.                        */
 #define FIPS_RNG_XKEY_LENGTH                    32  /* 256-bits */
 
+/* Do not test algorithms not approved for use in FIPS 140-2 - it adds
+ * unnecessary time and code overhead for no noticable gain.
+ * Build with -DRUN_ALL_SELFTESTS to compile the tests in
+ */
+
+#ifdef RUN_ALL_SELFTESTS
 static CK_RV
 sftk_fips_RC2_PowerUpSelfTest( void )
 {
     /* RC2 Known Key (40-bits). */
     static const PRUint8 rc2_known_key[] = { "RSARC" };
 
     /* RC2-CBC Known Initialization Vector (64-bits). */
     static const PRUint8 rc2_cbc_known_initialization_vector[] = {"Security"};
@@ -402,16 +408,17 @@ sftk_fips_DES_PowerUpSelfTest( void )
     if( ( des_status != SECSuccess ) ||
         ( des_bytes_decrypted != FIPS_DES_DECRYPT_LENGTH ) ||
         ( PORT_Memcmp( des_computed_plaintext, des_cbc_known_plaintext,
                        FIPS_DES_DECRYPT_LENGTH ) != 0 ) )
         return( CKR_DEVICE_ERROR );
 
     return( CKR_OK );
 }
+#endif
 
 
 static CK_RV
 sftk_fips_DES3_PowerUpSelfTest( void )
 {
     /* DES3 Known Key (56-bits). */
     static const PRUint8 des3_known_key[] = { "ANSI Triple-DES Key Data" };
 
@@ -1985,34 +1992,40 @@ sftk_fips_RNG_PowerUpSelfTest( void )
    if( ( rng_status != SECSuccess ) ||
        ( PORT_Memcmp( DSAX, rng_known_DSAX,
                       (FIPS_DSA_SUBPRIME_LENGTH) ) != 0 ) )
        return( CKR_DEVICE_ERROR );
        
    return( CKR_OK ); 
 }
 
-static CK_RV
-sftk_fipsSoftwareIntegrityTest(void)
+/* FIPS selftests are implemented in library constructors and abort on failure
+ * - if anybody gets to call this function it means the tests passed and this
+ *   can be a successful no-op
+ */
+CK_RV
+sftk_fipsPowerUpSelfTest( void )
 {
-    CK_RV crv = CKR_OK;
-
-    /* make sure that our check file signatures are OK */
-    if( !BLAPI_VerifySelf( NULL ) || 
-	!BLAPI_SHVerify( SOFTOKEN_LIB_NAME, (PRFuncPtr) sftk_fips_HMAC ) ) {
-	crv = CKR_DEVICE_ERROR; /* better error code? checksum error? */
-    }
-    return crv;
+    return CKR_OK;
 }
 
 CK_RV
-sftk_fipsPowerUpSelfTest( void )
+FIPS_cryptoSelftestSoftoken( void )
 {
     CK_RV rv;
 
+    /* intialise BL */
+    if( SECSuccess != BL_Init() )
+        return CKR_GENERAL_ERROR;
+
+    /* intialise RNG (needed for RSA blinging parameters */
+    if( SECSuccess != RNG_RNGInit() )
+        return CKR_GENERAL_ERROR;
+
+#ifdef RUN_ALL_SELFTESTS
     /* RC2 Power-Up SelfTest(s). */
     rv = sftk_fips_RC2_PowerUpSelfTest();
 
     if( rv != CKR_OK )
         return rv;
 
     /* RC4 Power-Up SelfTest(s). */
     rv = sftk_fips_RC4_PowerUpSelfTest();
@@ -2020,16 +2033,17 @@ sftk_fipsPowerUpSelfTest( void )
     if( rv != CKR_OK )
         return rv;
 
     /* DES Power-Up SelfTest(s). */
     rv = sftk_fips_DES_PowerUpSelfTest();
 
     if( rv != CKR_OK )
         return rv;
+#endif
 
     /* DES3 Power-Up SelfTest(s). */
     rv = sftk_fips_DES3_PowerUpSelfTest();
 
     if( rv != CKR_OK )
         return rv;
  
     /* AES Power-Up SelfTest(s) for 128-bit key. */
@@ -2045,27 +2059,29 @@ sftk_fipsPowerUpSelfTest( void )
         return rv;
 
     /* AES Power-Up SelfTest(s) for 256-bit key. */
     rv = sftk_fips_AES_PowerUpSelfTest(FIPS_AES_256_KEY_SIZE);
 
     if( rv != CKR_OK )
         return rv;
 
+#ifdef RUN_ALL_SELFTESTS
     /* MD2 Power-Up SelfTest(s). */
     rv = sftk_fips_MD2_PowerUpSelfTest();
 
     if( rv != CKR_OK )
         return rv;
 
     /* MD5 Power-Up SelfTest(s). */
     rv = sftk_fips_MD5_PowerUpSelfTest();
 
     if( rv != CKR_OK )
         return rv;
+#endif
 
     /* SHA-X Power-Up SelfTest(s). */
     rv = sftk_fips_SHA_PowerUpSelfTest();
 
     if( rv != CKR_OK )
         return rv;
 
     /* HMAC SHA-X Power-Up SelfTest(s). */
@@ -2095,18 +2111,12 @@ sftk_fipsPowerUpSelfTest( void )
 #ifndef NSS_DISABLE_ECC
     /* ECDSA Power-Up SelfTest(s). */
     rv = sftk_fips_ECDSA_PowerUpSelfTest();
 
     if( rv != CKR_OK )
         return rv;
 #endif
 
-    /* Software/Firmware Integrity Test. */
-    rv = sftk_fipsSoftwareIntegrityTest();
-
-    if( rv != CKR_OK )
-        return rv;
-
     /* Passed Power-Up SelfTest(s). */
     return( CKR_OK );
 }
 
diff --git a/lib/softoken/fipstokn.c b/lib/softoken/fipstokn.c
--- a/lib/softoken/fipstokn.c
+++ b/lib/softoken/fipstokn.c
@@ -445,30 +445,19 @@ CK_RV FC_Initialize(CK_VOID_PTR pReserve
     /* not an 'else' rv can be set by either SFTK_LowInit or SFTK_SlotInit*/
     if (crv != CKR_OK) {
 	sftk_fatalError = PR_TRUE;
 	return crv;
     }
 
     sftk_fatalError = PR_FALSE; /* any error has been reset */
 
-    crv = sftk_fipsPowerUpSelfTest();
-    if (crv != CKR_OK) {
-        nsc_CommonFinalize(NULL, PR_TRUE);
-	sftk_fatalError = PR_TRUE;
-	if (sftk_audit_enabled) {
-	    char msg[128];
-	    PR_snprintf(msg,sizeof msg,
-			"C_Initialize()=0x%08lX "
-			"power-up self-tests failed",
-			(PRUint32)crv);
-	    sftk_LogAuditMessage(NSS_AUDIT_ERROR, NSS_AUDIT_SELF_TEST, msg);
-	}
-	return crv;
-    }
+    /* FIPS selftests that were here have been moved to constructors
+     * (freebl, softoken and dbm) as to be executed at library load time */
+
     nsf_init = PR_TRUE;
 
     return CKR_OK;
 }
 
 /*FC_Finalize indicates that an application is done with the PKCS #11 library.*/
 CK_RV FC_Finalize (CK_VOID_PTR pReserved) {
    CK_RV crv;
diff --git a/lib/softoken/legacydb/fips.c b/lib/softoken/legacydb/fips.c
new file mode 100644
--- /dev/null
+++ b/lib/softoken/legacydb/fips.c
@@ -0,0 +1,25 @@
+#include "../../freebl/fips-selftest.inc"
+
+#include "fips.h"
+
+/*** private per-module symbols ***/
+
+/* crypto algorithms selftest wrapper */
+static fips_check_status
+fips_checkCryptoDbm(void)
+{
+    /* no checks in dbm */
+    return CHECK_OK;
+}
+
+/* constructor - load-time selfchecks */
+static void __attribute__ ((constructor))
+fips_initTestDbm(void)
+{
+    fips_state = fips_initTest("nssdbm", (PRFuncPtr)fips_checkCryptoDbm, NULL);
+
+    return;
+}
+
+/*** public per-module symbols ***/
+
diff --git a/lib/softoken/legacydb/fips.h b/lib/softoken/legacydb/fips.h
new file mode 100644
--- /dev/null
+++ b/lib/softoken/legacydb/fips.h
@@ -0,0 +1,5 @@
+#ifndef FIPS_H
+#define FIPS_H
+
+#endif
+
diff --git a/lib/softoken/legacydb/manifest.mn b/lib/softoken/legacydb/manifest.mn
--- a/lib/softoken/legacydb/manifest.mn
+++ b/lib/softoken/legacydb/manifest.mn
@@ -2,16 +2,17 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 CORE_DEPTH = ../../..
 
 MODULE = nss
 
 REQUIRES = dbm 
+DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\" -DSHLIB_VERSION=\"$(LIBRARY_VERSION)\"
 
 LIBRARY_NAME = nssdbm
 LIBRARY_VERSION = 3
 MAPFILE = $(OBJDIR)/nssdbm.def
 
 DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\"
 
 CSRCS = \
@@ -22,10 +23,11 @@ CSRCS = \
 	lgdestroy.c \
 	lgfind.c \
 	lginit.c \
 	lgutil.c \
 	lowcert.c \
 	lowkey.c \
 	pcertdb.c \
 	pk11db.c \
+	fips.c \
 	$(NULL)
 
diff --git a/lib/softoken/lgglue.c b/lib/softoken/lgglue.c
--- a/lib/softoken/lgglue.c
+++ b/lib/softoken/lgglue.c
@@ -256,17 +256,17 @@ sftkdbLoad_Legacy(PRBool isFIPS)
     LGSetCryptFunc setCryptFunction = NULL;
 
     if (legacy_glue_lib) {
 	/* this check is necessary because it's possible we loaded the
 	 * legacydb to read secmod.db, which told us whether we were in
 	 * FIPS mode or not. */
 	if (isFIPS && !legacy_glue_libCheckSucceeded) {
 	    if (legacy_glue_libCheckFailed || 
-		!BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) {
+		!BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open, NULL)) {
     	    	legacy_glue_libCheckFailed = PR_TRUE;
 		/* don't clobber legacy glue to avoid race. just let it
 		 * get cleared in shutdown */
 		return SECFailure;
 	    }
     	    legacy_glue_libCheckSucceeded = PR_TRUE;
 	} 
 	return SECSuccess;
@@ -295,17 +295,17 @@ sftkdbLoad_Legacy(PRBool isFIPS)
 	    !legacy_glue_releaseSecmod || !legacy_glue_deleteSecmod || 
 	    !legacy_glue_addSecmod || !setCryptFunction) {
 	PR_UnloadLibrary(lib);
 	return SECFailure;
     }
 
     /* verify the loaded library if we are in FIPS mode */
     if (isFIPS) {
-	if (!BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) {
+	if (!BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open, NULL)) {
 	    PR_UnloadLibrary(lib);
 	    return SECFailure;
 	}
     	legacy_glue_libCheckSucceeded = PR_TRUE;
     } 
 
     setCryptFunction(sftkdb_encrypt_stub,sftkdb_decrypt_stub);
     legacy_glue_lib = lib;
diff --git a/lib/softoken/manifest.mn b/lib/softoken/manifest.mn
--- a/lib/softoken/manifest.mn
+++ b/lib/softoken/manifest.mn
@@ -25,16 +25,17 @@ PRIVATE_EXPORTS = \
 	lowkeyi.h \
 	lowkeyti.h \
 	pkcs11ni.h \
 	softoken.h \
 	softoknt.h \
 	softkver.h \
 	sdb.h \
 	sftkdbt.h \
+	fips.h \
 	$(NULL)
 
 CSRCS = \
 	fipsaudt.c \
 	fipstest.c \
 	fipstokn.c \
 	lgglue.c   \
 	lowkey.c   \
@@ -46,16 +47,17 @@ CSRCS = \
 	sdb.c  \
 	sftkdb.c  \
 	sftkhmac.c  \
 	sftkpars.c  \
 	sftkpwd.c  \
 	softkver.c  \
 	tlsprf.c   \
 	jpakesftk.c \
+	fips.c \
 	$(NULL)
 
 ifdef SQLITE_UNSAFE_THREADS
 DEFINES += -DSQLITE_UNSAFE_THREADS
 endif
 
 # This part of the code, including all sub-dirs, can be optimized for size
 export ALLOW_OPT_CODE_SIZE = 1
