lynx   »   [go: up one dir, main page]

Bug 1729550 NSS needs FiPS 140-3 version indicators. NSS_3_73_BETA1
authorRobert Relyea <rrelyea@redhat.com>
Tue, 07 Sep 2021 16:18:08 -0700
changeset 16027 4b8ce96413381293f42c8034ab4976e2aa9af247
parent 16026 ea6fb7d0d0fc46e0dae98f119d6a457ef758a469
child 16028 0ee3564fdb1601e65abd93e888e4cb3ceab5f353
child 16037 f80fafd04cf82b4d315c8fe42bb4639703f6ee4f
push id4040
push userrrelyea@redhat.com
push dateWed, 17 Nov 2021 19:58:50 +0000
bugs1729550
Bug 1729550 NSS needs FiPS 140-3 version indicators. 1. This patch adds a new command, validation, which dumps the validation objects ina given token. It defaults to the softoken. 2. It sets up the infrastructure to allow creation at init time of token specific objects (like validation objects and profile objects) by: 2a. factoring out the code to get the next available object handle to a new function call sftk_getNextHandle(). 2b. The object freelists are now initialized before SFTK_SlotInit, so that SFTK_SlotInit can initialize these new token objects. 2c. A new staticly defined session is created to hand these object on. 2c1. sftk_NewSession and sftk_FreeSession has the initialization and clearing functions factored out from the actual space freeing clearing so they can be used on this staticly allocated session. (NOTE: NSS has two ways it handles this internally: use of Init/New Clear/Free functions as in this patch, or the use of a bool called 'FreeIt' added to the original function. There is no technical reason for why I used Init/New other than I didn't have to go change all the places the currently call them. These are internal private functions, so it's ok to change their signatures. 2c2. The static sessions are initialized on freed when the slot is created and destroyed. 3. For fips slot the validation object is created. The version number is selected at compile time with a build time environment variable. If no version number is provided, a default version number (related to the NSS version) is selected as well as the string 'unvalidated'. 4. The NSS spefic defines for Validation objects are defined in the NSS vendor space (until PKCS #11 v3.2 comes out with the official values). Differential Revision: https://phabricator.services.mozilla.com/D124951
cmd/manifest.mn
cmd/validation/Makefile
cmd/validation/manifest.mn
cmd/validation/validation.c
cmd/validation/validation.gyp
lib/softoken/config.mk
lib/softoken/pkcs11.c
lib/softoken/pkcs11i.h
lib/softoken/pkcs11u.c
lib/util/pkcs11n.h
nss.gyp
--- a/cmd/manifest.mn
+++ b/cmd/manifest.mn
@@ -71,16 +71,17 @@ NSS_SRCDIRS = \
  signtool \
  signver \
  smimetools  \
  ssltap  \
  strsclnt \
  symkeyutil \
  tests \
  tstclnt  \
+ validation  \
  vfychain \
  vfyserv \
  modutil \
  $(NULL)
 
 ifndef NSS_DISABLE_LIBPKIX
 NSS_SRCDIRS += \
  pkix-errcodes \
new file mode 100644
--- /dev/null
+++ b/cmd/validation/Makefile
@@ -0,0 +1,48 @@
+#! gmake
+#
+# 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/.
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY).   #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL)          #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL)       #
+#######################################################################
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL).      #
+#######################################################################
+
+include ../platlibs.mk
+
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL)                              #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL)                           #
+#######################################################################
+
+
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL).                              #
+#######################################################################
+
+
+include ../platrules.mk
+
new file mode 100644
--- /dev/null
+++ b/cmd/validation/manifest.mn
@@ -0,0 +1,23 @@
+#
+# 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 = ../..
+
+DEFINES += -DNSPR20
+
+# MODULE public and private header  directories are implicitly REQUIRED.
+MODULE = nss
+
+CSRCS = \
+	validation.c \
+	$(NULL)
+
+# The MODULE is always implicitly required.
+# Listing it here in REQUIRES makes it appear twice in the cc command line.
+REQUIRES = dbm seccmd
+
+PROGRAM = validation
+
+# USE_STATIC_LIBS = 1
new file mode 100644
--- /dev/null
+++ b/cmd/validation/validation.c
@@ -0,0 +1,251 @@
+/* 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/. */
+
+#ifdef _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#endif
+
+#include "nspr.h"
+#include "secutil.h"
+#include "pk11func.h"
+#include "nss.h"
+#include "secport.h"
+#include "secpkcs5.h"
+#include "sechash.h"
+#include "certdb.h"
+#include "secmod.h"
+
+static char *progName;
+PRBool debug = PR_FALSE;
+
+#define ERR_USAGE 2
+#define ERR_PK11GETSLOT 13
+
+static void
+Usage()
+{
+#define FPS PR_fprintf(PR_STDERR,
+    FPS "Usage:	 %s [-d certdir] [-P dbprefix] [-h tokenname]\n",
+				 progName);
+    FPS "\t\t [-k slotpwfile | -K slotpw] [-v]\n");
+
+    exit(ERR_USAGE);
+}
+
+typedef enum {
+    tagULong,
+    tagVersion,
+    tagUtf8
+} tagType;
+
+typedef struct {
+    const char *attributeName;
+    tagType attributeStorageType;
+} attributeTag;
+
+enum {
+    opt_CertDir = 0,
+    opt_TokenName,
+    opt_SlotPWFile,
+    opt_SlotPW,
+    opt_DBPrefix,
+    opt_Debug
+};
+
+static secuCommandFlag validation_options[] =
+    {
+      { /* opt_CertDir        */ 'd', PR_TRUE, 0, PR_FALSE },
+      { /* opt_TokenName      */ 'h', PR_TRUE, 0, PR_FALSE },
+      { /* opt_SlotPWFile     */ 'k', PR_TRUE, 0, PR_FALSE },
+      { /* opt_SlotPW         */ 'K', PR_TRUE, 0, PR_FALSE },
+      { /* opt_DBPrefix       */ 'P', PR_TRUE, 0, PR_FALSE },
+      { /* opt_Debug          */ 'v', PR_FALSE, 0, PR_FALSE }
+    };
+
+void
+dump_Raw(char *label, CK_ATTRIBUTE *attr)
+{
+    int i;
+    unsigned char *value = (unsigned char *)attr->pValue;
+    printf("0x");
+    for (i = 0; i < attr->ulValueLen; i++) {
+        printf("%02x", value[i]);
+    }
+    printf("<%s>\n", label);
+}
+
+SECStatus
+dump_validations(CK_OBJECT_CLASS objc, CK_ATTRIBUTE *template, int count,
+                 attributeTag *tags, PK11SlotInfo *slot)
+{
+    PK11GenericObject *objs, *obj;
+
+    objs = PK11_FindGenericObjects(slot, objc);
+
+    for (obj = objs; obj != NULL; obj = PK11_GetNextGenericObject(obj)) {
+        int i;
+        printf("Validation Object:\n");
+        PK11_ReadRawAttributes(NULL, PK11_TypeGeneric, obj, template, count);
+        for (i = 0; i < count; i++) {
+            CK_ULONG ulong;
+            CK_VERSION version;
+            int len = template[i].ulValueLen;
+            printf("    %s: ", tags[i].attributeName);
+            if (len < 0) {
+                printf("<failed>\n");
+            } else if (len == 0) {
+                printf("<empty>\n");
+            } else
+                switch (tags[i].attributeStorageType) {
+                    case tagULong:
+                        if (len != sizeof(CK_ULONG)) {
+                            dump_Raw("bad ulong", &template[i]);
+                            break;
+                        }
+                        ulong = *(CK_ULONG *)template[i].pValue;
+                        printf("%ld\n", ulong);
+                        break;
+                    case tagVersion:
+                        if (len != sizeof(CK_VERSION)) {
+                            dump_Raw("bad version", &template[i]);
+                            break;
+                        }
+                        version = *(CK_VERSION *)template[i].pValue;
+                        printf("%d.%d\n", version.major, version.minor);
+                        break;
+                    case tagUtf8:
+                        printf("%.*s\n", len, (char *)template[i].pValue);
+                        break;
+                    default:
+                        dump_Raw("unknown tag", &template[i]);
+                        break;
+                }
+            PORT_Free(template[i].pValue);
+            template[i].pValue = NULL;
+            template[i].ulValueLen = 0;
+        }
+    }
+    PK11_DestroyGenericObjects(objs);
+    return SECSuccess;
+}
+
+int
+main(int argc, char **argv)
+{
+    secuPWData slotPw = { PW_NONE, NULL };
+    secuPWData p12FilePw = { PW_NONE, NULL };
+    PK11SlotInfo *slot = NULL;
+    char *slotname = NULL;
+    char *dbprefix = "";
+    char *nssdir = NULL;
+    SECStatus rv;
+    secuCommand validation;
+    int local_errno = 0;
+
+    CK_ATTRIBUTE validation_template[] = {
+        { CKA_NSS_VALIDATION_TYPE, NULL, 0 },
+        { CKA_NSS_VALIDATION_VERSION, NULL, 0 },
+        { CKA_NSS_VALIDATION_LEVEL, NULL, 0 },
+        { CKA_NSS_VALIDATION_MODULE_ID, NULL, 0 }
+    };
+    attributeTag validation_tags[] = {
+        { "Validation Type", tagULong },
+        { "Validation Version", tagVersion },
+        { "Validation Level", tagULong },
+        { "Validation Module ID", tagUtf8 },
+    };
+
+#ifdef _CRTDBG_MAP_ALLOC
+    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+
+    validation.numCommands = 0;
+    validation.commands = 0;
+    validation.numOptions = PR_ARRAY_SIZE(validation_options);
+    validation.options = validation_options;
+
+    progName = strrchr(argv[0], '/');
+    progName = progName ? progName + 1 : argv[0];
+
+    rv = SECU_ParseCommandLine(argc, argv, progName, &validation);
+
+    if (rv != SECSuccess)
+        Usage();
+
+    debug = validation.options[opt_Debug].activated;
+
+    slotname = SECU_GetOptionArg(&validation, opt_TokenName);
+
+    if (validation.options[opt_SlotPWFile].activated) {
+        slotPw.source = PW_FROMFILE;
+        slotPw.data = PORT_Strdup(validation.options[opt_SlotPWFile].arg);
+    }
+
+    if (validation.options[opt_SlotPW].activated) {
+        slotPw.source = PW_PLAINTEXT;
+        slotPw.data = PORT_Strdup(validation.options[opt_SlotPW].arg);
+    }
+
+    if (validation.options[opt_CertDir].activated) {
+        nssdir = validation.options[opt_CertDir].arg;
+    }
+    if (validation.options[opt_DBPrefix].activated) {
+        dbprefix = validation.options[opt_DBPrefix].arg;
+    }
+
+    PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
+    if (nssdir == NULL && NSS_NoDB_Init("") == SECSuccess) {
+        rv = SECSuccess;
+        /* if the system isn't already in FIPS mode, we need
+         * to switch to FIPS mode */
+        if (!PK11_IsFIPS()) {
+            /* flip to FIPS mode */
+            SECMODModule *module = SECMOD_GetInternalModule();
+            rv = SECMOD_DeleteInternalModule(module->commonName);
+        }
+    } else if (nssdir != NULL) {
+        rv = NSS_Initialize(nssdir, dbprefix, dbprefix, "secmod.db", 0);
+    }
+    if (rv != SECSuccess) {
+        SECU_PrintPRandOSError(progName);
+        local_errno = -1;
+        goto done;
+    }
+
+    if (!slotname || PL_strcmp(slotname, "internal") == 0)
+        slot = PK11_GetInternalKeySlot();
+    else
+        slot = PK11_FindSlotByName(slotname);
+
+    if (!slot) {
+        SECU_PrintError(progName, "Invalid slot \"%s\"",
+                        slotname ? "internal" : slotname);
+        local_errno = ERR_PK11GETSLOT;
+        goto done;
+    }
+
+    rv = dump_validations(CKO_NSS_VALIDATION,
+                          validation_template,
+                          PR_ARRAY_SIZE(validation_template),
+                          validation_tags,
+                          slot);
+
+done:
+    if (slotPw.data != NULL)
+        PORT_ZFree(slotPw.data, PL_strlen(slotPw.data));
+    if (p12FilePw.data != NULL)
+        PORT_ZFree(p12FilePw.data, PL_strlen(p12FilePw.data));
+    if (slotname) {
+        PORT_Free(slotname);
+    }
+    if (slot)
+        PK11_FreeSlot(slot);
+    if (NSS_Shutdown() != SECSuccess) {
+        local_errno = 1;
+    }
+    PL_ArenaFinish();
+    PR_Cleanup();
+    return local_errno;
+}
new file mode 100644
--- /dev/null
+++ b/cmd/validation/validation.gyp
@@ -0,0 +1,30 @@
+# 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/.
+{
+  'includes': [
+    '../../coreconf/config.gypi',
+    '../../cmd/platlibs.gypi'
+  ],
+  'targets': [
+    {
+      'target_name': 'validation',
+      'type': 'executable',
+      'sources': [
+        'validation.c'
+      ],
+      'dependencies': [
+        '<(DEPTH)/exports.gyp:dbm_exports',
+        '<(DEPTH)/exports.gyp:nss_exports'
+      ]
+    }
+  ],
+  'target_defaults': {
+    'defines': [
+      'NSPR20'
+    ]
+  },
+  'variables': {
+    'module': 'nss'
+  }
+}
--- a/lib/softoken/config.mk
+++ b/lib/softoken/config.mk
@@ -54,8 +54,12 @@ endif
 ifeq ($(OS_TARGET),AIX)
 OS_LIBS += -lpthread
 endif
 
 ifdef NSS_ENABLE_FIPS_INDICATORS
 DEFINES += -DNSS_ENABLE_FIPS_INDICATORS
 endif
 
