Blame SOURCES/nss-3.71-fips-module-name.patch

10b7fa
diff --git a/cmd/manifest.mn b/cmd/manifest.mn
10b7fa
--- a/cmd/manifest.mn
10b7fa
+++ b/cmd/manifest.mn
10b7fa
@@ -76,6 +76,7 @@
10b7fa
  symkeyutil \
10b7fa
  tests \
10b7fa
  tstclnt  \
10b7fa
+ validation  \
10b7fa
  vfychain \
10b7fa
  vfyserv \
10b7fa
  modutil \
10b7fa
diff --git a/cmd/validation/Makefile b/cmd/validation/Makefile
10b7fa
new file mode 100644
10b7fa
--- /dev/null
10b7fa
+++ b/cmd/validation/Makefile
10b7fa
@@ -0,0 +1,48 @@
10b7fa
+#! gmake
10b7fa
+#
10b7fa
+# This Source Code Form is subject to the terms of the Mozilla Public
10b7fa
+# License, v. 2.0. If a copy of the MPL was not distributed with this
10b7fa
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
10b7fa
+
10b7fa
+#######################################################################
10b7fa
+# (1) Include initial platform-independent assignments (MANDATORY).   #
10b7fa
+#######################################################################
10b7fa
+
10b7fa
+include manifest.mn
10b7fa
+
10b7fa
+#######################################################################
10b7fa
+# (2) Include "global" configuration information. (OPTIONAL)          #
10b7fa
+#######################################################################
10b7fa
+
10b7fa
+include $(CORE_DEPTH)/coreconf/config.mk
10b7fa
+
10b7fa
+#######################################################################
10b7fa
+# (3) Include "component" configuration information. (OPTIONAL)       #
10b7fa
+#######################################################################
10b7fa
+
10b7fa
+#######################################################################
10b7fa
+# (4) Include "local" platform-dependent assignments (OPTIONAL).      #
10b7fa
+#######################################################################
10b7fa
+
10b7fa
+include ../platlibs.mk
10b7fa
+
10b7fa
+
10b7fa
+#######################################################################
10b7fa
+# (5) Execute "global" rules. (OPTIONAL)                              #
10b7fa
+#######################################################################
10b7fa
+
10b7fa
+include $(CORE_DEPTH)/coreconf/rules.mk
10b7fa
+
10b7fa
+#######################################################################
10b7fa
+# (6) Execute "component" rules. (OPTIONAL)                           #
10b7fa
+#######################################################################
10b7fa
+
10b7fa
+
10b7fa
+
10b7fa
+#######################################################################
10b7fa
+# (7) Execute "local" rules. (OPTIONAL).                              #
10b7fa
+#######################################################################
10b7fa
+
10b7fa
+
10b7fa
+include ../platrules.mk
10b7fa
+
10b7fa
diff --git a/cmd/validation/manifest.mn b/cmd/validation/manifest.mn
10b7fa
new file mode 100644
10b7fa
--- /dev/null
10b7fa
+++ b/cmd/validation/manifest.mn
10b7fa
@@ -0,0 +1,23 @@
10b7fa
+#
10b7fa
+# This Source Code Form is subject to the terms of the Mozilla Public
10b7fa
+# License, v. 2.0. If a copy of the MPL was not distributed with this
10b7fa
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
10b7fa
+
10b7fa
+CORE_DEPTH = ../..
10b7fa
+
10b7fa
+DEFINES += -DNSPR20
10b7fa
+
10b7fa
+# MODULE public and private header  directories are implicitly REQUIRED.
10b7fa
+MODULE = nss
10b7fa
+
10b7fa
+CSRCS = \
10b7fa
+	validation.c \
10b7fa
+	$(NULL)
10b7fa
+
10b7fa
+# The MODULE is always implicitly required.
10b7fa
+# Listing it here in REQUIRES makes it appear twice in the cc command line.
10b7fa
+REQUIRES = dbm seccmd
10b7fa
+
10b7fa
+PROGRAM = validation
10b7fa
+
10b7fa
+# USE_STATIC_LIBS = 1
10b7fa
diff --git a/cmd/validation/validation.c b/cmd/validation/validation.c
10b7fa
new file mode 100644
10b7fa
--- /dev/null
10b7fa
+++ b/cmd/validation/validation.c
10b7fa
@@ -0,0 +1,249 @@
10b7fa
+/* This Source Code Form is subject to the terms of the Mozilla Public
10b7fa
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
10b7fa
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
10b7fa
+
10b7fa
+#ifdef _CRTDBG_MAP_ALLOC
10b7fa
+#include <stdlib.h>
10b7fa
+#include <crtdbg.h>
10b7fa
+#endif
10b7fa
+
10b7fa
+#include "nspr.h"
10b7fa
+#include "secutil.h"
10b7fa
+#include "pk11func.h"
10b7fa
+#include "nss.h"
10b7fa
+#include "secport.h"
10b7fa
+#include "secpkcs5.h"
10b7fa
+#include "sechash.h"
10b7fa
+#include "certdb.h"
10b7fa
+#include "secmod.h"
10b7fa
+
10b7fa
+#define PKCS12_IN_BUFFER_SIZE 200
10b7fa
+
10b7fa
+static char *progName;
10b7fa
+PRBool debug = PR_FALSE;
10b7fa
+
10b7fa
+#define ERR_USAGE 2
10b7fa
+#define ERR_PK11GETSLOT 13
10b7fa
+
10b7fa
+static void
10b7fa
+Usage()
10b7fa
+{
10b7fa
+#define FPS PR_fprintf(PR_STDERR,
10b7fa
+    FPS "Usage:	 %s [-d certdir] [-P dbprefix] [-h tokenname]\n",
10b7fa
+				 progName);
10b7fa
+    FPS "\t\t [-k slotpwfile | -K slotpw] [-v]\n");
10b7fa
+
10b7fa
+    exit(ERR_USAGE);
10b7fa
+}
10b7fa
+
10b7fa
+typedef enum {
10b7fa
+    tagULong,
10b7fa
+    tagVersion,
10b7fa
+    tagUtf8
10b7fa
+} tagType;
10b7fa
+
10b7fa
+typedef struct {
10b7fa
+    const char *attributeName;
10b7fa
+    tagType attributeStorageType;
10b7fa
+} attributeTag;
10b7fa
+
10b7fa
+enum {
10b7fa
+    opt_CertDir = 0,
10b7fa
+    opt_TokenName,
10b7fa
+    opt_SlotPWFile,
10b7fa
+    opt_SlotPW,
10b7fa
+    opt_DBPrefix,
10b7fa
+    opt_Debug
10b7fa
+};
10b7fa
+
10b7fa
+static secuCommandFlag validation_options[] =
10b7fa
+    {
10b7fa
+      { /* opt_CertDir	       */ 'd', PR_TRUE, 0, PR_FALSE },
10b7fa
+      { /* opt_TokenName	       */ 'h', PR_TRUE, 0, PR_FALSE },
10b7fa
+      { /* opt_SlotPWFile	       */ 'k', PR_TRUE, 0, PR_FALSE },
10b7fa
+      { /* opt_SlotPW	       */ 'K', PR_TRUE, 0, PR_FALSE },
10b7fa
+      { /* opt_DBPrefix	       */ 'P', PR_TRUE, 0, PR_FALSE },
10b7fa
+      { /* opt_Debug	       */ 'v', PR_FALSE, 0, PR_FALSE }
10b7fa
+    };
10b7fa
+
10b7fa
+void
10b7fa
+dump_Raw(char *label, CK_ATTRIBUTE *attr)
10b7fa
+{
10b7fa
+    int i;
10b7fa
+    unsigned char *value = (unsigned char *)attr->pValue;
10b7fa
+    printf("0x");
10b7fa
+    for (i = 0; i < attr->ulValueLen; i++) {
10b7fa
+        printf("%02x", value[i]);
10b7fa
+    }
10b7fa
+    printf("<%s>\n", label);
10b7fa
+}
10b7fa
+
10b7fa
+SECStatus
10b7fa
+dump_validations(CK_OBJECT_CLASS objc, CK_ATTRIBUTE *template, int count,
10b7fa
+                 attributeTag *tags, PK11SlotInfo *slot)
10b7fa
+{
10b7fa
+    PK11GenericObject *objs, *obj;
10b7fa
+
10b7fa
+    objs = PK11_FindGenericObjects(slot, objc);
10b7fa
+
10b7fa
+    for (obj = objs; obj != NULL; obj = PK11_GetNextGenericObject(obj)) {
10b7fa
+        int i;
10b7fa
+        printf("Validation Object:\n");
10b7fa
+        PK11_ReadRawAttributes(NULL, PK11_TypeGeneric, obj, template, count);
10b7fa
+        for (i = 0; i < count; i++) {
10b7fa
+            CK_ULONG ulong;
10b7fa
+            CK_VERSION version;
10b7fa
+            int len = template[i].ulValueLen;
10b7fa
+            printf("    %s: ", tags[i].attributeName);
10b7fa
+            if (len < 0) {
10b7fa
+                printf("<failed>\n");
10b7fa
+            } else if (len == 0) {
10b7fa
+                printf("<empty>\n");
10b7fa
+            } else
10b7fa
+                switch (tags[i].attributeStorageType) {
10b7fa
+                    case tagULong:
10b7fa
+                        if (len != sizeof(CK_ULONG)) {
10b7fa
+                            dump_Raw("bad ulong", &template[i]);
10b7fa
+                            break;
10b7fa
+                        }
10b7fa
+                        ulong = *(CK_ULONG *)template[i].pValue;
10b7fa
+                        printf("%ld\n", ulong);
10b7fa
+                        break;
10b7fa
+                    case tagVersion:
10b7fa
+                        if (len != sizeof(CK_VERSION)) {
10b7fa
+                            dump_Raw("bad version", &template[i]);
10b7fa
+                            break;
10b7fa
+                        }
10b7fa
+                        version = *(CK_VERSION *)template[i].pValue;
10b7fa
+                        printf("%d.%d\n", version.major, version.minor);
10b7fa
+                        break;
10b7fa
+                    case tagUtf8:
10b7fa
+                        printf("%.*s\n", len, (char *)template[i].pValue);
10b7fa
+                        break;
10b7fa
+                    default:
10b7fa
+                        dump_Raw("unknown tag", &template[i]);
10b7fa
+                        break;
10b7fa
+                }
10b7fa
+            PORT_Free(template[i].pValue);
10b7fa
+            template[i].pValue = NULL;
10b7fa
+            template[i].ulValueLen = 0;
10b7fa
+        }
10b7fa
+    }
10b7fa
+    PK11_DestroyGenericObjects(objs);
10b7fa
+    return SECSuccess;
10b7fa
+}
10b7fa
+
10b7fa
+int
10b7fa
+main(int argc, char **argv)
10b7fa
+{
10b7fa
+    secuPWData slotPw = { PW_NONE, NULL };
10b7fa
+    secuPWData p12FilePw = { PW_NONE, NULL };
10b7fa
+    PK11SlotInfo *slot;
10b7fa
+    char *slotname = NULL;
10b7fa
+    char *dbprefix = "";
10b7fa
+    char *nssdir = NULL;
10b7fa
+    SECStatus rv;
10b7fa
+    secuCommand validation;
10b7fa
+    int local_errno = 0;
10b7fa
+
10b7fa
+    CK_ATTRIBUTE validation_template[] = {
10b7fa
+        { CKA_NSS_VALIDATION_TYPE, NULL, 0 },
10b7fa
+        { CKA_NSS_VALIDATION_VERSION, NULL, 0 },
10b7fa
+        { CKA_NSS_VALIDATION_LEVEL, NULL, 0 },
10b7fa
+        { CKA_NSS_VALIDATION_MODULE_ID, NULL, 0 }
10b7fa
+    };
10b7fa
+    attributeTag validation_tags[] = {
10b7fa
+        { "Validation Type", tagULong },
10b7fa
+        { "Validation Version", tagVersion },
10b7fa
+        { "Validation Level", tagULong },
10b7fa
+        { "Validation Module ID", tagUtf8 },
10b7fa
+    };
10b7fa
+
10b7fa
+#ifdef _CRTDBG_MAP_ALLOC
10b7fa
+    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
10b7fa
+#endif
10b7fa
+
10b7fa
+    validation.numCommands = 0;
10b7fa
+    validation.commands = 0;
10b7fa
+    validation.numOptions = PR_ARRAY_SIZE(validation_options);
10b7fa
+    validation.options = validation_options;
10b7fa
+
10b7fa
+    progName = strrchr(argv[0], '/');
10b7fa
+    progName = progName ? progName + 1 : argv[0];
10b7fa
+
10b7fa
+    rv = SECU_ParseCommandLine(argc, argv, progName, &validation);
10b7fa
+
10b7fa
+    if (rv != SECSuccess)
10b7fa
+        Usage();
10b7fa
+
10b7fa
+    debug = validation.options[opt_Debug].activated;
10b7fa
+
10b7fa
+    slotname = SECU_GetOptionArg(&validation, opt_TokenName);
10b7fa
+
10b7fa
+    if (validation.options[opt_SlotPWFile].activated) {
10b7fa
+        slotPw.source = PW_FROMFILE;
10b7fa
+        slotPw.data = PORT_Strdup(validation.options[opt_SlotPWFile].arg);
10b7fa
+    }
10b7fa
+
10b7fa
+    if (validation.options[opt_SlotPW].activated) {
10b7fa
+        slotPw.source = PW_PLAINTEXT;
10b7fa
+        slotPw.data = PORT_Strdup(validation.options[opt_SlotPW].arg);
10b7fa
+    }
10b7fa
+
10b7fa
+    if (validation.options[opt_CertDir].activated) {
10b7fa
+        nssdir = validation.options[opt_CertDir].arg;
10b7fa
+    }
10b7fa
+    if (validation.options[opt_DBPrefix].activated) {
10b7fa
+        dbprefix = validation.options[opt_DBPrefix].arg;
10b7fa
+    }
10b7fa
+
10b7fa
+    PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
10b7fa
+    if (nssdir == NULL && NSS_NoDB_Init("") == SECSuccess) {
10b7fa
+        rv = SECSuccess;
10b7fa
+        /* if the system isn't already in FIPS mode, we need
10b7fa
+         * to switch to FIPS mode */
10b7fa
+        if (!PK11_IsFIPS()) {
10b7fa
+            /* flip to FIPS mode */
10b7fa
+            SECMODModule *module = SECMOD_GetInternalModule();
10b7fa
+            rv = SECMOD_DeleteInternalModule(module->commonName);
10b7fa
+        }
10b7fa
+    } else {
10b7fa
+        rv = NSS_Initialize(nssdir, dbprefix, dbprefix,
10b7fa
+                            "secmod.db", 0);
10b7fa
+    }
10b7fa
+    if (rv != SECSuccess) {
10b7fa
+        SECU_PrintPRandOSError(progName);
10b7fa
+        exit(-1);
10b7fa
+    }
10b7fa
+
10b7fa
+    if (!slotname || PL_strcmp(slotname, "internal") == 0)
10b7fa
+        slot = PK11_GetInternalKeySlot();
10b7fa
+    else
10b7fa
+        slot = PK11_FindSlotByName(slotname);
10b7fa
+
10b7fa
+    if (!slot) {
10b7fa
+        SECU_PrintError(progName, "Invalid slot \"%s\"", slotname);
10b7fa
+        local_errno = ERR_PK11GETSLOT;
10b7fa
+        goto done;
10b7fa
+    }
10b7fa
+
10b7fa
+    rv = dump_validations(CKO_NSS_VALIDATION,
10b7fa
+                          validation_template,
10b7fa
+                          PR_ARRAY_SIZE(validation_template),
10b7fa
+                          validation_tags,
10b7fa
+                          slot);
10b7fa
+
10b7fa
+done:
10b7fa
+    if (slotPw.data != NULL)
10b7fa
+        PORT_ZFree(slotPw.data, PL_strlen(slotPw.data));
10b7fa
+    if (p12FilePw.data != NULL)
10b7fa
+        PORT_ZFree(p12FilePw.data, PL_strlen(p12FilePw.data));
10b7fa
+    if (slot)
10b7fa
+        PK11_FreeSlot(slot);
10b7fa
+    if (NSS_Shutdown() != SECSuccess) {
10b7fa
+        local_errno = 1;
10b7fa
+    }
10b7fa
+    PL_ArenaFinish();
10b7fa
+    PR_Cleanup();
10b7fa
+    return local_errno;
10b7fa
+}
10b7fa
diff --git a/cmd/validation/validation.gyp b/cmd/validation/validation.gyp
10b7fa
new file mode 100644
10b7fa
--- /dev/null
10b7fa
+++ b/cmd/validation/validation.gyp
10b7fa
@@ -0,0 +1,30 @@
10b7fa
+# This Source Code Form is subject to the terms of the Mozilla Public
10b7fa
+# License, v. 2.0. If a copy of the MPL was not distributed with this
10b7fa
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
10b7fa
+{
10b7fa
+  'includes': [
10b7fa
+    '../../coreconf/config.gypi',
10b7fa
+    '../../cmd/platlibs.gypi'
10b7fa
+  ],
10b7fa
+  'targets': [
10b7fa
+    {
10b7fa
+      'target_name': 'validation',
10b7fa
+      'type': 'executable',
10b7fa
+      'sources': [
10b7fa
+        'validation.c'
10b7fa
+      ],
10b7fa
+      'dependencies': [
10b7fa
+        '<(DEPTH)/exports.gyp:dbm_exports',
10b7fa
+        '<(DEPTH)/exports.gyp:nss_exports'
10b7fa
+      ]
10b7fa
+    }
10b7fa
+  ],
10b7fa
+  'target_defaults': {
10b7fa
+    'defines': [
10b7fa
+      'NSPR20'
10b7fa
+    ]
10b7fa
+  },
10b7fa
+  'variables': {
10b7fa
+    'module': 'nss'
10b7fa
+  }
10b7fa
+}
10b7fa
diff --git a/lib/softoken/config.mk b/lib/softoken/config.mk
10b7fa
--- a/lib/softoken/config.mk
10b7fa
+++ b/lib/softoken/config.mk
10b7fa
@@ -59,3 +59,7 @@
10b7fa
 DEFINES += -DNSS_ENABLE_FIPS_INDICATORS
