summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Relyea <rrelyea@redhat.com>2021-09-07 16:18:08 -0700
committerRobert Relyea <rrelyea@redhat.com>2021-09-07 16:18:08 -0700
commit3aac321166c6f2e1574431340ae4ffcda499a7c3 (patch)
tree4ae0c25ffb5ace3d6eafe060f8984dab708b51f3
parentff2a9a912667c239486de4351422bee7fabbd337 (diff)
downloadnss-hg-3aac321166c6f2e1574431340ae4ffcda499a7c3.tar.gz
Bug 1729550 NSS needs FiPS 140-3 version indicators.NSS_3_73_BETA1
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
-rw-r--r--cmd/manifest.mn1
-rw-r--r--cmd/validation/Makefile48
-rw-r--r--cmd/validation/manifest.mn23
-rw-r--r--cmd/validation/validation.c251
-rw-r--r--cmd/validation/validation.gyp30
-rw-r--r--lib/softoken/config.mk4
-rw-r--r--lib/softoken/pkcs11.c52
-rw-r--r--lib/softoken/pkcs11i.h13
-rw-r--r--lib/softoken/pkcs11u.c154
-rw-r--r--lib/util/pkcs11n.h11
-rw-r--r--nss.gyp1
11 files changed, 546 insertions, 42 deletions
diff --git a/cmd/manifest.mn b/cmd/manifest.mn
index bb5319a0f..aafcf86fd 100644
--- a/cmd/manifest.mn
+++ b/cmd/manifest.mn
@@ -76,6 +76,7 @@ NSS_SRCDIRS = \
symkeyutil \
tests \
tstclnt \
+ validation \
vfychain \
vfyserv \
modutil \
diff --git a/cmd/validation/Makefile b/cmd/validation/Makefile
new file mode 100644
index 000000000..d7c879aec
--- /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
+
diff --git a/cmd/validation/manifest.mn b/cmd/validation/manifest.mn
new file mode 100644
index 000000000..98fbe341d
--- /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
diff --git a/cmd/validation/validation.c b/cmd/validation/validation.c
new file mode 100644
index 000000000..f7b32a6f8
--- /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;
+}
diff --git a/cmd/validation/validation.gyp b/cmd/validation/validation.gyp
new file mode 100644
index 000000000..32edd30a4
--- /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'
+ }
+}
diff --git a/lib/softoken/config.mk b/lib/softoken/config.mk
index 771b93a3f..339f80493 100644
--- a/lib/softoken/config.mk
+++ b/lib/softoken/config.mk
@@ -59,3 +59,7 @@ 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
+
diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c
index 3f49333f8..dcb0c729d 100644
--- a/lib/softoken/pkcs11.c
+++ b/lib/softoken/pkcs11.c
@@ -75,7 +75,6 @@ static char libraryDescription_space[33];
* 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
@@ -1672,8 +1671,6 @@ 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;
@@ -1711,30 +1708,13 @@ sftk_handleObject(SFTKObject *object, SFTKSession *session)
* 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);
@@ -2875,10 +2855,15 @@ SFTK_SlotInit(char *configdir, char *updatedir, char *updateID,
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 */
@@ -2887,6 +2872,12 @@ SFTK_SlotInit(char *configdir, char *updatedir, char *updateID,
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;
@@ -3032,6 +3023,8 @@ SFTK_DestroySlotData(SFTKSlot *slot)
SFTK_ShutdownSlot(slot);
+ sftk_ClearSession(&slot->moduleObjects);
+
if (slot->tokObjHashTable) {
PL_HashTableDestroy(slot->tokObjHashTable);
slot->tokObjHashTable = NULL;
@@ -3262,6 +3255,7 @@ 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;
@@ -3341,7 +3335,14 @@ nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS)
"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,
@@ -3355,8 +3356,9 @@ nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS)
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
diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h
index 032e85fee..4365a115c 100644
--- a/lib/softoken/pkcs11i.h
+++ b/lib/softoken/pkcs11i.h
@@ -49,6 +49,8 @@
#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
@@ -375,6 +377,9 @@ struct SFTKSlotStr {
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 */
};
/*
@@ -766,6 +771,7 @@ 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.
@@ -787,7 +793,11 @@ 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);
@@ -955,6 +965,9 @@ CK_FLAGS sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE op);
* 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_ */
diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c
index f37aab92f..5299a700a 100644
--- a/lib/softoken/pkcs11u.c
+++ b/lib/softoken/pkcs11u.c
@@ -14,6 +14,7 @@
#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
@@ -1243,6 +1244,36 @@ sftk_FreeObject(SFTKObject *object)
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.
@@ -1848,23 +1879,13 @@ sftk_FreeContext(SFTKSessionContext *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;
@@ -1873,8 +1894,7 @@ sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication,
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;
@@ -1887,12 +1907,38 @@ sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication,
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;
@@ -1918,6 +1964,13 @@ sftk_DestroySession(SFTKSession *session)
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);
}
@@ -2386,3 +2439,70 @@ sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech, CK_ATTRIBUTE_TYPE op,
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;
+}
diff --git a/lib/util/pkcs11n.h b/lib/util/pkcs11n.h
index 9a8126a82..cb7672048 100644
--- a/lib/util/pkcs11n.h
+++ b/lib/util/pkcs11n.h
@@ -38,6 +38,9 @@
#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
@@ -99,6 +102,11 @@
#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:
*
@@ -344,6 +352,9 @@ typedef struct CK_NSS_AEAD_PARAMS {
#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.
diff --git a/nss.gyp b/nss.gyp
index 1b917386c..dfc723259 100644
--- a/nss.gyp
+++ b/nss.gyp
@@ -131,6 +131,7 @@
'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',
],