+ifdef NSS_FIPS_MODULE_ID
+DEFINES += -DNSS_FIPS_MODULE_ID=\"${NSS_FIPS_MODULE_ID}\"
+endif
+
--- a/lib/softoken/pkcs11.c
+++ b/lib/softoken/pkcs11.c
@@ -70,17 +70,16 @@ static char manufacturerID_space[33];
 static char *libraryDescription = "NSS Internal Crypto Services    ";
 static char libraryDescription_space[33];
 
 /*
  * In FIPS mode, we disallow login attempts for 1 second after a login
  * failure so that there are at most 60 login attempts per minute.
  */
 static PRIntervalTime loginWaitTime;
-static PRUint32 minSessionObjectHandle = 1U;
 
 #define __PASTE(x, y) x##y
 
 /*
  * we renamed all our internal functions, get the correct
  * definitions for them...
  */
 #undef CK_PKCS11_FUNCTION_INFO
@@ -1667,18 +1666,16 @@ sftk_handleKeyParameterObject(SFTKSessio
  * will be assigned an object handle, and the object installed in the session
  * or stored in the DB.
  */
 CK_RV
 sftk_handleObject(SFTKObject *object, SFTKSession *session)
 {
     SFTKSlot *slot = session->slot;
     SFTKAttribute *attribute;
-    SFTKObject *duplicateObject = NULL;
-    CK_OBJECT_HANDLE handle;
     CK_BBOOL ckfalse = CK_FALSE;
     CK_BBOOL cktrue = CK_TRUE;
     CK_RV crv;
 
     /* make sure all the base object types are defined. If not set the
      * defaults */
     crv = sftk_defaultAttribute(object, CKA_TOKEN, &ckfalse, sizeof(CK_BBOOL));
     if (crv != CKR_OK)
@@ -1706,40 +1703,23 @@ sftk_handleObject(SFTKObject *object, SF
 
     /* Assign a unique SESSION object handle to every new object,
      * whether it is a session object or a token object.
      * At this point, all new objects are structured as session objects.
      * Objects with the CKA_TOKEN attribute true will be turned into
      * token objects and will have a token object handle assigned to
      * them by a call to sftk_mkHandle in the handler for each object
      * class, invoked below.
-     *
+     *  
      * It may be helpful to note/remember that
      * sftk_narrowToXxxObject uses sftk_isToken,
      * sftk_isToken examines the sign bit of the object's handle, but
      * sftk_isTrue(...,CKA_TOKEN) examines the CKA_TOKEN attribute.
      */
-    do {
-        PRUint32 wrappedAround;
-
-        duplicateObject = NULL;
-        PZ_Lock(slot->objectLock);
-        wrappedAround = slot->sessionObjectHandleCount & SFTK_TOKEN_MASK;
-        handle = slot->sessionObjectHandleCount & ~SFTK_TOKEN_MASK;
-        if (!handle) /* don't allow zero handle */
-            handle = minSessionObjectHandle;
-        slot->sessionObjectHandleCount = (handle + 1U) | wrappedAround;
-        /* Is there already a session object with this handle? */
-        if (wrappedAround) {
-            sftkqueue_find(duplicateObject, handle, slot->sessObjHashTable,
-                           slot->sessObjHashSize);
-        }
-        PZ_Unlock(slot->objectLock);
-    } while (duplicateObject != NULL);
-    object->handle = handle;
+    object->handle = sftk_getNextHandle(slot);
 
     /* get the object class */
     attribute = sftk_FindAttribute(object, CKA_CLASS);
     if (attribute == NULL) {
         return CKR_TEMPLATE_INCOMPLETE;
     }
     object->objclass = *(CK_OBJECT_CLASS *)attribute->attrib.pValue;
     sftk_FreeAttribute(attribute);
@@ -2870,28 +2850,39 @@ SFTK_SlotInit(char *configdir, char *upd
     if (slot->sessObjHashTable == NULL)
         goto mem_loser;
     slot->tokObjHashTable = PL_NewHashTable(64, sftk_HashNumber, PL_CompareValues,
                                             SECITEM_HashCompare, NULL, 0);
     if (slot->tokObjHashTable == NULL)
         goto mem_loser;
 
     slot->sessionIDCount = 0;
-    slot->sessionObjectHandleCount = minSessionObjectHandle;
+    slot->sessionObjectHandleCount = NSC_MIN_SESSION_OBJECT_HANDLE;
     slot->slotID = slotID;
     sftk_setStringName(params->slotdes ? params->slotdes : sftk_getDefSlotName(slotID), slot->slotDescription,
                        sizeof(slot->slotDescription), PR_TRUE);
+    crv = sftk_InitSession(&slot->moduleObjects, slot, slotID, NULL, NULL,
+                           CKF_SERIAL_SESSION);
+    if (crv != CKR_OK) {
+        goto loser;
+    }
 
     /* call the reinit code to set everything that changes between token
      * init calls */
     crv = SFTK_SlotReInit(slot, configdir, updatedir, updateID,
                           params, moduleIndex);
     if (crv != CKR_OK) {
         goto loser;
     }
+    if (sftk_isFIPS(slotID)) {
+        crv = sftk_CreateValidationObjects(slot);
+        if (crv != CKR_OK) {
+            goto loser;
+        }
+    }
     crv = sftk_RegisterSlot(slot, moduleIndex);
     if (crv != CKR_OK) {
         goto loser;
     }
     return CKR_OK;
 
 mem_loser:
     crv = CKR_HOST_MEMORY;
@@ -3027,16 +3018,18 @@ SFTK_ShutdownSlot(SFTKSlot *slot)
  */
 CK_RV
 SFTK_DestroySlotData(SFTKSlot *slot)
 {
     unsigned int i;
 
     SFTK_ShutdownSlot(slot);
 
+    sftk_ClearSession(&slot->moduleObjects);
+
     if (slot->tokObjHashTable) {
         PL_HashTableDestroy(slot->tokObjHashTable);
         slot->tokObjHashTable = NULL;
     }
 
     if (slot->sessObjHashTable) {
         PORT_Free(slot->sessObjHashTable);
         slot->sessObjHashTable = NULL;
@@ -3257,16 +3250,17 @@ extern void sftk_PBELockShutdown(void);
 
 /* NSC_Initialize initializes the Cryptoki library. */
 CK_RV
 nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS)
 {
     CK_RV crv = CKR_OK;
     SECStatus rv;
     CK_C_INITIALIZE_ARGS *init_args = (CK_C_INITIALIZE_ARGS *)pReserved;
+    PRBool destroy_freelist_on_error = PR_TRUE;
     int i;
     unsigned int moduleIndex = isFIPS ? NSC_FIPS_MODULE : NSC_NON_FIPS_MODULE;
 
     if (isFIPS) {
         loginWaitTime = PR_SecondsToInterval(1);
     }
 
     ENABLE_FORK_CHECK();
@@ -3336,32 +3330,40 @@ nsc_CommonInitialize(CK_VOID_PTR pReserv
                 if (isFIPS && nsc_init) {
                     sftk_LogAuditMessage(NSS_AUDIT_INFO, NSS_AUDIT_FIPS_STATE,
                                          "enabled FIPS mode");
                 } else {
                     sftk_LogAuditMessage(NSS_AUDIT_INFO, NSS_AUDIT_FIPS_STATE,
                                          "disabled FIPS mode");
                 }
             }
+            /* if we have a peer open, we don't want to destroy the freelist
+             * from under the peer if we fail, the free list will be
+             * destroyed in that case when the C_Finalize is called for
+             * the peer */
+            destroy_freelist_on_error = PR_FALSE;
         }
+        /* allow us to create objects in SFTK_SlotInit */
+        sftk_InitFreeLists();
 
         for (i = 0; i < paramStrings.token_count; i++) {
             crv = SFTK_SlotInit(paramStrings.configdir,
                                 paramStrings.updatedir, paramStrings.updateID,
                                 &paramStrings.tokens[i], moduleIndex);
             if (crv != CKR_OK) {
                 nscFreeAllSlots(moduleIndex);
                 break;
             }
         }
     loser:
         sftk_freeParams(&paramStrings);
     }
-    if (CKR_OK == crv) {
-        sftk_InitFreeLists();
+    if (destroy_freelist_on_error && (CKR_OK != crv)) {
+        /* idempotent. If the list are already freed, this is a noop */
+        sftk_CleanupFreeLists();
     }
 
 #ifndef NO_FORK_CHECK
     if (CKR_OK == crv) {
 #if defined(CHECK_FORK_MIXED)
         /* Before Solaris 10, fork handlers are not unregistered at dlclose()
          * time. So, we only use pthread_atfork on Solaris 10 and later. For
          * earlier versions, we use PID checks.
--- a/lib/softoken/pkcs11i.h
+++ b/lib/softoken/pkcs11i.h
@@ -44,16 +44,18 @@
                              * matching when doing C_FindObject on token \
                              * objects. This will slow down search in    \
                              * NSS. */
 /* default search block allocations and increments */
 #define NSC_CERT_BLOCK_SIZE 50
 #define NSC_SEARCH_BLOCK_SIZE 5
 #define NSC_SLOT_LIST_BLOCK_SIZE 10
 
+#define NSC_MIN_SESSION_OBJECT_HANDLE 1U
+
 #define NSC_FIPS_MODULE 1
 #define NSC_NON_FIPS_MODULE 0
 
 /* these are data base storage hashes, not cryptographic hashes.. The define
  * the effective size of the various object hash tables */
 /* clients care more about memory usage than lookup performance on
  * cyrptographic objects. Clients also have less objects around to play with
  *
@@ -370,16 +372,19 @@ struct SFTKSlotStr {
     PLHashTable *tokObjHashTable;  /* invariant */
     SFTKObject **sessObjHashTable; /* variable - reset */
     unsigned int sessObjHashSize;  /* invariant */
     SFTKSession **head;            /* variable -reset */
     unsigned int sessHashSize;     /* invariant */
     char tokDescription[33];       /* per load */
     char updateTokDescription[33]; /* per load */
     char slotDescription[65];      /* invariant */
+    SFTKSession moduleObjects;     /* global session to hang module specific
+                                    * objects like profile objects or
+                                    * validation objects */
 };
 
 /*
  * special joint operations Contexts
  */
 struct SFTKHashVerifyInfoStr {
     SECOidTag hashOid;
     void *params;
@@ -761,16 +766,17 @@ extern unsigned int sftk_MapTrust(CK_TRU
 
 extern SFTKObject *sftk_NewObject(SFTKSlot *slot);
 extern CK_RV sftk_CopyObject(SFTKObject *destObject, SFTKObject *srcObject);
 extern SFTKFreeStatus sftk_FreeObject(SFTKObject *object);
 extern CK_RV sftk_DeleteObject(SFTKSession *session, SFTKObject *object);
 extern void sftk_ReferenceObject(SFTKObject *object);
 extern SFTKObject *sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle,
                                          SFTKSession *session);
+extern CK_OBJECT_HANDLE sftk_getNextHandle(SFTKSlot *slot);
 extern void sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object);
 extern void sftk_AddObject(SFTKSession *session, SFTKObject *object);
 /* clear out all the existing object ID to database key mappings.
  * used to reinit a token */
 extern CK_RV SFTK_ClearTokenKeyHashTable(SFTKSlot *slot);
 
 extern CK_RV sftk_searchObjectList(SFTKSearchResults *search,
                                    SFTKObject **head, unsigned int size,
@@ -782,17 +788,21 @@ extern void sftk_FreeObjectList(SFTKObje
 extern void sftk_FreeSearch(SFTKSearchResults *search);
 extern CK_RV sftk_handleObject(SFTKObject *object, SFTKSession *session);
 
 extern SFTKSlot *sftk_SlotFromID(CK_SLOT_ID slotID, PRBool all);
 extern SFTKSlot *sftk_SlotFromSessionHandle(CK_SESSION_HANDLE handle);
 extern CK_SLOT_ID sftk_SlotIDFromSessionHandle(CK_SESSION_HANDLE handle);
 extern SFTKSession *sftk_SessionFromHandle(CK_SESSION_HANDLE handle);
 extern void sftk_FreeSession(SFTKSession *session);
+extern void sftk_ClearSession(SFTKSession *session);
 extern void sftk_DestroySession(SFTKSession *session);
+extern CK_RV sftk_InitSession(SFTKSession *session, SFTKSlot *slot,
+                              CK_SLOT_ID slotID, CK_NOTIFY notify,
+                              CK_VOID_PTR pApplication, CK_FLAGS flags);
 extern SFTKSession *sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify,
                                     CK_VOID_PTR pApplication, CK_FLAGS flags);
 extern void sftk_update_state(SFTKSlot *slot, SFTKSession *session);
 extern void sftk_update_all_states(SFTKSlot *slot);
 extern void sftk_InitFreeLists(void);
 extern void sftk_CleanupFreeLists(void);
 
 /*
@@ -950,11 +960,14 @@ const SECItem *sftk_VerifyDH_Prime(SECIt
 /* check if dhSubPrime claims dhPrime is a safe prime. */
 SECStatus sftk_IsSafePrime(SECItem *dhPrime, SECItem *dhSubPrime, PRBool *isSafe);
 /* map an operation Attribute to a Mechanism flag */
 CK_FLAGS sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE op);
 /* check the FIPS table to determine if this current operation is allowed by
  * FIPS security policy */
 PRBool sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech,
                             CK_ATTRIBUTE_TYPE op, SFTKObject *source);
+/* add validation objects to the slot */
+CK_RV sftk_CreateValidationObjects(SFTKSlot *slot);
+
 SEC_END_PROTOS
 
 #endif /* _PKCS11I_H_ */
--- a/lib/softoken/pkcs11u.c
+++ b/lib/softoken/pkcs11u.c
@@ -9,16 +9,17 @@
 #include "lowkeyi.h"
 #include "secasn1.h"
 #include "blapi.h"
 #include "secerr.h"
 #include "prnetdb.h" /* for PR_ntohl */
 #include "sftkdb.h"
 #include "softoken.h"
 #include "secoid.h"
+#include "softkver.h"
 
 #if !defined(NSS_FIPS_DISABLED) && defined(NSS_ENABLE_FIPS_INDICATORS)
 /* this file should be supplied by the vendor and include all the
  * algorithms which have Algorithm certs and have been reviewed by
  * the lab. A blank file is included for the base so that FIPS mode
  * will still be compiled and run, but FIPS indicators will always
  * return PR_FALSE
  */
@@ -1238,16 +1239,46 @@ sftk_FreeObject(SFTKObject *object)
         if (crv != CKR_OK) {
             return SFTK_DestroyFailure;
         }
         return SFTK_Destroyed;
     }
     return SFTK_Busy;
 }
 
+/* find the next available object handle that isn't currently in use */
+/* NOTE: This function could loop forever if we've exhausted all
+ * 3^31-1 handles. This is highly unlikely (NSS has been running for
+ * decades with this code) uless we start increasing the size of the
+ * SFTK_TOKEN_MASK (which is just the high bit currently). */
+CK_OBJECT_HANDLE
+sftk_getNextHandle(SFTKSlot *slot)
+{
+    CK_OBJECT_HANDLE handle;
+    SFTKObject *duplicateObject = NULL;
+    do {
+        PRUint32 wrappedAround;
+
+        duplicateObject = NULL;
+        PZ_Lock(slot->objectLock);
+        wrappedAround = slot->sessionObjectHandleCount & SFTK_TOKEN_MASK;
+        handle = slot->sessionObjectHandleCount & ~SFTK_TOKEN_MASK;
+        if (!handle) /* don't allow zero handle */
+            handle = NSC_MIN_SESSION_OBJECT_HANDLE;
+        slot->sessionObjectHandleCount = (handle + 1U) | wrappedAround;
+        /* Is there already a session object with this handle? */
+        if (wrappedAround) {
+            sftkqueue_find(duplicateObject, handle, slot->sessObjHashTable,
+                           slot->sessObjHashSize);
+        }
+        PZ_Unlock(slot->objectLock);
+    } while (duplicateObject != NULL);
+    return handle;
+}
+
 /*
  * add an object to a slot and session queue. These two functions
  * adopt the object.
  */
 void
 sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object)
 {
     PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize);
@@ -1843,61 +1874,76 @@ sftk_FreeContext(SFTKSessionContext *con
     if (context->key) {
         sftk_FreeObject(context->key);
         context->key = NULL;
     }
     PORT_Free(context);
 }
 
 /*
- * create a new nession. NOTE: The session handle is not set, and the
+ * Init a new session. NOTE: The session handle is not set, and the
  * session is not added to the slot's session queue.
  */
-SFTKSession *
-sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication,
-                CK_FLAGS flags)
+CK_RV
+sftk_InitSession(SFTKSession *session, SFTKSlot *slot, CK_SLOT_ID slotID,
+                 CK_NOTIFY notify, CK_VOID_PTR pApplication, CK_FLAGS flags)
 {
-    SFTKSession *session;
-    SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
-
-    if (slot == NULL)
-        return NULL;
-
-    session = (SFTKSession *)PORT_Alloc(sizeof(SFTKSession));
-    if (session == NULL)
-        return NULL;
-
     session->next = session->prev = NULL;
     session->enc_context = NULL;
     session->hash_context = NULL;
     session->sign_context = NULL;
     session->search = NULL;
     session->objectIDCount = 1;
     session->objectLock = PZ_NewLock(nssILockObject);
     if (session->objectLock == NULL) {
-        PORT_Free(session);
-        return NULL;
+        return CKR_HOST_MEMORY;
     }
     session->objects[0] = NULL;
 
     session->slot = slot;
     session->notify = notify;
     session->appData = pApplication;
     session->info.flags = flags;
     session->info.slotID = slotID;
     session->info.ulDeviceError = 0;
     sftk_update_state(slot, session);
     /* no ops completed yet, so the last one couldn't be a FIPS op */
     session->lastOpWasFIPS = PR_FALSE;
+    return CKR_OK;
+}
+
+/*
+ * Create a new session and init it.
+ */
+SFTKSession *
+sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication,
+                CK_FLAGS flags)
+{
+    SFTKSession *session;
+    SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
+    CK_RV crv;
+
+    if (slot == NULL)
+        return NULL;
+
+    session = (SFTKSession *)PORT_Alloc(sizeof(SFTKSession));
+    if (session == NULL)
+        return NULL;
+
+    crv = sftk_InitSession(session, slot, slotID, notify, pApplication, flags);
+    if (crv != CKR_OK) {
+        PORT_Free(session);
+        return NULL;
+    }
     return session;
 }
 
 /* free all the data associated with a session. */
 void
