summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Relyea <rrelyea@redhat.com>2021-05-11 20:04:22 -0700
committerRobert Relyea <rrelyea@redhat.com>2021-05-11 20:04:22 -0700
commitfa7f2a3cefd191cc9fb55ddfc8c904e69c907a80 (patch)
treee713c1156fee284d0397bfbfd4b90e4b1112f9a3
parent1afcaab5dbb8816221287d880fe4ec85e8b4b24e (diff)
downloadnss-hg-fa7f2a3cefd191cc9fb55ddfc8c904e69c907a80.tar.gz
Bug 1710773 NSS needs FIPS 180-3 FIPS indicators. r=mt
Changes from the review: The while loop was taken out of it's subshell pipe, which prevented the selfserv PID from being passed on to the final selfserv-kill. This eventally lead to a freeze on windows. The last paragraph of ISO 19790:2012 section 7.2.4.2 states: All services shall [02.24] provide an indicator when the service utilises an approved cryptographic algorithm, security function or process in an approved manner and those services or processes specified in 7.4.3 This means our libraries need to grow an API or provide some additional information via contexts or similar in order for an application to be able to query this indicator. This can't be just a Security Policy description because ISO 24759:2017 section 6.2.4.2 states: TE02.24.02: The tester shall execute all services and verify that the indicator provides an unambiguous indication of whether the service utilizes an approved cryptographic algorithm, security function or process in an approved manner or not. The indicator can't be just a marker over an algorithm either, because it needs to show different values based on whether the algorithm parameters causes the algorithm to run in approved or non-approved mode (ie keys outside of valid range for RSA means RSA is being used in non-approved mode ...) For NSS, there is a PKCS #11 design: https://docs.google.com/document/d/1Me9YksPE7K1Suvk9Ls5PqJXPpDmpAboLsrq0z54m_tA/edit?usp=sharing This patch implments the above design as well as: 1) NSS proper functions to access these indicators from either the pk11wrap layer or the ssl layer. 2) Updates to the ssl tests which will output the value of the Changes decription by file: cmd/selfserv/selfserv.c Add a FIPS indicator if the connection was excuted in FIPS mode on a FIPS token. cmd/strsclnt/strsclnt.c Add a FIPS indicator if the connection was excuted in FIPS mode on a FIPS token. cmd/tstclnt/tstclnt.c Add a FIPS indicator if the connection was excuted in FIPS mode on a FIPS token. lib/nss/nss.def Add the new pk11 functions to access the fips indicator. lib/pk11wrap/pk11cxt.c Implement a function to get the FIPS indicator for the current PK11Context. lib/pk11wrap/pk11load.c Get the fips indicator function from the PKCS #11 module using the vendor function interface from PKCS #11 v3.0 lib/pk11wrap/pk11obj.c Implement a function to get the FIPS indicator for a specific PKCS #11 object. lib/pk11wrap/pk11priv.h Add a generalized helper function to get the FIPS indicator used by all the other exported functions to get FIPS indicator. lib/pk11wrap/pk11pub.h Add function to get the FIPS indicator for the current PK11Context. lib/pk11wrap/pk11slot.c Implement a generalized helper function to get the FIPS indicator. Implement a function to get the FIPS indicator for the latest single shot operation on the slot. lib/pk11wrap/secmodt.h Add a new field to hold the fipsIndicator function. lib/softoken/fips_algorithms.h New sample header which vendors can replace with their own table. In the default NSS case, the table in this header will be empty. lib/softoken/fipstokn.c Add Vendor specific interface for the FIPS indicator to the FIPS token. lib/softoken/pkcs11.c Add Vendor specific interface for the FIPS indicator to the non-FIPS token. Factor out the code tha maps an attribute value to a mechanism flag to it's own file so it can be used by other parts of softoken. (new function is in pkcs11u.c Implement the function that returns the FIPS indicator. This function fetches the indicator from either the session or the object or both. The session indicator is in the crypto context (except the last operation indicator, which is in the session itself. The object indicator is in the base object. lib/softoken/pkcs11c.c Record the FIPS indicator in the various helper function. - sftk_TerminateOp is called when a crypto operation had been finalized, so we can store that fips indicator in the lastOpWasFIPS field. - sftk_InitGeneric is called when a crypto operation has been initialized, so we can make a preliminary determination if the operation is within the FIPS policy (could later change bases on other operations. For this to work, we need the actual mechanism, so pMechanism is now a parameter to sftk_InitGeneric. - sftk_HKDF - HKDF when used in TLS has the unusual characteristic that the salt could actually be a key. In this case, usually the base key is some known public value which would not be FIPS generated, but the security is based on whether the salt is really a FIPS generated key. In this case we redo the calculation based on the salt key. lib/softoken/pkcs11i.h - add the FIPS indicators to the various structures (crypto contexts, sessions, objects). - add the FIPS indicators function list - add pMechanism the the sftkInitGeneric function. - add the helper function to map Attribute Types to Mechanism Flags. - add the function that will look up the current operation in the FIPS table to determine that it is allowed by policy. lib/softoken/pkcs11u.c - include the new fips_algorithms.h (if NSS_FIPS_DISABLED is not on) - handle the FIPS status for objects and session on creation an copy. - implement the helper function to map Attribute Types to Mechanism Flags. - get the key length of a key. This involves getting the key type and then using the key type to determin the appropriate attribute to fetch. Most keys it's simply the CKA_VALUE. ECC is special, we get the key length from the curve. Since only a subset of curves can be FIPS Curves, we use key length to return false for other curves. - the handle special function handles any unusal semantics for various mechanism types. This function precodes possible mechanism semantics we may need to check. The special handling can be selected by the mechanism table in fips_algorithms.h - sftk_operationIsFIPS - the actual function to determine if the givelib/n operation is in the FIPS table. lib/softoken/sftkmessage.c - just need to update the sftk_InitGeneric function to pass the mechanism. lib/ssl/ssl3con.c - and functions to query the underlying crypto contexts to see if the current ssl session is running in FIPS approved mode based on the security policy. It does so by checking the CipherSpecIsFIPS function to verify that both the mac and the encryption algorithm FIPS conforms to the ciphers in the security profile (using PK11_GetFIPSStatus). We check both the cipher specs for read and write. These underlying specs depends on the keys used in these specs being generated with FIPS approved algorithms as well, so this verifies the kea and kdf functions as well. lib/ssl/sslimpl.h - ass ssl_isFIPS() so it can be used by other files here in the ssl directory. lib/ssl/sslinfo.c - set the new isFIPS field in the existing sslinfo structure. SSL_GetChannelInfo knows how to handle sslinfo structures that are smaller then expected and larger than expected. unknown fields will be set to '0' (so new applications running against old versions will always get zero for new fields). sslinfo that are smaller will only return a the subset the calling application expects (so old applications will not get the new fields). lib/ssl/sslt.h - Add the new isFIPS field (must be at the end of the ChannelInfo structure). lib/util/pkcs11n.h - add the new FIPS indicator defines. tests/ssl/ssl.h - The main changes was to turn on verbose for the coverage tests so we can test the FIPS indicators on various cipher suites. NOTE: this only works with either NSS_TEST_FIPS_ALGORIHTMS set, or a vendor fips_algorthims.h, so vendors will need to do their own test interpretation. While working in ssl.sh I fixed an number of other issues: - many tests that were skipped in FIPS mode were skipped not because they didn't work in FIPS mode, but because tstclnt requires a password when running in FIPS mode. I've now added the password if the function is running in fips mode and removed the fips restrictions. - dtls had a race condition. the server side needed to come up before the client, but couldn't end before the client ran. We already had a sleep to guarrentee the former, I added a sleep before sending the server it's data to handle the latter. - CURVE25519 is the default ECC curve, but it's not a fiPS curve, so I disable it in FIPS mode so we will actually get FIPS indicators when using ECDHE. - I added TLS 1.3 to the coverage tests. Differential Revision: https://phabricator.services.mozilla.com/D115034
-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