summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--automation/abi-check/expected-report-libnss3.so.txt17
-rw-r--r--automation/abi-check/expected-report-libssl3.so.txt10
-rw-r--r--cmd/selfserv/selfserv.c5
-rw-r--r--cmd/strsclnt/strsclnt.c5
-rw-r--r--cmd/tstclnt/tstclnt.c5
-rw-r--r--lib/nss/nss.def10
-rw-r--r--lib/pk11wrap/pk11cxt.c10
-rw-r--r--lib/pk11wrap/pk11load.c7
-rw-r--r--lib/pk11wrap/pk11obj.c15
-rw-r--r--lib/pk11wrap/pk11priv.h5
-rw-r--r--lib/pk11wrap/pk11pub.h18
-rw-r--r--lib/pk11wrap/pk11slot.c33
-rw-r--r--lib/pk11wrap/secmodt.h3
-rw-r--r--lib/softoken/config.mk5
-rw-r--r--lib/softoken/fips_algorithms.h170
-rw-r--r--lib/softoken/fipstokn.c5
-rw-r--r--lib/softoken/pkcs11.c166
-rw-r--r--lib/softoken/pkcs11c.c48
-rw-r--r--lib/softoken/pkcs11i.h12
-rw-r--r--lib/softoken/pkcs11u.c264
-rw-r--r--lib/softoken/sftkmessage.c4
-rw-r--r--lib/ssl/ssl3con.c35
-rw-r--r--lib/ssl/sslimpl.h3
-rw-r--r--lib/ssl/sslinfo.c1
-rw-r--r--lib/ssl/sslt.h5
-rw-r--r--lib/util/pkcs11n.h24
-rwxr-xr-xtests/ssl/ssl.sh129
-rw-r--r--tests/ssl/sslcov.txt7
28 files changed, 901 insertions, 120 deletions
diff --git a/automation/abi-check/expected-report-libnss3.so.txt b/automation/abi-check/expected-report-libnss3.so.txt
index e69de29bb..d34243d92 100644
--- a/automation/abi-check/expected-report-libnss3.so.txt
+++ b/automation/abi-check/expected-report-libnss3.so.txt
@@ -0,0 +1,17 @@
+
+3 Added functions:
+
+ 'function PRBool PK11_ContextGetFIPSStatus(PK11Context*)' {PK11_ContextGetFIPSStatus@@NSS_3.66}
+ 'function PRBool PK11_ObjectGetFIPSStatus(PK11ObjectType, void*)' {PK11_ObjectGetFIPSStatus@@NSS_3.66}
+ 'function PRBool PK11_SlotGetLastFIPSStatus(PK11SlotInfo*)' {PK11_SlotGetLastFIPSStatus@@NSS_3.66}
+
+1 function with some indirect sub-type change:
+
+ [C]'function SECStatus PK11_GetModInfo(SECMODModule*, CK_INFO*)' at pk11util.c:613:1 has some indirect sub-type changes:
+ parameter 1 of type 'SECMODModule*' has sub-type changes:
+ in pointed to type 'typedef SECMODModule' at secmodt.h:29:1:
+ underlying type 'struct SECMODModuleStr' at secmodt.h:44:1 changed:
+ type size changed from 1664 to 1728 bits
+ 1 data member insertion:
+ 'CK_NSS_GetFIPSStatus SECMODModuleStr::fipsIndicator', at offset 1664 (in bits) at secmodt.h:79:1
+ no data member changes (2 filtered);
diff --git a/automation/abi-check/expected-report-libssl3.so.txt b/automation/abi-check/expected-report-libssl3.so.txt
index e69de29bb..e3bb57179 100644
--- a/automation/abi-check/expected-report-libssl3.so.txt
+++ b/automation/abi-check/expected-report-libssl3.so.txt
@@ -0,0 +1,10 @@
+
+1 function with some indirect sub-type change:
+
+ [C]'function SECStatus SSL_GetChannelInfo(PRFileDesc*, SSLChannelInfo*, PRUintn)' at sslinfo.c:14:1 has some indirect sub-type changes:
+ parameter 2 of type 'SSLChannelInfo*' has sub-type changes:
+ in pointed to type 'typedef SSLChannelInfo' at sslt.h:383:1:
+ underlying type 'struct SSLChannelInfoStr' at sslt.h:299:1 changed:
+ type size changed from 1024 to 1088 bits
+ 1 data member insertion:
+ 'PRBool SSLChannelInfoStr::isFIPS', at offset 1024 (in bits) at sslt.h:379:1
diff --git a/cmd/selfserv/selfserv.c b/cmd/selfserv/selfserv.c
index 00de3a6b7..5094cc7bf 100644
--- a/cmd/selfserv/selfserv.c
+++ b/cmd/selfserv/selfserv.c
@@ -404,10 +404,11 @@ printSecurityInfo(PRFileDesc *fd)
&suite, sizeof suite);
if (result == SECSuccess) {
FPRINTF(stderr,
- "selfserv: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
+ "selfserv: SSL version %d.%d using %d-bit %s with %d-bit %s MAC%s\n",
channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
suite.effectiveKeyBits, suite.symCipherName,
- suite.macBits, suite.macAlgorithmName);
+ suite.macBits, suite.macAlgorithmName,
+ channel.isFIPS ? " FIPS" : "");
FPRINTF(stderr,
"selfserv: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
" Compression: %s, Extended Master Secret: %s\n",
diff --git a/cmd/strsclnt/strsclnt.c b/cmd/strsclnt/strsclnt.c
index 3d9fc4f78..7bc36db3f 100644
--- a/cmd/strsclnt/strsclnt.c
+++ b/cmd/strsclnt/strsclnt.c
@@ -295,10 +295,11 @@ printSecurityInfo(PRFileDesc *fd)
&suite, sizeof suite);
if (result == SECSuccess) {
FPRINTF(stderr,
- "strsclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
+ "strsclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC%s\n",
channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
suite.effectiveKeyBits, suite.symCipherName,
- suite.macBits, suite.macAlgorithmName);
+ suite.macBits, suite.macAlgorithmName,
+ channel.isFIPS ? " FIPS" : "");
FPRINTF(stderr,
"strsclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
" Compression: %s\n",
diff --git a/cmd/tstclnt/tstclnt.c b/cmd/tstclnt/tstclnt.c
index 2c108c612..8b9efa007 100644
--- a/cmd/tstclnt/tstclnt.c
+++ b/cmd/tstclnt/tstclnt.c
@@ -168,10 +168,11 @@ printSecurityInfo(PRFileDesc *fd)
&suite, sizeof suite);
if (result == SECSuccess) {
FPRINTF(stderr,
- "tstclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
+ "tstclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC%s\n",
channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
suite.effectiveKeyBits, suite.symCipherName,
- suite.macBits, suite.macAlgorithmName);
+ suite.macBits, suite.macAlgorithmName,
+ channel.isFIPS ? " FIPS" : "");
FPRINTF(stderr,
"tstclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
" Compression: %s, Extended Master Secret: %s\n"
diff --git a/lib/nss/nss.def b/lib/nss/nss.def
index 46bd41a60..e87395ba9 100644
--- a/lib/nss/nss.def
+++ b/lib/nss/nss.def
@@ -1222,11 +1222,19 @@ PK11_HPKE_ImportContext;
;+};
;+NSS_3.65 { # NSS 3.65 release
;+ global:
+HASH_GetHMACOidTagByHashOidTag;
PK11_CreateContextByPubKey;
PK11_CreateContextByPrivKey;
PK11_ExportEncryptedPrivKeyInfoV2;
PK11_ExportEncryptedPrivateKeyInfoV2;
-HASH_GetHMACOidTagByHashOidTag;
+;+ local:
+;+ *;
+;+};
+;+NSS_3.66 { # NSS 3.66 release
+;+ global:
+PK11_ContextGetFIPSStatus;
+PK11_ObjectGetFIPSStatus;
+PK11_SlotGetLastFIPSStatus;
;+ local:
;+ *;
;+};
diff --git a/lib/pk11wrap/pk11cxt.c b/lib/pk11wrap/pk11cxt.c
index 3e80e8754..d94d6fc68 100644
--- a/lib/pk11wrap/pk11cxt.c
+++ b/lib/pk11wrap/pk11cxt.c
@@ -1783,3 +1783,13 @@ PK11_DigestFinal(PK11Context *context, unsigned char *data,
*outLen = (unsigned int)len;
return SECSuccess;
}
+
+PRBool
+PK11_ContextGetFIPSStatus(PK11Context *context)
+{
+ if (context->slot == NULL) {
+ return PR_FALSE;
+ }
+ return pk11slot_GetFIPSStatus(context->slot, context->session,
+ CK_INVALID_HANDLE, context->init ? CKT_NSS_SESSION_CHECK : CKT_NSS_SESSION_LAST_CHECK);
+}
diff --git a/lib/pk11wrap/pk11load.c b/lib/pk11wrap/pk11load.c
index 2bc41dbc4..a318e92fa 100644
--- a/lib/pk11wrap/pk11load.c
+++ b/lib/pk11wrap/pk11load.c
@@ -409,6 +409,8 @@ secmod_LoadPKCS11Module(SECMODModule *mod, SECMODModule **oldModule)
if (mod->loaded)
return SECSuccess;
+ mod->fipsIndicator = NULL;
+
/* internal modules get loaded from their internal list */
if (mod->internal && (mod->dllName == NULL)) {
#ifdef NSS_STATIC_SOFTOKEN
@@ -514,6 +516,11 @@ secmod_LoadPKCS11Module(SECMODModule *mod, SECMODModule **oldModule)
}
mod->functionList = interface->pFunctionList;
mod->flags = interface->flags;
+ /* if we have a fips indicator, grab it */
+ if ((*ientry)((CK_UTF8CHAR_PTR) "Vendor NSS FIPS Interface", NULL,
+ &interface, 0) == CKR_OK) {
+ mod->fipsIndicator = ((CK_NSS_FIPS_FUNCTIONS *)(interface->pFunctionList))->NSC_NSSGetFIPSStatus;
+ }
} else {
if ((*fentry)((CK_FUNCTION_LIST_PTR *)&mod->functionList) != CKR_OK)
goto fail;
diff --git a/lib/pk11wrap/pk11obj.c b/lib/pk11wrap/pk11obj.c
index aaaf6586f..8ece7a6d4 100644
--- a/lib/pk11wrap/pk11obj.c
+++ b/lib/pk11wrap/pk11obj.c
@@ -2265,3 +2265,18 @@ pk11_GetLowLevelKeyFromHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle)
return item;
}
+
+PRBool
+PK11_ObjectGetFIPSStatus(PK11ObjectType objType, void *objSpec)
+{
+ PK11SlotInfo *slot = NULL;
+ CK_OBJECT_HANDLE handle = 0;
+
+ handle = PK11_GetObjectHandle(objType, objSpec, &slot);
+ if (handle == CK_INVALID_HANDLE) {
+ PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
+ return PR_FALSE;
+ }
+ return pk11slot_GetFIPSStatus(slot, slot->session, handle,
+ CKT_NSS_OBJECT_CHECK);
+}
diff --git a/lib/pk11wrap/pk11priv.h b/lib/pk11wrap/pk11priv.h
index e9977cfdb..faf9ad298 100644
--- a/lib/pk11wrap/pk11priv.h
+++ b/lib/pk11wrap/pk11priv.h
@@ -200,6 +200,11 @@ SECStatus pk11_setGlobalOptions(PRBool noSingleThreadedModules,
/* return whether NSS is allowed to call C_Finalize */
PRBool pk11_getFinalizeModulesOption(void);
+/* fetch the FIPS state from the fips indicator, public versions of
+ * this function operate on the slot, the context, and the object */
+PRBool pk11slot_GetFIPSStatus(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object, CK_ULONG operationType);
+
SEC_END_PROTOS
#endif
diff --git a/lib/pk11wrap/pk11pub.h b/lib/pk11wrap/pk11pub.h
index 53350f76d..a2a647320 100644
--- a/lib/pk11wrap/pk11pub.h
+++ b/lib/pk11wrap/pk11pub.h
@@ -1029,6 +1029,24 @@ PRBool SECMOD_HasRootCerts(void);
*/
int SECMOD_GetSystemFIPSEnabled(void);
+/* FIPS indicator functions. Some operations are physically allowed, but
+ * are against the NSS FIPS security policy. This is because sometimes NSS
+ * functions are used in non-security contexts. You can call these functions
+ * to determine if you are operating inside or outside the the current vendor's
+ * FIPS Security Policy for NSS. NOTE: if the current version of NSS is not
+ * actually FIPS certified, then these functions will always return PR_FALSE */
+
+/* This function tells if if the last single shot operation on the slot
+ * was inside or outside the FIPS security policy */
+PRBool PK11_SlotGetLastFIPSStatus(PK11SlotInfo *slot);
+/* This tells you if the current operation is within the FIPS security policy. If
+ * you have called finalize on the context, it tells you if the last operation
+ * was within the FIPS security policy */
+PRBool PK11_ContextGetFIPSStatus(PK11Context *context);
+/* This tells you if the requested object was created in accordance to the
+ * NSS FIPS security policy. */
+PRBool PK11_ObjectGetFIPSStatus(PK11ObjectType objType, void *objSpec);
+
SEC_END_PROTOS
#endif
diff --git a/lib/pk11wrap/pk11slot.c b/lib/pk11wrap/pk11slot.c
index 2f805431d..c320019f9 100644
--- a/lib/pk11wrap/pk11slot.c
+++ b/lib/pk11wrap/pk11slot.c
@@ -2665,6 +2665,39 @@ PK11Slot_GetNSSToken(PK11SlotInfo *sl)
return sl->nssToken;
}
+PRBool
+pk11slot_GetFIPSStatus(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object, CK_ULONG operationType)
+{
+ SECMODModule *mod = slot->module;
+ CK_RV crv;
+ CK_ULONG fipsState = CKS_NSS_FIPS_NOT_OK;
+
+ /* handle the obvious conditions:
+ * 1) the module doesn't have a fipsIndicator - fips state must be false */
+ if (mod->fipsIndicator == NULL) {
+ return PR_FALSE;
+ }
+ /* 2) the session doesn't exist - fips state must be false */
+ if (session == CK_INVALID_HANDLE) {
+ return PR_FALSE;
+ }
+
+ /* go fetch the state */
+ crv = mod->fipsIndicator(session, object, operationType, &fipsState);
+ if (crv != CKR_OK) {
+ return PR_FALSE;
+ }
+ return (fipsState == CKS_NSS_FIPS_OK) ? PR_TRUE : PR_FALSE;
+}
+
+PRBool
+PK11_SlotGetLastFIPSStatus(PK11SlotInfo *slot)
+{
+ return pk11slot_GetFIPSStatus(slot, slot->session, CK_INVALID_HANDLE,
+ CKT_NSS_SESSION_LAST_CHECK);
+}
+
/*
* wait for a token to change it's state. The application passes in the expected
* new state in event.
diff --git a/lib/pk11wrap/secmodt.h b/lib/pk11wrap/secmodt.h
index 34fd4cce1..5f15e5967 100644
--- a/lib/pk11wrap/secmodt.h
+++ b/lib/pk11wrap/secmodt.h
@@ -74,6 +74,9 @@ struct SECMODModuleStr {
* events (SECMOD_WaitForAnyTokenEvent) */
CK_VERSION cryptokiVersion; /* version of this library */
CK_FLAGS flags; /* pkcs11 v3 flags */
+ /* Warning this could go way in future versions of NSS
+ * when FIPS indicators wind up in the functionList */
+ CK_NSS_GetFIPSStatus fipsIndicator;
};
/* evControlMask flags */
diff --git a/lib/softoken/config.mk b/lib/softoken/config.mk
index 14ea5d6e4..771b93a3f 100644
--- a/lib/softoken/config.mk
+++ b/lib/softoken/config.mk
@@ -54,3 +54,8 @@ endif
ifeq ($(OS_TARGET),AIX)
OS_LIBS += -lpthread
endif
+
+ifdef NSS_ENABLE_FIPS_INDICATORS
+DEFINES += -DNSS_ENABLE_FIPS_INDICATORS
+endif
+
diff --git a/lib/softoken/fips_algorithms.h b/lib/softoken/fips_algorithms.h
new file mode 100644
index 000000000..c964d2eea
--- /dev/null
+++ b/lib/softoken/fips_algorithms.h
@@ -0,0 +1,170 @@
+/* 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/. */
+
+/*
+ * Vendors should replace this header file with the file containing those
+ * algorithms which have NIST algorithm Certificates.
+ */
+
+/* handle special cases. Classes require existing code to already be
+ * in place for that class */
+typedef enum {
+ SFTKFIPSNone = 0,
+ SFTKFIPSDH, /* allow only specific primes */
+ SFTKFIPSECC, /* not just keys but specific curves */
+ SFTKFIPSAEAD /* single shot AEAD functions not allowed in FIPS mode */
+} SFTKFIPSSpecialClass;
+
+typedef struct SFTKFIPSAlgorithmListStr SFTKFIPSAlgorithmList;
+struct SFTKFIPSAlgorithmListStr {
+ CK_MECHANISM_TYPE type;
+ CK_MECHANISM_INFO info;
+ CK_ULONG step;
+ SFTKFIPSSpecialClass special;
+};
+
+SFTKFIPSAlgorithmList sftk_fips_mechs[] = {
+/* A sample set of algorithms to allow basic testing in our continous
+ * testing infrastructure. The vendor version should replace this with
+ * a version that matches their algorithm testing and security policy */
+/* NOTE, This looks a lot like the PKCS #11 mechanism list in pkcs11.c, it
+ * differs in the following ways:
+ * 1) the addition of step and class elements to help restrict
+ * the supported key sizes and types.
+ * 2) The mechanism flags are restricted to only those that map to
+ * fips approved operations.
+ * 3) All key sizes are in bits, independent of mechanism.
+ * 4) You can add more then one entry for the same mechanism to handle
+ * multiple descrete keys where the MIN/MAX/STEP semantics doesn't apply
+ * or where different operations have different key requirements.
+ * This table does not encode all the modules legal FIPS semantics, only
+ * those semantics that might possibly change due to algorithms dropping
+ * of the security policy late in the process. */
+/* handy common flag types */
+#define CKF_KPG CKF_GENERATE_KEY_PAIR
+#define CKF_GEN CKF_GENERATE
+#define CKF_SGN (CKF_SIGN | CKF_VERIFY)
+#define CKF_ENC (CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP)
+#define CKF_KEK (CKF_WRAP | CKF_UNWRAP)
+#define CKF_KEA CKF_DERIVE
+#define CKF_KDF CKF_DERIVE
+#define CKF_HSH CKF_DIGEST
+#define CK_MAX 0xffffffffUL
+/* mechanisms using the same key types share the same key type
+ * limits */
+#define RSA_FB_KEY 2048, 4096 /* min, max */
+#define RSA_FB_STEP 1024
+#define DSA_FB_KEY 2048, 4096 /* min, max */
+#define DSA_FB_STEP 1024
+#define DH_FB_KEY 2048, 4096 /* min, max */
+#define DH_FB_STEP 1024
+#define EC_FB_KEY 256, 521 /* min, max */
+#define EC_FB_STEP 1 /* key limits handled by special operation */
+#define AES_FB_KEY 128, 256
+#define AES_FB_STEP 64
+ { CKM_RSA_PKCS_KEY_PAIR_GEN, { RSA_FB_KEY, CKF_KPG }, RSA_FB_STEP, SFTKFIPSNone },
+ { CKM_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+ { CKM_RSA_PKCS_OAEP, { RSA_FB_KEY, CKF_ENC }, RSA_FB_STEP, SFTKFIPSNone },
+ /* -------------- RSA Multipart Signing Operations -------------------- */
+ { CKM_SHA224_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+ { CKM_SHA256_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+ { CKM_SHA384_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+ { CKM_SHA512_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+ { CKM_SHA224_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+ { CKM_SHA256_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+ { CKM_SHA384_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+ { CKM_SHA512_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+ /* ------------------------- DSA Operations --------------------------- */
+ { CKM_DSA_KEY_PAIR_GEN, { DSA_FB_KEY, CKF_KPG }, DSA_FB_STEP, SFTKFIPSNone },
+ { CKM_DSA, { DSA_FB_KEY, CKF_SGN }, DSA_FB_STEP, SFTKFIPSNone },
+ { CKM_DSA_PARAMETER_GEN, { DSA_FB_KEY, CKF_KPG }, DSA_FB_STEP, SFTKFIPSNone },
+ { CKM_DSA_SHA224, { DSA_FB_KEY, CKF_SGN }, DSA_FB_STEP, SFTKFIPSNone },
+ { CKM_DSA_SHA256, { DSA_FB_KEY, CKF_SGN }, DSA_FB_STEP, SFTKFIPSNone },
+ { CKM_DSA_SHA384, { DSA_FB_KEY, CKF_SGN }, DSA_FB_STEP, SFTKFIPSNone },
+ { CKM_DSA_SHA512, { DSA_FB_KEY, CKF_SGN }, DSA_FB_STEP, SFTKFIPSNone },
+ /* -------------------- Diffie Hellman Operations --------------------- */
+ /* no diffie hellman yet */
+ { CKM_DH_PKCS_KEY_PAIR_GEN, { DH_FB_KEY, CKF_KPG }, DH_FB_STEP, SFTKFIPSDH },
+ { CKM_DH_PKCS_DERIVE, { DH_FB_KEY, CKF_KEA }, DH_FB_STEP, SFTKFIPSDH },
+ /* -------------------- Elliptic Curve Operations --------------------- */
+ { CKM_EC_KEY_PAIR_GEN, { EC_FB_KEY, CKF_KPG }, EC_FB_STEP, SFTKFIPSECC },
+ { CKM_ECDH1_DERIVE, { EC_FB_KEY, CKF_KEA }, EC_FB_STEP, SFTKFIPSECC },
+ { CKM_ECDSA, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC },
+ { CKM_ECDSA_SHA224, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC },
+ { CKM_ECDSA_SHA256, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC },
+ { CKM_ECDSA_SHA384, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC },
+ { CKM_ECDSA_SHA512, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC },
+ /* ------------------------- RC2 Operations --------------------------- */
+ /* ------------------------- AES Operations --------------------------- */
+ { CKM_AES_KEY_GEN, { AES_FB_KEY, CKF_GEN }, AES_FB_STEP, SFTKFIPSNone },
+ { CKM_AES_ECB, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+ { CKM_AES_CBC, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+ { CKM_AES_MAC, { AES_FB_KEY, CKF_SGN }, AES_FB_STEP, SFTKFIPSNone },
+ { CKM_AES_MAC_GENERAL, { AES_FB_KEY, CKF_SGN }, AES_FB_STEP, SFTKFIPSNone },
+ { CKM_AES_CMAC, { AES_FB_KEY, CKF_SGN }, AES_FB_STEP, SFTKFIPSNone },
+ { CKM_AES_CMAC_GENERAL, { AES_FB_KEY, CKF_SGN }, AES_FB_STEP, SFTKFIPSNone },
+ { CKM_AES_CBC_PAD, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+ { CKM_AES_CTS, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+ { CKM_AES_CTR, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+ { CKM_AES_GCM, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSAEAD },
+ { CKM_AES_KEY_WRAP, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+ { CKM_AES_KEY_WRAP_PAD, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+ { CKM_AES_KEY_WRAP_KWP, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+ { CKM_AES_XCBC_MAC_96, { 96, 96, CKF_SGN }, 1, SFTKFIPSNone },
+ { CKM_AES_XCBC_MAC, { 128, 128, CKF_SGN }, 1, SFTKFIPSNone },
+ /* ------------------------- Hashing Operations ----------------------- */
+ { CKM_SHA224, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone },
+ { CKM_SHA224_HMAC, { 112, 224, CKF_SGN }, 1, SFTKFIPSNone },
+ { CKM_SHA224_HMAC_GENERAL, { 112, 224, CKF_SGN }, 1, SFTKFIPSNone },
+ { CKM_SHA256, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone },
+ { CKM_SHA256_HMAC, { 128, 256, CKF_SGN }, 1, SFTKFIPSNone },
+ { CKM_SHA256_HMAC_GENERAL, { 128, 256, CKF_SGN }, 1, SFTKFIPSNone },
+ { CKM_SHA384, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone },
+ { CKM_SHA384_HMAC, { 192, 384, CKF_SGN }, 1, SFTKFIPSNone },
+ { CKM_SHA384_HMAC_GENERAL, { 192, 384, CKF_SGN }, 1, SFTKFIPSNone },
+ { CKM_SHA512, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone },
+ { CKM_SHA512_HMAC, { 256, 512, CKF_SGN }, 1, SFTKFIPSNone },
+ { CKM_SHA512_HMAC_GENERAL, { 256, 512, CKF_SGN }, 1, SFTKFIPSNone },
+ /* --------------------- Secret Key Operations ------------------------ */
+ { CKM_GENERIC_SECRET_KEY_GEN, { 8, 256, CKF_GEN }, 1, SFTKFIPSNone },
+ /* ---------------------- SSL/TLS operations ------------------------- */
+ { CKM_SHA224_KEY_DERIVATION, { 112, 224, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_SHA256_KEY_DERIVATION, { 128, 256, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_SHA384_KEY_DERIVATION, { 192, 284, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_SHA512_KEY_DERIVATION, { 256, 512, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_TLS12_MASTER_KEY_DERIVE, { 384, 384, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_TLS12_MASTER_KEY_DERIVE_DH, { DH_FB_KEY, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_TLS12_KEY_AND_MAC_DERIVE, { 384, 384, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_TLS_PRF_GENERAL, { 8, 512, CKF_SGN }, 1, SFTKFIPSNone },
+ { CKM_TLS_MAC, { 8, 512, CKF_SGN }, 1, SFTKFIPSNone },
+ /* sigh, is this algorithm really tested. ssl doesn't seem to have a
+ * way of turning the extension off */
+ { CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE, { 192, 1024, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH, { 192, 1024, CKF_DERIVE }, 1, SFTKFIPSNone },
+
+ /* ------------------------- HKDF Operations -------------------------- */
+ { CKM_HKDF_DERIVE, { 8, 255 * 64 * 8, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_HKDF_DATA, { 8, 255 * 64 * 8, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_HKDF_KEY_GEN, { 160, 224, CKF_GEN }, 1, SFTKFIPSNone },
+ { CKM_HKDF_KEY_GEN, { 256, 512, CKF_GEN }, 128, SFTKFIPSNone },
+ /* ------------------ NIST 800-108 Key Derivations ------------------- */
+ { CKM_SP800_108_COUNTER_KDF, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_SP800_108_FEEDBACK_KDF, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_SP800_108_DOUBLE_PIPELINE_KDF, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_NSS_SP800_108_COUNTER_KDF_DERIVE_DATA, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_NSS_SP800_108_FEEDBACK_KDF_DERIVE_DATA, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_NSS_SP800_108_DOUBLE_PIPELINE_KDF_DERIVE_DATA, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+ /* --------------------IPSEC ----------------------- */
+ { CKM_NSS_IKE_PRF_PLUS_DERIVE, { 8, 255 * 64, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_NSS_IKE_PRF_DERIVE, { 8, 64, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_NSS_IKE1_PRF_DERIVE, { 8, 64, CKF_KDF }, 1, SFTKFIPSNone },
+ { CKM_NSS_IKE1_APP_B_PRF_DERIVE, { 8, 255 * 64, CKF_KDF }, 1, SFTKFIPSNone },
+ /* ------------------ PBE Key Derivations ------------------- */
+ { CKM_PKCS5_PBKD2, { 1, 256, CKF_GEN }, 1, SFTKFIPSNone },
+ { CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN, { 224, 224, CKF_GEN }, 1, SFTKFIPSNone },
+ { CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN, { 256, 256, CKF_GEN }, 1, SFTKFIPSNone },
+ { CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN, { 384, 384, CKF_GEN }, 1, SFTKFIPSNone },
+ { CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN, { 512, 512, CKF_GEN }, 1, SFTKFIPSNone }
+};
+const int SFTK_NUMBER_FIPS_ALGORITHMS = PR_ARRAY_SIZE(sftk_fips_mechs);
diff --git a/lib/softoken/fipstokn.c b/lib/softoken/fipstokn.c
index 1dabc59e2..43e8c3847 100644
--- a/lib/softoken/fipstokn.c
+++ b/lib/softoken/fipstokn.c
@@ -301,10 +301,11 @@ static CK_FUNCTION_LIST sftk_fipsTable_v2 = {
static CK_INTERFACE fips_interfaces[] = {
{ (CK_UTF8CHAR_PTR) "PKCS 11", &sftk_fipsTable, NSS_INTERFACE_FLAGS },
{ (CK_UTF8CHAR_PTR) "PKCS 11", &sftk_fipsTable_v2, NSS_INTERFACE_FLAGS },
- { (CK_UTF8CHAR_PTR) "Vendor NSS Module Interface", &sftk_module_funcList, NSS_INTERFACE_FLAGS }
+ { (CK_UTF8CHAR_PTR) "Vendor NSS Module Interface", &sftk_module_funcList, NSS_INTERFACE_FLAGS },
+ { (CK_UTF8CHAR_PTR) "Vendor NSS FIPS Interface", &sftk_fips_funcList, NSS_INTERFACE_FLAGS }
};
/* must match the count of interfaces in fips_interfaces above*/
-#define FIPS_INTERFACE_COUNT 3
+#define FIPS_INTERFACE_COUNT 4
/* CKO_NOT_A_KEY can be any object class that's not a key object. */
#define CKO_NOT_A_KEY CKO_DATA
diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c
index eba27d208..3f49333f8 100644
--- a/lib/softoken/pkcs11.c
+++ b/lib/softoken/pkcs11.c
@@ -145,16 +145,27 @@ CK_NSS_MODULE_FUNCTIONS sftk_module_funcList = {
NSC_ModuleDBFunc
};
+static CK_RV
+nsc_NSSGetFIPSStatus(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hObject,
+ CK_ULONG ulOperationType,
+ CK_ULONG *pulFIPSStatus);
+CK_NSS_FIPS_FUNCTIONS sftk_fips_funcList = {
+ { 1, 0 },
+ nsc_NSSGetFIPSStatus
+};
+
/*
* Array is orderd by default first
*/
static CK_INTERFACE nss_interfaces[] = {
{ (CK_UTF8CHAR_PTR) "PKCS 11", &sftk_funcList, NSS_INTERFACE_FLAGS },
{ (CK_UTF8CHAR_PTR) "PKCS 11", &sftk_funcList_v2, NSS_INTERFACE_FLAGS },
- { (CK_UTF8CHAR_PTR) "Vendor NSS Module Interface", &sftk_module_funcList, NSS_INTERFACE_FLAGS }
+ { (CK_UTF8CHAR_PTR) "Vendor NSS Module Interface", &sftk_module_funcList, NSS_INTERFACE_FLAGS },
+ { (CK_UTF8CHAR_PTR) "Vendor NSS FIPS Interface", &sftk_fips_funcList, NSS_INTERFACE_FLAGS }
};
/* must match the count of interfaces in nss_interfaces above */
-#define NSS_INTERFACE_COUNT 3
+#define NSS_INTERFACE_COUNT 4
/* List of DES Weak Keys */
typedef unsigned char desKey[8];
@@ -3849,50 +3860,10 @@ CK_RV
sftk_MechAllowsOperation(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE op)
{
CK_ULONG i;
- CK_FLAGS flags;
+ CK_FLAGS flags = sftk_AttributeToFlags(op);
- switch (op) {
- case CKA_ENCRYPT:
- flags = CKF_ENCRYPT;
- break;
- case CKA_DECRYPT:
- flags = CKF_DECRYPT;
- break;
- case CKA_WRAP:
- flags = CKF_WRAP;
- break;
- case CKA_UNWRAP:
- flags = CKF_UNWRAP;
- break;
- case CKA_SIGN:
- flags = CKF_SIGN;
- break;
- case CKA_SIGN_RECOVER:
- flags = CKF_SIGN_RECOVER;
- break;
- case CKA_VERIFY:
- flags = CKF_VERIFY;
- break;
- case CKA_VERIFY_RECOVER:
- flags = CKF_VERIFY_RECOVER;
- break;
- case CKA_DERIVE:
- flags = CKF_DERIVE;
- break;
- case CKA_NSS_MESSAGE | CKA_ENCRYPT:
- flags = CKF_MESSAGE_ENCRYPT;
- break;
- case CKA_NSS_MESSAGE | CKA_DECRYPT:
- flags = CKF_MESSAGE_DECRYPT;
- break;
- case CKA_NSS_MESSAGE | CKA_SIGN:
- flags = CKF_MESSAGE_SIGN;
- break;
- case CKA_NSS_MESSAGE | CKA_VERIFY:
- flags = CKF_MESSAGE_VERIFY;
- break;
- default:
- return CKR_ARGUMENTS_BAD;
+ if (flags == 0) {
+ return CKR_ARGUMENTS_BAD;
}
for (i = 0; i < mechanismCount; i++) {
if (type == mechanisms[i].type) {
@@ -4625,6 +4596,8 @@ NSC_CreateObject(CK_SESSION_HANDLE hSession,
if (object == NULL) {
return CKR_HOST_MEMORY;
}
+ object->isFIPS = PR_FALSE; /* if we created the object on the fly,
+ * it's not a FIPS object */
/*
* load the template values into the object
@@ -5298,3 +5271,106 @@ NSC_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot,
return CKR_FUNCTION_NOT_SUPPORTED;
}
+
+static CK_RV
+nsc_NSSGetFIPSStatus(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hObject,
+ CK_ULONG ulOperationType,
+ CK_ULONG *pulFIPSStatus)
+{
+ CK_ULONG sessionState = CKS_NSS_UNINITIALIZED;
+ CK_ULONG objectState = CKS_NSS_UNINITIALIZED;
+ PRBool needSession = PR_FALSE;
+ PRBool needObject = PR_FALSE;
+ SFTKSession *session;
+ SFTKObject *object;
+
+ *pulFIPSStatus = CKS_NSS_FIPS_NOT_OK;
+
+ /* first determine what we need to look up */
+ switch (ulOperationType) {
+ case CKT_NSS_SESSION_CHECK:
+ case CKT_NSS_SESSION_LAST_CHECK:
+ needSession = PR_TRUE;
+ needObject = PR_FALSE;
+ break;
+ case CKT_NSS_OBJECT_CHECK:
+ needSession = PR_FALSE;
+ needObject = PR_TRUE;
+ break;
+ case CKT_NSS_BOTH_CHECK:
+ needSession = PR_TRUE;
+ needObject = PR_TRUE;
+ break;
+ default:
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ /* we always need the session handle, the object handle is only
+ * meaningful if there is a session */
+ session = sftk_SessionFromHandle(hSession);
+ if (!session) {
+ return CKR_SESSION_HANDLE_INVALID;
+ }
+ if (needSession) {
+ if (CKT_NSS_SESSION_LAST_CHECK == ulOperationType) {
+ sessionState = session->lastOpWasFIPS ? CKS_NSS_FIPS_OK : CKS_NSS_FIPS_NOT_OK;
+ } else {
+ if (session->enc_context) {
+ sessionState = session->enc_context->isFIPS ? CKS_NSS_FIPS_OK : CKS_NSS_FIPS_NOT_OK;
+ }
+ if (sessionState != CKS_NSS_FIPS_NOT_OK && session->hash_context) {
+ sessionState = session->hash_context->isFIPS ? CKS_NSS_FIPS_OK : CKS_NSS_FIPS_NOT_OK;
+ }
+ /* sessionState is set to CKS_NSS_UNINITIALIZED if neither
+ * context exists */
+ }
+ }
+
+ if (needObject) {
+ object = sftk_ObjectFromHandle(hObject, session);
+ if (!object) {
+ sftk_FreeSession(session);
+ return CKR_OBJECT_HANDLE_INVALID;
+ }
+ objectState = object->isFIPS ? CKS_NSS_FIPS_OK : CKS_NSS_FIPS_NOT_OK;
+ sftk_FreeObject(object);
+ }
+
+ sftk_FreeSession(session);
+
+ /* If we didn't fetch the state, then it is uninitialized.
+ * The session state can also be uninitialized if there are no active
+ * crypto operations on the session. Turns out the rules for combining
+ * the states are the same whether or not the state was uninitialzed
+ * because we didn't fetch it or because there wasn't a state to fetch.
+ */
+
+ /* if the object State is uninitialized, return the state of the session. */
+ if (objectState == CKS_NSS_UNINITIALIZED) {
+ /* if they are both uninitalized, return CKS_FIPS_NOT_OK */
+ if (sessionState == CKS_NSS_UNINITIALIZED) {
+ /* *pulFIPSStatus already set to CKS_FIPS_NOT_OK */
+ return CKR_OK;
+ }
+ *pulFIPSStatus = sessionState;
+ return CKR_OK;
+ }
+ /* objectState is initialized, if sessionState is uninitialized, we can
+ * just return objectState */
+ if (sessionState == CKS_NSS_UNINITIALIZED) {
+ *pulFIPSStatus = objectState;
+ return CKR_OK;
+ }
+
+ /* they are are not equal, one must be CKS_FIPS_NOT_OK, so we return that
+ * value CKS_FIPS_NOT_OK */
+ if (objectState != sessionState) {
+ /* *pulFIPSStatus already set to CKS_FIPS_NOT_OK */
+ return CKR_OK;
+ }
+
+ /* objectState and sessionState or the same, so we can return either */
+ *pulFIPSStatus = sessionState;
+ return CKR_OK;
+}
diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
index 977880ed2..c3216b3fd 100644
--- a/lib/softoken/pkcs11c.c
+++ b/lib/softoken/pkcs11c.c
@@ -400,6 +400,7 @@ void
sftk_TerminateOp(SFTKSession *session, SFTKContextType ctype,
SFTKSessionContext *context)
{
+ session->lastOpWasFIPS = context->isFIPS;
sftk_FreeContext(context);
sftk_SetContextByType(session, ctype, NULL);
}
@@ -413,7 +414,8 @@ sftk_TerminateOp(SFTKSession *session, SFTKContextType ctype,
* all need to do at the beginning. This is done here.
*/
CK_RV
-sftk_InitGeneric(SFTKSession *session, SFTKSessionContext **contextPtr,
+sftk_InitGeneric(SFTKSession *session, CK_MECHANISM *pMechanism,
+ SFTKSessionContext **contextPtr,
SFTKContextType ctype, SFTKObject **keyPtr,
CK_OBJECT_HANDLE hKey, CK_KEY_TYPE *keyTypePtr,
CK_OBJECT_CLASS pubKeyType, CK_ATTRIBUTE_TYPE operation)
@@ -435,7 +437,9 @@ sftk_InitGeneric(SFTKSession *session, SFTKSessionContext **contextPtr,
}
/* make sure it's a valid key for this operation */
- if (((key->objclass != CKO_SECRET_KEY) && (key->objclass != pubKeyType)) || !sftk_isTrue(key, operation)) {
+ if (((key->objclass != CKO_SECRET_KEY) &&
+ (key->objclass != pubKeyType)) ||
+ !sftk_isTrue(key, operation)) {
sftk_FreeObject(key);
return CKR_KEY_TYPE_INCONSISTENT;
}
@@ -473,7 +477,8 @@ sftk_InitGeneric(SFTKSession *session, SFTKSessionContext **contextPtr,
context->key = key;
context->blockSize = 0;
context->maxLen = 0;
-
+ context->isFIPS = sftk_operationIsFIPS(session->slot, pMechanism,
+ operation, key);
*contextPtr = context;
return CKR_OK;
}
@@ -813,8 +818,10 @@ sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
if (session == NULL)
return CKR_SESSION_HANDLE_INVALID;
- crv = sftk_InitGeneric(session, &context, contextType, &key, hKey, &key_type,
- isEncrypt ? CKO_PUBLIC_KEY : CKO_PRIVATE_KEY, keyUsage);
+ crv = sftk_InitGeneric(session, pMechanism, &context, contextType, &key,
+ hKey, &key_type,
+ isEncrypt ? CKO_PUBLIC_KEY : CKO_PRIVATE_KEY,
+ keyUsage);
if (crv != CKR_OK) {
sftk_FreeSession(session);
@@ -1900,7 +1907,8 @@ NSC_DigestInit(CK_SESSION_HANDLE hSession,
session = sftk_SessionFromHandle(hSession);
if (session == NULL)
return CKR_SESSION_HANDLE_INVALID;
- crv = sftk_InitGeneric(session, &context, SFTK_HASH, NULL, 0, NULL, 0, 0);
+ crv = sftk_InitGeneric(session, pMechanism, &context, SFTK_HASH,
+ NULL, 0, NULL, 0, CKA_DIGEST);
if (crv != CKR_OK) {
sftk_FreeSession(session);
return crv;
@@ -2766,8 +2774,8 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
session = sftk_SessionFromHandle(hSession);
if (session == NULL)
return CKR_SESSION_HANDLE_INVALID;
- crv = sftk_InitGeneric(session, &context, SFTK_SIGN, &key, hKey, &key_type,
- CKO_PRIVATE_KEY, CKA_SIGN);
+ crv = sftk_InitGeneric(session, pMechanism, &context, SFTK_SIGN, &key,
+ hKey, &key_type, CKO_PRIVATE_KEY, CKA_SIGN);
if (crv != CKR_OK) {
sftk_FreeSession(session);
return crv;
@@ -3565,8 +3573,8 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSession,
session = sftk_SessionFromHandle(hSession);
if (session == NULL)
return CKR_SESSION_HANDLE_INVALID;
- crv = sftk_InitGeneric(session, &context, SFTK_VERIFY, &key, hKey, &key_type,
- CKO_PUBLIC_KEY, CKA_VERIFY);
+ crv = sftk_InitGeneric(session, pMechanism, &context, SFTK_VERIFY, &key,
+ hKey, &key_type, CKO_PUBLIC_KEY, CKA_VERIFY);
if (crv != CKR_OK) {
sftk_FreeSession(session);
return crv;
@@ -3894,7 +3902,7 @@ NSC_VerifyRecoverInit(CK_SESSION_HANDLE hSession,
session = sftk_SessionFromHandle(hSession);
if (session == NULL)
return CKR_SESSION_HANDLE_INVALID;
- crv = sftk_InitGeneric(session, &context, SFTK_VERIFY_RECOVER,
+ crv = sftk_InitGeneric(session, pMechanism, &context, SFTK_VERIFY_RECOVER,
&key, hKey, &key_type, CKO_PUBLIC_KEY, CKA_VERIFY_RECOVER);
if (crv != CKR_OK) {
sftk_FreeSession(session);
@@ -6536,6 +6544,9 @@ NSC_UnwrapKey(CK_SESSION_HANDLE hSession,
return CKR_SESSION_HANDLE_INVALID;
}
+ /* mark the key as FIPS if the previous operation was all FIPS */
+ key->isFIPS = session->lastOpWasFIPS;
+
/*
* handle the base object stuff
*/
@@ -7006,6 +7017,16 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_SESSION_HANDLE hSession,
if (saltKey == NULL) {
return CKR_KEY_HANDLE_INVALID;
}
+ /* if the base key is not fips, but the salt key is, the
+ * resulting key can be fips */
+ if (isFIPS && (key->isFIPS == 0) && (saltKey->isFIPS == 1)) {
+ CK_MECHANISM mech;
+ mech.mechanism = CKM_HKDF_DERIVE;
+ mech.pParameter = params;
+ mech.ulParameterLen = sizeof(*params);
+ key->isFIPS = sftk_operationIsFIPS(saltKey->slot, &mech,
+ CKA_DERIVE, saltKey);
+ }
saltKey_att = sftk_FindAttribute(saltKey, CKA_VALUE);
if (saltKey_att == NULL) {
sftk_FreeObject(saltKey);
@@ -7251,6 +7272,9 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
sourceKey = sftk_ObjectFromHandle(hBaseKey, session);
sftk_FreeSession(session);
+ /* is this eventually succeeds, lastOpWasFIPS will be set the resulting key's
+ * FIPS state below. */
+ session->lastOpWasFIPS = PR_FALSE;
if (sourceKey == NULL) {
sftk_FreeObject(key);
return CKR_KEY_HANDLE_INVALID;
@@ -7265,6 +7289,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
return CKR_KEY_HANDLE_INVALID;
}
}
+ key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_DERIVE, sourceKey);
switch (mechanism) {
/* get a public key from a private key. nsslowkey_ConvertToPublickey()
@@ -8704,6 +8729,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
}
crv = sftk_handleObject(key, session);
+ session->lastOpWasFIPS = key->isFIPS;
sftk_FreeSession(session);
*phKey = key->handle;
sftk_FreeObject(key);
diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h
index 26efe158b..aa212f09e 100644
--- a/lib/softoken/pkcs11i.h
+++ b/lib/softoken/pkcs11i.h
@@ -191,6 +191,7 @@ struct SFTKObjectStr {
SFTKSlot *slot;
void *objectInfo;
SFTKFree infoFree;
+ PRBool isFIPS;
};
struct SFTKTokenObjectStr {
@@ -266,6 +267,7 @@ struct SFTKSessionContextStr {
PRBool rsa; /* is rsa */
PRBool doPad; /* use PKCS padding for block ciphers */
PRBool isXCBC; /* xcbc, use special handling in final */
+ PRBool isFIPS; /* current operation is in FIPS mode */
unsigned int blockSize; /* blocksize for padding */
unsigned int padDataLength; /* length of the valid data in padbuf */
/** latest incomplete block of data for block cipher */
@@ -307,6 +309,7 @@ struct SFTKSessionStr {
SFTKSessionContext *enc_context;
SFTKSessionContext *hash_context;
SFTKSessionContext *sign_context;
+ PRBool lastOpWasFIPS;
SFTKObjectList *objects[1];
};
@@ -689,6 +692,7 @@ struct sftk_MACCtxStr {
typedef struct sftk_MACCtxStr sftk_MACCtx;
extern CK_NSS_MODULE_FUNCTIONS sftk_module_funcList;
+extern CK_NSS_FIPS_FUNCTIONS sftk_fips_funcList;
SEC_BEGIN_PROTOS
@@ -795,6 +799,7 @@ extern void sftk_CleanupFreeLists(void);
* Helper functions to handle the session crypto contexts
*/
extern CK_RV sftk_InitGeneric(SFTKSession *session,
+ CK_MECHANISM *pMechanism,
SFTKSessionContext **contextPtr,
SFTKContextType ctype, SFTKObject **keyPtr,
CK_OBJECT_HANDLE hKey, CK_KEY_TYPE *keyTypePtr,
@@ -944,7 +949,12 @@ char **NSC_ModuleDBFunc(unsigned long function, char *parameters, void *args);
const SECItem *sftk_VerifyDH_Prime(SECItem *dhPrime);
/* 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);
SEC_END_PROTOS
#endif /* _PKCS11I_H_ */
diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c
index 4b314f4b8..43d4ba9d5 100644
--- a/lib/softoken/pkcs11u.c
+++ b/lib/softoken/pkcs11u.c
@@ -13,6 +13,18 @@
#include "prnetdb.h" /* for PR_ntohl */
#include "sftkdb.h"
#include "softoken.h"
+#include "secoid.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
+ */
+#include "fips_algorithms.h"
+#define NSS_HAS_FIPS_INDICATORS 1
+#endif
/*
* ******************** Error mapping *******************************
@@ -1081,6 +1093,7 @@ sftk_NewObject(SFTKSlot *slot)
object->handle = 0;
object->next = object->prev = NULL;
object->slot = slot;
+ object->isFIPS = sftk_isFIPS(slot->slotID);
object->refCount = 1;
sessObject->sessionList.next = NULL;
@@ -1634,6 +1647,7 @@ sftk_CopyObject(SFTKObject *destObject, SFTKObject *srcObject)
SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject);
unsigned int i;
+ destObject->isFIPS = srcObject->isFIPS;
if (src_so == NULL) {
return sftk_CopyTokenObject(destObject, srcObject);
}
@@ -1871,6 +1885,8 @@ sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication,
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 session;
}
@@ -1994,6 +2010,7 @@ sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle)
goto loser;
}
object->slot = slot;
+ object->isFIPS = sftk_isFIPS(slot->slotID);
object->objectInfo = NULL;
object->infoFree = NULL;
if (!hasLocks) {
@@ -2122,3 +2139,250 @@ sftk_EncodeInteger(PRUint64 integer, CK_ULONG num_bits, CK_BBOOL littleEndian,
}
}
}
+
+CK_FLAGS
+sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE op)
+{
+ CK_FLAGS flags = 0;
+
+ switch (op) {
+ case CKA_ENCRYPT:
+ flags = CKF_ENCRYPT;
+ break;
+ case CKA_DECRYPT:
+ flags = CKF_DECRYPT;
+ break;
+ case CKA_WRAP:
+ flags = CKF_WRAP;
+ break;
+ case CKA_UNWRAP:
+ flags = CKF_UNWRAP;
+ break;
+ case CKA_SIGN:
+ flags = CKF_SIGN;
+ break;
+ case CKA_SIGN_RECOVER:
+ flags = CKF_SIGN_RECOVER;
+ break;
+ case CKA_VERIFY:
+ flags = CKF_VERIFY;
+ break;
+ case CKA_VERIFY_RECOVER:
+ flags = CKF_VERIFY_RECOVER;
+ break;
+ case CKA_DERIVE:
+ flags = CKF_DERIVE;
+ break;
+ /* fake attribute to select digesting */
+ case CKA_DIGEST:
+ flags = CKF_DIGEST;
+ break;
+ case CKA_NSS_MESSAGE | CKA_ENCRYPT:
+ flags = CKF_MESSAGE_ENCRYPT;
+ break;
+ case CKA_NSS_MESSAGE | CKA_DECRYPT:
+ flags = CKF_MESSAGE_DECRYPT;
+ break;
+ case CKA_NSS_MESSAGE | CKA_SIGN:
+ flags = CKF_MESSAGE_SIGN;
+ break;
+ case CKA_NSS_MESSAGE | CKA_VERIFY:
+ flags = CKF_MESSAGE_VERIFY;
+ break;
+ default:
+ break;
+ }
+ return flags;
+}
+
+#ifdef NSS_HAS_FIPS_INDICATORS
+/* sigh, we probably need a version of this in secutil so that both
+ * softoken and NSS can use it */
+static SECOidTag
+sftk_quickGetECCCurveOid(SFTKObject *source)
+{
+ SFTKAttribute *attribute = sftk_FindAttribute(source, CKA_EC_PARAMS);
+ unsigned char *encoded;
+ int len;
+ SECItem oid;
+ SECOidTag tag;
+
+ if (attribute == NULL) {
+ return SEC_OID_UNKNOWN;
+ }
+ encoded = attribute->attrib.pValue;
+ len = attribute->attrib.ulValueLen;
+ if ((len < 2) || (encoded[0] != SEC_ASN1_OBJECT_ID) ||
+ (len != encoded[1] + 2)) {
+ sftk_FreeAttribute(attribute);
+ return SEC_OID_UNKNOWN;
+ }
+ oid.data = encoded + 2;
+ oid.len = len - 2;
+ tag = SECOID_FindOIDTag(&oid);
+ sftk_FreeAttribute(attribute);
+ return tag;
+}
+
+/* This function currently only returns valid lengths for
+ * FIPS approved ECC curves. If we want to make this generic
+ * in the future, that Curve determination can be done in
+ * the sftk_handleSpecial. Since it's currently only used
+ * in FIPS indicators, it's currently only compiled with
+ * the FIPS indicator code */
+static int
+sftk_getKeyLength(SFTKObject *source)
+{
+ CK_KEY_TYPE keyType = CK_INVALID_HANDLE;
+ CK_ATTRIBUTE_TYPE keyAttribute;
+ CK_ULONG keyLength = 0;
+ SFTKAttribute *attribute;
+ CK_RV crv;
+
+ /* If we don't have a key, then it doesn't have a length.
+ * this may be OK (say we are hashing). The mech info will
+ * sort this out because algorithms which expect no keys
+ * will accept zero length for the keys */
+ if (source == NULL) {
+ return 0;
+ }
+
+ crv = sftk_GetULongAttribute(source, CKA_KEY_TYPE, &keyType);
+ if (crv != CKR_OK) {
+ /* sometimes we're passed a data object, in that case the
+ * key length is CKA_VALUE, which is the default */
+ keyType = CKK_INVALID_KEY_TYPE;
+ }
+ if (keyType == CKK_EC) {
+ SECOidTag curve = sftk_quickGetECCCurveOid(source);
+ switch (curve) {
+ case SEC_OID_CURVE25519:
+ /* change when we start algorithm testing on curve25519 */
+ return 0;
+ case SEC_OID_SECG_EC_SECP256R1:
+ return 256;
+ case SEC_OID_SECG_EC_SECP384R1:
+ return 384;
+ case SEC_OID_SECG_EC_SECP521R1:
+ /* this is a lie, but it makes the table easier. We don't
+ * have to have a double entry for every ECC mechanism */
+ return 512;
+ default:
+ break;
+ }
+ /* other curves aren't NIST approved, returning 0 will cause these
+ * curves to fail FIPS length criteria */
+ return 0;
+ }
+
+ switch (keyType) {
+ case CKK_RSA:
+ keyAttribute = CKA_MODULUS;
+ break;
+ case CKK_DSA:
+ case CKK_DH:
+ keyAttribute = CKA_PRIME;
+ break;
+ default:
+ keyAttribute = CKA_VALUE;
+ break;
+ }
+ attribute = sftk_FindAttribute(source, keyAttribute);
+ if (attribute) {
+ keyLength = attribute->attrib.ulValueLen * 8;
+ sftk_FreeAttribute(attribute);
+ }
+ return keyLength;
+}
+
+/*
+ * handle specialized FIPS semantics that are too complicated to
+ * handle with just a table. NOTE: this means any additional semantics
+ * would have to be coded here before they can be added to the table */
+static PRBool
+sftk_handleSpecial(SFTKSlot *slot, CK_MECHANISM *mech,
+ SFTKFIPSAlgorithmList *mechInfo, SFTKObject *source)
+{
+ switch (mechInfo->special) {
+ case SFTKFIPSDH: {
+ SECItem dhPrime;
+ const SECItem *dhSubPrime;
+ CK_RV crv = sftk_Attribute2SecItem(NULL, &dhPrime,
+ source, CKA_PRIME);
+ if (crv != CKR_OK) {
+ return PR_FALSE;
+ }
+ dhSubPrime = sftk_VerifyDH_Prime(&dhPrime);
+ SECITEM_ZfreeItem(&dhPrime, PR_FALSE);
+ return (dhSubPrime) ? PR_TRUE : PR_FALSE;
+ }
+ case SFTKFIPSNone:
+ return PR_FALSE;
+ case SFTKFIPSECC:
+ /* we've already handled the curve selection in the 'getlength'
+ * function */
+ return PR_TRUE;
+ case SFTKFIPSAEAD: {
+ if (mech->ulParameterLen == 0) {
+ /* AEAD ciphers are only in FIPS mode if we are using the
+ * MESSAGE interface. This takes an empty parameter
+ * in the init function */
+ return PR_TRUE;
+ }
+ return PR_FALSE;
+ }
+ default:
+ break;
+ }
+ /* if we didn't understand the special processing, mark it non-fips */
+ return PR_FALSE;
+}
+#endif
+
+PRBool
+sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech, CK_ATTRIBUTE_TYPE op,
+ SFTKObject *source)
+{
+#ifndef NSS_HAS_FIPS_INDICATORS
+ return PR_FALSE;
+#else
+ int i;
+ CK_FLAGS opFlags;
+ CK_ULONG keyLength;
+
+ /* handle all the quick stuff first */
+ if (!sftk_isFIPS(slot->slotID)) {
+ return PR_FALSE;
+ }
+ if (source && !source->isFIPS) {
+ return PR_FALSE;
+ }
+ if (mech == NULL) {
+ return PR_FALSE;
+ }
+
+ /* now get the calculated values */
+ opFlags = sftk_AttributeToFlags(op);
+ if (opFlags == 0) {
+ return PR_FALSE;
+ }
+ keyLength = sftk_getKeyLength(source);
+
+ /* check against our algorithm array */
+ for (i = 0; i < SFTK_NUMBER_FIPS_ALGORITHMS; i++) {
+ SFTKFIPSAlgorithmList *mechs = &sftk_fips_mechs[i];
+ /* if we match the number of records exactly, then we are an
+ * approved algorithm in the approved mode with an approved key */
+ if (((mech->mechanism == mechs->type) &&
+ (opFlags == (mechs->info.flags & opFlags)) &&
+ (keyLength <= mechs->info.ulMaxKeySize) &&
+ (keyLength >= mechs->info.ulMinKeySize) &&
+ ((keyLength - mechs->info.ulMinKeySize) % mechs->step) == 0) &&
+ ((mechs->special == SFTKFIPSNone) ||
+ sftk_handleSpecial(slot, mech, mechs, source))) {
+ return PR_TRUE;
+ }
+ }
+ return PR_FALSE;
+#endif
+}
diff --git a/lib/softoken/sftkmessage.c b/lib/softoken/sftkmessage.c
index 76bc9b479..3e45445e8 100644
--- a/lib/softoken/sftkmessage.c
+++ b/lib/softoken/sftkmessage.c
@@ -72,8 +72,8 @@ sftk_MessageCryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
if (session == NULL)
return CKR_SESSION_HANDLE_INVALID;
- crv = sftk_InitGeneric(session, &context, contextType, &key, hKey,
- &key_type, CKO_SECRET_KEY, operation);
+ crv = sftk_InitGeneric(session, pMechanism, &context, contextType, &key,
+ hKey, &key_type, CKO_SECRET_KEY, operation);
if (crv != CKR_OK) {
sftk_FreeSession(session);
return crv;
diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c
index fd491f896..a3f0a776e 100644
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -13876,6 +13876,41 @@ ssl3_DestroySSL3Info(sslSocket *ss)
sslBuffer_Clear(&ss->ssl3.hs.greaseEchBuf);
}
+/* check if the current cipher spec is FIPS. We only need to
+ * check the contexts here, if the kea, prf or keys were not FIPS,
+ * that status would have been rolled up in the create context
+ * call */
+static PRBool
+ssl_cipherSpecIsFips(ssl3CipherSpec *spec)
+{
+ if (!spec || !spec->cipherDef) {
+ return PR_FALSE;
+ }
+
+ if (spec->cipherDef->type != type_aead) {
+ if (spec->keyMaterial.macContext == NULL) {
+ return PR_FALSE;
+ }
+ if (!PK11_ContextGetFIPSStatus(spec->keyMaterial.macContext)) {
+ return PR_FALSE;
+ }
+ }
+ if (!spec->cipherContext) {
+ return PR_FALSE;
+ }
+ return PK11_ContextGetFIPSStatus(spec->cipherContext);
+}
+
+/* return true if the current operation is running in FIPS mode */
+PRBool
+ssl_isFIPS(sslSocket *ss)
+{
+ if (!ssl_cipherSpecIsFips(ss->ssl3.crSpec)) {
+ return PR_FALSE;
+ }
+ return ssl_cipherSpecIsFips(ss->ssl3.cwSpec);
+}
+
/*
* parse the policy value for a single algorithm in a cipher_suite,
* return TRUE if we disallow by the cipher suite by policy
diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h
index 1b7dfb107..f4264b834 100644
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -1847,6 +1847,9 @@ PK11SymKey *ssl_unwrapSymKey(PK11SymKey *wrapKey,
CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
int keySize, CK_FLAGS keyFlags, void *pinArg);
+/* determine if the current ssl connection is operating in FIPS mode */
+PRBool ssl_isFIPS(sslSocket *ss);
+
/* Experimental APIs. Remove when stable. */
SECStatus SSLExp_SetResumptionTokenCallback(PRFileDesc *fd,
diff --git a/lib/ssl/sslinfo.c b/lib/ssl/sslinfo.c
index 65aafe94a..d0f0701ae 100644
--- a/lib/ssl/sslinfo.c
+++ b/lib/ssl/sslinfo.c
@@ -110,6 +110,7 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
sidLen = PR_MIN(sidLen, sizeof inf.sessionID);
inf.sessionIDLength = sidLen;
memcpy(inf.sessionID, sid->u.ssl3.sessionID, sidLen);
+ inf.isFIPS = ssl_isFIPS(ss);
}
}
diff --git a/lib/ssl/sslt.h b/lib/ssl/sslt.h
index 2bc151c63..f8210ccfb 100644
--- a/lib/ssl/sslt.h
+++ b/lib/ssl/sslt.h
@@ -373,6 +373,11 @@ typedef struct SSLChannelInfoStr {
* with TLS 1.3 Encrypted Client Hello. */
PRBool echAccepted;
+ /* The following field was added in NSS 3.66 */
+ /* This filed is PR_TRUE if the FIPS indicator is true for the
+ * current connection */
+ PRBool isFIPS;
+
/* When adding new fields to this structure, please document the
* NSS version in which they were added. */
} SSLChannelInfo;
diff --git a/lib/util/pkcs11n.h b/lib/util/pkcs11n.h
index 193985044..9a8126a82 100644
--- a/lib/util/pkcs11n.h
+++ b/lib/util/pkcs11n.h
@@ -269,6 +269,16 @@
#define CKM_TLS_PRF_GENERAL 0x80000373UL
+/* FIPS Indicator defines */
+#define CKS_NSS_UNINITIALIZED 0xffffffffUL
+#define CKS_NSS_FIPS_NOT_OK 0UL
+#define CKS_NSS_FIPS_OK 1UL
+
+#define CKT_NSS_SESSION_CHECK 1UL
+#define CKT_NSS_OBJECT_CHECK 2UL
+#define CKT_NSS_BOTH_CHECK 3UL
+#define CKT_NSS_SESSION_LAST_CHECK 4UL
+
typedef struct CK_NSS_JPAKEPublicValue {
CK_BYTE *pGX;
CK_ULONG ulGXLen;
@@ -589,6 +599,18 @@ typedef struct CK_NSS_MODULE_FUNCTIONS {
CK_NSS_ModuleDBFunc NSC_ModuleDBFunc;
} CK_NSS_MODULE_FUNCTIONS;
+/* FIPS Indicator Interface. This may move to the normal PKCS #11 table
+ * in the future. For now it's called "Vendor NSS FIPS Interface" */
+typedef CK_RV (*CK_NSS_GetFIPSStatus)(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hObject,
+ CK_ULONG ulOperationType,
+ CK_ULONG *pulFIPSStatus);
+
+typedef struct CK_NSS_FIPS_FUNCTIONS {
+ CK_VERSION version;
+ CK_NSS_GetFIPSStatus NSC_NSSGetFIPSStatus;
+} CK_NSS_FIPS_FUNCTIONS;
+
/* There was an inconsistency between the spec and the header file in defining
* the CK_GCM_PARAMS structure. The authoritative reference is the header file,
* but NSS used the spec when adding it to its own header. In V3 we've
@@ -613,7 +635,7 @@ typedef CK_NSS_GCM_PARAMS CK_PTR CK_NSS_GCM_PARAMS_PTR;
#define CK_INVALID_SESSION CK_INVALID_HANDLE
#define CKR_KEY_PARAMS_INVALID 0x0000006B
-/* use the old wrong CK_GCM_PARAMS is NSS_PCKS11_2_0_COMPAT is defined */
+/* use the old wrong CK_GCM_PARAMS if NSS_PCKS11_2_0_COMPAT is defined */
typedef struct CK_NSS_GCM_PARAMS CK_GCM_PARAMS;
typedef CK_NSS_GCM_PARAMS CK_PTR CK_GCM_PARAMS_PTR;
diff --git a/tests/ssl/ssl.sh b/tests/ssl/ssl.sh
index 7e74397c9..acd4c8cda 100755
--- a/tests/ssl/ssl.sh
+++ b/tests/ssl/ssl.sh
@@ -115,9 +115,20 @@ ssl_init()
NON_EC_SUITES=":0016:0032:0033:0038:0039:003B:003C:003D:0040:0041:0067:006A:006B"
NON_EC_SUITES="${NON_EC_SUITES}:0084:009C:009D:009E:009F:00A2:00A3:CCAAcdeinvyz"
+ TLS13_SUITES=":1301:1302:1303"
# List of cipher suites to test, including ECC cipher suites.
CIPHER_SUITES="-c ${EC_SUITES}${NON_EC_SUITES}"
+ TLS13_CIPHER_SUITES="-c ${TLS13_SUITES}${EC_SUITES}${NON_EC_SUITES}"
+
+ # in fips mode, turn off curve25519 until it's NIST approved
+ FIPS_OPTIONS="-I P256,P384,P521,FF2048,FF3072,FF4096,FF6144,FF8192"
+
+ # in non-fips mode, tstclnt may run without the db password in some
+ # cases, but in fips mode it's always needed
+ CLIENT_PW=""
+ CLIENT_PW_FIPS="-w nss"
+ CLIENT_PW_NORMAL=""
if [ "${OS_ARCH}" != "WINNT" ]; then
ulimit -n 1000 # make sure we have enough file descriptors
@@ -292,17 +303,30 @@ ignore_blank_lines()
########################################################################
ssl_cov()
{
- #verbose="-v"
+ verbose_save=${verbose}
+ verbose="-v"
html_head "SSL Cipher Coverage $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE"
testname=""
+ SAVE_SERVER_OPTIONS=${SERVER_OPTIONS}
+ if [ "${SERVER_MODE}" = "fips" ] ; then
+ SERVER_OPTIONS="${SERVER_OPTIONS} ${FIPS_OPTIONS}"
+ fi
+ SAVE_CLIENT_OPTIONS=${CLIENT_OPTIONS}
+ if [ "${CLIENT_MODE}" = "fips" ] ; then
+ CLIENT_OPTIONS="${CLIENT_OPTIONS} ${FIPS_OPTIONS}"
+ fi
+
start_selfserv $CIPHER_SUITES # Launch the server
VMIN="ssl3"
VMAX="tls1.1"
-
- ignore_blank_lines ${SSLCOV} | \
+ # can't use a pipe here, because we may have to restart selfserv, and
+ # doing so hides the server pid environment variable in the subshell in
+ # cygwin, which means we can't kill selfserv at the end here.
+ SSL_COV_TMP=$(mktemp /tmp/ssl_cov.XXXXXX)
+ ignore_blank_lines ${SSLCOV} > ${SSL_COV_TMP}
while read ectype testmax param testname
do
echo "${testname}" | grep "EXPORT" > /dev/null
@@ -326,6 +350,31 @@ ssl_cov()
if [ "$testmax" = "TLS12" ]; then
VMAX="tls1.2"
fi
+ if [ "$testmax" = "TLS13" ]; then
+ # if our selfserv can only do up to tls1.2
+ # restart it so it can do tls1.3, This requires
+ # moving VMIN up to tls1.0 because you can't enable SSL3 and
+ # TLS 1.3.
+ if [ "$VMIN" = "ssl3" ]; then
+ SERVER_VMIN="tls1.0"
+ SERVER_VMAX="tls1.3"
+ kill_selfserv
+ start_selfserv ${TLS13_CIPHER_SUITES}
+ unset SERVER_VMIN
+ unset SERVER_VMAX
+ VMIN="tls1.0"
+ fi
+ VMAX="tls1.3"
+ fi
+ # if we are testing ssl3 and our server can only do down to tls1.1,
+ # restart it to enable ssl3
+ if [ "$VMAX" = "ssl3" -a "$VMIN" = "tls1.1" ]; then
+ kill_selfserv
+ start_selfserv $CIPHER_SUITES
+ VMIN="ssl3"
+ fi
+
+
echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} \\"
echo " -f -d ${P_R_CLIENTDIR} $verbose -w nss < ${REQUEST_FILE}"
@@ -339,8 +388,12 @@ ssl_cov()
rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
html_msg $ret 0 "${testname}" \
"produced a returncode of $ret, expected is 0"
- done
+ done < ${SSL_COV_TMP}
+ rm -f ${SSL_COV_TMP}
+ SERVER_OPTIONS=${SAVE_SERVER_OPTIONS}
+ CLIENT_OPTIONS=${SAVE_CLIENT_OPTIONS}
+ verbose=${verbose_save}
kill_selfserv
html "</TABLE><BR>"
}
@@ -469,10 +522,6 @@ ssl_stapling_sub()
echo "$SCRIPTNAME: skipping $testname for $NORM_EXT"
return 0
fi
- if [ "$SERVER_MODE" = "fips" -o "$CLIENT_MODE" = "fips" ] ; then
- echo "$SCRIPTNAME: skipping $testname (non-FIPS only)"
- return 0
- fi
SAVE_SERVER_OPTIONS=${SERVER_OPTIONS}
SERVER_OPTIONS="${SERVER_OPTIONS} ${SO}"
@@ -485,10 +534,10 @@ ssl_stapling_sub()
start_selfserv
echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${P_R_CLIENTDIR} $verbose ${CLIENT_OPTIONS} \\"
- echo " -c v -T -O -F -M 1 -V ssl3:tls1.2 < ${REQUEST_FILE}"
+ echo " -c v -T -O -F -M 1 -V ssl3:tls1.2 ${CLIENT_PW} < ${REQUEST_FILE}"
rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${CLIENT_OPTIONS} \
- -d ${P_R_CLIENTDIR} $verbose -c v -T -O -F -M 1 -V ssl3:tls1.2 < ${REQUEST_FILE} \
+ -d ${P_R_CLIENTDIR} $verbose -c v -T -O -F -M 1 -V ssl3:tls1.2 ${CLIENT_PW} < ${REQUEST_FILE} \
>${TMP}/$HOST.tmp.$$ 2>&1
ret=$?
cat ${TMP}/$HOST.tmp.$$
@@ -518,10 +567,6 @@ ssl_stapling_stress()
echo "$SCRIPTNAME: skipping $testname for $NORM_EXT"
return 0
fi
- if [ "$SERVER_MODE" = "fips" -o "$CLIENT_MODE" = "fips" ] ; then
- echo "$SCRIPTNAME: skipping $testname (non-FIPS only)"
- return 0
- fi
SAVE_SERVER_OPTIONS=${SERVER_OPTIONS}
SERVER_OPTIONS="${SERVER_OPTIONS} ${SO}"
@@ -592,11 +637,6 @@ ssl_signed_cert_timestamps()
testname="ssl_signed_cert_timestamps"
value=0
- if [ "$SERVER_MODE" = "fips" -o "$CLIENT_MODE" = "fips" ] ; then
- echo "$SCRIPTNAME: skipping $testname (non-FIPS only)"
- return 0
- fi
-
echo "${testname}"
start_selfserv
@@ -604,10 +644,10 @@ ssl_signed_cert_timestamps()
# Since we don't have server-side support, this test only covers advertising the
# extension in the client hello.
echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${P_R_CLIENTDIR} $verbose ${CLIENT_OPTIONS} \\"
- echo " -U -V tls1.0:tls1.2 < ${REQUEST_FILE}"
+ echo " -U -V tls1.0:tls1.2 ${CLIENT_PW} < ${REQUEST_FILE}"
rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${CLIENT_OPTIONS} \
- -d ${P_R_CLIENTDIR} $verbose -U -V tls1.0:tls1.2 < ${REQUEST_FILE} \
+ -d ${P_R_CLIENTDIR} $verbose -U -V tls1.0:tls1.2 ${CLIENT_PW} < ${REQUEST_FILE} \
>${TMP}/$HOST.tmp.$$ 2>&1
ret=$?
cat ${TMP}/$HOST.tmp.$$
@@ -652,7 +692,7 @@ ssl_stress()
start_selfserv `echo "$sparam" | sed -e 's,_, ,g'`
if [ "`uname -n`" = "sjsu" ] ; then
- echo "debugging disapering selfserv... ps -ef | grep selfserv"
+ echo "debugging disappearing selfserv... ps -ef | grep selfserv"
ps -ef | grep selfserv
fi
@@ -1275,27 +1315,22 @@ ssl_dtls()
testname="ssl_dtls"
value=0
- if [ "$SERVER_MODE" = "fips" -o "$CLIENT_MODE" = "fips" ] ; then
- echo "$SCRIPTNAME: skipping $testname (non-FIPS only)"
- return 0
- fi
-
echo "${testname}"
- echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${P_R_SERVERDIR} $verbose ${SERVER_OPTIONS} \\"
- echo " -U -V tls1.1:tls1.2 -P server -Q < ${REQUEST_FILE} &"
+ echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${SERVER_OPTIONS} \\"
+ echo " -d ${P_R_SERVERDIR} $verbose -U -V tls1.1:tls1.2 -P server -n ${HOSTADDR} -w nss < ${REQUEST_FILE} &"
- ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${SERVER_OPTIONS} \
- -d ${P_R_SERVERDIR} $verbose -U -V tls1.1:tls1.2 -P server -n ${HOSTADDR} -w nss < ${REQUEST_FILE} 2>&1 &
+ (sleep 2; cat ${REQUEST_FILE}) | ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${SERVER_OPTIONS} \
+ -d ${P_R_SERVERDIR} $verbose -U -V tls1.1:tls1.2 -P server -n ${HOSTADDR} -w nss 2>&1 &
PID=$!
sleep 1
- echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${P_R_CLIENTDIR} $verbose ${CLIENT_OPTIONS} \\"
- echo " -U -V tls1.1:tls1.2 -P client -Q < ${REQUEST_FILE}"
+ echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${CLIENT_OPTIONS} \\"
+ echo " -d ${P_R_CLIENTDIR} $verbose -U -V tls1.1:tls1.2 -P client -Q ${CLIENT_PW} < ${REQUEST_FILE}"
${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${CLIENT_OPTIONS} \
- -d ${P_R_CLIENTDIR} $verbose -U -V tls1.1:tls1.2 -P client -Q < ${REQUEST_FILE} 2>&1
+ -d ${P_R_CLIENTDIR} $verbose -U -V tls1.1:tls1.2 -P client -Q ${CLIENT_PW} < ${REQUEST_FILE} 2>&1
ret=$?
html_msg $ret $value "${testname}" \
"produced a returncode of $ret, expected is $value"
@@ -1310,11 +1345,6 @@ ssl_dtls()
#########################################################################
ssl_scheme()
{
- if [ "$SERVER_MODE" = "fips" -o "$CLIENT_MODE" = "fips" ] ; then
- echo "$SCRIPTNAME: skipping $testname (non-FIPS only)"
- return 0
- fi
-
html_head "SSL SCHEME $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE"
NO_ECC_CERTS=1
@@ -1327,9 +1357,9 @@ ssl_scheme()
start_selfserv -V tls1.2:tls1.2 -J "$sscheme"
echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${P_R_CLIENTDIR} $verbose ${CLIENT_OPTIONS} \\"
- echo " -V tls1.2:tls1.2 -J "$cscheme" < ${REQUEST_FILE}"
+ echo " -V tls1.2:tls1.2 -J "$cscheme" ${CLIENT_PW} < ${REQUEST_FILE}"
${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${CLIENT_OPTIONS} \
- -d ${P_R_CLIENTDIR} $verbose -V tls1.2:tls1.2 -J "$cscheme" < ${REQUEST_FILE} 2>&1
+ -d ${P_R_CLIENTDIR} $verbose -V tls1.2:tls1.2 -J "$cscheme" ${CLIENT_PW} < ${REQUEST_FILE} 2>&1
ret=$?
# If both schemes include just one option and those options don't
# match, then the test should fail; otherwise, assume that it works.
@@ -1355,11 +1385,6 @@ ssl_scheme()
#########################################################################
ssl_scheme_stress()
{
- if [ "$SERVER_MODE" = "fips" -o "$CLIENT_MODE" = "fips" ] ; then
- echo "$SCRIPTNAME: skipping $testname (non-FIPS only)"
- return 0
- fi
-
html_head "SSL SCHEME $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE"
NO_ECC_CERTS=1
@@ -1372,9 +1397,9 @@ ssl_scheme_stress()
start_selfserv -V tls1.2:tls1.2 -J "$sscheme"
echo "strsclnt -4 -q -p ${PORT} -d ${P_R_CLIENTDIR} $verbose ${CLIENT_OPTIONS} \\"
- echo " -V tls1.2:tls1.2 -J "$cscheme" ${HOSTADDR} < ${REQUEST_FILE}"
+ echo " -V tls1.2:tls1.2 -J "$cscheme" ${HOSTADDR} ${CLIENT_PW} < ${REQUEST_FILE}"
${PROFTOOL} ${BINDIR}/strsclnt -4 -q -p ${PORT} ${CLIENT_OPTIONS} \
- -d ${P_R_CLIENTDIR} $verbose -V tls1.2:tls1.2 -J "$cscheme" ${HOSTADDR} < ${REQUEST_FILE} 2>&1
+ -d ${P_R_CLIENTDIR} $verbose -V tls1.2:tls1.2 -J "$cscheme" ${HOSTADDR} ${CLIENT_PW} < ${REQUEST_FILE} 2>&1
ret=$?
# If both schemes include just one option and those options don't
# match, then the test should fail; otherwise, assume that it works.
@@ -1411,9 +1436,9 @@ ssl_exporter()
start_selfserv -V tls1.2:tls1.2 -x "$exporter"
echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${P_R_CLIENTDIR} $verbose ${CLIENT_OPTIONS} \\"
- echo " -V tls1.2:tls1.2 -x $exporter < ${REQUEST_FILE}"
+ echo " -V tls1.2:tls1.2 -x $exporter ${CLIENT_PW} < ${REQUEST_FILE}"
${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${CLIENT_OPTIONS} \
- -d ${P_R_CLIENTDIR} $verbose -V tls1.2:tls1.2 -x "$exporter" < ${REQUEST_FILE} 2>&1 > client.out
+ -d ${P_R_CLIENTDIR} $verbose -V tls1.2:tls1.2 -x "$exporter" ${CLIENT_PW} < ${REQUEST_FILE} 2>&1 > client.out
kill_selfserv
diff <(LC_ALL=C grep -A1 "^ *Keying Material:" server.out) \
<(LC_ALL=C grep -A1 "^ *Keying Material:" client.out)
@@ -1629,9 +1654,11 @@ ssl_run_tests()
case "${CLIENT_MODE}" in
"normal")
CLIENT_OPTIONS=
+ CLIENT_PW=${CLIENT_PW_NORMAL}
;;
"fips")
- SERVER_OPTIONS=
+ CLIENT_OPTIONS=
+ CLIENT_PW=${CLIENT_PW_FIPS}
ssl_set_fips client on
;;
*)
diff --git a/tests/ssl/sslcov.txt b/tests/ssl/sslcov.txt
index 93f247b96..ca79a5e09 100644
--- a/tests/ssl/sslcov.txt
+++ b/tests/ssl/sslcov.txt
@@ -66,6 +66,9 @@
noECC TLS12 :009E TLS12_DHE_RSA_WITH_AES_128_GCM_SHA256
noECC TLS12 :00A2 TLS12_DHE_DSS_WITH_AES_128_GCM_SHA256
noECC TLS12 :CCAA TLS12_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+ noECC TLS13 :1301 TLS13_DHE_WITH_AES_128_GCM_SHA256
+ noECC TLS13 :1302 TLS13_DHE_WITH_AES_256_GCM_SHA384
+ noECC TLS13 :1303 TLS13_DHE_WITH_CHACHA20_POLY1305_SHA256
#
# ECC ciphers (TLS)
#
@@ -146,3 +149,7 @@
#
ECC TLS12 :C02F TLS12_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - RSA-PSS
ECC TLS12 :C030 TLS12_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - RSA-PSS
+# test TLS 1.3
+ ECC TLS13 :1301 TLS13_ECDHE_WITH_AES_128_GCM_SHA256
+ ECC TLS13 :1302 TLS13_ECDHE_WITH_AES_256_GCM_SHA384
+ ECC TLS13 :1303 TLS13_ECDHE_WITH_CHACHA20_POLY1305_SHA256