-sftk_DestroySession(SFTKSession *session)
+sftk_ClearSession(SFTKSession *session)
 {
     SFTKObjectList *op, *next;
 
     /* clean out the attributes */
     /* since no one is referencing us, it's safe to walk the chain
      * without a lock */
     for (op = session->objects[0]; op != NULL; op = next) {
         next = op->next;
@@ -1913,16 +1959,23 @@ sftk_DestroySession(SFTKSession *session
         sftk_FreeContext(session->hash_context);
     }
     if (session->sign_context) {
         sftk_FreeContext(session->sign_context);
     }
     if (session->search) {
         sftk_FreeSearch(session->search);
     }
+}
+
+/* free the data associated with the session, and the session */
+void
+sftk_DestroySession(SFTKSession *session)
+{
+    sftk_ClearSession(session);
     PORT_Free(session);
 }
 
 /*
  * look up a session structure from a session handle
  * generate a reference to it.
  */
 SFTKSession *
@@ -2381,8 +2434,75 @@ sftk_operationIsFIPS(SFTKSlot *slot, CK_
             ((mechs->special == SFTKFIPSNone) ||
              sftk_handleSpecial(slot, mech, mechs, source))) {
             return PR_TRUE;
         }
     }
     return PR_FALSE;
 #endif
 }