10b7fa
 endif
10b7fa
 
10b7fa
+ifdef NSS_FIPS_MODULE_ID
10b7fa
+DEFINES += -DNSS_FIPS_MODULE_ID=\"${NSS_FIPS_MODULE_ID}\"
10b7fa
+endif
10b7fa
+
10b7fa
diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c
10b7fa
--- a/lib/softoken/pkcs11.c
10b7fa
+++ b/lib/softoken/pkcs11.c
10b7fa
@@ -75,7 +75,6 @@
10b7fa
  * failure so that there are at most 60 login attempts per minute.
10b7fa
  */
10b7fa
 static PRIntervalTime loginWaitTime;
10b7fa
-static PRUint32 minSessionObjectHandle = 1U;
10b7fa
 
10b7fa
 #define __PASTE(x, y) x##y
10b7fa
 
10b7fa
@@ -1672,8 +1671,6 @@
10b7fa
 {
10b7fa
     SFTKSlot *slot = session->slot;
10b7fa
     SFTKAttribute *attribute;
10b7fa
-    SFTKObject *duplicateObject = NULL;
10b7fa
-    CK_OBJECT_HANDLE handle;
10b7fa
     CK_BBOOL ckfalse = CK_FALSE;
10b7fa
     CK_BBOOL cktrue = CK_TRUE;
10b7fa
     CK_RV crv;
10b7fa
@@ -1711,30 +1708,13 @@
10b7fa
      * token objects and will have a token object handle assigned to
10b7fa
      * them by a call to sftk_mkHandle in the handler for each object
10b7fa
      * class, invoked below.
10b7fa
-     *
10b7fa
+     *  
10b7fa
      * It may be helpful to note/remember that
10b7fa
      * sftk_narrowToXxxObject uses sftk_isToken,
10b7fa
      * sftk_isToken examines the sign bit of the object's handle, but
10b7fa
      * sftk_isTrue(...,CKA_TOKEN) examines the CKA_TOKEN attribute.
10b7fa
      */
10b7fa
-    do {
10b7fa
-        PRUint32 wrappedAround;
10b7fa
-
10b7fa
-        duplicateObject = NULL;
10b7fa
-        PZ_Lock(slot->objectLock);
10b7fa
-        wrappedAround = slot->sessionObjectHandleCount & SFTK_TOKEN_MASK;
10b7fa
-        handle = slot->sessionObjectHandleCount & ~SFTK_TOKEN_MASK;
10b7fa
-        if (!handle) /* don't allow zero handle */
10b7fa
-            handle = minSessionObjectHandle;
10b7fa
-        slot->sessionObjectHandleCount = (handle + 1U) | wrappedAround;
10b7fa
-        /* Is there already a session object with this handle? */
10b7fa
-        if (wrappedAround) {
10b7fa
-            sftkqueue_find(duplicateObject, handle, slot->sessObjHashTable,
10b7fa
-                           slot->sessObjHashSize);
10b7fa
-        }
10b7fa
-        PZ_Unlock(slot->objectLock);
10b7fa
-    } while (duplicateObject != NULL);
10b7fa
-    object->handle = handle;
10b7fa
+    object->handle = sftk_getNextHandle(slot);
10b7fa
 
10b7fa
     /* get the object class */
10b7fa
     attribute = sftk_FindAttribute(object, CKA_CLASS);
10b7fa
@@ -2875,10 +2855,15 @@
10b7fa
         goto mem_loser;
10b7fa
 
10b7fa
     slot->sessionIDCount = 0;
10b7fa
-    slot->sessionObjectHandleCount = minSessionObjectHandle;
10b7fa
+    slot->sessionObjectHandleCount = NSC_MIN_SESSION_OBJECT_HANDLE;
10b7fa
     slot->slotID = slotID;
10b7fa
     sftk_setStringName(params->slotdes ? params->slotdes : sftk_getDefSlotName(slotID), slot->slotDescription,
10b7fa
                        sizeof(slot->slotDescription), PR_TRUE);
10b7fa
+    crv = sftk_InitSession(&slot->moduleObjects, slot, slotID, NULL, NULL,
10b7fa
+                           CKF_SERIAL_SESSION);
10b7fa
+    if (crv != CKR_OK) {
10b7fa
+        goto loser;
10b7fa
+    }
10b7fa
 
10b7fa
     /* call the reinit code to set everything that changes between token
10b7fa
      * init calls */
10b7fa
@@ -2887,6 +2872,12 @@
10b7fa
     if (crv != CKR_OK) {
10b7fa
         goto loser;
10b7fa
     }
10b7fa
+    if (sftk_isFIPS(slotID)) {
10b7fa
+        crv = sftk_CreateValidationObjects(slot);
10b7fa
+        if (crv != CKR_OK) {
10b7fa
+            goto loser;
10b7fa
+        }
10b7fa
+    }
10b7fa
     crv = sftk_RegisterSlot(slot, moduleIndex);
10b7fa
     if (crv != CKR_OK) {
10b7fa
         goto loser;
10b7fa
@@ -3032,6 +3023,8 @@
10b7fa
 
10b7fa
     SFTK_ShutdownSlot(slot);
10b7fa
 
10b7fa
+    sftk_ClearSession(&slot->moduleObjects);
10b7fa
+
10b7fa
     if (slot->tokObjHashTable) {
10b7fa
         PL_HashTableDestroy(slot->tokObjHashTable);
10b7fa
         slot->tokObjHashTable = NULL;
10b7fa
@@ -3262,6 +3255,7 @@
10b7fa
     CK_RV crv = CKR_OK;
10b7fa
     SECStatus rv;
10b7fa
     CK_C_INITIALIZE_ARGS *init_args = (CK_C_INITIALIZE_ARGS *)pReserved;
10b7fa
+    PRBool destroy_freelist_on_error = PR_TRUE;
10b7fa
     int i;
10b7fa
     unsigned int moduleIndex = isFIPS ? NSC_FIPS_MODULE : NSC_NON_FIPS_MODULE;
10b7fa
 
10b7fa
@@ -3341,7 +3335,14 @@
10b7fa
                                          "disabled FIPS mode");
10b7fa
                 }
10b7fa
             }