+
+/*
+ * create the FIPS Validation objects. If the vendor
+ * doesn't supply an NSS_FIPS_MODULE_ID, at compile time,
+ * then we assumethis is an unvalidated module.
+ */
+CK_RV
+sftk_CreateValidationObjects(SFTKSlot *slot)
+{
+    const char *module_id;
+    int module_id_len;
+    CK_RV crv = CKR_OK;
+    /* we currently use vendor specific values until the validation
+     * objects are approved for PKCS #11 v3.2. */
+    CK_OBJECT_CLASS cko_validation = CKO_NSS_VALIDATION;
+    CK_NSS_VALIDATION_TYPE ckv_fips = CKV_NSS_FIPS_140;
+    CK_VERSION fips_version = { 3, 0 }; /* FIPS-140-3 */
+    CK_ULONG fips_level = 1;            /* or 2 if you validated at level 2 */
+
+#ifndef NSS_FIPS_MODULE_ID
+#define NSS_FIPS_MODULE_ID "Generic NSS " SOFTOKEN_VERSION " Unvalidated"
+#endif
+    module_id = NSS_FIPS_MODULE_ID;
+    module_id_len = sizeof(NSS_FIPS_MODULE_ID) - 1;
+    SFTKObject *object;
+
+    object = sftk_NewObject(slot); /* fill in the handle later */
+    if (object == NULL) {
+        return CKR_HOST_MEMORY;
+    }
+    object->isFIPS = PR_FALSE;
+
+    crv = sftk_AddAttributeType(object, CKA_CLASS,
+                                &cko_validation, sizeof(cko_validation));
+    if (crv != CKR_OK) {
+        goto loser;
+    }
+    crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_TYPE,
+                                &ckv_fips, sizeof(ckv_fips));
+    if (crv != CKR_OK) {
+        goto loser;
+    }
+    crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_VERSION,
+                                &fips_version, sizeof(fips_version));
+    if (crv != CKR_OK) {
+        goto loser;
+    }
+    crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_LEVEL,
+                                &fips_level, sizeof(fips_level));
+    if (crv != CKR_OK) {
+        goto loser;
+    }
+    crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_MODULE_ID,
+                                module_id, module_id_len);
+    if (crv != CKR_OK) {
+        goto loser;
+    }
+
+    /* future, fill in validation certificate information from a supplied
+     * pointer to a config file */
+    object->handle = sftk_getNextHandle(slot);
+    object->slot = slot;
+    sftk_AddObject(&slot->moduleObjects, object);
+loser:
+    sftk_FreeObject(object);
+    return crv;
+}
--- a/lib/util/pkcs11n.h
+++ b/lib/util/pkcs11n.h
@@ -33,16 +33,19 @@
 #define CKO_NSS (CKO_VENDOR_DEFINED | NSSCK_VENDOR_NSS)
 
 #define CKO_NSS_CRL (CKO_NSS + 1)
 #define CKO_NSS_SMIME (CKO_NSS + 2)
 #define CKO_NSS_TRUST (CKO_NSS + 3)
 #define CKO_NSS_BUILTIN_ROOT_LIST (CKO_NSS + 4)
 #define CKO_NSS_NEWSLOT (CKO_NSS + 5)
 #define CKO_NSS_DELSLOT (CKO_NSS + 6)
+#define CKO_NSS_VALIDATION (CKO_NSS + 7)
+
+#define CKV_NSS_FIPS_140 (CKO_NSS + 1)
 
 /*
  * NSS-defined key types
  *
  */
 #define CKK_NSS (CKK_VENDOR_DEFINED | NSSCK_VENDOR_NSS)
 
 #define CKK_NSS_PKCS8 (CKK_NSS + 1)
@@ -94,16 +97,21 @@
 #define CKA_NSS_JPAKE_GX4 (CKA_NSS + 31)
 #define CKA_NSS_JPAKE_X2 (CKA_NSS + 32)
 #define CKA_NSS_JPAKE_X2S (CKA_NSS + 33)
 
 #define CKA_NSS_MOZILLA_CA_POLICY (CKA_NSS + 34)
 #define CKA_NSS_SERVER_DISTRUST_AFTER (CKA_NSS + 35)
 #define CKA_NSS_EMAIL_DISTRUST_AFTER (CKA_NSS + 36)
 
+#define CKA_NSS_VALIDATION_TYPE (CKA_NSS + 36)
+#define CKA_NSS_VALIDATION_VERSION (CKA_NSS + 37)
+#define CKA_NSS_VALIDATION_LEVEL (CKA_NSS + 38)
+#define CKA_NSS_VALIDATION_MODULE_ID (CKA_NSS + 39)
+
 /*
  * Trust attributes:
  *
  * If trust goes standard, these probably will too.  So I'll
  * put them all in one place.
  */
 
 #define CKA_TRUST (CKA_NSS + 0x2000)