10b7fa
+            /* if we have a peer open, we don't want to destroy the freelist
10b7fa
+             * from under the peer if we fail, the free list will be
10b7fa
+             * destroyed in that case when the C_Finalize is called for
10b7fa
+             * the peer */
10b7fa
+            destroy_freelist_on_error = PR_FALSE;
10b7fa
         }
10b7fa
+        /* allow us to create objects in SFTK_SlotInit */
10b7fa
+        sftk_InitFreeLists();
10b7fa
 
10b7fa
         for (i = 0; i < paramStrings.token_count; i++) {
10b7fa
             crv = SFTK_SlotInit(paramStrings.configdir,
10b7fa
@@ -3355,8 +3356,9 @@
10b7fa
     loser:
10b7fa
         sftk_freeParams(&paramStrings);
10b7fa
     }
10b7fa
-    if (CKR_OK == crv) {
10b7fa
-        sftk_InitFreeLists();
10b7fa
+    if (destroy_freelist_on_error && (CKR_OK != crv)) {
10b7fa
+        /* idempotent. If the list are already freed, this is a noop */
10b7fa
+        sftk_CleanupFreeLists();
10b7fa
     }
10b7fa
 
10b7fa
 #ifndef NO_FORK_CHECK
10b7fa
diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h
10b7fa
--- a/lib/softoken/pkcs11i.h
10b7fa
+++ b/lib/softoken/pkcs11i.h
10b7fa
@@ -49,6 +49,8 @@
10b7fa
 #define NSC_SEARCH_BLOCK_SIZE 5
10b7fa
 #define NSC_SLOT_LIST_BLOCK_SIZE 10
10b7fa
 
10b7fa
+#define NSC_MIN_SESSION_OBJECT_HANDLE 1U
10b7fa
+
10b7fa
 #define NSC_FIPS_MODULE 1
10b7fa
 #define NSC_NON_FIPS_MODULE 0
10b7fa
 
10b7fa
@@ -375,6 +377,9 @@
10b7fa
     char tokDescription[33];       /* per load */
10b7fa
     char updateTokDescription[33]; /* per load */
10b7fa
     char slotDescription[65];      /* invariant */
10b7fa
+    SFTKSession moduleObjects;     /* global session to hang module specific
10b7fa
+                                    * objects like profile objects or
10b7fa
+                                    * validation objects */
10b7fa
 };
10b7fa
 
10b7fa
 /*
10b7fa
@@ -766,6 +771,7 @@
10b7fa
 extern void sftk_ReferenceObject(SFTKObject *object);
10b7fa
 extern SFTKObject *sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle,
10b7fa
                                          SFTKSession *session);
10b7fa
+extern CK_OBJECT_HANDLE sftk_getNextHandle(SFTKSlot *slot);
10b7fa
 extern void sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object);
10b7fa
 extern void sftk_AddObject(SFTKSession *session, SFTKObject *object);
10b7fa
 /* clear out all the existing object ID to database key mappings.
10b7fa
@@ -787,7 +793,11 @@
10b7fa
 extern CK_SLOT_ID sftk_SlotIDFromSessionHandle(CK_SESSION_HANDLE handle);
10b7fa
 extern SFTKSession *sftk_SessionFromHandle(CK_SESSION_HANDLE handle);
10b7fa
 extern void sftk_FreeSession(SFTKSession *session);
10b7fa
+extern void sftk_ClearSession(SFTKSession *session);
10b7fa
 extern void sftk_DestroySession(SFTKSession *session);
10b7fa
+extern CK_RV sftk_InitSession(SFTKSession *session, SFTKSlot *slot,
10b7fa
+                              CK_SLOT_ID slotID, CK_NOTIFY notify,
10b7fa
+                              CK_VOID_PTR pApplication, CK_FLAGS flags);
10b7fa
 extern SFTKSession *sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify,
10b7fa
                                     CK_VOID_PTR pApplication, CK_FLAGS flags);
10b7fa
 extern void sftk_update_state(SFTKSlot *slot, SFTKSession *session);
10b7fa
@@ -955,6 +965,9 @@
10b7fa
  * FIPS security policy */
10b7fa
 PRBool sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech,
10b7fa
                             CK_ATTRIBUTE_TYPE op, SFTKObject *source);
10b7fa
+/* add validation objects to the slot */
10b7fa
+CK_RV sftk_CreateValidationObjects(SFTKSlot *slot);
10b7fa
+
10b7fa
 SEC_END_PROTOS
10b7fa
 
10b7fa
 #endif /* _PKCS11I_H_ */
10b7fa
diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c
10b7fa
--- a/lib/softoken/pkcs11u.c
10b7fa
+++ b/lib/softoken/pkcs11u.c
10b7fa
@@ -14,6 +14,7 @@
10b7fa
 #include "sftkdb.h"
10b7fa
 #include "softoken.h"
10b7fa
 #include "secoid.h"
10b7fa
+#include "softkver.h"
10b7fa
 
10b7fa
 #if !defined(NSS_FIPS_DISABLED) && defined(NSS_ENABLE_FIPS_INDICATORS)
10b7fa
 /* this file should be supplied by the vendor and include all the
10b7fa
@@ -1243,6 +1244,32 @@
10b7fa
     return SFTK_Busy;
10b7fa
 }
10b7fa
 
10b7fa
+/* find the next available object handle that isn't currently in use */
10b7fa
+CK_OBJECT_HANDLE
10b7fa
+sftk_getNextHandle(SFTKSlot *slot)
10b7fa
+{
10b7fa
+    CK_OBJECT_HANDLE handle;
10b7fa
+    SFTKObject *duplicateObject = NULL;
10b7fa
+    do {
10b7fa
+        PRUint32 wrappedAround;
10b7fa
+
10b7fa
+        duplicateObject = NULL;
10b7fa
+        PZ_Lock(slot->objectLock);
10b7fa
+        wrappedAround = slot->sessionObjectHandleCount & SFTK_TOKEN_MASK;
10b7fa
+        handle = slot->sessionObjectHandleCount & ~SFTK_TOKEN_MASK;
10b7fa
+        if (!handle) /* don't allow zero handle */
10b7fa
+            handle = NSC_MIN_SESSION_OBJECT_HANDLE;
10b7fa
+        slot->sessionObjectHandleCount = (handle + 1U) | wrappedAround;
10b7fa
+        /* Is there already a session object with this handle? */
10b7fa
+        if (wrappedAround) {
10b7fa
+            sftkqueue_find(duplicateObject, handle, slot->sessObjHashTable,
10b7fa
+                           slot->sessObjHashSize);
10b7fa
+        }
10b7fa
+        PZ_Unlock(slot->objectLock);
10b7fa
+    } while (duplicateObject != NULL);
10b7fa
+    return handle;
10b7fa
+}
10b7fa
+
10b7fa
 /*
10b7fa
  * add an object to a slot and session queue. These two functions
10b7fa
  * adopt the object.
10b7fa
@@ -1848,23 +1875,13 @@
10b7fa
 }
10b7fa
 
10b7fa
 /*
10b7fa
- * create a new nession. NOTE: The session handle is not set, and the
10b7fa
+ * Init a new session. NOTE: The session handle is not set, and the
10b7fa
  * session is not added to the slot's session queue.
10b7fa
  */