@@ -339,16 +347,19 @@ typedef struct CK_NSS_AEAD_PARAMS {
  * NSS-defined return values
  *
  */
 #define CKR_NSS (CKM_VENDOR_DEFINED | NSSCK_VENDOR_NSS)
 
 #define CKR_NSS_CERTDB_FAILED (CKR_NSS + 1)
 #define CKR_NSS_KEYDB_FAILED (CKR_NSS + 2)
 
+/* NSS specific types */
+typedef CK_ULONG CK_NSS_VALIDATION_TYPE;
+
 /* Mandatory parameter for the CKM_NSS_HKDF_* key deriviation mechanisms.
    See RFC 5869.
 
     bExtract: If set, HKDF-Extract will be applied to the input key. If
               the optional salt is given, it is used; otherwise, the salt is
               set to a sequence of zeros equal in length to the HMAC output.
               If bExpand is not set, then the key template given to
               C_DeriveKey must indicate an output key size less than or equal
--- a/nss.gyp
+++ b/nss.gyp
@@ -126,16 +126,17 @@
               'dependencies': [
                 'cmd/crlutil/crlutil.gyp:crlutil',
                 'cmd/pwdecrypt/pwdecrypt.gyp:pwdecrypt',
                 'cmd/signtool/signtool.gyp:signtool',
                 'cmd/signver/signver.gyp:signver',
                 'cmd/smimetools/smimetools.gyp:cmsutil',
                 'cmd/ssltap/ssltap.gyp:ssltap',
                 'cmd/symkeyutil/symkeyutil.gyp:symkeyutil',
+                'cmd/validation/validation.gyp:validation',
                 'nss-tool/nss_tool.gyp:nss',
                 'nss-tool/nss_tool.gyp:hw-support',
               ],
             }],
           ],
         },
       ],
     }, { # else, i.e. mozpkix_only==1
Лучший частный хостинг