10b7fa
-SFTKSession *
10b7fa
-sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication,
10b7fa
-                CK_FLAGS flags)
10b7fa
+CK_RV
10b7fa
+sftk_InitSession(SFTKSession *session, SFTKSlot *slot, CK_SLOT_ID slotID,
10b7fa
+                 CK_NOTIFY notify, CK_VOID_PTR pApplication, CK_FLAGS flags)
10b7fa
 {
10b7fa
-    SFTKSession *session;
10b7fa
-    SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
10b7fa
-
10b7fa
-    if (slot == NULL)
10b7fa
-        return NULL;
10b7fa
-
10b7fa
-    session = (SFTKSession *)PORT_Alloc(sizeof(SFTKSession));
10b7fa
-    if (session == NULL)
10b7fa
-        return NULL;
10b7fa
-
10b7fa
     session->next = session->prev = NULL;
10b7fa
     session->enc_context = NULL;
10b7fa
     session->hash_context = NULL;
10b7fa
@@ -1873,8 +1890,7 @@
10b7fa
     session->objectIDCount = 1;
10b7fa
     session->objectLock = PZ_NewLock(nssILockObject);
10b7fa
     if (session->objectLock == NULL) {
10b7fa
-        PORT_Free(session);
10b7fa
-        return NULL;
10b7fa
+        return CKR_HOST_MEMORY;
10b7fa
     }
10b7fa
     session->objects[0] = NULL;
10b7fa
 
10b7fa
@@ -1887,12 +1903,38 @@
10b7fa
     sftk_update_state(slot, session);
10b7fa
     /* no ops completed yet, so the last one couldn't be a FIPS op */
10b7fa
     session->lastOpWasFIPS = PR_FALSE;
10b7fa
+    return CKR_OK;
10b7fa
+}
10b7fa
+
10b7fa
+/*
10b7fa
+ * Create a new session and init it.
10b7fa
+ */
10b7fa
+SFTKSession *
10b7fa
+sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication,
10b7fa
+                CK_FLAGS flags)
10b7fa
+{
10b7fa
+    SFTKSession *session;
10b7fa
+    SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
10b7fa
+    CK_RV crv;
10b7fa
+
10b7fa
+    if (slot == NULL)
10b7fa
+        return NULL;
10b7fa
+
10b7fa
+    session = (SFTKSession *)PORT_Alloc(sizeof(SFTKSession));
10b7fa
+    if (session == NULL)
10b7fa
+        return NULL;
10b7fa
+
10b7fa
+    crv = sftk_InitSession(session, slot, slotID, notify, pApplication, flags);
10b7fa
+    if (crv != CKR_OK) {
10b7fa
+        PORT_Free(session);
10b7fa
+        return NULL;
10b7fa
+    }
10b7fa
     return session;
10b7fa
 }
10b7fa
 
10b7fa
 /* free all the data associated with a session. */
10b7fa
 void
10b7fa
-sftk_DestroySession(SFTKSession *session)
10b7fa
+sftk_ClearSession(SFTKSession *session)
10b7fa
 {
10b7fa
     SFTKObjectList *op, *next;
10b7fa
 
10b7fa
@@ -1918,6 +1960,13 @@
10b7fa
     if (session->search) {
10b7fa
         sftk_FreeSearch(session->search);
10b7fa
     }
10b7fa
+}
10b7fa
+
10b7fa
+/* free the data associated with the session, and the session */
10b7fa
+void
10b7fa
+sftk_DestroySession(SFTKSession *session)
10b7fa
+{
10b7fa
+    sftk_ClearSession(session);
10b7fa
     PORT_Free(session);
10b7fa
 }
10b7fa
 
10b7fa
@@ -2386,3 +2435,70 @@
10b7fa
     return PR_FALSE;
10b7fa
 #endif
10b7fa
 }
10b7fa
+
10b7fa
+/*
10b7fa
+ * create the FIPS Validation objects. If the vendor
10b7fa
+ * doesn't supply an NSS_FIPS_MODULE_ID, at compile time,
10b7fa
+ * then we assumethis is an unvalidated module.
10b7fa
+ */
10b7fa
+CK_RV
10b7fa
+sftk_CreateValidationObjects(SFTKSlot *slot)
10b7fa
+{
10b7fa
+    const char *module_id;
10b7fa
+    int module_id_len;
10b7fa
+    CK_RV crv = CKR_OK;
10b7fa
+    /* we currently use vendor specific values until the validation
10b7fa
+     * objects are approved for PKCS #11 v3.2. */
10b7fa
+    CK_OBJECT_CLASS cko_validation = CKO_NSS_VALIDATION;
10b7fa
+    CK_NSS_VALIDATION_TYPE ckv_fips = CKV_NSS_FIPS_140;
10b7fa
+    CK_VERSION fips_version = { 3, 0 }; /* FIPS-140-3 */
10b7fa
+    CK_ULONG fips_level = 1;            /* or 2 if you validated at level 2 */
10b7fa
+
10b7fa
+#ifndef NSS_FIPS_MODULE_ID
10b7fa
+#define NSS_FIPS_MODULE_ID "Generic NSS " SOFTOKEN_VERSION " Unvalidated"
10b7fa
+#endif
10b7fa
+    module_id = NSS_FIPS_MODULE_ID;
10b7fa
+    module_id_len = sizeof(NSS_FIPS_MODULE_ID) - 1;
10b7fa
+    SFTKObject *object;
10b7fa
+
10b7fa
+    object = sftk_NewObject(slot); /* fill in the handle later */
10b7fa
+    if (object == NULL) {
10b7fa
+        return CKR_HOST_MEMORY;
10b7fa
+    }
10b7fa
+    object->isFIPS = PR_FALSE;
10b7fa
+
10b7fa
+    crv = sftk_AddAttributeType(object, CKA_CLASS,
10b7fa
+                                &cko_validation, sizeof(cko_validation));
10b7fa
+    if (crv != CKR_OK) {
10b7fa
+        goto loser;
10b7fa
+    }
10b7fa
+    crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_TYPE,
10b7fa
+                                &ckv_fips, sizeof(ckv_fips));
10b7fa
+    if (crv != CKR_OK) {
10b7fa
+        goto loser;
10b7fa
+    }
10b7fa
+    crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_VERSION,
10b7fa
+                                &fips_version, sizeof(fips_version));
10b7fa
+    if (crv != CKR_OK) {
10b7fa
+        goto loser;
10b7fa
+    }
10b7fa
+    crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_LEVEL,
10b7fa
+                                &fips_level, sizeof(fips_level));
10b7fa
+    if (crv != CKR_OK) {
10b7fa
+        goto loser;
10b7fa
+    }
10b7fa
+    crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_MODULE_ID,
10b7fa
+                                module_id, module_id_len);
10b7fa
+    if (crv != CKR_OK) {
10b7fa
+        goto loser;
10b7fa
+    }
10b7fa
+
10b7fa
+    /* future, fill in validation certificate information from a supplied
10b7fa
+     * pointer to a config file */
10b7fa
+    object->handle = sftk_getNextHandle(slot);
10b7fa
+    object->slot = slot;
10b7fa
+    sftk_AddObject(&slot->moduleObjects, object);
10b7fa
+loser:
10b7fa
+    sftk_FreeObject(object);
10b7fa
+    return crv;
10b7fa
+}
10b7fa
diff --git a/lib/util/pkcs11n.h b/lib/util/pkcs11n.h
10b7fa
--- a/lib/util/pkcs11n.h
10b7fa
+++ b/lib/util/pkcs11n.h
10b7fa
@@ -38,6 +38,9 @@
10b7fa
 #define CKO_NSS_BUILTIN_ROOT_LIST (CKO_NSS + 4)
10b7fa
 #define CKO_NSS_NEWSLOT (CKO_NSS + 5)
10b7fa
 #define CKO_NSS_DELSLOT (CKO_NSS + 6)
10b7fa
+#define CKO_NSS_VALIDATION (CKO_NSS + 7)
10b7fa
+
10b7fa
+#define CKV_NSS_FIPS_140 (CKO_NSS + 1)
10b7fa
 
10b7fa
 /*
10b7fa
  * NSS-defined key types
10b7fa
@@ -99,6 +102,11 @@
10b7fa
 #define CKA_NSS_SERVER_DISTRUST_AFTER (CKA_NSS + 35)
10b7fa
 #define CKA_NSS_EMAIL_DISTRUST_AFTER (CKA_NSS + 36)
10b7fa
 
10b7fa
+#define CKA_NSS_VALIDATION_TYPE (CKA_NSS + 36)
10b7fa
+#define CKA_NSS_VALIDATION_VERSION (CKA_NSS + 37)
10b7fa
+#define CKA_NSS_VALIDATION_LEVEL (CKA_NSS + 38)
10b7fa
+#define CKA_NSS_VALIDATION_MODULE_ID (CKA_NSS + 39)
10b7fa
+
10b7fa
 /*
10b7fa
  * Trust attributes:
10b7fa
  *
10b7fa
@@ -344,6 +352,9 @@
10b7fa
 #define CKR_NSS_CERTDB_FAILED (CKR_NSS + 1)
10b7fa
 #define CKR_NSS_KEYDB_FAILED (CKR_NSS + 2)
10b7fa
 
10b7fa
+/* NSS specific types */
10b7fa
+typedef CK_ULONG CK_NSS_VALIDATION_TYPE;
10b7fa
+
10b7fa
 /* Mandatory parameter for the CKM_NSS_HKDF_* key deriviation mechanisms.
10b7fa
    See RFC 5869.
10b7fa
 
10b7fa
diff --git a/nss.gyp b/nss.gyp
10b7fa
--- a/nss.gyp
10b7fa
+++ b/nss.gyp
10b7fa
@@ -131,6 +131,7 @@
10b7fa
                 'cmd/smimetools/smimetools.gyp:cmsutil',
10b7fa
                 'cmd/ssltap/ssltap.gyp:ssltap',
10b7fa
                 'cmd/symkeyutil/symkeyutil.gyp:symkeyutil',
10b7fa
+                'cmd/validation/validation.gyp:validation',
10b7fa
                 'nss-tool/nss_tool.gyp:nss',
10b7fa
                 'nss-tool/nss_tool.gyp:hw-support',
10b7fa
               ],
10b7fa