diff --git a/.gitignore b/.gitignore index 42f8cb6..a250c86 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,8 @@ SOURCES/cert8.db.xml SOURCES/cert9.db.xml SOURCES/key3.db.xml SOURCES/key4.db.xml -SOURCES/nss-3.41.tar.gz +SOURCES/nss-3.44.tar.gz SOURCES/nss-config.xml +SOURCES/nss-softokn-cavs-1.0.tar.gz SOURCES/secmod.db.xml SOURCES/setup-nsssysinit.xml diff --git a/.nss.metadata b/.nss.metadata index 359f253..bd0ba0b 100644 --- a/.nss.metadata +++ b/.nss.metadata @@ -7,7 +7,8 @@ bd748cf6e1465a1bbe6e751b72ffc0076aff0b50 SOURCES/blank-secmod.db ea6705e15999bdc6365f05b3d66f9c1d49677f84 SOURCES/cert9.db.xml 24c123810543ff0f6848647d6d910744e275fb01 SOURCES/key3.db.xml af51b16a56fda1f7525a0eed3ecbdcbb4133be0c SOURCES/key4.db.xml -69c60e8d3190573dbcbc01f50e68e3ceb7d92522 SOURCES/nss-3.41.tar.gz +44a83b1bf4efd27605177ecdbf217e579ae8c8ae SOURCES/nss-3.44.tar.gz 2905c9b06e7e686c9e3c0b5736a218766d4ae4c2 SOURCES/nss-config.xml +d8a7f044570732caf4ed06fd44a63b3e86ea2a16 SOURCES/nss-softokn-cavs-1.0.tar.gz ca9ebf79c1437169a02527c18b1e3909943c4be9 SOURCES/secmod.db.xml bcbe05281b38d843273f91ae3f9f19f70c7d97b3 SOURCES/setup-nsssysinit.xml diff --git a/SOURCES/enable-fips-when-system-is-in-fips-mode.patch b/SOURCES/enable-fips-when-system-is-in-fips-mode.patch deleted file mode 100644 index dde5dcb..0000000 --- a/SOURCES/enable-fips-when-system-is-in-fips-mode.patch +++ /dev/null @@ -1,79 +0,0 @@ -diff -up nss/lib/pk11wrap/pk11pars.c.852023_enable_fips_when_in_fips_mode nss/lib/pk11wrap/pk11pars.c ---- nss/lib/pk11wrap/pk11pars.c.852023_enable_fips_when_in_fips_mode 2018-03-05 16:58:32.000000000 +0100 -+++ nss/lib/pk11wrap/pk11pars.c 2018-03-09 17:24:39.815838810 +0100 -@@ -671,6 +671,10 @@ SECMOD_CreateModuleEx(const char *librar - - mod->internal = NSSUTIL_ArgHasFlag("flags", "internal", nssc); - mod->isFIPS = NSSUTIL_ArgHasFlag("flags", "FIPS", nssc); -+ /* if the system FIPS mode is enabled, force FIPS to be on */ -+ if (SECMOD_GetSystemFIPSEnabled()) { -+ mod->isFIPS = PR_TRUE; -+ } - mod->isCritical = NSSUTIL_ArgHasFlag("flags", "critical", nssc); - slotParams = NSSUTIL_ArgGetParamValue("slotParams", nssc); - mod->slotInfo = NSSUTIL_ArgParseSlotInfo(mod->arena, slotParams, -diff -up nss/lib/pk11wrap/pk11util.c.852023_enable_fips_when_in_fips_mode nss/lib/pk11wrap/pk11util.c ---- nss/lib/pk11wrap/pk11util.c.852023_enable_fips_when_in_fips_mode 2018-03-05 16:58:32.000000000 +0100 -+++ nss/lib/pk11wrap/pk11util.c 2018-03-09 17:25:46.804347730 +0100 -@@ -95,6 +95,26 @@ SECMOD_Shutdown() - return SECSuccess; - } - -+int SECMOD_GetSystemFIPSEnabled(void) { -+#ifdef LINUX -+ FILE *f; -+ char d; -+ size_t size; -+ -+ f = fopen("/proc/sys/crypto/fips_enabled", "r"); -+ if (!f) -+ return 0; -+ -+ size = fread(&d, 1, 1, f); -+ fclose(f); -+ if (size != 1) -+ return 0; -+ if (d == '1') -+ return 1; -+#endif -+ return 0; -+} -+ - /* - * retrieve the internal module - */ -@@ -428,7 +448,7 @@ SECMOD_DeleteInternalModule(const char * - SECMODModuleList **mlpp; - SECStatus rv = SECFailure; - -- if (pendingModule) { -+ if (SECMOD_GetSystemFIPSEnabled() || pendingModule) { - PORT_SetError(SEC_ERROR_MODULE_STUCK); - return rv; - } -@@ -963,7 +983,7 @@ SECMOD_CanDeleteInternalModule(void) - #ifdef NSS_FIPS_DISABLED - return PR_FALSE; - #else -- return (PRBool)(pendingModule == NULL); -+ return (PRBool) ((pendingModule == NULL) && !SECMOD_GetSystemFIPSEnabled()); - #endif - } - -diff -up nss/lib/pk11wrap/secmodi.h.852023_enable_fips_when_in_fips_mode nss/lib/pk11wrap/secmodi.h ---- nss/lib/pk11wrap/secmodi.h.852023_enable_fips_when_in_fips_mode 2018-03-05 16:58:32.000000000 +0100 -+++ nss/lib/pk11wrap/secmodi.h 2018-03-09 17:24:39.816838788 +0100 -@@ -115,6 +115,13 @@ PK11SymKey *pk11_TokenKeyGenWithFlagsAnd - CK_MECHANISM_TYPE pk11_GetPBECryptoMechanism(SECAlgorithmID *algid, - SECItem **param, SECItem *pwd, PRBool faulty3DES); - -+/* Get the state of the system FIPS mode */ -+/* NSS uses this to force FIPS mode if the system bit is on. Applications which -+ * use the SECMOD_CanDeleteInteral() to check to see if they can switch to or -+ * from FIPS mode will automatically be told that they can't swith out of FIPS -+ * mode */ -+int SECMOD_GetSystemFIPSEnabled(); -+ - extern void pk11sdr_Init(void); - extern void pk11sdr_Shutdown(void); - diff --git a/SOURCES/nss-3.39-create-public-key-on-private-import.patch b/SOURCES/nss-3.39-create-public-key-on-private-import.patch deleted file mode 100644 index c17a38a..0000000 --- a/SOURCES/nss-3.39-create-public-key-on-private-import.patch +++ /dev/null @@ -1,804 +0,0 @@ -# HG changeset patch -# User Robert Relyea -# Date 1544226862 28800 -# Fri Dec 07 15:54:22 2018 -0800 -# Node ID 521a5b2f10cc197b9349df033f9d3cca0b5226c5 -# Parent 5ac4d4904afae59149bb1fab49c3b21244a51a22 -try: -b do -u all - p all -t all - -diff --git a/cmd/manifest.mn b/cmd/manifest.mn ---- a/cmd/manifest.mn -+++ b/cmd/manifest.mn -@@ -51,16 +51,17 @@ NSS_SRCDIRS = \ - ocspclnt \ - ocspresp \ - oidcalc \ - p7content \ - p7env \ - p7sign \ - p7verify \ - pk12util \ -+ pk11import \ - pk11ectest \ - pk11gcmtest \ - pk11mode \ - pk1sign \ - pp \ - pwdecrypt \ - rsaperf \ - rsapoptst \ -diff --git a/cmd/pk11import/Makefile b/cmd/pk11import/Makefile -new file mode 100644 ---- /dev/null -+++ b/cmd/pk11import/Makefile -@@ -0,0 +1,43 @@ -+#! gmake -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+####################################################################### -+# (1) Include initial platform-independent assignments (MANDATORY). # -+####################################################################### -+ -+include manifest.mn -+ -+####################################################################### -+# (2) Include "global" configuration information. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/config.mk -+ -+####################################################################### -+# (3) Include "component" configuration information. (OPTIONAL) # -+####################################################################### -+ -+####################################################################### -+# (4) Include "local" platform-dependent assignments (OPTIONAL). # -+####################################################################### -+ -+include ../platlibs.mk -+ -+####################################################################### -+# (5) Execute "global" rules. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/rules.mk -+ -+####################################################################### -+# (6) Execute "component" rules. (OPTIONAL) # -+####################################################################### -+ -+####################################################################### -+# (7) Execute "local" rules. (OPTIONAL). # -+####################################################################### -+ -+include ../platrules.mk -diff --git a/cmd/pk11import/manifest.mn b/cmd/pk11import/manifest.mn -new file mode 100644 ---- /dev/null -+++ b/cmd/pk11import/manifest.mn -@@ -0,0 +1,15 @@ -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+CORE_DEPTH = ../.. -+ -+MODULE = nss -+ -+CSRCS = pk11import.c \ -+ $(NULL) -+ -+REQUIRES = seccmd -+ -+PROGRAM = pk11import -+ -diff --git a/cmd/pk11import/pk11import.c b/cmd/pk11import/pk11import.c -new file mode 100644 ---- /dev/null -+++ b/cmd/pk11import/pk11import.c -@@ -0,0 +1,410 @@ -+/* 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/. */ -+ -+#include "secutil.h" -+#include "secmod.h" -+#include "cert.h" -+#include "secoid.h" -+#include "nss.h" -+#include "pk11pub.h" -+#include "pk11pqg.h" -+ -+/* NSPR 2.0 header files */ -+#include "prinit.h" -+#include "prprf.h" -+#include "prsystem.h" -+#include "prmem.h" -+/* Portable layer header files */ -+#include "plstr.h" -+ -+SECOidData * -+getCurveFromString(char *curve_name) -+{ -+ SECOidTag tag = SEC_OID_SECG_EC_SECP256R1; -+ -+ if (PORT_Strcasecmp(curve_name, "NISTP256") == 0) { -+ } else if (PORT_Strcasecmp(curve_name, "NISTP384") == 0) { -+ tag = SEC_OID_SECG_EC_SECP384R1; -+ } else if (PORT_Strcasecmp(curve_name, "NISTP521") == 0) { -+ tag = SEC_OID_SECG_EC_SECP521R1; -+ } else if (PORT_Strcasecmp(curve_name, "Curve25519") == 0) { -+ tag = SEC_OID_CURVE25519; -+ } -+ return SECOID_FindOIDByTag(tag); -+} -+ -+void -+dumpItem(const char *label, const SECItem *item) -+{ -+ int i; -+ printf("%s = [%d bytes] {", label, item->len); -+ for (i = 0; i < item->len; i++) { -+ if ((i & 0xf) == 0) -+ printf("\n "); -+ else -+ printf(", "); -+ printf("%02x", item->data[i]); -+ } -+ printf("};\n"); -+} -+ -+SECStatus -+handleEncryptedPrivateImportTest(char *progName, PK11SlotInfo *slot, -+ char *testname, CK_MECHANISM_TYPE genMech, void *params, void *pwArgs) -+{ -+ SECStatus rv = SECSuccess; -+ SECItem privID = { 0 }; -+ SECItem pubID = { 0 }; -+ SECItem pubValue = { 0 }; -+ SECItem pbePwItem = { 0 }; -+ SECItem nickname = { 0 }; -+ SECItem token = { 0 }; -+ SECKEYPublicKey *pubKey = NULL; -+ SECKEYPrivateKey *privKey = NULL; -+ PK11GenericObject *objs = NULL; -+ PK11GenericObject *obj = NULL; -+ SECKEYEncryptedPrivateKeyInfo *epki = NULL; -+ PRBool keyFound = 0; -+ KeyType keyType; -+ -+ fprintf(stderr, "Testing %s PrivateKeyImport ***********************\n", -+ testname); -+ -+ /* generate a temp key */ -+ privKey = PK11_GenerateKeyPair(slot, genMech, params, &pubKey, -+ PR_FALSE, PR_TRUE, pwArgs); -+ if (privKey == NULL) { -+ SECU_PrintError(progName, "PK11_GenerateKeyPair Failed"); -+ goto cleanup; -+ } -+ -+ /* wrap the temp key */ -+ pbePwItem.data = (unsigned char *)"pw"; -+ pbePwItem.len = 2; -+ epki = PK11_ExportEncryptedPrivKeyInfo(slot, SEC_OID_AES_256_CBC, -+ &pbePwItem, privKey, 1, NULL); -+ if (epki == NULL) { -+ SECU_PrintError(progName, "PK11_ExportEncryptedPrivKeyInfo Failed"); -+ goto cleanup; -+ } -+ -+ /* Save the public value, which we will need on import */ -+ keyType = pubKey->keyType; -+ switch (keyType) { -+ case rsaKey: -+ SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.rsa.modulus); -+ break; -+ case dhKey: -+ SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.dh.publicValue); -+ break; -+ case dsaKey: -+ SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.dsa.publicValue); -+ break; -+ case ecKey: -+ SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.ec.publicValue); -+ break; -+ default: -+ fprintf(stderr, "Unknown keytype = %d\n", keyType); -+ goto cleanup; -+ } -+ dumpItem("pubValue", &pubValue); -+ -+ /* when Asymetric keys represent session keys, those session keys are -+ * destroyed when we destroy the Asymetric key representations */ -+ SECKEY_DestroyPublicKey(pubKey); -+ pubKey = NULL; -+ SECKEY_DestroyPrivateKey(privKey); -+ privKey = NULL; -+ -+ /* unwrap the temp key as a perm */ -+ nickname.data = (unsigned char *)"testKey"; -+ nickname.len = sizeof("testKey"); -+ rv = PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(slot, epki, &pbePwItem, -+ &nickname, &pubValue, PR_TRUE, PR_TRUE, keyType, 0, &privKey, NULL); -+ if (rv != SECSuccess) { -+ SECU_PrintError(progName, "PK11_ImportEncryptedPrivateKeyInfo Failed"); -+ goto cleanup; -+ } -+ -+ /* verify the public key exists */ -+ rv = PK11_ReadRawAttribute(PK11_TypePrivKey, privKey, CKA_ID, &privID); -+ if (rv != SECSuccess) { -+ SECU_PrintError(progName, -+ "Couldn't read CKA_ID from pub key, checking next key"); -+ goto cleanup; -+ } -+ dumpItem("privKey CKA_ID", &privID); -+ objs = PK11_FindGenericObjects(slot, CKO_PUBLIC_KEY); -+ for (obj = objs; obj; obj = PK11_GetNextGenericObject(obj)) { -+ rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_ID, &pubID); -+ if (rv != SECSuccess) { -+ SECU_PrintError(progName, -+ "Couldn't read CKA_ID from pub key, checking next key"); -+ continue; -+ } -+ dumpItem("pubKey CKA_ID", &pubID); -+ if (!SECITEM_ItemsAreEqual(&privID, &pubID)) { -+ fprintf(stderr, -+ "CKA_ID does not match priv key, checking next key\n"); -+ SECITEM_FreeItem(&pubID, PR_FALSE); -+ continue; -+ } -+ SECITEM_FreeItem(&pubID, PR_FALSE); -+ rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_TOKEN, &token); -+ if (rv == SECSuccess) { -+ if (token.len == 1) { -+ keyFound = token.data[0]; -+ } -+ SECITEM_FreeItem(&token, PR_FALSE); -+ } -+ if (keyFound) { -+ printf("matching public key found\n"); -+ break; -+ } -+ printf("Matching key was not a token key, checking next key\n"); -+ } -+cleanup: -+ if (objs) { -+ PK11_DestroyGenericObjects(objs); -+ } -+ if (pubValue.data) { -+ SECITEM_FreeItem(&pubValue, PR_FALSE); -+ } -+ if (privID.data) { -+ SECITEM_FreeItem(&privID, PR_FALSE); -+ } -+ if (epki) { -+ PORT_FreeArena(epki->arena, PR_TRUE); -+ } -+ if (pubKey) { -+ SECKEY_DestroyPublicKey(pubKey); -+ } -+ if (privKey) { -+ SECKEY_DestroyPrivateKey(privKey); -+ } -+ fprintf(stderr, "%s PrivateKeyImport %s ***********************\n", -+ testname, keyFound ? "PASSED" : "FAILED"); -+ return keyFound ? SECSuccess : SECFailure; -+} -+ -+static const char *const usageInfo[] = { -+ "pk11import - test PK11_PrivateKeyImport()" -+ "Options:", -+ " -d certdir directory containing cert database", -+ " -k keysize size of the rsa, dh, and dsa key to test (default 1024)", -+ " -C ecc_curve ecc curve (default )", -+ " -f pwFile file to fetch the password from", -+ " -p pwString password", -+ " -r skip rsa test", -+ " -D skip dsa test", -+ " -h skip dh test", -+ " -e skip ec test", -+}; -+static int nUsageInfo = sizeof(usageInfo) / sizeof(char *); -+ -+static void -+Usage(char *progName, FILE *outFile) -+{ -+ int i; -+ fprintf(outFile, "Usage: %s [ commands ] options\n", progName); -+ for (i = 0; i < nUsageInfo; i++) -+ fprintf(outFile, "%s\n", usageInfo[i]); -+ exit(-1); -+} -+ -+enum { -+ opt_CertDir, -+ opt_KeySize, -+ opt_ECCurve, -+ opt_PWFile, -+ opt_PWString, -+ opt_NoRSA, -+ opt_NoDSA, -+ opt_NoDH, -+ opt_NoEC -+}; -+ -+static secuCommandFlag options[] = -+ { -+ { /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE }, -+ { /* opt_KeySize */ 'k', PR_TRUE, 0, PR_FALSE }, -+ { /* opt_ECCurve */ 'C', PR_TRUE, 0, PR_FALSE }, -+ { /* opt_PWFile */ 'f', PR_TRUE, 0, PR_FALSE }, -+ { /* opt_PWString */ 'p', PR_TRUE, 0, PR_FALSE }, -+ { /* opt_NORSA */ 'r', PR_FALSE, 0, PR_FALSE }, -+ { /* opt_NoDSA */ 'D', PR_FALSE, 0, PR_FALSE }, -+ { /* opt_NoDH */ 'h', PR_FALSE, 0, PR_FALSE }, -+ { /* opt_NoEC */ 'e', PR_FALSE, 0, PR_FALSE }, -+ }; -+ -+int -+main(int argc, char **argv) -+{ -+ char *progName; -+ SECStatus rv; -+ secuCommand args; -+ PK11SlotInfo *slot = NULL; -+ PRBool failed = PR_FALSE; -+ secuPWData pwArgs = { PW_NONE, 0 }; -+ PRBool doRSA = PR_TRUE; -+ PRBool doDSA = PR_TRUE; -+ PRBool doDH = PR_FALSE; /* NSS currently can't export wrapped DH keys */ -+ PRBool doEC = PR_TRUE; -+ PQGParams *pqgParams = NULL; -+ int keySize; -+ -+ args.numCommands = 0; -+ args.numOptions = sizeof(options) / sizeof(secuCommandFlag); -+ args.commands = NULL; -+ args.options = options; -+ -+#ifdef XP_PC -+ progName = strrchr(argv[0], '\\'); -+#else -+ progName = strrchr(argv[0], '/'); -+#endif -+ progName = progName ? progName + 1 : argv[0]; -+ -+ rv = SECU_ParseCommandLine(argc, argv, progName, &args); -+ if (SECSuccess != rv) { -+ Usage(progName, stderr); -+ } -+ -+ /* Set the certdb directory (default is ~/.netscape) */ -+ rv = NSS_InitReadWrite(SECU_ConfigDirectory(args.options[opt_CertDir].arg)); -+ if (rv != SECSuccess) { -+ SECU_PrintPRandOSError(progName); -+ return 255; -+ } -+ PK11_SetPasswordFunc(SECU_GetModulePassword); -+ -+ /* below here, goto cleanup */ -+ SECU_RegisterDynamicOids(); -+ -+ /* handle the arguments */ -+ if (args.options[opt_PWFile].arg) { -+ pwArgs.source = PW_FROMFILE; -+ pwArgs.data = args.options[opt_PWFile].arg; -+ } -+ if (args.options[opt_PWString].arg) { -+ pwArgs.source = PW_PLAINTEXT; -+ pwArgs.data = args.options[opt_PWString].arg; -+ } -+ if (args.options[opt_NoRSA].activated) { -+ doRSA = PR_FALSE; -+ } -+ if (args.options[opt_NoDSA].activated) { -+ doDSA = PR_FALSE; -+ } -+ if (args.options[opt_NoDH].activated) { -+ doDH = PR_FALSE; -+ } -+ if (args.options[opt_NoEC].activated) { -+ doEC = PR_FALSE; -+ } -+ -+ slot = PK11_GetInternalKeySlot(); -+ if (slot == NULL) { -+ SECU_PrintError(progName, "Couldn't find the internal key slot\n"); -+ return 255; -+ } -+ rv = PK11_Authenticate(slot, PR_TRUE, &pwArgs); -+ if (rv != SECSuccess) { -+ SECU_PrintError(progName, "Failed to log into slot"); -+ PK11_FreeSlot(slot); -+ return 255; -+ } -+ -+ keySize = 1024; -+ if (args.options[opt_KeySize].activated && -+ args.options[opt_KeySize].arg) { -+ keySize = atoi(args.options[opt_KeySize].arg); -+ } -+ -+ if (doDSA || doDH) { -+ PQGVerify *pqgVfy; -+ rv = PK11_PQG_ParamGenV2(keySize, 0, keySize / 16, &pqgParams, &pqgVfy); -+ if (rv == SECSuccess) { -+ PK11_PQG_DestroyVerify(pqgVfy); -+ } else { -+ SECU_PrintError(progName, -+ "PK11_PQG_ParamGenV2 failed, can't test DH or DSA"); -+ doDSA = doDH = PR_FALSE; -+ failed = PR_TRUE; -+ } -+ } -+ -+ if (doRSA) { -+ PK11RSAGenParams rsaParams; -+ rsaParams.keySizeInBits = keySize; -+ rsaParams.pe = 0x010001; -+ rv = handleEncryptedPrivateImportTest(progName, slot, "RSA", -+ CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams, &pwArgs); -+ if (rv != SECSuccess) { -+ fprintf(stderr, "RSA Import Failed!\n"); -+ failed = PR_TRUE; -+ } -+ } -+ if (doDSA) { -+ rv = handleEncryptedPrivateImportTest(progName, slot, "DSA", -+ CKM_DSA_KEY_PAIR_GEN, pqgParams, &pwArgs); -+ if (rv != SECSuccess) { -+ fprintf(stderr, "DSA Import Failed!\n"); -+ failed = PR_TRUE; -+ } -+ } -+ if (doDH) { -+ SECKEYDHParams dhParams; -+ dhParams.prime = pqgParams->prime; -+ dhParams.base = pqgParams->base; -+ rv = handleEncryptedPrivateImportTest(progName, slot, "DH", -+ CKM_DH_PKCS_KEY_PAIR_GEN, &dhParams, &pwArgs); -+ if (rv != SECSuccess) { -+ fprintf(stderr, "DH Import Failed!\n"); -+ failed = PR_TRUE; -+ } -+ } -+ if (doEC) { -+ SECKEYECParams ecParams; -+ SECOidData *curve = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); -+ if (args.options[opt_ECCurve].activated && -+ args.options[opt_ECCurve].arg) { -+ curve = getCurveFromString(args.options[opt_ECCurve].arg); -+ } -+ ecParams.data = PORT_Alloc(curve->oid.len + 2); -+ if (ecParams.data == NULL) { -+ rv = SECFailure; -+ goto ec_failed; -+ } -+ ecParams.data[0] = SEC_ASN1_OBJECT_ID; -+ ecParams.data[1] = (unsigned char)curve->oid.len; -+ PORT_Memcpy(&ecParams.data[2], curve->oid.data, curve->oid.len); -+ ecParams.len = curve->oid.len + 2; -+ rv = handleEncryptedPrivateImportTest(progName, slot, "ECC", -+ CKM_EC_KEY_PAIR_GEN, &ecParams, &pwArgs); -+ PORT_Free(ecParams.data); -+ ec_failed: -+ if (rv != SECSuccess) { -+ fprintf(stderr, "ECC Import Failed!\n"); -+ failed = PR_TRUE; -+ } -+ } -+ -+ if (pqgParams) { -+ PK11_PQG_DestroyParams(pqgParams); -+ } -+ -+ if (slot) { -+ PK11_FreeSlot(slot); -+ } -+ -+ rv = NSS_Shutdown(); -+ if (rv != SECSuccess) { -+ fprintf(stderr, "Shutdown failed\n"); -+ SECU_PrintPRandOSError(progName); -+ return 255; -+ } -+ -+ return failed ? 1 : 0; -+} -diff --git a/cmd/pk11import/pk11import.gyp b/cmd/pk11import/pk11import.gyp -new file mode 100644 ---- /dev/null -+++ b/cmd/pk11import/pk11import.gyp -@@ -0,0 +1,25 @@ -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+{ -+ 'includes': [ -+ '../../coreconf/config.gypi', -+ '../../cmd/platlibs.gypi' -+ ], -+ 'targets': [ -+ { -+ 'target_name': 'pk11import', -+ 'type': 'executable', -+ 'sources': [ -+ 'pk11import.c' -+ ], -+ 'dependencies': [ -+ '<(DEPTH)/exports.gyp:dbm_exports', -+ '<(DEPTH)/exports.gyp:nss_exports' -+ ] -+ } -+ ], -+ 'variables': { -+ 'module': 'nss' -+ } -+} -diff --git a/lib/pk11wrap/pk11akey.c b/lib/pk11wrap/pk11akey.c ---- a/lib/pk11wrap/pk11akey.c -+++ b/lib/pk11wrap/pk11akey.c -@@ -1672,16 +1672,96 @@ PK11_MakeKEAPubKey(unsigned char *keyDat - rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.KEAKey, &pkData); - if (rv != SECSuccess) { - PORT_FreeArena(arena, PR_FALSE); - return NULL; - } - return pubk; - } - -+SECStatus -+SECKEY_SetPublicValue(SECKEYPrivateKey *privKey, SECItem *publicValue) -+{ -+ SECStatus rv; -+ SECKEYPublicKey pubKey; -+ PLArenaPool *arena; -+ PK11SlotInfo *slot = privKey->pkcs11Slot; -+ CK_OBJECT_HANDLE privKeyID = privKey->pkcs11ID; -+ -+ pubKey.arena = NULL; -+ pubKey.keyType = privKey->keyType; -+ pubKey.pkcs11Slot = NULL; -+ pubKey.pkcs11ID = CK_INVALID_HANDLE; -+ /* can't use PORT_InitCheapArena here becase SECKEY_DestroyPublic is used -+ * to free it, and it uses PORT_FreeArena which not only frees the -+ * underlying arena, it also frees the allocated arena struct. */ -+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); -+ pubKey.arena = arena; -+ if (arena == NULL) { -+ return SECFailure; -+ } -+ rv = SECFailure; -+ switch (privKey->keyType) { -+ default: -+ /* error code already set to SECFailure */ -+ break; -+ case rsaKey: -+ pubKey.u.rsa.modulus = *publicValue; -+ rv = PK11_ReadAttribute(slot, privKeyID, CKA_PUBLIC_EXPONENT, -+ arena, &pubKey.u.rsa.publicExponent); -+ break; -+ case dsaKey: -+ pubKey.u.dsa.publicValue = *publicValue; -+ rv = PK11_ReadAttribute(slot, privKeyID, CKA_PRIME, -+ arena, &pubKey.u.dsa.params.prime); -+ if (rv != SECSuccess) { -+ break; -+ } -+ rv = PK11_ReadAttribute(slot, privKeyID, CKA_SUBPRIME, -+ arena, &pubKey.u.dsa.params.subPrime); -+ if (rv != SECSuccess) { -+ break; -+ } -+ rv = PK11_ReadAttribute(slot, privKeyID, CKA_BASE, -+ arena, &pubKey.u.dsa.params.base); -+ break; -+ case dhKey: -+ pubKey.u.dh.publicValue = *publicValue; -+ rv = PK11_ReadAttribute(slot, privKeyID, CKA_PRIME, -+ arena, &pubKey.u.dh.prime); -+ if (rv != SECSuccess) { -+ break; -+ } -+ rv = PK11_ReadAttribute(slot, privKeyID, CKA_BASE, -+ arena, &pubKey.u.dh.base); -+ break; -+ case ecKey: -+ pubKey.u.ec.publicValue = *publicValue; -+ pubKey.u.ec.encoding = ECPoint_Undefined; -+ pubKey.u.ec.size = 0; -+ rv = PK11_ReadAttribute(slot, privKeyID, CKA_EC_PARAMS, -+ arena, &pubKey.u.ec.DEREncodedParams); -+ break; -+ } -+ if (rv == SECSuccess) { -+ rv = PK11_ImportPublicKey(slot, &pubKey, PR_TRUE); -+ } -+ /* Even though pubKey is stored on the stack, we've allocated -+ * some of it's data from the arena. SECKEY_DestroyPublicKey -+ * destroys keys by freeing the arena, so this will clean up all -+ * the data we allocated specifically for the key above. It will -+ * also free any slot references which we may have picked up in -+ * PK11_ImportPublicKey. It won't delete the underlying key if -+ * its a Token/Permanent key (which it will be if -+ * PK11_ImportPublicKey succeeds). */ -+ SECKEY_DestroyPublicKey(&pubKey); -+ -+ return rv; -+} -+ - /* - * NOTE: This function doesn't return a SECKEYPrivateKey struct to represent - * the new private key object. If it were to create a session object that - * could later be looked up by its nickname, it would leak a SECKEYPrivateKey. - * So isPerm must be true. - */ - SECStatus - PK11_ImportEncryptedPrivateKeyInfo(PK11SlotInfo *slot, -@@ -1797,22 +1877,16 @@ try_faulty_3des: - - PORT_Assert(usage != NULL); - PORT_Assert(usageCount != 0); - privKey = PK11_UnwrapPrivKey(slot, key, cryptoMechType, - crypto_param, &epki->encryptedData, - nickname, publicValue, isPerm, isPrivate, - key_type, usage, usageCount, wincx); - if (privKey) { -- if (privk) { -- *privk = privKey; -- } else { -- SECKEY_DestroyPrivateKey(privKey); -- } -- privKey = NULL; - rv = SECSuccess; - goto done; - } - - /* if we are unable to import the key and the pbeMechType is - * CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC, then it is possible that - * the encrypted blob was created with a buggy key generation method - * which is described in the PKCS 12 implementation notes. So we -@@ -1832,16 +1906,35 @@ try_faulty_3des: - faulty3DES = PR_TRUE; - goto try_faulty_3des; - } - - /* key import really did fail */ - rv = SECFailure; - - done: -+ if ((rv == SECSuccess) && isPerm) { -+ /* If we are importing a token object, -+ * create the corresponding public key. -+ * If this fails, just continue as the target -+ * token simply might not support persistant -+ * public keys. Such tokens are usable, but -+ * need to be authenticated before searching -+ * for user certs. */ -+ (void)SECKEY_SetPublicValue(privKey, publicValue); -+ } -+ -+ if (privKey) { -+ if (privk) { -+ *privk = privKey; -+ } else { -+ SECKEY_DestroyPrivateKey(privKey); -+ } -+ privKey = NULL; -+ } - if (crypto_param != NULL) { - SECITEM_ZfreeItem(crypto_param, PR_TRUE); - } - - if (key != NULL) { - PK11_FreeSymKey(key); - } - -diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c ---- a/lib/softoken/pkcs11.c -+++ b/lib/softoken/pkcs11.c -@@ -1810,29 +1810,36 @@ sftk_GetPubKey(SFTKObject *object, CK_KE - * Some curves are always pressumed to be non-DER. - */ - if (pubKey->u.ec.publicValue.len == keyLen && - (pubKey->u.ec.ecParams.fieldID.type == ec_field_plain || - pubKey->u.ec.publicValue.data[0] == EC_POINT_FORM_UNCOMPRESSED)) { - break; /* key was not DER encoded, no need to unwrap */ - } - -- PORT_Assert(pubKey->u.ec.ecParams.name != ECCurve25519); -+ /* The PKCS #11 spec says that the Params should be DER encoded. Even though the params from the -+ * Certificate aren't according the the ECCurve 25519 spec. We should accept this encoding. -+ PORT_Assert(pubKey->u.ec.ecParams.name != ECCurve25519); */ - - /* handle the encoded case */ - if ((pubKey->u.ec.publicValue.data[0] == SEC_ASN1_OCTET_STRING) && - pubKey->u.ec.publicValue.len > keyLen) { - SECItem publicValue; - SECStatus rv; - - rv = SEC_QuickDERDecodeItem(arena, &publicValue, - SEC_ASN1_GET(SEC_OctetStringTemplate), - &pubKey->u.ec.publicValue); - /* nope, didn't decode correctly */ -- if ((rv != SECSuccess) || (publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) || (publicValue.len != keyLen)) { -+ if ((rv != SECSuccess) || (publicValue.len != keyLen)) { -+ crv = CKR_ATTRIBUTE_VALUE_INVALID; -+ break; -+ } -+ /* we don't handle compressed points except in the case of ECCurve25519 */ -+ if ((pubKey->u.ec.ecParams.fieldID.type != ec_field_plain) && (publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED)) { - crv = CKR_ATTRIBUTE_VALUE_INVALID; - break; - } - /* replace our previous with the decoded key */ - pubKey->u.ec.publicValue = publicValue; - break; - } - crv = CKR_ATTRIBUTE_VALUE_INVALID; -diff --git a/nss.gyp b/nss.gyp ---- a/nss.gyp -+++ b/nss.gyp -@@ -159,16 +159,17 @@ - 'cmd/oidcalc/oidcalc.gyp:oidcalc', - 'cmd/p7content/p7content.gyp:p7content', - 'cmd/p7env/p7env.gyp:p7env', - 'cmd/p7sign/p7sign.gyp:p7sign', - 'cmd/p7verify/p7verify.gyp:p7verify', - 'cmd/pk11ectest/pk11ectest.gyp:pk11ectest', - 'cmd/pk11gcmtest/pk11gcmtest.gyp:pk11gcmtest', - 'cmd/pk11mode/pk11mode.gyp:pk11mode', -+ 'cmd/pk11import/pk11import.gyp:pk11import', - 'cmd/pk1sign/pk1sign.gyp:pk1sign', - 'cmd/pp/pp.gyp:pp', - 'cmd/rsaperf/rsaperf.gyp:rsaperf', - 'cmd/rsapoptst/rsapoptst.gyp:rsapoptst', - 'cmd/sdrtest/sdrtest.gyp:sdrtest', - 'cmd/selfserv/selfserv.gyp:selfserv', - 'cmd/shlibsign/mangle/mangle.gyp:mangle', - 'cmd/strsclnt/strsclnt.gyp:strsclnt', -diff --git a/tests/dbtests/dbtests.sh b/tests/dbtests/dbtests.sh ---- a/tests/dbtests/dbtests.sh -+++ b/tests/dbtests/dbtests.sh -@@ -247,16 +247,35 @@ dbtest_main() - # the old one should still be there... - ${BINDIR}/certutil -L -n bob -d ${CONFLICT_DIR} - ret=$? - if [ $ret -ne 0 ]; then - html_failed "Nicknane conflict test-setting nickname conflict incorrectly worked" - else - html_passed "Nicknane conflict test-setting nickname conflict was correctly rejected" - fi -- -+ # import a token private key and make sure the corresponding public key is -+ # created -+ ${BINDIR}/pk11import -d ${CONFLICT_DIR} -f ${R_PWFILE} -+ echo ${BINDIR}/pk11import -d ${CONFLICT_DIR} -f ${R_PWFILE} -+ ret=$? -+ if [ $ret -ne 0 ]; then -+ html_failed "Importing Token Private Key does not create the corrresponding Public Key" -+ else -+ html_passed "Importing Token Private Key correctly creates the corrresponding Public Key" -+ fi -+ # import a token private key and make sure the corresponding public key is -+ # created -+ ${BINDIR}/pk11import -r -D -h -C Curve25519 -d ${CONFLICT_DIR} -f ${R_PWFILE} -+ echo ${BINDIR}/pk11import -r -D -h -C Curve25519 -d ${CONFLICT_DIR} -f ${R_PWFILE} -+ ret=$? -+ if [ $ret -ne 0 ]; then -+ html_failed "Importing ECC Curve 25519 Token Private Key does not create the corrresponding Public Key" -+ else -+ html_passed "Importing ECC Curve 25519 Token Private Key correctly creates the corrresponding Public Key" -+ fi - } - - ################## main ################################################# - - dbtest_init - dbtest_main 2>&1 - dbtest_cleanup diff --git a/SOURCES/nss-8-add-ipsec-usage-to-manpage.patch b/SOURCES/nss-8-add-ipsec-usage-to-manpage.patch new file mode 100644 index 0000000..028ad4b --- /dev/null +++ b/SOURCES/nss-8-add-ipsec-usage-to-manpage.patch @@ -0,0 +1,13 @@ +diff -up ./doc/certutil.xml.ipsec_doc ./doc/certutil.xml +--- ./doc/certutil.xml.ipsec_doc 2019-05-10 14:14:18.000000000 -0700 ++++ ./doc/certutil.xml 2019-06-05 16:49:44.229301383 -0700 +@@ -428,6 +428,9 @@ of the attribute codes: + + J (as an object signer) + ++ ++I (as an IPSEC user) ++ + + + diff --git a/SOURCES/nss-8-fix-public-key-from-priv.patch b/SOURCES/nss-8-fix-public-key-from-priv.patch new file mode 100644 index 0000000..1a3d1b4 --- /dev/null +++ b/SOURCES/nss-8-fix-public-key-from-priv.patch @@ -0,0 +1,571 @@ +diff -up ./gtests/pk11_gtest/pk11_import_unittest.cc.pub-priv-mech ./gtests/pk11_gtest/pk11_import_unittest.cc +--- ./gtests/pk11_gtest/pk11_import_unittest.cc.pub-priv-mech 2019-05-10 14:14:18.000000000 -0700 ++++ ./gtests/pk11_gtest/pk11_import_unittest.cc 2019-06-05 16:43:42.276498676 -0700 +@@ -78,17 +78,40 @@ class Pk11KeyImportTestBase : public ::t + CK_MECHANISM_TYPE mech_; + + private: ++ SECItem GetPublicComponent(ScopedSECKEYPublicKey& pub_key) { ++ SECItem null = { siBuffer, NULL, 0}; ++ switch(SECKEY_GetPublicKeyType(pub_key.get())) { ++ case rsaKey: ++ case rsaPssKey: ++ case rsaOaepKey: ++ return pub_key->u.rsa.modulus; ++ case keaKey: ++ return pub_key->u.kea.publicValue; ++ case dsaKey: ++ return pub_key->u.dsa.publicValue; ++ case dhKey: ++ return pub_key->u.dh.publicValue; ++ case ecKey: ++ return pub_key->u.ec.publicValue; ++ case fortezzaKey: /* depricated */ ++ case nullKey: ++ /* didn't use default here so we can catch new key types at compile time */ ++ break; ++ } ++ return null; ++ } + void CheckForPublicKey(const ScopedSECKEYPrivateKey& priv_key, + const SECItem* expected_public) { + // Verify the public key exists. + StackSECItem priv_id; ++ KeyType type = SECKEY_GetPrivateKeyType(priv_key.get()); + SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, priv_key.get(), + CKA_ID, &priv_id); + ASSERT_EQ(SECSuccess, rv) << "Couldn't read CKA_ID from private key: " + << PORT_ErrorToName(PORT_GetError()); + + CK_ATTRIBUTE_TYPE value_type = CKA_VALUE; +- switch (SECKEY_GetPrivateKeyType(priv_key.get())) { ++ switch (type) { + case rsaKey: + value_type = CKA_MODULUS; + break; +@@ -106,6 +129,8 @@ class Pk11KeyImportTestBase : public ::t + FAIL() << "unknown key type"; + } + ++ // Scan public key objects until we find one with the same CKA_ID as ++ // priv_key + std::unique_ptr objs( + PK11_FindGenericObjects(slot_.get(), CKO_PUBLIC_KEY)); + ASSERT_NE(nullptr, objs); +@@ -128,20 +153,46 @@ class Pk11KeyImportTestBase : public ::t + ASSERT_EQ(1U, token.len); + ASSERT_NE(0, token.data[0]); + +- StackSECItem value; +- rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, value_type, &value); ++ StackSECItem raw_value; ++ SECItem decoded_value; ++ rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, value_type, &raw_value); + ASSERT_EQ(SECSuccess, rv); ++ SECItem value = raw_value; + ++ // Decode the EC_POINT and check the output against expected. + // CKA_EC_POINT isn't stable, see Bug 1520649. ++ ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); ++ ASSERT_TRUE(arena); + if (value_type == CKA_EC_POINT) { +- continue; +- } + ++ // If this fails due to the noted inconsistency, we may need to ++ // check the whole raw_value, or remove a leading UNCOMPRESSED_POINT tag ++ rv = SEC_QuickDERDecodeItem(arena.get(), &decoded_value, ++ SEC_ASN1_GET(SEC_OctetStringTemplate), ++ &raw_value); ++ ASSERT_EQ(SECSuccess, rv); ++ value = decoded_value; ++ } + ASSERT_TRUE(SECITEM_ItemsAreEqual(expected_public, &value)) + << "expected: " + << DataBuffer(expected_public->data, expected_public->len) + << std::endl + << "actual: " << DataBuffer(value.data, value.len) << std::endl; ++ ++ // Finally, convert the private to public and ensure it matches. ++ ScopedSECKEYPublicKey pub_key( ++ SECKEY_ConvertToPublicKey(priv_key.get())); ++ ASSERT_TRUE(pub_key); ++ SECItem converted_public = GetPublicComponent(pub_key); ++ ASSERT_TRUE(converted_public.len != 0); ++ ++ ASSERT_TRUE(SECITEM_ItemsAreEqual(expected_public, &converted_public)) ++ << "expected: " ++ << DataBuffer(expected_public->data, expected_public->len) ++ << std::endl ++ << "actual: " ++ << DataBuffer(converted_public.data, converted_public.len) ++ << std::endl; + } + } + +diff -up ./lib/cryptohi/seckey.c.pub-priv-mech ./lib/cryptohi/seckey.c +--- ./lib/cryptohi/seckey.c.pub-priv-mech 2019-05-10 14:14:18.000000000 -0700 ++++ ./lib/cryptohi/seckey.c 2019-06-05 16:43:42.277498676 -0700 +@@ -1206,6 +1206,37 @@ SECKEY_CopyPublicKey(const SECKEYPublicK + return NULL; + } + ++/* ++ * Use the private key to find a public key handle. The handle will be on ++ * the same slot as the private key. ++ */ ++static CK_OBJECT_HANDLE ++seckey_FindPublicKeyHandle(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk) ++{ ++ CK_OBJECT_HANDLE keyID; ++ ++ /* this helper function is only used below. If we want to make this more ++ * general, we would need to free up any already cached handles if the ++ * slot doesn't match up with the private key slot */ ++ PORT_Assert(pubk->pkcs11ID == CK_INVALID_HANDLE); ++ ++ /* first look for a matching public key */ ++ keyID = PK11_MatchItem(privk->pkcs11Slot, privk->pkcs11ID, CKO_PUBLIC_KEY); ++ if (keyID != CK_INVALID_HANDLE) { ++ return keyID; ++ } ++ ++ /* none found, create a temp one, make the pubk the owner */ ++ pubk->pkcs11ID = PK11_DerivePubKeyFromPrivKey(privk); ++ if (pubk->pkcs11ID == CK_INVALID_HANDLE) { ++ /* end of the road. Token doesn't have matching public key, nor can ++ * token regenerate a new public key from and existing private key. */ ++ return CK_INVALID_HANDLE; ++ } ++ pubk->pkcs11Slot = PK11_ReferenceSlot(privk->pkcs11Slot); ++ return pubk->pkcs11ID; ++} ++ + SECKEYPublicKey * + SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privk) + { +@@ -1213,6 +1244,8 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateK + PLArenaPool *arena; + CERTCertificate *cert; + SECStatus rv; ++ CK_OBJECT_HANDLE pubKeyHandle; ++ SECItem decodedPoint; + + /* + * First try to look up the cert. +@@ -1243,11 +1276,47 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateK + + switch (privk->keyType) { + case nullKey: +- case dhKey: +- case dsaKey: + /* Nothing to query, if the cert isn't there, we're done -- no way + * to get the public key */ + break; ++ case dsaKey: ++ pubKeyHandle = seckey_FindPublicKeyHandle(privk, pubk); ++ if (pubKeyHandle == CK_INVALID_HANDLE) ++ break; ++ rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, ++ CKA_BASE, arena, &pubk->u.dsa.params.base); ++ if (rv != SECSuccess) ++ break; ++ rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, ++ CKA_PRIME, arena, &pubk->u.dsa.params.prime); ++ if (rv != SECSuccess) ++ break; ++ rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, ++ CKA_SUBPRIME, arena, &pubk->u.dsa.params.subPrime); ++ if (rv != SECSuccess) ++ break; ++ rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, ++ CKA_VALUE, arena, &pubk->u.dsa.publicValue); ++ if (rv != SECSuccess) ++ break; ++ return pubk; ++ case dhKey: ++ pubKeyHandle = seckey_FindPublicKeyHandle(privk, pubk); ++ if (pubKeyHandle == CK_INVALID_HANDLE) ++ break; ++ rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, ++ CKA_BASE, arena, &pubk->u.dh.base); ++ if (rv != SECSuccess) ++ break; ++ rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, ++ CKA_PRIME, arena, &pubk->u.dh.prime); ++ if (rv != SECSuccess) ++ break; ++ rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, ++ CKA_VALUE, arena, &pubk->u.dh.publicValue); ++ if (rv != SECSuccess) ++ break; ++ return pubk; + case rsaKey: + rv = PK11_ReadAttribute(privk->pkcs11Slot, privk->pkcs11ID, + CKA_MODULUS, arena, &pubk->u.rsa.modulus); +@@ -1258,7 +1327,6 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateK + if (rv != SECSuccess) + break; + return pubk; +- break; + case ecKey: + rv = PK11_ReadAttribute(privk->pkcs11Slot, privk->pkcs11ID, + CKA_EC_PARAMS, arena, &pubk->u.ec.DEREncodedParams); +@@ -1268,7 +1336,23 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateK + rv = PK11_ReadAttribute(privk->pkcs11Slot, privk->pkcs11ID, + CKA_EC_POINT, arena, &pubk->u.ec.publicValue); + if (rv != SECSuccess || pubk->u.ec.publicValue.len == 0) { +- break; ++ pubKeyHandle = seckey_FindPublicKeyHandle(privk, pubk); ++ if (pubKeyHandle == CK_INVALID_HANDLE) ++ break; ++ rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, ++ CKA_EC_POINT, arena, &pubk->u.ec.publicValue); ++ if (rv != SECSuccess) ++ break; ++ } ++ /* ec.publicValue should be decoded, PKCS #11 defines CKA_EC_POINT ++ * as encoded, but it's not always. try do decoded it and if it ++ * succeeds store the decoded value */ ++ rv = SEC_QuickDERDecodeItem(arena, &decodedPoint, ++ SEC_ASN1_GET(SEC_OctetStringTemplate), &pubk->u.ec.publicValue); ++ if (rv == SECSuccess) { ++ /* both values are in the public key arena, so it's safe to ++ * overwrite the old value */ ++ pubk->u.ec.publicValue = decodedPoint; + } + pubk->u.ec.encoding = ECPoint_Undefined; + return pubk; +@@ -1276,7 +1360,9 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateK + break; + } + +- PORT_FreeArena(arena, PR_FALSE); ++ /* must use Destroy public key here, because some paths create temporary ++ * PKCS #11 objects which need to be freed */ ++ SECKEY_DestroyPublicKey(pubk); + return NULL; + } + +diff -up ./lib/pk11wrap/pk11priv.h.pub-priv-mech ./lib/pk11wrap/pk11priv.h +--- ./lib/pk11wrap/pk11priv.h.pub-priv-mech 2019-05-10 14:14:18.000000000 -0700 ++++ ./lib/pk11wrap/pk11priv.h 2019-06-05 16:43:42.277498676 -0700 +@@ -111,6 +111,7 @@ CK_OBJECT_HANDLE PK11_FindObjectForCert( + PK11SymKey *pk11_CopyToSlot(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, + CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey); + unsigned int pk11_GetPredefinedKeyLength(CK_KEY_TYPE keyType); ++CK_OBJECT_HANDLE PK11_DerivePubKeyFromPrivKey(SECKEYPrivateKey *privKey); + + /********************************************************************** + * Certs +diff -up ./lib/pk11wrap/pk11skey.c.pub-priv-mech ./lib/pk11wrap/pk11skey.c +--- ./lib/pk11wrap/pk11skey.c.pub-priv-mech 2019-06-05 16:37:38.726685789 -0700 ++++ ./lib/pk11wrap/pk11skey.c 2019-06-05 16:43:42.278498675 -0700 +@@ -1841,6 +1841,35 @@ loser: + } + + /* ++ * This regenerate a public key from a private key. This function is currently ++ * NSS private. If we want to make it public, we need to add and optional ++ * template or at least flags (a.la. PK11_DeriveWithFlags). ++ */ ++CK_OBJECT_HANDLE ++PK11_DerivePubKeyFromPrivKey(SECKEYPrivateKey *privKey) ++{ ++ PK11SlotInfo *slot = privKey->pkcs11Slot; ++ CK_MECHANISM mechanism; ++ CK_OBJECT_HANDLE objectID = CK_INVALID_HANDLE; ++ CK_RV crv; ++ ++ mechanism.mechanism = CKM_NSS_PUB_FROM_PRIV; ++ mechanism.pParameter = NULL; ++ mechanism.ulParameterLen = 0; ++ ++ PK11_EnterSlotMonitor(slot); ++ crv = PK11_GETTAB(slot)->C_DeriveKey(slot->session, &mechanism, ++ privKey->pkcs11ID, NULL, 0, ++ &objectID); ++ PK11_ExitSlotMonitor(slot); ++ if (crv != CKR_OK) { ++ PORT_SetError(PK11_MapError(crv)); ++ return CK_INVALID_HANDLE; ++ } ++ return objectID; ++} ++ ++/* + * This Generates a wrapping key based on a privateKey, publicKey, and two + * random numbers. For Mail usage RandomB should be NULL. In the Sender's + * case RandomA is generate, outherwize it is passed. +diff -up ./lib/softoken/lowkey.c.pub-priv-mech ./lib/softoken/lowkey.c +--- ./lib/softoken/lowkey.c.pub-priv-mech 2019-05-10 14:14:18.000000000 -0700 ++++ ./lib/softoken/lowkey.c 2019-06-05 16:44:20.469479019 -0700 +@@ -261,6 +261,7 @@ NSSLOWKEYPublicKey * + nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privk) + { + NSSLOWKEYPublicKey *pubk; ++ SECItem publicValue; + PLArenaPool *arena; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); +@@ -301,6 +302,19 @@ nsslowkey_ConvertToPublicKey(NSSLOWKEYPr + + pubk->arena = arena; + pubk->keyType = privk->keyType; ++ /* if the public key value doesn't exist, calculate it */ ++ if (privk->u.dsa.publicValue.len == 0) { ++ rv = DH_Derive(&privk->u.dsa.params.base, &privk->u.dsa.params.prime, ++ &privk->u.dsa.privateValue, &publicValue, 0); ++ if (rv != SECSuccess) { ++ break; ++ } ++ rv = SECITEM_CopyItem(privk->arena, &privk->u.dsa.publicValue, &publicValue); ++ SECITEM_FreeItem(&publicValue, PR_FALSE); ++ if (rv != SECSuccess) { ++ break; ++ } ++ } + rv = SECITEM_CopyItem(arena, &pubk->u.dsa.publicValue, + &privk->u.dsa.publicValue); + if (rv != SECSuccess) +@@ -327,6 +341,19 @@ nsslowkey_ConvertToPublicKey(NSSLOWKEYPr + + pubk->arena = arena; + pubk->keyType = privk->keyType; ++ /* if the public key value doesn't exist, calculate it */ ++ if (privk->u.dh.publicValue.len == 0) { ++ rv = DH_Derive(&privk->u.dh.base, &privk->u.dh.prime, ++ &privk->u.dh.privateValue, &publicValue, 0); ++ if (rv != SECSuccess) { ++ break; ++ } ++ rv = SECITEM_CopyItem(privk->arena, &privk->u.dh.publicValue, &publicValue); ++ SECITEM_FreeItem(&publicValue, PR_FALSE); ++ if (rv != SECSuccess) { ++ break; ++ } ++ } + rv = SECITEM_CopyItem(arena, &pubk->u.dh.publicValue, + &privk->u.dh.publicValue); + if (rv != SECSuccess) +diff -up ./lib/softoken/pkcs11c.c.pub-priv-mech ./lib/softoken/pkcs11c.c +--- ./lib/softoken/pkcs11c.c.pub-priv-mech 2019-06-05 16:37:38.743685780 -0700 ++++ ./lib/softoken/pkcs11c.c 2019-06-05 16:44:20.472479017 -0700 +@@ -6569,6 +6569,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession + extractValue = PR_FALSE; + classType = CKO_PRIVATE_KEY; + break; ++ case CKM_NSS_PUB_FROM_PRIV: ++ extractValue = PR_FALSE; ++ classType = CKO_PUBLIC_KEY; ++ break; + case CKM_NSS_JPAKE_FINAL_SHA1: /* fall through */ + case CKM_NSS_JPAKE_FINAL_SHA256: /* fall through */ + case CKM_NSS_JPAKE_FINAL_SHA384: /* fall through */ +@@ -6610,6 +6614,35 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession + } + + switch (mechanism) { ++ /* get a public key from a private key. nsslowkey_ConvertToPublickey() ++ * will generate the public portion if it doesn't already exist. */ ++ case CKM_NSS_PUB_FROM_PRIV: { ++ NSSLOWKEYPrivateKey *privKey; ++ NSSLOWKEYPublicKey *pubKey; ++ int error; ++ ++ crv = sftk_GetULongAttribute(sourceKey, CKA_KEY_TYPE, &keyType); ++ if (crv != CKR_OK) { ++ break; ++ } ++ ++ /* privKey is stored in sourceKey and will be destroyed when ++ * the sourceKey is freed. */ ++ privKey = sftk_GetPrivKey(sourceKey, keyType, &crv); ++ if (privKey == NULL) { ++ break; ++ } ++ pubKey = nsslowkey_ConvertToPublicKey(privKey); ++ if (pubKey == NULL) { ++ error = PORT_GetError(); ++ crv = sftk_MapCryptError(error); ++ break; ++ } ++ crv = sftk_PutPubKey(key, sourceKey, keyType, pubKey); ++ nsslowkey_DestroyPublicKey(pubKey); ++ break; ++ } ++ + case CKM_NSS_IKE_PRF_DERIVE: + if (pMechanism->ulParameterLen != + sizeof(CK_NSS_IKE_PRF_DERIVE_PARAMS)) { +diff -up ./lib/softoken/pkcs11.c.pub-priv-mech ./lib/softoken/pkcs11.c +--- ./lib/softoken/pkcs11.c.pub-priv-mech 2019-06-05 16:37:38.728685788 -0700 ++++ ./lib/softoken/pkcs11.c 2019-06-05 16:44:20.473479017 -0700 +@@ -2206,6 +2206,123 @@ sftk_GetPrivKey(SFTKObject *object, CK_K + return priv; + } + ++/* populate a public key object from a lowpublic keys structure */ ++CK_RV ++sftk_PutPubKey(SFTKObject *publicKey, SFTKObject *privateKey, CK_KEY_TYPE keyType, NSSLOWKEYPublicKey *pubKey) ++{ ++ CK_OBJECT_CLASS classType = CKO_PUBLIC_KEY; ++ CK_BBOOL cktrue = CK_TRUE; ++ CK_RV crv = CKR_OK; ++ sftk_DeleteAttributeType(publicKey, CKA_CLASS); ++ sftk_DeleteAttributeType(publicKey, CKA_KEY_TYPE); ++ sftk_DeleteAttributeType(publicKey, CKA_VALUE); ++ ++ switch (keyType) { ++ case CKK_RSA: ++ sftk_DeleteAttributeType(publicKey, CKA_MODULUS); ++ sftk_DeleteAttributeType(publicKey, CKA_PUBLIC_EXPONENT); ++ /* format the keys */ ++ /* fill in the RSA dependent paramenters in the public key */ ++ crv = sftk_AddAttributeType(publicKey, CKA_MODULUS, ++ sftk_item_expand(&pubKey->u.rsa.modulus)); ++ if (crv != CKR_OK) ++ break; ++ crv = sftk_AddAttributeType(publicKey, CKA_PUBLIC_EXPONENT, ++ sftk_item_expand(&pubKey->u.rsa.publicExponent)); ++ break; ++ case CKK_DSA: ++ sftk_DeleteAttributeType(publicKey, CKA_PRIME); ++ sftk_DeleteAttributeType(publicKey, CKA_SUBPRIME); ++ sftk_DeleteAttributeType(publicKey, CKA_BASE); ++ crv = sftk_AddAttributeType(publicKey, CKA_PRIME, ++ sftk_item_expand(&pubKey->u.dsa.params.prime)); ++ if (crv != CKR_OK) { ++ break; ++ } ++ crv = sftk_AddAttributeType(publicKey, CKA_SUBPRIME, ++ sftk_item_expand(&pubKey->u.dsa.params.subPrime)); ++ if (crv != CKR_OK) { ++ break; ++ } ++ crv = sftk_AddAttributeType(publicKey, CKA_BASE, ++ sftk_item_expand(&pubKey->u.dsa.params.base)); ++ if (crv != CKR_OK) { ++ break; ++ } ++ crv = sftk_AddAttributeType(publicKey, CKA_VALUE, ++ sftk_item_expand(&pubKey->u.dsa.publicValue)); ++ break; ++ ++ case CKK_DH: ++ sftk_DeleteAttributeType(publicKey, CKA_PRIME); ++ sftk_DeleteAttributeType(publicKey, CKA_BASE); ++ crv = sftk_AddAttributeType(publicKey, CKA_PRIME, ++ sftk_item_expand(&pubKey->u.dh.prime)); ++ if (crv != CKR_OK) { ++ break; ++ } ++ crv = sftk_AddAttributeType(publicKey, CKA_BASE, ++ sftk_item_expand(&pubKey->u.dh.base)); ++ if (crv != CKR_OK) { ++ break; ++ } ++ crv = sftk_AddAttributeType(publicKey, CKA_VALUE, ++ sftk_item_expand(&pubKey->u.dh.publicValue)); ++ break; ++ ++ case CKK_EC: ++ sftk_DeleteAttributeType(publicKey, CKA_EC_PARAMS); ++ sftk_DeleteAttributeType(publicKey, CKA_EC_POINT); ++ ++ crv = sftk_AddAttributeType(publicKey, CKA_EC_PARAMS, ++ sftk_item_expand(&pubKey->u.ec.ecParams.DEREncoding)); ++ if (crv != CKR_OK) { ++ break; ++ } ++ ++ crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT, ++ sftk_item_expand(&pubKey->u.ec.publicValue)); ++ break; ++ ++ default: ++ return CKR_KEY_TYPE_INCONSISTENT; ++ } ++ crv = sftk_AddAttributeType(publicKey, CKA_CLASS, &classType, ++ sizeof(CK_OBJECT_CLASS)); ++ if (crv != CKR_OK) ++ return crv; ++ crv = sftk_AddAttributeType(publicKey, CKA_KEY_TYPE, &keyType, ++ sizeof(CK_KEY_TYPE)); ++ if (crv != CKR_OK) ++ return crv; ++ /* now handle the operator attributes */ ++ if (sftk_isTrue(privateKey, CKA_DECRYPT)) { ++ crv = sftk_forceAttribute(publicKey, CKA_ENCRYPT, &cktrue, sizeof(CK_BBOOL)); ++ if (crv != CKR_OK) { ++ return crv; ++ } ++ } ++ if (sftk_isTrue(privateKey, CKA_SIGN)) { ++ crv = sftk_forceAttribute(publicKey, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL)); ++ if (crv != CKR_OK) { ++ return crv; ++ } ++ } ++ if (sftk_isTrue(privateKey, CKA_SIGN_RECOVER)) { ++ crv = sftk_forceAttribute(publicKey, CKA_VERIFY_RECOVER, &cktrue, sizeof(CK_BBOOL)); ++ if (crv != CKR_OK) { ++ return crv; ++ } ++ } ++ if (sftk_isTrue(privateKey, CKA_DERIVE)) { ++ crv = sftk_forceAttribute(publicKey, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL)); ++ if (crv != CKR_OK) { ++ return crv; ++ } ++ } ++ return crv; ++} ++ + /* + **************************** Symetric Key utils ************************ + */ +diff -up ./lib/softoken/pkcs11i.h.pub-priv-mech ./lib/softoken/pkcs11i.h +--- ./lib/softoken/pkcs11i.h.pub-priv-mech 2019-06-05 16:37:38.730685787 -0700 ++++ ./lib/softoken/pkcs11i.h 2019-06-05 16:44:20.473479017 -0700 +@@ -695,6 +695,9 @@ extern NSSLOWKEYPublicKey *sftk_GetPubKe + CK_KEY_TYPE key_type, CK_RV *crvp); + extern NSSLOWKEYPrivateKey *sftk_GetPrivKey(SFTKObject *object, + CK_KEY_TYPE key_type, CK_RV *crvp); ++extern CK_RV sftk_PutPubKey(SFTKObject *publicKey, SFTKObject *privKey, ++ CK_KEY_TYPE keyType, ++ NSSLOWKEYPublicKey *pubKey); + extern void sftk_FormatDESKey(unsigned char *key, int length); + extern PRBool sftk_CheckDESKey(unsigned char *key); + extern PRBool sftk_IsWeakKey(unsigned char *key, CK_KEY_TYPE key_type); +diff -up ./lib/util/pkcs11n.h.pub-priv-mech ./lib/util/pkcs11n.h +--- ./lib/util/pkcs11n.h.pub-priv-mech 2019-06-05 16:37:38.733685785 -0700 ++++ ./lib/util/pkcs11n.h 2019-06-05 16:44:54.389461561 -0700 +@@ -152,11 +152,6 @@ + #define CKM_NSS_HKDF_SHA384 (CKM_NSS + 5) + #define CKM_NSS_HKDF_SHA512 (CKM_NSS + 6) + +-/* IKE mechanism (to be proposed to PKCS #11 */ +-#define CKM_NSS_IKE_PRF_PLUS_DERIVE (CKM_NSS + 7) +-#define CKM_NSS_IKE_PRF_DERIVE (CKM_NSS + 8) +-#define CKM_NSS_IKE1_PRF_DERIVE (CKM_NSS + 9) +-#define CKM_NSS_IKE1_APP_B_PRF_DERIVE (CKM_NSS + 10) + + /* J-PAKE round 1 key generation mechanisms. + * +@@ -238,6 +233,15 @@ + + #define CKM_NSS_CHACHA20_CTR (CKM_NSS + 33) + ++/* IKE mechanism (to be proposed to PKCS #11 */ ++#define CKM_NSS_IKE_PRF_PLUS_DERIVE (CKM_NSS + 34) ++#define CKM_NSS_IKE_PRF_DERIVE (CKM_NSS + 35) ++#define CKM_NSS_IKE1_PRF_DERIVE (CKM_NSS + 36) ++#define CKM_NSS_IKE1_APP_B_PRF_DERIVE (CKM_NSS + 37) ++ ++/* Derive a public key from a bare private key */ ++#define CKM_NSS_PUB_FROM_PRIV (CKM_NSS + 40) ++ + /* + * HISTORICAL: + * Do not attempt to use these. They are only used by NETSCAPE's internal diff --git a/SOURCES/nss-disable-pkcs1-sigalgs-tls13.patch b/SOURCES/nss-disable-pkcs1-sigalgs-tls13.patch new file mode 100644 index 0000000..1b57e75 --- /dev/null +++ b/SOURCES/nss-disable-pkcs1-sigalgs-tls13.patch @@ -0,0 +1,202 @@ +# HG changeset patch +# User Daiki Ueno +# Date 1559031046 -7200 +# Tue May 28 10:10:46 2019 +0200 +# Node ID 0a4e8b72a92e144663c2f35d3836f7828cfc97f2 +# Parent 370a9e85f216f5f4ff277995a997c5c9b23a819f +Bug 1552208, prohibit use of RSASSA-PKCS1-v1_5 algorithms in TLS 1.3, r=mt + +Reviewers: mt + +Reviewed By: mt + +Subscribers: mt, jcj, ueno, rrelyea, HubertKario, KevinJacobs + +Tags: #secure-revision, #bmo-crypto-core-security + +Bug #: 1552208 + +Differential Revision: https://phabricator.services.mozilla.com/D32454 + +diff --git a/gtests/ssl_gtest/ssl_auth_unittest.cc b/gtests/ssl_gtest/ssl_auth_unittest.cc +--- a/gtests/ssl_gtest/ssl_auth_unittest.cc ++++ b/gtests/ssl_gtest/ssl_auth_unittest.cc +@@ -701,6 +701,44 @@ TEST_P(TlsConnectTls12, ClientAuthIncons + ConnectExpectAlert(server_, kTlsAlertIllegalParameter); + } + ++TEST_P(TlsConnectTls13, ClientAuthPkcs1SignatureScheme) { ++ static const SSLSignatureScheme kSignatureScheme[] = { ++ ssl_sig_rsa_pkcs1_sha256, ssl_sig_rsa_pss_rsae_sha256}; ++ ++ Reset(TlsAgent::kServerRsa, "rsa"); ++ client_->SetSignatureSchemes(kSignatureScheme, ++ PR_ARRAY_SIZE(kSignatureScheme)); ++ server_->SetSignatureSchemes(kSignatureScheme, ++ PR_ARRAY_SIZE(kSignatureScheme)); ++ client_->SetupClientAuth(); ++ server_->RequestClientAuth(true); ++ ++ auto capture_cert_verify = MakeTlsFilter( ++ client_, kTlsHandshakeCertificateVerify); ++ capture_cert_verify->EnableDecryption(); ++ ++ Connect(); ++ CheckSigScheme(capture_cert_verify, 0, server_, ssl_sig_rsa_pss_rsae_sha256, ++ 1024); ++} ++ ++TEST_P(TlsConnectTls13, ClientAuthPkcs1SignatureSchemeOnly) { ++ static const SSLSignatureScheme kSignatureScheme[] = { ++ ssl_sig_rsa_pkcs1_sha256}; ++ ++ Reset(TlsAgent::kServerRsa, "rsa"); ++ client_->SetSignatureSchemes(kSignatureScheme, ++ PR_ARRAY_SIZE(kSignatureScheme)); ++ server_->SetSignatureSchemes(kSignatureScheme, ++ PR_ARRAY_SIZE(kSignatureScheme)); ++ client_->SetupClientAuth(); ++ server_->RequestClientAuth(true); ++ ++ ConnectExpectAlert(server_, kTlsAlertHandshakeFailure); ++ server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); ++ client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP); ++} ++ + class TlsZeroCertificateRequestSigAlgsFilter : public TlsHandshakeFilter { + public: + TlsZeroCertificateRequestSigAlgsFilter(const std::shared_ptr& a) +@@ -933,7 +971,7 @@ TEST_P(TlsConnectTls13, InconsistentSign + client_->CheckErrorCode(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); + } + +-TEST_P(TlsConnectTls12Plus, RequestClientAuthWithSha384) { ++TEST_P(TlsConnectTls12, RequestClientAuthWithSha384) { + server_->SetSignatureSchemes(kSignatureSchemeRsaSha384, + PR_ARRAY_SIZE(kSignatureSchemeRsaSha384)); + server_->RequestClientAuth(false); +@@ -1395,12 +1433,21 @@ TEST_P(TlsSignatureSchemeConfiguration, + INSTANTIATE_TEST_CASE_P( + SignatureSchemeRsa, TlsSignatureSchemeConfiguration, + ::testing::Combine( +- TlsConnectTestBase::kTlsVariantsAll, TlsConnectTestBase::kTlsV12Plus, ++ TlsConnectTestBase::kTlsVariantsAll, TlsConnectTestBase::kTlsV12, + ::testing::Values(TlsAgent::kServerRsaSign), + ::testing::Values(ssl_auth_rsa_sign), + ::testing::Values(ssl_sig_rsa_pkcs1_sha256, ssl_sig_rsa_pkcs1_sha384, + ssl_sig_rsa_pkcs1_sha512, ssl_sig_rsa_pss_rsae_sha256, + ssl_sig_rsa_pss_rsae_sha384))); ++// RSASSA-PKCS1-v1_5 is not allowed to be used in TLS 1.3 ++INSTANTIATE_TEST_CASE_P( ++ SignatureSchemeRsaTls13, TlsSignatureSchemeConfiguration, ++ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll, ++ TlsConnectTestBase::kTlsV13, ++ ::testing::Values(TlsAgent::kServerRsaSign), ++ ::testing::Values(ssl_auth_rsa_sign), ++ ::testing::Values(ssl_sig_rsa_pss_rsae_sha256, ++ ssl_sig_rsa_pss_rsae_sha384))); + // PSS with SHA-512 needs a bigger key to work. + INSTANTIATE_TEST_CASE_P( + SignatureSchemeBigRsa, TlsSignatureSchemeConfiguration, +diff --git a/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc b/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc +--- a/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc ++++ b/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc +@@ -68,12 +68,6 @@ class TlsCipherSuiteTestBase : public Tl + virtual void SetupCertificate() { + if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) { + switch (sig_scheme_) { +- case ssl_sig_rsa_pkcs1_sha256: +- case ssl_sig_rsa_pkcs1_sha384: +- case ssl_sig_rsa_pkcs1_sha512: +- Reset(TlsAgent::kServerRsaSign); +- auth_type_ = ssl_auth_rsa_sign; +- break; + case ssl_sig_rsa_pss_rsae_sha256: + case ssl_sig_rsa_pss_rsae_sha384: + Reset(TlsAgent::kServerRsaSign); +@@ -330,6 +324,12 @@ static SSLSignatureScheme kSignatureSche + ssl_sig_rsa_pss_pss_sha256, ssl_sig_rsa_pss_pss_sha384, + ssl_sig_rsa_pss_pss_sha512}; + ++static SSLSignatureScheme kSignatureSchemesParamsArrTls13[] = { ++ ssl_sig_ecdsa_secp256r1_sha256, ssl_sig_ecdsa_secp384r1_sha384, ++ ssl_sig_rsa_pss_rsae_sha256, ssl_sig_rsa_pss_rsae_sha384, ++ ssl_sig_rsa_pss_rsae_sha512, ssl_sig_rsa_pss_pss_sha256, ++ ssl_sig_rsa_pss_pss_sha384, ssl_sig_rsa_pss_pss_sha512}; ++ + INSTANTIATE_CIPHER_TEST_P(RC4, Stream, V10ToV12, kDummyNamedGroupParams, + kDummySignatureSchemesParams, + TLS_RSA_WITH_RC4_128_SHA, +@@ -394,7 +394,7 @@ INSTANTIATE_CIPHER_TEST_P( + #ifndef NSS_DISABLE_TLS_1_3 + INSTANTIATE_CIPHER_TEST_P(TLS13, All, V13, + ::testing::ValuesIn(kFasterDHEGroups), +- ::testing::ValuesIn(kSignatureSchemesParamsArr), ++ ::testing::ValuesIn(kSignatureSchemesParamsArrTls13), + TLS_AES_128_GCM_SHA256, TLS_CHACHA20_POLY1305_SHA256, + TLS_AES_256_GCM_SHA384); + INSTANTIATE_CIPHER_TEST_P(TLS13AllGroups, All, V13, +diff --git a/gtests/ssl_gtest/ssl_extension_unittest.cc b/gtests/ssl_gtest/ssl_extension_unittest.cc +--- a/gtests/ssl_gtest/ssl_extension_unittest.cc ++++ b/gtests/ssl_gtest/ssl_extension_unittest.cc +@@ -436,14 +436,14 @@ TEST_P(TlsExtensionTest12Plus, Signature + } + + TEST_F(TlsExtensionTest13Stream, SignatureAlgorithmsPrecedingGarbage) { +- // 31 unknown signature algorithms followed by sha-256, rsa ++ // 31 unknown signature algorithms followed by sha-256, rsa-pss + const uint8_t val[] = { + 0x00, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0x01}; ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x04}; + DataBuffer extension(val, sizeof(val)); + MakeTlsFilter(client_, ssl_signature_algorithms_xtn, + extension); +diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c +--- a/lib/ssl/ssl3con.c ++++ b/lib/ssl/ssl3con.c +@@ -64,6 +64,7 @@ static SECStatus ssl3_FlushHandshakeMess + static CK_MECHANISM_TYPE ssl3_GetHashMechanismByHashType(SSLHashType hashType); + static CK_MECHANISM_TYPE ssl3_GetMgfMechanismByHashType(SSLHashType hash); + PRBool ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme); ++PRBool ssl_IsRsaPkcs1SignatureScheme(SSLSignatureScheme scheme); + PRBool ssl_IsDsaSignatureScheme(SSLSignatureScheme scheme); + + const PRUint8 ssl_hello_retry_random[] = { +@@ -4101,6 +4102,9 @@ ssl_SignatureSchemeValid(SSLSignatureSch + if (ssl_SignatureSchemeToHashType(scheme) == ssl_hash_sha1) { + return PR_FALSE; + } ++ if (ssl_IsRsaPkcs1SignatureScheme(scheme)) { ++ return PR_FALSE; ++ } + /* With TLS 1.3, EC keys should have been selected based on calling + * ssl_SignatureSchemeFromSpki(), reject them otherwise. */ + return spkiOid != SEC_OID_ANSIX962_EC_PUBLIC_KEY; +@@ -4351,6 +4355,22 @@ ssl_IsRsaPssSignatureScheme(SSLSignature + } + + PRBool ++ssl_IsRsaPkcs1SignatureScheme(SSLSignatureScheme scheme) ++{ ++ switch (scheme) { ++ case ssl_sig_rsa_pkcs1_sha256: ++ case ssl_sig_rsa_pkcs1_sha384: ++ case ssl_sig_rsa_pkcs1_sha512: ++ case ssl_sig_rsa_pkcs1_sha1: ++ return PR_TRUE; ++ ++ default: ++ return PR_FALSE; ++ } ++ return PR_FALSE; ++} ++ ++PRBool + ssl_IsDsaSignatureScheme(SSLSignatureScheme scheme) + { + switch (scheme) { diff --git a/SOURCES/nss-drbg-continuous.patch b/SOURCES/nss-drbg-continuous.patch new file mode 100644 index 0000000..742f2e4 --- /dev/null +++ b/SOURCES/nss-drbg-continuous.patch @@ -0,0 +1,169 @@ +# HG changeset patch +# User Daiki Ueno +# Date 1561465415 -7200 +# Tue Jun 25 14:23:35 2019 +0200 +# Node ID a0114e3d8b22d4c6ee77504c483a0fe0037f4c71 +# Parent 313dfef345bd93bc67982249bffa2cfdd5a9d1b5 +Bug 1560329, drbg: perform continuous test on entropy source + +Summary: FIPS 140-2 section 4.9.2 requires a conditional self test to check that consecutive entropy blocks from the system are different. As neither getentropy() nor /dev/urandom provides that check on the output, this adds the self test at caller side. + +Reviewers: rrelyea + +Bug #: 1560329 + +Differential Revision: https://phabricator.services.mozilla.com/D35636 + +diff --git a/lib/freebl/drbg.c b/lib/freebl/drbg.c +--- a/lib/freebl/drbg.c ++++ b/lib/freebl/drbg.c +@@ -30,6 +30,7 @@ + #define PRNG_ADDITONAL_DATA_CACHE_SIZE (8 * 1024) /* must be less than \ + * PRNG_MAX_ADDITIONAL_BYTES \ + */ ++#define PRNG_ENTROPY_BLOCK_SIZE SHA256_LENGTH + + /* RESEED_COUNT is how many calls to the prng before we need to reseed + * under normal NIST rules, you must return an error. In the NSS case, we +@@ -96,6 +97,8 @@ struct RNGContextStr { + PRUint32 additionalAvail; + PRBool isValid; /* false if RNG reaches an invalid state */ + PRBool isKatTest; /* true if running NIST PRNG KAT tests */ ++ /* for continuous entropy check */ ++ PRUint8 previousEntropyHash[SHA256_LENGTH]; + }; + + typedef struct RNGContextStr RNGContext; +@@ -169,6 +172,82 @@ prng_instantiate(RNGContext *rng, const + return SECSuccess; + } + ++static PRCallOnceType coRNGInitEntropy; ++ ++static PRStatus ++prng_initEntropy(void) ++{ ++ size_t length; ++ PRUint8 block[PRNG_ENTROPY_BLOCK_SIZE]; ++ SHA256Context ctx; ++ ++ /* For FIPS 140-2 4.9.2 continuous random number generator test, ++ * fetch the initial entropy from the system RNG and keep it for ++ * later comparison. */ ++ length = RNG_SystemRNG(block, sizeof(block)); ++ if (length == 0) { ++ return PR_FAILURE; /* error is already set */ ++ } ++ PORT_Assert(length == sizeof(block)); ++ ++ /* Store the hash of the entropy block rather than the block ++ * itself for backward secrecy. */ ++ SHA256_Begin(&ctx); ++ SHA256_Update(&ctx, block, sizeof(block)); ++ SHA256_End(&ctx, globalrng->previousEntropyHash, NULL, ++ sizeof(globalrng->previousEntropyHash)); ++ PORT_Memset(block, 0, sizeof(block)); ++ return PR_SUCCESS; ++} ++ ++static SECStatus ++prng_getEntropy(PRUint8 *buffer, size_t requestLength) ++{ ++ size_t total = 0; ++ PRUint8 block[PRNG_ENTROPY_BLOCK_SIZE]; ++ PRUint8 hash[SHA256_LENGTH]; ++ SHA256Context ctx; ++ SECStatus rv = SECSuccess; ++ ++ if (PR_CallOnce(&coRNGInitEntropy, prng_initEntropy) != PR_SUCCESS) { ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); ++ return SECFailure; ++ } ++ ++ /* For FIPS 140-2 4.9.2 continuous random generator test, ++ * iteratively fetch fixed sized blocks from the system and ++ * compare consecutive blocks. */ ++ while (total < requestLength) { ++ size_t length = RNG_SystemRNG(block, sizeof(block)); ++ if (length == 0) { ++ rv = SECFailure; /* error is already set */ ++ goto out; ++ } ++ PORT_Assert(length == sizeof(block)); ++ ++ /* Store the hash of the entropy block rather than the block ++ * itself for backward secrecy. */ ++ SHA256_Begin(&ctx); ++ SHA256_Update(&ctx, block, sizeof(block)); ++ SHA256_End(&ctx, hash, NULL, sizeof(hash)); ++ ++ if (PORT_Memcmp(globalrng->previousEntropyHash, hash, sizeof(hash)) == 0) { ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); ++ rv = SECFailure; ++ goto out; ++ } ++ PORT_Memcpy(globalrng->previousEntropyHash, hash, sizeof(hash)); ++ length = PR_MIN(requestLength - total, sizeof(block)); ++ PORT_Memcpy(buffer, block, length); ++ total += length; ++ buffer += length; ++ } ++ ++ out: ++ PORT_Memset(block, 0, sizeof block); ++ return rv; ++} ++ + /* + * Update the global random number generator with more seeding + * material. Use the Hash_DRBG reseed algorithm from NIST SP-800-90 +@@ -182,11 +261,15 @@ prng_reseed(RNGContext *rng, const PRUin + { + PRUint8 noiseData[(sizeof rng->V_Data) + PRNG_SEEDLEN]; + PRUint8 *noise = &noiseData[0]; ++ SECStatus rv; + + /* if entropy wasn't supplied, fetch it. (normal operation case) */ + if (entropy == NULL) { +- entropy_len = (unsigned int)RNG_SystemRNG( +- &noiseData[sizeof rng->V_Data], PRNG_SEEDLEN); ++ entropy_len = PRNG_SEEDLEN; ++ rv = prng_getEntropy(&noiseData[sizeof rng->V_Data], entropy_len); ++ if (rv != SECSuccess) { ++ return SECFailure; /* error is already set */ ++ } + } else { + /* NOTE: this code is only available for testing, not to applications */ + /* if entropy was too big for the stack variable, get it from malloc */ +@@ -384,7 +467,6 @@ static PRStatus + rng_init(void) + { + PRUint8 bytes[PRNG_SEEDLEN * 2]; /* entropy + nonce */ +- unsigned int numBytes; + SECStatus rv = SECSuccess; + + if (globalrng == NULL) { +@@ -403,18 +485,17 @@ rng_init(void) + } + + /* Try to get some seed data for the RNG */ +- numBytes = (unsigned int)RNG_SystemRNG(bytes, sizeof bytes); +- PORT_Assert(numBytes == 0 || numBytes == sizeof bytes); +- if (numBytes != 0) { ++ rv = prng_getEntropy(bytes, sizeof bytes); ++ if (rv == SECSuccess) { + /* if this is our first call, instantiate, otherwise reseed + * prng_instantiate gets a new clean state, we want to mix + * any previous entropy we may have collected */ + if (V(globalrng)[0] == 0) { +- rv = prng_instantiate(globalrng, bytes, numBytes); ++ rv = prng_instantiate(globalrng, bytes, sizeof bytes); + } else { +- rv = prng_reseed_test(globalrng, bytes, numBytes, NULL, 0); ++ rv = prng_reseed_test(globalrng, bytes, sizeof bytes, NULL, 0); + } +- memset(bytes, 0, numBytes); ++ memset(bytes, 0, sizeof bytes); + } else { + PZ_DestroyLock(globalrng->lock); + globalrng->lock = NULL; diff --git a/SOURCES/nss-dsa.patch b/SOURCES/nss-dsa.patch deleted file mode 100644 index 6a068f7..0000000 --- a/SOURCES/nss-dsa.patch +++ /dev/null @@ -1,170 +0,0 @@ -# HG changeset patch -# User Daiki Ueno -# Date 1542120846 -3600 -# Tue Nov 13 15:54:06 2018 +0100 -# Node ID 5046749fa8a56a99c251bc1cdd1b3302f43947d2 -# Parent 0d97145d524ab35b8bc2a4a8aea60a83bd244f14 -Bug 1493936, add a new "DSA" policy keyword - -Summary: -This adds a new policy keyword "DSA" to explicitly disable DSA in TLS 1.2 or earlier. - -We could make this a bit more generic, e.g., by adding "ECDSA", "RSA-PSS" etc. However, considering the current use of policy in [fedora-crypto-policies](https://gitlab.com/redhat-crypto/fedora-crypto-policies), I realized that adding new keywords may cause compatibility problems; because the Fedora configuration has `disallow=ALL`, all new keywords would be disabled by default. I think it's okay for DSA, though. - -Reviewers: kaie - -Reviewed By: kaie - -Bug #: 1493936 - -Differential Revision: https://phabricator.services.mozilla.com/D6777 - -diff --git a/lib/certhigh/certvfy.c b/lib/certhigh/certvfy.c ---- a/lib/certhigh/certvfy.c -+++ b/lib/certhigh/certvfy.c -@@ -37,7 +37,7 @@ CERT_CertTimesValid(CERTCertificate *c) - return (valid == secCertTimeValid) ? SECSuccess : SECFailure; - } - --SECStatus -+static SECStatus - checkKeyParams(const SECAlgorithmID *sigAlgorithm, const SECKEYPublicKey *key) - { - SECStatus rv; -@@ -47,6 +47,12 @@ checkKeyParams(const SECAlgorithmID *sig - PRInt32 minLen, len; - - sigAlg = SECOID_GetAlgorithmTag(sigAlgorithm); -+ rv = NSS_GetAlgorithmPolicy(sigAlg, &policyFlags); -+ if (rv == SECSuccess && -+ !(policyFlags & NSS_USE_ALG_IN_CERT_SIGNATURE)) { -+ PORT_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); -+ return SECFailure; -+ } - - switch (sigAlg) { - case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: -diff --git a/lib/pk11wrap/pk11pars.c b/lib/pk11wrap/pk11pars.c ---- a/lib/pk11wrap/pk11pars.c -+++ b/lib/pk11wrap/pk11pars.c -@@ -384,18 +384,26 @@ static const oidValDef kxOptList[] = { - { CIPHER_NAME("ECDH-RSA"), SEC_OID_TLS_ECDH_RSA, NSS_USE_ALG_IN_SSL_KX }, - }; - -+static const oidValDef signOptList[] = { -+ /* Signatures */ -+ { CIPHER_NAME("DSA"), SEC_OID_ANSIX9_DSA_SIGNATURE, -+ NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE }, -+}; -+ - typedef struct { - const oidValDef *list; - PRUint32 entries; - const char *description; -+ PRBool allowEmpty; - } algListsDef; - - static const algListsDef algOptLists[] = { -- { curveOptList, PR_ARRAY_SIZE(curveOptList), "ECC" }, -- { hashOptList, PR_ARRAY_SIZE(hashOptList), "HASH" }, -- { macOptList, PR_ARRAY_SIZE(macOptList), "MAC" }, -- { cipherOptList, PR_ARRAY_SIZE(cipherOptList), "CIPHER" }, -- { kxOptList, PR_ARRAY_SIZE(kxOptList), "OTHER-KX" }, -+ { curveOptList, PR_ARRAY_SIZE(curveOptList), "ECC", PR_FALSE }, -+ { hashOptList, PR_ARRAY_SIZE(hashOptList), "HASH", PR_FALSE }, -+ { macOptList, PR_ARRAY_SIZE(macOptList), "MAC", PR_FALSE }, -+ { cipherOptList, PR_ARRAY_SIZE(cipherOptList), "CIPHER", PR_FALSE }, -+ { kxOptList, PR_ARRAY_SIZE(kxOptList), "OTHER-KX", PR_FALSE }, -+ { signOptList, PR_ARRAY_SIZE(signOptList), "OTHER-SIGN", PR_TRUE }, - }; - - static const optionFreeDef sslOptList[] = { -@@ -718,7 +726,7 @@ secmod_sanityCheckCryptoPolicy(void) - for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) { - const algListsDef *algOptList = &algOptLists[i]; - fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-%s: %u\n", enabledCount[i] ? sInfo : sWarn, algOptList->description, enabledCount[i]); -- if (!enabledCount[i]) { -+ if (!enabledCount[i] && !algOptList->allowEmpty) { - haveWarning = PR_TRUE; - } - } -diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c ---- a/lib/ssl/ssl3con.c -+++ b/lib/ssl/ssl3con.c -@@ -64,6 +64,7 @@ static SECStatus ssl3_FlushHandshakeMess - static CK_MECHANISM_TYPE ssl3_GetHashMechanismByHashType(SSLHashType hashType); - static CK_MECHANISM_TYPE ssl3_GetMgfMechanismByHashType(SSLHashType hash); - PRBool ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme); -+PRBool ssl_IsDsaSignatureScheme(SSLSignatureScheme scheme); - - const PRUint8 ssl_hello_retry_random[] = { - 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, -@@ -4309,6 +4310,22 @@ ssl_IsRsaPssSignatureScheme(SSLSignature - return PR_FALSE; - } - -+PRBool -+ssl_IsDsaSignatureScheme(SSLSignatureScheme scheme) -+{ -+ switch (scheme) { -+ case ssl_sig_dsa_sha256: -+ case ssl_sig_dsa_sha384: -+ case ssl_sig_dsa_sha512: -+ case ssl_sig_dsa_sha1: -+ return PR_TRUE; -+ -+ default: -+ return PR_FALSE; -+ } -+ return PR_FALSE; -+} -+ - SSLAuthType - ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme) - { -@@ -6017,6 +6034,13 @@ ssl_CanUseSignatureScheme(SSLSignatureSc - return PR_FALSE; - } - -+ if (ssl_IsDsaSignatureScheme(scheme) && -+ (NSS_GetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE, &policy) == -+ SECSuccess) && -+ !(policy & NSS_USE_ALG_IN_SSL_KX)) { -+ return PR_FALSE; -+ } -+ - hashType = ssl_SignatureSchemeToHashType(scheme); - if (requireSha1 && (hashType != ssl_hash_sha1)) { - return PR_FALSE; -@@ -9490,6 +9514,14 @@ ssl3_EncodeSigAlgs(const sslSocket *ss, - continue; - } - -+ /* Skip DSA scheme if it is disabled by policy. */ -+ if (ssl_IsDsaSignatureScheme(ss->ssl3.signatureSchemes[i]) && -+ (NSS_GetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE, &policy) == -+ SECSuccess) && -+ !(policy & NSS_USE_ALG_IN_SSL_KX)) { -+ continue; -+ } -+ - if ((NSS_GetAlgorithmPolicy(hashOID, &policy) != SECSuccess) || - (policy & NSS_USE_ALG_IN_SSL_KX)) { - rv = sslBuffer_AppendNumber(buf, ss->ssl3.signatureSchemes[i], 2); -diff --git a/tests/ssl/sslpolicy.txt b/tests/ssl/sslpolicy.txt ---- a/tests/ssl/sslpolicy.txt -+++ b/tests/ssl/sslpolicy.txt -@@ -74,6 +74,8 @@ - # SECT409R1 - # SECT571K1 - # SECT571R1 -+# Signatures: -+# DSA - # Hashes: - # MD2 - # MD4 -@@ -172,3 +174,4 @@ - 1 noECC SSL3 d allow=tls-version-min=tls1.0:tls-version-max=tls1.2 Disallow Version Exlicitly - 1 noECC SSL3 d disallow=all_allow=hmac-sha1:sha256:rsa:des-ede3-cbc:tls-version-min=tls1.0:tls-version-max=tls1.2 Disallow Version Implicitly Narrow. - 1 noECC SSL3 d disallow=all_allow=md2/all:md4/all:md5/all:sha1/all:sha256/all:sha384/all:sha512/all:hmac-sha1/all:hmac-sha224/all:hmac-sha256/all:hmac-sha384/all:hmac-sha512/all:hmac-md5/all:camellia128-cbc/all:camellia192-cbc/all:camellia256-cbc/all:seed-cbc/all:des-ede3-cbc/all:des-40-cbc/all:des-cbc/all:null-cipher/all:rc2/all:rc4/all:idea/all:rsa/all:rsa-export/all:dhe-rsa/all:dhe-dss/all:ecdhe-ecdsa/all:ecdhe-rsa/all:ecdh-ecdsa/all:ecdh-rsa/all:tls-version-min=tls1.0:tls-version-max=tls1.2 Disallow Version Implicitly. -+ 0 noECC SSL3 d disallow=dsa Disallow DSA Signatures Explicitly. diff --git a/SOURCES/nss-dso-ldflags.patch b/SOURCES/nss-dso-ldflags.patch index fe39ae3..d5485ae 100644 --- a/SOURCES/nss-dso-ldflags.patch +++ b/SOURCES/nss-dso-ldflags.patch @@ -1,12 +1,8 @@ -diff --git a/coreconf/Linux.mk b/coreconf/Linux.mk ---- a/coreconf/Linux.mk -+++ b/coreconf/Linux.mk -@@ -135,17 +135,17 @@ ifeq ($(KERNEL),Linux) - endif - OS_LIBS = $(OS_PTHREAD) -ldl -lc - - ifdef USE_PTHREADS - DEFINES += -D_REENTRANT +Index: nss/coreconf/Linux.mk +=================================================================== +--- nss.orig/coreconf/Linux.mk ++++ nss/coreconf/Linux.mk +@@ -144,7 +144,7 @@ ifdef USE_PTHREADS endif DSO_CFLAGS = -fPIC @@ -15,8 +11,3 @@ diff --git a/coreconf/Linux.mk b/coreconf/Linux.mk # The linker on Red Hat Linux 7.2 and RHEL 2.1 (GNU ld version 2.11.90.0.8) # incorrectly reports undefined references in the libraries we link with, so # we don't use -z defs there. - # Also, -z defs conflicts with Address Sanitizer, which emits relocations - # against the libsanitizer runtime built into the main executable. - ZDEFS_FLAG = -Wl,-z,defs - DSO_LDOPTS += $(if $(findstring 2.11.90.0.8,$(shell ld -v)),,$(ZDEFS_FLAG)) - LDFLAGS += $(ARCHFLAG) -z noexecstack diff --git a/SOURCES/nss-fips-disable-tls13.patch b/SOURCES/nss-fips-disable-tls13.patch new file mode 100644 index 0000000..8b30bbc --- /dev/null +++ b/SOURCES/nss-fips-disable-tls13.patch @@ -0,0 +1,30 @@ +diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c +--- a/lib/ssl/sslsock.c ++++ b/lib/ssl/sslsock.c +@@ -2382,16 +2382,26 @@ ssl3_CreateOverlapWithPolicy(SSLProtocol + rv = ssl3_GetEffectiveVersionPolicy(protocolVariant, + &effectivePolicyBoundary); + if (rv == SECFailure) { + /* SECFailure means internal failure or invalid configuration. */ + overlap->min = overlap->max = SSL_LIBRARY_VERSION_NONE; + return SECFailure; + } + ++ /* TODO: TLSv1.3 doesn't work yet under FIPS mode */ ++ if (PK11_IsFIPS()) { ++ if (effectivePolicyBoundary.min >= SSL_LIBRARY_VERSION_TLS_1_3) { ++ effectivePolicyBoundary.min = SSL_LIBRARY_VERSION_TLS_1_2; ++ } ++ if (effectivePolicyBoundary.max >= SSL_LIBRARY_VERSION_TLS_1_3) { ++ effectivePolicyBoundary.max = SSL_LIBRARY_VERSION_TLS_1_2; ++ } ++ } ++ + vrange.min = PR_MAX(input->min, effectivePolicyBoundary.min); + vrange.max = PR_MIN(input->max, effectivePolicyBoundary.max); + + if (vrange.max < vrange.min) { + /* there was no overlap, turn off range altogether */ + overlap->min = overlap->max = SSL_LIBRARY_VERSION_NONE; + return SECFailure; + } diff --git a/SOURCES/nss-fipstest-tls12-prf.patch b/SOURCES/nss-fipstest-tls12-prf.patch new file mode 100644 index 0000000..207a0c0 --- /dev/null +++ b/SOURCES/nss-fipstest-tls12-prf.patch @@ -0,0 +1,81 @@ +# HG changeset patch +# User Tomas Mraz +# Date 1560861770 -7200 +# Tue Jun 18 14:42:50 2019 +0200 +# Node ID 6ef49fe67d6227a1d290da5537ec0dade379a15a +# Parent ebc93d6daeaa9001d31fd18b5199779da99ae9aa +Bug 1559906, fipstest: use CKM_TLS12_MASTER_KEY_DERIVE in TLS test, r=rrelyea + +This also lets us CAVS tests more than just SHA256. + +diff --git a/cmd/fipstest/fipstest.c b/cmd/fipstest/fipstest.c +--- a/cmd/fipstest/fipstest.c ++++ b/cmd/fipstest/fipstest.c +@@ -6669,12 +6669,13 @@ tls(char *reqfn) + + CK_MECHANISM master_mech = { CKM_TLS_MASTER_KEY_DERIVE, NULL, 0 }; + CK_MECHANISM key_block_mech = { CKM_TLS_KEY_AND_MAC_DERIVE, NULL, 0 }; +- CK_SSL3_MASTER_KEY_DERIVE_PARAMS master_params; +- CK_SSL3_KEY_MAT_PARAMS key_block_params; ++ CK_TLS12_MASTER_KEY_DERIVE_PARAMS master_params; ++ CK_TLS12_KEY_MAT_PARAMS key_block_params; + CK_SSL3_KEY_MAT_OUT key_material; + CK_RV crv; + + /* set up PKCS #11 parameters */ ++ master_params.prfHashMechanism = CKM_SHA256; + master_params.pVersion = NULL; + master_params.RandomInfo.pClientRandom = clientHello_random; + master_params.RandomInfo.ulClientRandomLen = sizeof(clientHello_random); +@@ -6682,6 +6683,7 @@ tls(char *reqfn) + master_params.RandomInfo.ulServerRandomLen = sizeof(serverHello_random); + master_mech.pParameter = (void *)&master_params; + master_mech.ulParameterLen = sizeof(master_params); ++ key_block_params.prfHashMechanism = CKM_SHA256; + key_block_params.ulMacSizeInBits = 0; + key_block_params.ulKeySizeInBits = 0; + key_block_params.ulIVSizeInBits = 0; +@@ -6724,13 +6726,39 @@ tls(char *reqfn) + if (buf[0] == '[') { + if (strncmp(buf, "[TLS", 4) == 0) { + if (buf[7] == '0') { ++ /* CK_SSL3_MASTER_KEY_DERIVE_PARAMS is a subset of ++ * CK_TLS12_MASTER_KEY_DERIVE_PARAMS and ++ * CK_SSL3_KEY_MAT_PARAMS is a subset of ++ * CK_TLS12_KEY_MAT_PARAMS. The latter params have ++ * an extra prfHashMechanism field at the end. */ + master_mech.mechanism = CKM_TLS_MASTER_KEY_DERIVE; + key_block_mech.mechanism = CKM_TLS_KEY_AND_MAC_DERIVE; ++ master_mech.ulParameterLen = sizeof(CK_SSL3_MASTER_KEY_DERIVE_PARAMS); ++ key_block_mech.ulParameterLen = sizeof(CK_SSL3_KEY_MAT_PARAMS); + } else if (buf[7] == '2') { +- master_mech.mechanism = +- CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256; +- key_block_mech.mechanism = +- CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256; ++ if (strncmp(&buf[10], "SHA-1", 5) == 0) { ++ master_params.prfHashMechanism = CKM_SHA_1; ++ key_block_params.prfHashMechanism = CKM_SHA_1; ++ } else if (strncmp(&buf[10], "SHA-224", 7) == 0) { ++ master_params.prfHashMechanism = CKM_SHA224; ++ key_block_params.prfHashMechanism = CKM_SHA224; ++ } else if (strncmp(&buf[10], "SHA-256", 7) == 0) { ++ master_params.prfHashMechanism = CKM_SHA256; ++ key_block_params.prfHashMechanism = CKM_SHA256; ++ } else if (strncmp(&buf[10], "SHA-384", 7) == 0) { ++ master_params.prfHashMechanism = CKM_SHA384; ++ key_block_params.prfHashMechanism = CKM_SHA384; ++ } else if (strncmp(&buf[10], "SHA-512", 7) == 0) { ++ master_params.prfHashMechanism = CKM_SHA512; ++ key_block_params.prfHashMechanism = CKM_SHA512; ++ } else { ++ fprintf(tlsresp, "ERROR: Unable to find prf Hash type"); ++ goto loser; ++ } ++ master_mech.mechanism = CKM_TLS12_MASTER_KEY_DERIVE; ++ key_block_mech.mechanism = CKM_TLS12_KEY_AND_MAC_DERIVE; ++ master_mech.ulParameterLen = sizeof(master_params); ++ key_block_mech.ulParameterLen = sizeof(key_block_params); + } else { + fprintf(stderr, "Unknown TLS type %x\n", + (unsigned int)buf[0]); diff --git a/SOURCES/nss-ike-patch.patch b/SOURCES/nss-ike-patch.patch new file mode 100644 index 0000000..3ecfa63 --- /dev/null +++ b/SOURCES/nss-ike-patch.patch @@ -0,0 +1,4513 @@ +diff --git a/cmd/fipstest/README b/cmd/fipstest/README +new file mode 100644 +--- /dev/null ++++ b/cmd/fipstest/README +@@ -0,0 +1,1 @@ ++The scripts have been moved to tests/fips/cavs_scripts +diff --git a/cmd/fipstest/aes.sh b/cmd/fipstest/aes.sh +deleted file mode 100644 +--- a/cmd/fipstest/aes.sh ++++ /dev/null +@@ -1,112 +0,0 @@ +-#!/bin/sh +-# +-# 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/. +-# +-# +-# A Bourne shell script for running the NIST AES Algorithm Validation Suite +-# +-# Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment +-# variables appropriately so that the fipstest command and the NSPR and NSS +-# shared libraries/DLLs are on the search path. Then run this script in the +-# directory where the REQUEST (.req) files reside. The script generates the +-# RESPONSE (.rsp) files in the same directory. +- +-BASEDIR=${1-.} +-TESTDIR=${BASEDIR}/AES +-COMMAND=${2-run} +-REQDIR=${TESTDIR}/req +-RSPDIR=${TESTDIR}/resp +- +-cbc_kat_requests=" +-CBCGFSbox128.req +-CBCGFSbox192.req +-CBCGFSbox256.req +-CBCKeySbox128.req +-CBCKeySbox192.req +-CBCKeySbox256.req +-CBCVarKey128.req +-CBCVarKey192.req +-CBCVarKey256.req +-CBCVarTxt128.req +-CBCVarTxt192.req +-CBCVarTxt256.req +-" +- +-cbc_mct_requests=" +-CBCMCT128.req +-CBCMCT192.req +-CBCMCT256.req +-" +- +-cbc_mmt_requests=" +-CBCMMT128.req +-CBCMMT192.req +-CBCMMT256.req +-" +- +-ecb_kat_requests=" +-ECBGFSbox128.req +-ECBGFSbox192.req +-ECBGFSbox256.req +-ECBKeySbox128.req +-ECBKeySbox192.req +-ECBKeySbox256.req +-ECBVarKey128.req +-ECBVarKey192.req +-ECBVarKey256.req +-ECBVarTxt128.req +-ECBVarTxt192.req +-ECBVarTxt256.req +-" +- +-ecb_mct_requests=" +-ECBMCT128.req +-ECBMCT192.req +-ECBMCT256.req +-" +- +-ecb_mmt_requests=" +-ECBMMT128.req +-ECBMMT192.req +-ECBMMT256.req +-" +- +-if [ ${COMMAND} = "verify" ]; then +- for request in $cbc_kat_requests $cbc_mct_requests $cbc_mmt_requests $ecb_kat_requests $ecb_mct_requests $ecb_mmt_requests; do +- sh ./validate1.sh ${TESTDIR} $request +- done +- exit 0 +-fi +- +-for request in $cbc_kat_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest aes kat cbc ${REQDIR}/$request > ${RSPDIR}/$response +-done +-for request in $cbc_mct_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest aes mct cbc ${REQDIR}/$request > ${RSPDIR}/$response +-done +-for request in $cbc_mmt_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest aes mmt cbc ${REQDIR}/$request > ${RSPDIR}/$response +-done +-for request in $ecb_kat_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest aes kat ecb ${REQDIR}/$request > ${RSPDIR}/$response +-done +-for request in $ecb_mct_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest aes mct ecb ${REQDIR}/$request > ${RSPDIR}/$response +-done +-for request in $ecb_mmt_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest aes mmt ecb ${REQDIR}/$request > ${RSPDIR}/$response +-done +diff --git a/cmd/fipstest/aesgcm.sh b/cmd/fipstest/aesgcm.sh +deleted file mode 100644 +--- a/cmd/fipstest/aesgcm.sh ++++ /dev/null +@@ -1,67 +0,0 @@ +-#!/bin/sh +-# +-# 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/. +-# +-# A Bourne shell script for running the NIST AES Algorithm Validation Suite +-# +-# Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment +-# variables appropriately so that the fipstest command and the NSPR and NSS +-# shared libraries/DLLs are on the search path. Then run this script in the +-# directory where the REQUEST (.req) files reside. The script generates the +-# RESPONSE (.rsp) files in the same directory. +- +-BASEDIR=${1-.} +-TESTDIR=${BASEDIR}/AES_GCM +-COMMAND=${2-run} +-REQDIR=${TESTDIR}/req +-RSPDIR=${TESTDIR}/resp +- +-gcm_decrypt_requests=" +-gcmDecrypt128.req +-gcmDecrypt192.req +-gcmDecrypt256.req +-" +- +-gcm_encrypt_extiv_requests=" +-gcmEncryptExtIV128.req +-gcmEncryptExtIV192.req +-gcmEncryptExtIV256.req +-" +-gcm_encrypt_intiv_requests=" +-" +- +-#gcm_encrypt_intiv_requests=" +-#gcmEncryptIntIV128.req +-#gcmEncryptIntIV192.req +-#gcmEncryptIntIV256.req +-#" +- +-if [ ${COMMAND} = "verify" ]; then +- for request in $gcm_decrypt_requests $gcm_encrypt_extiv_requests; do +- sh ./validate1.sh ${TESTDIR} $request ' ' '-e /Reason:/d' +- done +- for request in $gcm_encrypt_intiv_requests; do +- name=`basename $request .req` +- echo ">>>>> $name" +- fipstest aes gcm decrypt ${RSPDIR}/$name.rsp | grep FAIL +- done +- exit 0 +-fi +- +-for request in $gcm_decrypt_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest aes gcm decrypt ${REQDIR}/$request > ${RSPDIR}/$response +-done +-for request in $gcm_encrypt_intiv_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest aes gcm encrypt_intiv ${REQDIR}/$request > ${RSPDIR}/$response +-done +-for request in $gcm_encrypt_extiv_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest aes gcm encrypt_extiv ${REQDIR}/$request > ${RSPDIR}/$response +-done +diff --git a/cmd/fipstest/dsa.sh b/cmd/fipstest/dsa.sh +deleted file mode 100755 +--- a/cmd/fipstest/dsa.sh ++++ /dev/null +@@ -1,71 +0,0 @@ +-#!/bin/sh +-# +-# 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/. +-# +-# A Bourne shell script for running the NIST DSA Validation System +-# +-# Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment +-# variables appropriately so that the fipstest command and the NSPR and NSS +-# shared libraries/DLLs are on the search path. Then run this script in the +-# directory where the REQUEST (.req) files reside. The script generates the +-# RESPONSE (.rsp) files in the same directory. +-BASEDIR=${1-.} +-TESTDIR=${BASEDIR}/DSA2 +-COMMAND=${2-run} +-REQDIR=${TESTDIR}/req +-RSPDIR=${TESTDIR}/resp +- +- +-# +-# several of the DSA tests do use known answer tests to verify the result. +-# in those cases, feed generated tests back into the fipstest tool and +-# see if we can verify those value. NOTE: th PQGVer and SigVer tests verify +-# the dsa pqgver and dsa sigver functions, so we know they can detect errors +-# in those PQGGen and SigGen. Only the KeyPair verify is potentially circular. +-# +-if [ ${COMMAND} = "verify" ]; then +-# verify generated keys +- name=KeyPair +- echo ">>>>> $name" +- fipstest dsa keyver ${RSPDIR}/$name.rsp | grep ^Result.=.F +-# verify generated pqg values +- name=PQGGen +- echo ">>>>> $name" +- fipstest dsa pqgver ${RSPDIR}/$name.rsp | grep ^Result.=.F +-# verify PQGVer with known answer +-# sh ./validate1.sh ${TESTDIR} PQGVer.req ' ' '-e /^Result.=.F/s;.(.*);; -e /^Result.=.P/s;.(.*);;' +-# verify signatures +- name=SigGen +- echo ">>>>> $name" +- fipstest dsa sigver ${RSPDIR}/$name.rsp | grep ^Result.=.F +-# verify SigVer with known answer +- sh ./validate1.sh ${TESTDIR} SigVer.req ' ' '-e /^X.=/d -e /^Result.=.F/s;.(.*);;' +- exit 0 +-fi +- +-request=KeyPair.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest dsa keypair ${REQDIR}/$request > ${RSPDIR}/$response +- +-request=PQGGen.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest dsa pqggen ${REQDIR}/$request > ${RSPDIR}/$response +- +-request=PQGVer1863.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest dsa pqgver ${REQDIR}/$request > ${RSPDIR}/$response +- +-request=SigGen.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest dsa siggen ${REQDIR}/$request > ${RSPDIR}/$response +- +-request=SigVer.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest dsa sigver ${REQDIR}/$request > ${RSPDIR}/$response +diff --git a/cmd/fipstest/ecdsa.sh b/cmd/fipstest/ecdsa.sh +deleted file mode 100644 +--- a/cmd/fipstest/ecdsa.sh ++++ /dev/null +@@ -1,60 +0,0 @@ +-#!/bin/sh +-# +-# 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/. +-# +-# A Bourne shell script for running the NIST ECDSA Validation System +-# +-# Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment +-# variables appropriately so that the fipstest command and the NSPR and NSS +-# shared libraries/DLLs are on the search path. Then run this script in the +-# directory where the REQUEST (.req) files reside. The script generates the +-# RESPONSE (.rsp) files in the same directory. +-BASEDIR=${1-.} +-TESTDIR=${BASEDIR}/ECDSA2 +-COMMAND=${2-run} +-REQDIR=${TESTDIR}/req +-RSPDIR=${TESTDIR}/resp +- +-# +-# several of the ECDSA tests do not use known answer tests to verify the result. +-# In those cases, feed generated tests back into the fipstest tool and +-# see if we can verify those value. NOTE: PQGVer and SigVer tests verify +-# the dsa pqgver and dsa sigver functions, so we know they can detect errors +-# in those PQGGen and SigGen. Only the KeyPair verify is potentially circular. +-# +-if [ ${COMMAND} = "verify" ]; then +-# verify generated keys +- name=KeyPair +- echo ">>>>> $name" +- fipstest ecdsa keyver ${RSPDIR}/$name.rsp | grep ^Result.=.F +- sh ./validate1.sh ${TESTDIR} PKV.req ' ' '-e /^X.=/d -e /^Result.=.F/s;.(.*);; -e /^Result.=.P/s;.(.*);;' +-# verify signatures +- name=SigGen +- echo ">>>>> $name" +- fipstest ecdsa sigver ${RSPDIR}/$name.rsp | grep ^Result.=.F +-# verify SigVer with known answer +- sh ./validate1.sh ${TESTDIR} SigVer.req ' ' '-e /^X.=/d -e /^Result.=.F/s;.(.*);; -e /^Result.=.P/s;.(.*);;' +- exit 0 +-fi +- +-request=KeyPair.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest ecdsa keypair ${REQDIR}/$request > ${RSPDIR}/$response +- +-request=PKV.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest ecdsa pkv ${REQDIR}/$request > ${RSPDIR}/$response +- +-request=SigGen.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest ecdsa siggen ${REQDIR}/$request > ${RSPDIR}/$response +- +-request=SigVer.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest ecdsa sigver ${REQDIR}/$request > ${RSPDIR}/$response +diff --git a/cmd/fipstest/fipstest.c b/cmd/fipstest/fipstest.c +--- a/cmd/fipstest/fipstest.c ++++ b/cmd/fipstest/fipstest.c +@@ -29,16 +29,21 @@ + #undef CK_PKCS11_FUNCTION_INFO + #undef CK_NEED_ARG_LIST + #undef __PASTE + #define SSL3_RANDOM_LENGTH 32 + + #if 0 + #include "../../lib/freebl/mpi/mpi.h" + #endif ++#define MATCH_OPENSSL 1 ++/*#define MATCH_NIST 1 */ ++#ifdef MATCH_NIST ++#define VERBOSE_REASON 1 ++#endif + + extern SECStatus + EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams); + extern SECStatus + EC_CopyParams(PLArenaPool *arena, ECParams *dstParams, + const ECParams *srcParams); + + #define ENCRYPT 1 +@@ -3164,16 +3169,20 @@ ecdh_functional(char *reqfn, PRBool resp + fprintf(stderr, "generate key had invalid public value len\n"); + goto loser; + } + uit_len = (uit_len - 1) / 2; + if (ecpriv->publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) { + fprintf(stderr, "generate key was compressed\n"); + goto loser; + } ++ fputs("deIUT = ", ecdhresp); ++ to_hex_str(buf, ecpriv->privateValue.data, ecpriv->privateValue.len); ++ fputs(buf, ecdhresp); ++ fputc('\n', ecdhresp); + fputs("QeIUTx = ", ecdhresp); + to_hex_str(buf, &ecpriv->publicValue.data[1], uit_len); + fputs(buf, ecdhresp); + fputc('\n', ecdhresp); + fputs("QeIUTy = ", ecdhresp); + to_hex_str(buf, &ecpriv->publicValue.data[1 + uit_len], uit_len); + fputs(buf, ecdhresp); + fputc('\n', ecdhresp); +@@ -3210,17 +3219,16 @@ loser: + } + } + if (pubkey.data != NULL) { + PORT_Free(pubkey.data); + } + fclose(ecdhreq); + } + +-#define MATCH_OPENSSL 1 + /* + * Perform the ECDH Validity Test. + * + * reqfn is the pathname of the REQUEST file. + * + * The output RESPONSE file is written to stdout. + */ + void +@@ -3403,42 +3411,47 @@ ecdh_verify(char *reqfn, PRBool response + if (strncmp(buf, "QeIUTx", 6) == 0) { + fputs(buf, ecdhresp); + continue; + } + if (strncmp(buf, "QeIUTy", 6) == 0) { + fputs(buf, ecdhresp); + continue; + } +- if (strncmp(buf, "CAVSHashZZ", 10) == 0) { ++ if ((strncmp(buf, "CAVSHashZZ", 10) == 0) || ++ (strncmp(buf, "HashZZ", 6) == 0)) { + fputs(buf, ecdhresp); +- i = 10; ++ i = (buf[0] == 'C') ? 10 : 6; + while (isspace(buf[i]) || buf[i] == '=') { + i++; + } + from_hex_str(cavsHashBuf, fips_hashLen(hash), &buf[i]); + if (current_ecparams == NULL) { + fprintf(stderr, "no curve defined for type defined\n"); + goto loser; + } + /* validate CAVS public key */ + if (EC_ValidatePublicKey(current_ecparams, &pubkey) != SECSuccess) { +-#ifdef MATCH_OPENSSL ++#ifdef VERBOSE_REASON ++ fprintf(ecdhresp, "Result = F # key didn't validate\n"); ++#else + fprintf(ecdhresp, "Result = F\n"); +-#else +- fprintf(ecdhresp, "Result = F # key didn't validate\n"); + #endif + continue; + } + + /* ECDH */ + if (ECDH_Derive(&pubkey, current_ecparams, &private_value, + PR_FALSE, &ZZ) != SECSuccess) { +- fprintf(stderr, "Derive failed\n"); +- goto loser; ++#ifdef VERBOSE_REASON ++ fprintf(ecdhresp, "Result = F # derive failure\n"); ++#else ++ fprintf(ecdhresp, "Result = F\n"); ++#endif ++ continue; + } + /* output ZZ */ + #ifndef MATCH_OPENSSL + fputs("Z = ", ecdhresp); + to_hex_str(buf, ZZ.data, ZZ.len); + fputs(buf, ecdhresp); + fputc('\n', ecdhresp); + #endif +@@ -3450,20 +3463,20 @@ ecdh_verify(char *reqfn, PRBool response + SECITEM_FreeItem(&ZZ, PR_FALSE); + #ifndef MATCH_NIST + fputs("IUTHashZZ = ", ecdhresp); + to_hex_str(buf, hashBuf, fips_hashLen(hash)); + fputs(buf, ecdhresp); + fputc('\n', ecdhresp); + #endif + if (memcmp(hashBuf, cavsHashBuf, fips_hashLen(hash)) != 0) { +-#ifdef MATCH_OPENSSL ++#ifdef VERBOSE_REASON ++ fprintf(ecdhresp, "Result = F # hash doesn't match\n"); ++#else + fprintf(ecdhresp, "Result = F\n"); +-#else +- fprintf(ecdhresp, "Result = F # hash doesn't match\n"); + #endif + } else { + fprintf(ecdhresp, "Result = P\n"); + } + #ifndef MATCH_OPENSSL + fputc('\n', ecdhresp); + #endif + continue; +@@ -3670,17 +3683,16 @@ dh_functional(char *reqfn, PRBool respon + } + loser: + if (dsapriv != NULL) { + PORT_FreeArena(dsapriv->params.arena, PR_TRUE); + } + fclose(dhreq); + } + +-#define MATCH_OPENSSL 1 + /* + * Perform the DH Validity Test. + * + * reqfn is the pathname of the REQUEST file. + * + * The output RESPONSE file is written to stdout. + */ + void +@@ -3841,19 +3853,20 @@ dh_verify(char *reqfn, PRBool response) + continue; + } + /* YephemUIT = ... */ + if (strncmp(buf, "YephemIUT", 9) == 0) { + fputs(buf, dhresp); + continue; + } + /* CAVSHashZZ = ... */ +- if (strncmp(buf, "CAVSHashZZ", 10) == 0) { ++ if ((strncmp(buf, "CAVSHashZZ", 10) == 0) || ++ (strncmp(buf, "HashZZ", 6) == 0)) { + fputs(buf, dhresp); +- i = 10; ++ i = buf[0] == 'C' ? 10 : 6; + while (isspace(buf[i]) || buf[i] == '=') { + i++; + } + from_hex_str(cavsHashBuf, fips_hashLen(hash), &buf[i]); + /* do the DH operation*/ + if (DH_Derive(&pubkey, &pqg.prime, &privkey, + &ZZ, pqg.prime.len) != SECSuccess) { + fprintf(stderr, "Derive failed\n"); +@@ -3866,17 +3879,17 @@ dh_verify(char *reqfn, PRBool response) + fputs(buf, dhresp); + fputc('\n', dhresp); + #endif + if (fips_hashBuf(hash, hashBuf, ZZ.data, ZZ.len) != SECSuccess) { + fprintf(stderr, "hash of derived key failed\n"); + goto loser; + } + SECITEM_FreeItem(&ZZ, PR_FALSE); +-#ifndef MATCH_NIST_ ++#ifndef MATCH_NIST + fputs("IUTHashZZ = ", dhresp); + to_hex_str(buf, hashBuf, fips_hashLen(hash)); + fputs(buf, dhresp); + fputc('\n', dhresp); + #endif + if (memcmp(hashBuf, cavsHashBuf, fips_hashLen(hash)) != 0) { + fprintf(dhresp, "Result = F\n"); + } else { +@@ -6895,16 +6908,1306 @@ loser: + if (master_secret) + free(master_secret); + if (key_block) + free(key_block); + if (tlsreq) + fclose(tlsreq); + } + ++void ++ikev1(char *reqfn) ++{ ++ char buf[4096]; /* holds one line from the input REQUEST file. ++ * needs to be large enough to hold the longest ++ * line "g^xy = <2048 hex digits>\n". ++ */ ++ unsigned char *gxy = NULL; ++ int gxy_len; ++ unsigned char *Ni = NULL; ++ int Ni_len; ++ unsigned char *Nr = NULL; ++ int Nr_len; ++ unsigned char CKYi[8]; ++ int CKYi_len; ++ unsigned char CKYr[8]; ++ int CKYr_len; ++ unsigned int i, j; ++ FILE *ikereq = NULL; /* input stream from the REQUEST file */ ++ FILE *ikeresp; /* output stream to the RESPONSE file */ ++ ++ CK_SLOT_ID slotList[10]; ++ CK_SLOT_ID slotID; ++ CK_ULONG slotListCount = sizeof(slotList) / sizeof(slotList[0]); ++ CK_ULONG count; ++ static const CK_C_INITIALIZE_ARGS pk11args = { ++ NULL, NULL, NULL, NULL, CKF_LIBRARY_CANT_CREATE_OS_THREADS, ++ (void *)"flags=readOnly,noCertDB,noModDB", NULL ++ }; ++ static CK_OBJECT_CLASS ck_secret = CKO_SECRET_KEY; ++ static CK_KEY_TYPE ck_generic = CKK_GENERIC_SECRET; ++ static CK_BBOOL ck_true = CK_TRUE; ++ static CK_ULONG keyLen = 1; ++ CK_ATTRIBUTE gxy_template[] = { ++ { CKA_VALUE, NULL, 0 }, /* must be first */ ++ { CKA_CLASS, &ck_secret, sizeof(ck_secret) }, ++ { CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) }, ++ { CKA_DERIVE, &ck_true, sizeof(ck_true) }, ++ }; ++ CK_ULONG gxy_template_count = ++ sizeof(gxy_template) / sizeof(gxy_template[0]); ++ CK_ATTRIBUTE derive_template[] = { ++ { CKA_CLASS, &ck_secret, sizeof(ck_secret) }, ++ { CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) }, ++ { CKA_DERIVE, &ck_true, sizeof(ck_true) }, ++ { CKA_VALUE_LEN, &keyLen, sizeof(keyLen) }, /* must be last */ ++ }; ++ CK_ULONG derive_template_count = ++ sizeof(derive_template) / sizeof(derive_template[0]); ++ CK_ATTRIBUTE skeyid_template = ++ { CKA_VALUE, NULL, 0 }; ++ CK_ATTRIBUTE skeyid_d_template = ++ { CKA_VALUE, NULL, 0 }; ++ CK_ATTRIBUTE skeyid_a_template = ++ { CKA_VALUE, NULL, 0 }; ++ CK_ATTRIBUTE skeyid_e_template = ++ { CKA_VALUE, NULL, 0 }; ++ unsigned char skeyid_secret[HASH_LENGTH_MAX]; ++ unsigned char skeyid_d_secret[HASH_LENGTH_MAX]; ++ unsigned char skeyid_a_secret[HASH_LENGTH_MAX]; ++ unsigned char skeyid_e_secret[HASH_LENGTH_MAX]; ++ ++ CK_MECHANISM ike_mech = { CKM_NSS_IKE_PRF_DERIVE, NULL, 0 }; ++ CK_MECHANISM ike1_mech = { CKM_NSS_IKE1_PRF_DERIVE, NULL, 0 }; ++ CK_NSS_IKE_PRF_DERIVE_PARAMS ike_prf; ++ CK_NSS_IKE1_PRF_DERIVE_PARAMS ike1_prf; ++ CK_RV crv; ++ ++ /* set up PKCS #11 parameters */ ++ ike_prf.bDataAsKey = PR_TRUE; ++ ike_prf.bRekey = PR_FALSE; ++ ike_prf.hNewKey = CK_INVALID_HANDLE; ++ CKYi_len = sizeof(CKYi); ++ CKYr_len = sizeof(CKYr); ++ ike1_prf.pCKYi = CKYi; ++ ike1_prf.ulCKYiLen = CKYi_len; ++ ike1_prf.pCKYr = CKYr; ++ ike1_prf.ulCKYrLen = CKYr_len; ++ ike_mech.pParameter = &ike_prf; ++ ike_mech.ulParameterLen = sizeof(ike_prf); ++ ike1_mech.pParameter = &ike1_prf; ++ ike1_mech.ulParameterLen = sizeof(ike1_prf); ++ skeyid_template.pValue = skeyid_secret; ++ skeyid_template.ulValueLen = HASH_LENGTH_MAX; ++ skeyid_d_template.pValue = skeyid_d_secret; ++ skeyid_d_template.ulValueLen = HASH_LENGTH_MAX; ++ skeyid_a_template.pValue = skeyid_a_secret; ++ skeyid_a_template.ulValueLen = HASH_LENGTH_MAX; ++ skeyid_e_template.pValue = skeyid_e_secret; ++ skeyid_e_template.ulValueLen = HASH_LENGTH_MAX; ++ ++ crv = NSC_Initialize((CK_VOID_PTR)&pk11args); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_Initialize failed crv=0x%x\n", (unsigned int)crv); ++ goto loser; ++ } ++ count = slotListCount; ++ crv = NSC_GetSlotList(PR_TRUE, slotList, &count); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetSlotList failed crv=0x%x\n", (unsigned int)crv); ++ goto loser; ++ } ++ if ((count > slotListCount) || count < 1) { ++ fprintf(stderr, ++ "NSC_GetSlotList returned too many or too few slots: %d slots max=%d min=1\n", ++ (int)count, (int)slotListCount); ++ goto loser; ++ } ++ slotID = slotList[0]; ++ ikereq = fopen(reqfn, "r"); ++ ikeresp = stdout; ++ while (fgets(buf, sizeof buf, ikereq) != NULL) { ++ /* a comment or blank line */ ++ if (buf[0] == '#' || buf[0] == '\n') { ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* [.....] */ ++ if (buf[0] == '[') { ++ if (strncmp(buf, "[SHA-1]", 7) == 0) { ++ ike_prf.prfMechanism = CKM_SHA_1_HMAC; ++ ike1_prf.prfMechanism = CKM_SHA_1_HMAC; ++ } ++ if (strncmp(buf, "[SHA-224]", 9) == 0) { ++ ike_prf.prfMechanism = CKM_SHA224_HMAC; ++ ike1_prf.prfMechanism = CKM_SHA224_HMAC; ++ } ++ if (strncmp(buf, "[SHA-256]", 9) == 0) { ++ ike_prf.prfMechanism = CKM_SHA256_HMAC; ++ ike1_prf.prfMechanism = CKM_SHA256_HMAC; ++ } ++ if (strncmp(buf, "[SHA-384]", 9) == 0) { ++ ike_prf.prfMechanism = CKM_SHA384_HMAC; ++ ike1_prf.prfMechanism = CKM_SHA384_HMAC; ++ } ++ if (strncmp(buf, "[SHA-512]", 9) == 0) { ++ ike_prf.prfMechanism = CKM_SHA512_HMAC; ++ ike1_prf.prfMechanism = CKM_SHA512_HMAC; ++ } ++ if (strncmp(buf, "[AES-XCBC", 9) == 0) { ++ ike_prf.prfMechanism = CKM_AES_XCBC_MAC; ++ ike1_prf.prfMechanism = CKM_AES_XCBC_MAC; ++ } ++ if (strncmp(buf, "[g^xy", 5) == 0) { ++ if (sscanf(buf, "[g^xy length = %d]", ++ &gxy_len) != 1) { ++ goto loser; ++ } ++ gxy_len = gxy_len / 8; ++ if (gxy) ++ free(gxy); ++ gxy = malloc(gxy_len); ++ gxy_template[0].pValue = gxy; ++ gxy_template[0].ulValueLen = gxy_len; ++ } ++ if (strncmp(buf, "[Ni", 3) == 0) { ++ if (sscanf(buf, "[Ni length = %d]", &Ni_len) != 1) { ++ goto loser; ++ } ++ Ni_len = Ni_len / 8; ++ if (Ni) ++ free(Ni); ++ Ni = malloc(Ni_len); ++ ike_prf.pNi = Ni; ++ ike_prf.ulNiLen = Ni_len; ++ } ++ if (strncmp(buf, "[Nr", 3) == 0) { ++ if (sscanf(buf, "[Nr length = %d]", &Nr_len) != 1) { ++ goto loser; ++ } ++ Nr_len = Nr_len / 8; ++ if (Nr) ++ free(Nr); ++ Nr = malloc(Nr_len); ++ ike_prf.pNr = Nr; ++ ike_prf.ulNrLen = Nr_len; ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* "COUNT = x" begins a new data set */ ++ if (strncmp(buf, "COUNT", 5) == 0) { ++ /* zeroize the variables for the test with this data set */ ++ memset(gxy, 0, gxy_len); ++ memset(Ni, 0, Ni_len); ++ memset(Nr, 0, Nr_len); ++ memset(CKYi, 0, CKYi_len); ++ memset(CKYr, 0, CKYr_len); ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* Ni = ... */ ++ if (strncmp(buf, "Ni", 2) == 0) { ++ i = 2; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < Ni_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &Ni[j]); ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* Nr = ... */ ++ if (strncmp(buf, "Nr", 2) == 0) { ++ i = 2; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < Nr_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &Nr[j]); ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* CKYi = ... */ ++ if (strncmp(buf, "CKY_I", 5) == 0) { ++ i = 5; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < CKYi_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &CKYi[j]); ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* CKYr = ... */ ++ if (strncmp(buf, "CKY_R", 5) == 0) { ++ i = 5; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < CKYr_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &CKYr[j]); ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* g^xy = ... */ ++ if (strncmp(buf, "g^xy", 4) == 0) { ++ CK_SESSION_HANDLE session; ++ CK_OBJECT_HANDLE gxy_handle; ++ CK_OBJECT_HANDLE skeyid_handle; ++ CK_OBJECT_HANDLE skeyid_d_handle; ++ CK_OBJECT_HANDLE skeyid_a_handle; ++ CK_OBJECT_HANDLE skeyid_e_handle; ++ i = 4; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < gxy_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &gxy[j]); ++ } ++ fputs(buf, ikeresp); ++ crv = NSC_OpenSession(slotID, 0, NULL, NULL, &session); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_OpenSession failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ crv = NSC_CreateObject(session, gxy_template, ++ gxy_template_count, &gxy_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_CreateObject failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ /* get the skeyid key */ ++ crv = NSC_DeriveKey(session, &ike_mech, gxy_handle, ++ derive_template, derive_template_count - 1, ++ &skeyid_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_DeriveKey(skeyid) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ skeyid_template.ulValueLen = HASH_LENGTH_MAX; ++ crv = NSC_GetAttributeValue(session, skeyid_handle, ++ &skeyid_template, 1); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetAttribute(skeyid) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ /* use the length of the skeyid to set the target length of all the ++ * other keys */ ++ keyLen = skeyid_template.ulValueLen; ++ ike1_prf.hKeygxy = gxy_handle; ++ ike1_prf.bHasPrevKey = PR_FALSE; ++ ike1_prf.keyNumber = 0; ++ crv = NSC_DeriveKey(session, &ike1_mech, skeyid_handle, ++ derive_template, derive_template_count, ++ &skeyid_d_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_DeriveKey(skeyid_d) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ ++ ike1_prf.hKeygxy = gxy_handle; ++ ike1_prf.bHasPrevKey = CK_TRUE; ++ ike1_prf.hPrevKey = skeyid_d_handle; ++ ike1_prf.keyNumber = 1; ++ crv = NSC_DeriveKey(session, &ike1_mech, skeyid_handle, ++ derive_template, derive_template_count, ++ &skeyid_a_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_DeriveKey(skeyid_a) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ ike1_prf.hKeygxy = gxy_handle; ++ ike1_prf.bHasPrevKey = CK_TRUE; ++ ike1_prf.hPrevKey = skeyid_a_handle; ++ ike1_prf.keyNumber = 2; ++ crv = NSC_DeriveKey(session, &ike1_mech, skeyid_handle, ++ derive_template, derive_template_count, ++ &skeyid_e_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_DeriveKey(skeyid_e) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ fputs("SKEYID = ", ikeresp); ++ to_hex_str(buf, skeyid_secret, keyLen); ++ fputs(buf, ikeresp); ++ fputc('\n', ikeresp); ++ ++ skeyid_d_template.ulValueLen = keyLen; ++ crv = NSC_GetAttributeValue(session, skeyid_d_handle, ++ &skeyid_d_template, 1); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetAttribute(skeyid_d) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ fputs("SKEYID_d = ", ikeresp); ++ to_hex_str(buf, skeyid_d_secret, skeyid_d_template.ulValueLen); ++ fputs(buf, ikeresp); ++ fputc('\n', ikeresp); ++ ++ skeyid_a_template.ulValueLen = keyLen; ++ crv = NSC_GetAttributeValue(session, skeyid_a_handle, ++ &skeyid_a_template, 1); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetAttribute(skeyid_a) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ fputs("SKEYID_a = ", ikeresp); ++ to_hex_str(buf, skeyid_a_secret, skeyid_a_template.ulValueLen); ++ fputs(buf, ikeresp); ++ fputc('\n', ikeresp); ++ ++ skeyid_e_template.ulValueLen = keyLen; ++ crv = NSC_GetAttributeValue(session, skeyid_e_handle, ++ &skeyid_e_template, 1); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetAttribute(skeyid_e) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ fputs("SKEYID_e = ", ikeresp); ++ to_hex_str(buf, skeyid_e_secret, skeyid_e_template.ulValueLen); ++ fputs(buf, ikeresp); ++ fputc('\n', ikeresp); ++ ++ crv = NSC_CloseSession(session); ++ continue; ++ } ++ } ++loser: ++ NSC_Finalize(NULL); ++ if (gxy) ++ free(gxy); ++ if (Ni) ++ free(Ni); ++ if (Nr) ++ free(Nr); ++ if (ikereq) ++ fclose(ikereq); ++} ++ ++void ++ikev1_psk(char *reqfn) ++{ ++ char buf[4096]; /* holds one line from the input REQUEST file. ++ * needs to be large enough to hold the longest ++ * line "g^xy = <2048 hex digits>\n". ++ */ ++ unsigned char *gxy = NULL; ++ int gxy_len; ++ unsigned char *Ni = NULL; ++ int Ni_len; ++ unsigned char *Nr = NULL; ++ int Nr_len; ++ unsigned char CKYi[8]; ++ int CKYi_len; ++ unsigned char CKYr[8]; ++ int CKYr_len; ++ unsigned char *psk = NULL; ++ int psk_len; ++ unsigned int i, j; ++ FILE *ikereq = NULL; /* input stream from the REQUEST file */ ++ FILE *ikeresp; /* output stream to the RESPONSE file */ ++ ++ CK_SLOT_ID slotList[10]; ++ CK_SLOT_ID slotID; ++ CK_ULONG slotListCount = sizeof(slotList) / sizeof(slotList[0]); ++ CK_ULONG count; ++ static const CK_C_INITIALIZE_ARGS pk11args = { ++ NULL, NULL, NULL, NULL, CKF_LIBRARY_CANT_CREATE_OS_THREADS, ++ (void *)"flags=readOnly,noCertDB,noModDB", NULL ++ }; ++ static CK_OBJECT_CLASS ck_secret = CKO_SECRET_KEY; ++ static CK_KEY_TYPE ck_generic = CKK_GENERIC_SECRET; ++ static CK_BBOOL ck_true = CK_TRUE; ++ static CK_ULONG keyLen = 1; ++ CK_ATTRIBUTE gxy_template[] = { ++ { CKA_VALUE, NULL, 0 }, /* must be first */ ++ { CKA_CLASS, &ck_secret, sizeof(ck_secret) }, ++ { CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) }, ++ { CKA_DERIVE, &ck_true, sizeof(ck_true) }, ++ }; ++ CK_ULONG gxy_template_count = ++ sizeof(gxy_template) / sizeof(gxy_template[0]); ++ CK_ATTRIBUTE psk_template[] = { ++ { CKA_VALUE, NULL, 0 }, /* must be first */ ++ { CKA_CLASS, &ck_secret, sizeof(ck_secret) }, ++ { CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) }, ++ { CKA_DERIVE, &ck_true, sizeof(ck_true) }, ++ }; ++ CK_ULONG psk_template_count = ++ sizeof(psk_template) / sizeof(psk_template[0]); ++ CK_ATTRIBUTE derive_template[] = { ++ { CKA_CLASS, &ck_secret, sizeof(ck_secret) }, ++ { CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) }, ++ { CKA_DERIVE, &ck_true, sizeof(ck_true) }, ++ { CKA_VALUE_LEN, &keyLen, sizeof(keyLen) }, /* must be last */ ++ }; ++ CK_ULONG derive_template_count = ++ sizeof(derive_template) / sizeof(derive_template[0]); ++ CK_ATTRIBUTE skeyid_template = ++ { CKA_VALUE, NULL, 0 }; ++ CK_ATTRIBUTE skeyid_d_template = ++ { CKA_VALUE, NULL, 0 }; ++ CK_ATTRIBUTE skeyid_a_template = ++ { CKA_VALUE, NULL, 0 }; ++ CK_ATTRIBUTE skeyid_e_template = ++ { CKA_VALUE, NULL, 0 }; ++ unsigned char skeyid_secret[HASH_LENGTH_MAX]; ++ unsigned char skeyid_d_secret[HASH_LENGTH_MAX]; ++ unsigned char skeyid_a_secret[HASH_LENGTH_MAX]; ++ unsigned char skeyid_e_secret[HASH_LENGTH_MAX]; ++ ++ CK_MECHANISM ike_mech = { CKM_NSS_IKE_PRF_DERIVE, NULL, 0 }; ++ CK_MECHANISM ike1_mech = { CKM_NSS_IKE1_PRF_DERIVE, NULL, 0 }; ++ CK_NSS_IKE_PRF_DERIVE_PARAMS ike_prf; ++ CK_NSS_IKE1_PRF_DERIVE_PARAMS ike1_prf; ++ CK_RV crv; ++ ++ /* set up PKCS #11 parameters */ ++ ike_prf.bDataAsKey = PR_FALSE; ++ ike_prf.bRekey = PR_FALSE; ++ ike_prf.hNewKey = CK_INVALID_HANDLE; ++ CKYi_len = 8; ++ CKYr_len = 8; ++ ike1_prf.pCKYi = CKYi; ++ ike1_prf.ulCKYiLen = CKYi_len; ++ ike1_prf.pCKYr = CKYr; ++ ike1_prf.ulCKYrLen = CKYr_len; ++ ike_mech.pParameter = &ike_prf; ++ ike_mech.ulParameterLen = sizeof(ike_prf); ++ ike1_mech.pParameter = &ike1_prf; ++ ike1_mech.ulParameterLen = sizeof(ike1_prf); ++ skeyid_template.pValue = skeyid_secret; ++ skeyid_template.ulValueLen = HASH_LENGTH_MAX; ++ skeyid_d_template.pValue = skeyid_d_secret; ++ skeyid_d_template.ulValueLen = HASH_LENGTH_MAX; ++ skeyid_a_template.pValue = skeyid_a_secret; ++ skeyid_a_template.ulValueLen = HASH_LENGTH_MAX; ++ skeyid_e_template.pValue = skeyid_e_secret; ++ skeyid_e_template.ulValueLen = HASH_LENGTH_MAX; ++ ++ crv = NSC_Initialize((CK_VOID_PTR)&pk11args); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_Initialize failed crv=0x%x\n", (unsigned int)crv); ++ goto loser; ++ } ++ count = slotListCount; ++ crv = NSC_GetSlotList(PR_TRUE, slotList, &count); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetSlotList failed crv=0x%x\n", (unsigned int)crv); ++ goto loser; ++ } ++ if ((count > slotListCount) || count < 1) { ++ fprintf(stderr, ++ "NSC_GetSlotList returned too many or too few slots: %d slots max=%d min=1\n", ++ (int)count, (int)slotListCount); ++ goto loser; ++ } ++ slotID = slotList[0]; ++ ikereq = fopen(reqfn, "r"); ++ ikeresp = stdout; ++ while (fgets(buf, sizeof buf, ikereq) != NULL) { ++ /* a comment or blank line */ ++ if (buf[0] == '#' || buf[0] == '\n') { ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* [.....] */ ++ if (buf[0] == '[') { ++ if (strncmp(buf, "[SHA-1]", 7) == 0) { ++ ike_prf.prfMechanism = CKM_SHA_1_HMAC; ++ ike1_prf.prfMechanism = CKM_SHA_1_HMAC; ++ } ++ if (strncmp(buf, "[SHA-224]", 9) == 0) { ++ ike_prf.prfMechanism = CKM_SHA224_HMAC; ++ ike1_prf.prfMechanism = CKM_SHA224_HMAC; ++ } ++ if (strncmp(buf, "[SHA-256]", 9) == 0) { ++ ike_prf.prfMechanism = CKM_SHA256_HMAC; ++ ike1_prf.prfMechanism = CKM_SHA256_HMAC; ++ } ++ if (strncmp(buf, "[SHA-384]", 9) == 0) { ++ ike_prf.prfMechanism = CKM_SHA384_HMAC; ++ ike1_prf.prfMechanism = CKM_SHA384_HMAC; ++ } ++ if (strncmp(buf, "[SHA-512]", 9) == 0) { ++ ike_prf.prfMechanism = CKM_SHA512_HMAC; ++ ike1_prf.prfMechanism = CKM_SHA512_HMAC; ++ } ++ if (strncmp(buf, "[AES-XCBC", 9) == 0) { ++ ike_prf.prfMechanism = CKM_AES_XCBC_MAC; ++ ike1_prf.prfMechanism = CKM_AES_XCBC_MAC; ++ } ++ if (strncmp(buf, "[g^xy", 5) == 0) { ++ if (sscanf(buf, "[g^xy length = %d]", ++ &gxy_len) != 1) { ++ goto loser; ++ } ++ gxy_len = gxy_len / 8; ++ if (gxy) ++ free(gxy); ++ gxy = malloc(gxy_len); ++ gxy_template[0].pValue = gxy; ++ gxy_template[0].ulValueLen = gxy_len; ++ } ++ if (strncmp(buf, "[pre-shared-key", 15) == 0) { ++ if (sscanf(buf, "[pre-shared-key length = %d]", ++ &psk_len) != 1) { ++ goto loser; ++ } ++ psk_len = psk_len / 8; ++ if (psk) ++ free(psk); ++ psk = malloc(psk_len); ++ psk_template[0].pValue = psk; ++ psk_template[0].ulValueLen = psk_len; ++ } ++ if (strncmp(buf, "[Ni", 3) == 0) { ++ if (sscanf(buf, "[Ni length = %d]", &Ni_len) != 1) { ++ goto loser; ++ } ++ Ni_len = Ni_len / 8; ++ if (Ni) ++ free(Ni); ++ Ni = malloc(Ni_len); ++ ike_prf.pNi = Ni; ++ ike_prf.ulNiLen = Ni_len; ++ } ++ if (strncmp(buf, "[Nr", 3) == 0) { ++ if (sscanf(buf, "[Nr length = %d]", &Nr_len) != 1) { ++ goto loser; ++ } ++ Nr_len = Nr_len / 8; ++ if (Nr) ++ free(Nr); ++ Nr = malloc(Nr_len); ++ ike_prf.pNr = Nr; ++ ike_prf.ulNrLen = Nr_len; ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* "COUNT = x" begins a new data set */ ++ if (strncmp(buf, "COUNT", 5) == 0) { ++ /* zeroize the variables for the test with this data set */ ++ memset(gxy, 0, gxy_len); ++ memset(Ni, 0, Ni_len); ++ memset(Nr, 0, Nr_len); ++ memset(CKYi, 0, CKYi_len); ++ memset(CKYr, 0, CKYr_len); ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* Ni = ... */ ++ if (strncmp(buf, "Ni", 2) == 0) { ++ i = 2; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < Ni_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &Ni[j]); ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* Nr = ... */ ++ if (strncmp(buf, "Nr", 2) == 0) { ++ i = 2; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < Nr_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &Nr[j]); ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* CKYi = ... */ ++ if (strncmp(buf, "CKY_I", 5) == 0) { ++ i = 5; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < CKYi_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &CKYi[j]); ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* CKYr = ... */ ++ if (strncmp(buf, "CKY_R", 5) == 0) { ++ i = 5; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < CKYr_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &CKYr[j]); ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* g^xy = ... */ ++ if (strncmp(buf, "g^xy", 4) == 0) { ++ i = 4; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < gxy_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &gxy[j]); ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* pre-shared-key = ... */ ++ if (strncmp(buf, "pre-shared-key", 14) == 0) { ++ CK_SESSION_HANDLE session; ++ CK_OBJECT_HANDLE gxy_handle; ++ CK_OBJECT_HANDLE psk_handle; ++ CK_OBJECT_HANDLE skeyid_handle; ++ CK_OBJECT_HANDLE skeyid_d_handle; ++ CK_OBJECT_HANDLE skeyid_a_handle; ++ CK_OBJECT_HANDLE skeyid_e_handle; ++ i = 14; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < psk_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &psk[j]); ++ } ++ fputs(buf, ikeresp); ++ crv = NSC_OpenSession(slotID, 0, NULL, NULL, &session); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_OpenSession failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ crv = NSC_CreateObject(session, psk_template, ++ psk_template_count, &psk_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_CreateObject(psk) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ crv = NSC_CreateObject(session, gxy_template, ++ gxy_template_count, &gxy_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_CreateObject(gxy) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ /* get the skeyid key */ ++ crv = NSC_DeriveKey(session, &ike_mech, psk_handle, ++ derive_template, derive_template_count - 1, ++ &skeyid_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_DeriveKey(skeyid) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ skeyid_template.ulValueLen = HASH_LENGTH_MAX; ++ crv = NSC_GetAttributeValue(session, skeyid_handle, ++ &skeyid_template, 1); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetAttribute(skeyid) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ /* use the length of the skeyid to set the target length of all the ++ * other keys */ ++ keyLen = skeyid_template.ulValueLen; ++ ike1_prf.hKeygxy = gxy_handle; ++ ike1_prf.bHasPrevKey = PR_FALSE; ++ ike1_prf.keyNumber = 0; ++ crv = NSC_DeriveKey(session, &ike1_mech, skeyid_handle, ++ derive_template, derive_template_count, ++ &skeyid_d_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_DeriveKey(skeyid_d) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ ++ ike1_prf.hKeygxy = gxy_handle; ++ ike1_prf.bHasPrevKey = CK_TRUE; ++ ike1_prf.hPrevKey = skeyid_d_handle; ++ ike1_prf.keyNumber = 1; ++ crv = NSC_DeriveKey(session, &ike1_mech, skeyid_handle, ++ derive_template, derive_template_count, ++ &skeyid_a_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_DeriveKey(skeyid_a) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ ike1_prf.hKeygxy = gxy_handle; ++ ike1_prf.bHasPrevKey = CK_TRUE; ++ ike1_prf.hPrevKey = skeyid_a_handle; ++ ike1_prf.keyNumber = 2; ++ crv = NSC_DeriveKey(session, &ike1_mech, skeyid_handle, ++ derive_template, derive_template_count, ++ &skeyid_e_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_DeriveKey(skeyid_e) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ fputs("SKEYID = ", ikeresp); ++ to_hex_str(buf, skeyid_secret, keyLen); ++ fputs(buf, ikeresp); ++ fputc('\n', ikeresp); ++ ++ skeyid_d_template.ulValueLen = keyLen; ++ crv = NSC_GetAttributeValue(session, skeyid_d_handle, ++ &skeyid_d_template, 1); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetAttribute(skeyid_d) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ fputs("SKEYID_d = ", ikeresp); ++ to_hex_str(buf, skeyid_d_secret, skeyid_d_template.ulValueLen); ++ fputs(buf, ikeresp); ++ fputc('\n', ikeresp); ++ ++ skeyid_a_template.ulValueLen = keyLen; ++ crv = NSC_GetAttributeValue(session, skeyid_a_handle, ++ &skeyid_a_template, 1); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetAttribute(skeyid_a) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ fputs("SKEYID_a = ", ikeresp); ++ to_hex_str(buf, skeyid_a_secret, skeyid_a_template.ulValueLen); ++ fputs(buf, ikeresp); ++ fputc('\n', ikeresp); ++ ++ skeyid_e_template.ulValueLen = keyLen; ++ crv = NSC_GetAttributeValue(session, skeyid_e_handle, ++ &skeyid_e_template, 1); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetAttribute(skeyid_e) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ fputs("SKEYID_e = ", ikeresp); ++ to_hex_str(buf, skeyid_e_secret, skeyid_e_template.ulValueLen); ++ fputs(buf, ikeresp); ++ fputc('\n', ikeresp); ++ ++ crv = NSC_CloseSession(session); ++ continue; ++ } ++ } ++loser: ++ NSC_Finalize(NULL); ++ if (psk) ++ free(psk); ++ if (gxy) ++ free(gxy); ++ if (Ni) ++ free(Ni); ++ if (Nr) ++ free(Nr); ++ if (ikereq) ++ fclose(ikereq); ++} ++ ++void ++ikev2(char *reqfn) ++{ ++ char buf[4096]; /* holds one line from the input REQUEST file. ++ * needs to be large enough to hold the longest ++ * line "g^xy = <2048 hex digits>\n". ++ */ ++ unsigned char *gir = NULL; ++ unsigned char *gir_new = NULL; ++ int gir_len; ++ unsigned char *Ni = NULL; ++ int Ni_len; ++ unsigned char *Nr = NULL; ++ int Nr_len; ++ unsigned char *SPIi = NULL; ++ int SPIi_len = 8; ++ unsigned char *SPIr = NULL; ++ int SPIr_len = 8; ++ unsigned char *DKM = NULL; ++ int DKM_len; ++ unsigned char *DKM_child = NULL; ++ int DKM_child_len; ++ unsigned char *seed_data = NULL; ++ int seed_data_len = 0; ++ unsigned int i, j; ++ FILE *ikereq = NULL; /* input stream from the REQUEST file */ ++ FILE *ikeresp; /* output stream to the RESPONSE file */ ++ ++ CK_SLOT_ID slotList[10]; ++ CK_SLOT_ID slotID; ++ CK_ULONG slotListCount = sizeof(slotList) / sizeof(slotList[0]); ++ CK_ULONG count; ++ static const CK_C_INITIALIZE_ARGS pk11args = { ++ NULL, NULL, NULL, NULL, CKF_LIBRARY_CANT_CREATE_OS_THREADS, ++ (void *)"flags=readOnly,noCertDB,noModDB", NULL ++ }; ++ static CK_OBJECT_CLASS ck_secret = CKO_SECRET_KEY; ++ static CK_KEY_TYPE ck_generic = CKK_GENERIC_SECRET; ++ static CK_BBOOL ck_true = CK_TRUE; ++ static CK_ULONG keyLen = 1; ++ CK_ATTRIBUTE gir_template[] = { ++ { CKA_VALUE, NULL, 0 }, ++ { CKA_CLASS, &ck_secret, sizeof(ck_secret) }, ++ { CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) }, ++ { CKA_DERIVE, &ck_true, sizeof(ck_true) }, ++ }; ++ CK_ULONG gir_template_count = ++ sizeof(gir_template) / sizeof(gir_template[0]); ++ CK_ATTRIBUTE gir_new_template[] = { ++ { CKA_VALUE, NULL, 0 }, ++ { CKA_CLASS, &ck_secret, sizeof(ck_secret) }, ++ { CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) }, ++ { CKA_DERIVE, &ck_true, sizeof(ck_true) }, ++ }; ++ CK_ULONG gir_new_template_count = ++ sizeof(gir_new_template) / sizeof(gir_new_template[0]); ++ CK_ATTRIBUTE derive_template[] = { ++ { CKA_CLASS, &ck_secret, sizeof(ck_secret) }, ++ { CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) }, ++ { CKA_DERIVE, &ck_true, sizeof(ck_true) }, ++ { CKA_VALUE_LEN, &keyLen, sizeof(keyLen) }, ++ }; ++ CK_ULONG derive_template_count = ++ sizeof(derive_template) / sizeof(derive_template[0]); ++ CK_ATTRIBUTE skeyseed_template = ++ { CKA_VALUE, NULL, 0 }; ++ CK_ATTRIBUTE dkm_template = ++ { CKA_VALUE, NULL, 0 }; ++ CK_ATTRIBUTE dkm_child_template = ++ { CKA_VALUE, NULL, 0 }; ++ unsigned char skeyseed_secret[HASH_LENGTH_MAX]; ++ ++ CK_MECHANISM ike_mech = { CKM_NSS_IKE_PRF_DERIVE, NULL, 0 }; ++ CK_MECHANISM ike2_mech = { CKM_NSS_IKE_PRF_PLUS_DERIVE, NULL, 0 }; ++ CK_MECHANISM subset_mech = { CKM_EXTRACT_KEY_FROM_KEY, NULL, 0 }; ++ CK_NSS_IKE_PRF_DERIVE_PARAMS ike_prf; ++ CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS ike2_prf; ++ CK_EXTRACT_PARAMS subset_params; ++ CK_RV crv; ++ ++ /* set up PKCS #11 parameters */ ++ ike_mech.pParameter = &ike_prf; ++ ike_mech.ulParameterLen = sizeof(ike_prf); ++ ike2_mech.pParameter = &ike2_prf; ++ ike2_mech.ulParameterLen = sizeof(ike2_prf); ++ subset_mech.pParameter = &subset_params; ++ subset_mech.ulParameterLen = sizeof(subset_params); ++ subset_params = 0; ++ skeyseed_template.pValue = skeyseed_secret; ++ skeyseed_template.ulValueLen = HASH_LENGTH_MAX; ++ ++ crv = NSC_Initialize((CK_VOID_PTR)&pk11args); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_Initialize failed crv=0x%x\n", (unsigned int)crv); ++ goto loser; ++ } ++ count = slotListCount; ++ crv = NSC_GetSlotList(PR_TRUE, slotList, &count); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetSlotList failed crv=0x%x\n", (unsigned int)crv); ++ goto loser; ++ } ++ if ((count > slotListCount) || count < 1) { ++ fprintf(stderr, ++ "NSC_GetSlotList returned too many or too few slots: %d slots max=%d min=1\n", ++ (int)count, (int)slotListCount); ++ goto loser; ++ } ++ slotID = slotList[0]; ++ ikereq = fopen(reqfn, "r"); ++ ikeresp = stdout; ++ while (fgets(buf, sizeof buf, ikereq) != NULL) { ++ /* a comment or blank line */ ++ if (buf[0] == '#' || buf[0] == '\n') { ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* [.....] */ ++ if (buf[0] == '[') { ++ if (strncmp(buf, "[SHA-1]", 7) == 0) { ++ ike_prf.prfMechanism = CKM_SHA_1_HMAC; ++ ike2_prf.prfMechanism = CKM_SHA_1_HMAC; ++ } ++ if (strncmp(buf, "[SHA-224]", 9) == 0) { ++ ike_prf.prfMechanism = CKM_SHA224_HMAC; ++ ike2_prf.prfMechanism = CKM_SHA224_HMAC; ++ } ++ if (strncmp(buf, "[SHA-256]", 9) == 0) { ++ ike_prf.prfMechanism = CKM_SHA256_HMAC; ++ ike2_prf.prfMechanism = CKM_SHA256_HMAC; ++ } ++ if (strncmp(buf, "[SHA-384]", 9) == 0) { ++ ike_prf.prfMechanism = CKM_SHA384_HMAC; ++ ike2_prf.prfMechanism = CKM_SHA384_HMAC; ++ } ++ if (strncmp(buf, "[SHA-512]", 9) == 0) { ++ ike_prf.prfMechanism = CKM_SHA512_HMAC; ++ ike2_prf.prfMechanism = CKM_SHA512_HMAC; ++ } ++ if (strncmp(buf, "[AES-XCBC", 9) == 0) { ++ ike_prf.prfMechanism = CKM_AES_XCBC_MAC; ++ ike2_prf.prfMechanism = CKM_AES_XCBC_MAC; ++ } ++ if (strncmp(buf, "[g^ir", 5) == 0) { ++ if (sscanf(buf, "[g^ir length = %d]", ++ &gir_len) != 1) { ++ goto loser; ++ } ++ gir_len = gir_len / 8; ++ if (gir) ++ free(gir); ++ if (gir_new) ++ free(gir_new); ++ gir = malloc(gir_len); ++ gir_new = malloc(gir_len); ++ gir_template[0].pValue = gir; ++ gir_template[0].ulValueLen = gir_len; ++ gir_new_template[0].pValue = gir_new; ++ gir_new_template[0].ulValueLen = gir_len; ++ } ++ if (strncmp(buf, "[Ni", 3) == 0) { ++ if (sscanf(buf, "[Ni length = %d]", &Ni_len) != 1) { ++ goto loser; ++ } ++ Ni_len = Ni_len / 8; ++ } ++ if (strncmp(buf, "[Nr", 3) == 0) { ++ if (sscanf(buf, "[Nr length = %d]", &Nr_len) != 1) { ++ goto loser; ++ } ++ Nr_len = Nr_len / 8; ++ } ++ if (strncmp(buf, "[DKM", 4) == 0) { ++ if (sscanf(buf, "[DKM length = %d]", ++ &DKM_len) != 1) { ++ goto loser; ++ } ++ DKM_len = DKM_len / 8; ++ if (DKM) ++ free(DKM); ++ DKM = malloc(DKM_len); ++ dkm_template.pValue = DKM; ++ dkm_template.ulValueLen = DKM_len; ++ } ++ if (strncmp(buf, "[Child SA DKM", 13) == 0) { ++ if (sscanf(buf, "[Child SA DKM length = %d]", ++ &DKM_child_len) != 1) { ++ goto loser; ++ } ++ DKM_child_len = DKM_child_len / 8; ++ if (DKM_child) ++ free(DKM_child); ++ DKM_child = malloc(DKM_child_len); ++ dkm_child_template.pValue = DKM_child; ++ dkm_child_template.ulValueLen = DKM_child_len; ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* "COUNT = x" begins a new data set */ ++ if (strncmp(buf, "COUNT", 5) == 0) { ++ /* zeroize the variables for the test with this data set */ ++ int new_seed_len = Ni_len + Nr_len + SPIi_len + SPIr_len; ++ if (seed_data_len != new_seed_len) { ++ if (seed_data) ++ free(seed_data); ++ seed_data_len = new_seed_len; ++ seed_data = malloc(seed_data_len); ++ Ni = seed_data; ++ Nr = &seed_data[Ni_len]; ++ SPIi = &seed_data[Ni_len + Nr_len]; ++ SPIr = &seed_data[new_seed_len - SPIr_len]; ++ ike_prf.pNi = Ni; ++ ike_prf.ulNiLen = Ni_len; ++ ike_prf.pNr = Nr; ++ ike_prf.ulNrLen = Nr_len; ++ ike2_prf.pSeedData = seed_data; ++ } ++ memset(gir, 0, gir_len); ++ memset(gir_new, 0, gir_len); ++ memset(seed_data, 0, seed_data_len); ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* Ni = ... */ ++ if (strncmp(buf, "Ni", 2) == 0) { ++ i = 2; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < Ni_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &Ni[j]); ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* Nr = ... */ ++ if (strncmp(buf, "Nr", 2) == 0) { ++ i = 2; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < Nr_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &Nr[j]); ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* g^ir (new) = ... */ ++ if (strncmp(buf, "g^ir (new)", 10) == 0) { ++ i = 10; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < gir_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &gir_new[j]); ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* g^ir = ... */ ++ if (strncmp(buf, "g^ir", 4) == 0) { ++ i = 4; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < gir_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &gir[j]); ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* SPIi = ... */ ++ if (strncmp(buf, "SPIi", 4) == 0) { ++ i = 4; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < SPIi_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &SPIi[j]); ++ } ++ fputs(buf, ikeresp); ++ continue; ++ } ++ /* SPIr = ... */ ++ if (strncmp(buf, "SPIr", 4) == 0) { ++ CK_SESSION_HANDLE session; ++ CK_OBJECT_HANDLE gir_handle; ++ CK_OBJECT_HANDLE gir_new_handle; ++ CK_OBJECT_HANDLE skeyseed_handle; ++ CK_OBJECT_HANDLE sk_d_handle; ++ CK_OBJECT_HANDLE skeyseed_new_handle; ++ CK_OBJECT_HANDLE dkm_handle; ++ CK_OBJECT_HANDLE dkm_child_handle; ++ i = 4; ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ for (j = 0; j < SPIr_len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &SPIr[j]); ++ } ++ fputs(buf, ikeresp); ++ crv = NSC_OpenSession(slotID, 0, NULL, NULL, &session); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_OpenSession failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ crv = NSC_CreateObject(session, gir_template, ++ gir_template_count, &gir_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_CreateObject (g^ir) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ crv = NSC_CreateObject(session, gir_new_template, ++ gir_new_template_count, &gir_new_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_CreateObject (g^ir new) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ /* get the SKEYSEED key */ ++ ike_prf.bDataAsKey = CK_TRUE; ++ ike_prf.bRekey = CK_FALSE; ++ ike_prf.hNewKey = CK_INVALID_HANDLE; ++ crv = NSC_DeriveKey(session, &ike_mech, gir_handle, ++ derive_template, derive_template_count - 1, ++ &skeyseed_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_DeriveKey(skeyid) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ skeyseed_template.ulValueLen = HASH_LENGTH_MAX; ++ crv = NSC_GetAttributeValue(session, skeyseed_handle, ++ &skeyseed_template, 1); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetAttribute(skeyid) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ fputs("SKEYSEED = ", ikeresp); ++ to_hex_str(buf, skeyseed_secret, skeyseed_template.ulValueLen); ++ fputs(buf, ikeresp); ++ fputc('\n', ikeresp); ++ ++ /* get DKM */ ++ keyLen = DKM_len; ++ ike2_prf.bHasSeedKey = CK_FALSE; ++ ike2_prf.hSeedKey = CK_INVALID_HANDLE; ++ ike2_prf.ulSeedDataLen = seed_data_len; ++ crv = NSC_DeriveKey(session, &ike2_mech, skeyseed_handle, ++ derive_template, derive_template_count, ++ &dkm_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_DeriveKey(DKM) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ crv = NSC_GetAttributeValue(session, dkm_handle, ++ &dkm_template, 1); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetAttribute(DKM) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ fputs("DKM = ", ikeresp); ++ to_hex_str(buf, DKM, DKM_len); ++ fputs(buf, ikeresp); ++ fputc('\n', ikeresp); ++ ++ /* get the sk_d from the DKM */ ++ keyLen = skeyseed_template.ulValueLen; ++ crv = NSC_DeriveKey(session, &subset_mech, dkm_handle, ++ derive_template, derive_template_count, ++ &sk_d_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_DeriveKey(sk_d) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ ++ /* get DKM child */ ++ keyLen = DKM_child_len; ++ ike2_prf.bHasSeedKey = CK_FALSE; ++ ike2_prf.hSeedKey = CK_INVALID_HANDLE; ++ ike2_prf.ulSeedDataLen = Ni_len + Nr_len; ++ crv = NSC_DeriveKey(session, &ike2_mech, sk_d_handle, ++ derive_template, derive_template_count, ++ &dkm_child_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_DeriveKey(DKM Child SA) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ crv = NSC_GetAttributeValue(session, dkm_child_handle, ++ &dkm_child_template, 1); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetAttribute(DKM Child SA) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ fputs("DKM(Child SA) = ", ikeresp); ++ to_hex_str(buf, DKM_child, DKM_child_len); ++ fputs(buf, ikeresp); ++ fputc('\n', ikeresp); ++ ++ /* get DKM child D-H*/ ++ keyLen = DKM_child_len; ++ ike2_prf.bHasSeedKey = CK_TRUE; ++ ike2_prf.hSeedKey = gir_new_handle; ++ ike2_prf.ulSeedDataLen = Ni_len + Nr_len; ++ crv = NSC_DeriveKey(session, &ike2_mech, sk_d_handle, ++ derive_template, derive_template_count, ++ &dkm_child_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_DeriveKey(DKM Child SA D-H) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ crv = NSC_GetAttributeValue(session, dkm_child_handle, ++ &dkm_child_template, 1); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetAttribute(DKM Child SA D-H) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ fputs("DKM(Child SA D-H) = ", ikeresp); ++ to_hex_str(buf, DKM_child, DKM_child_len); ++ fputs(buf, ikeresp); ++ fputc('\n', ikeresp); ++ ++ /* get SKEYSEED(rekey) */ ++ ike_prf.bDataAsKey = CK_FALSE; ++ ike_prf.bRekey = CK_TRUE; ++ ike_prf.hNewKey = gir_new_handle; ++ crv = NSC_DeriveKey(session, &ike_mech, sk_d_handle, ++ derive_template, derive_template_count - 1, ++ &skeyseed_new_handle); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_DeriveKey(skeyid rekey) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ skeyseed_template.ulValueLen = HASH_LENGTH_MAX; ++ crv = NSC_GetAttributeValue(session, skeyseed_new_handle, ++ &skeyseed_template, 1); ++ if (crv != CKR_OK) { ++ fprintf(stderr, "NSC_GetAttribute(skeyid) failed crv=0x%x\n", ++ (unsigned int)crv); ++ goto loser; ++ } ++ fputs("SKEYSEED(rekey) = ", ikeresp); ++ to_hex_str(buf, skeyseed_secret, skeyseed_template.ulValueLen); ++ fputs(buf, ikeresp); ++ fputc('\n', ikeresp); ++ ++ crv = NSC_CloseSession(session); ++ continue; ++ } ++ } ++loser: ++ NSC_Finalize(NULL); ++ if (gir) ++ free(gir); ++ if (gir_new) ++ free(gir_new); ++ if (seed_data) ++ free(seed_data); ++ if (DKM) ++ free(DKM); ++ if (DKM_child) ++ free(DKM_child); ++ if (ikereq) ++ fclose(ikereq); ++} ++ + int + main(int argc, char **argv) + { + if (argc < 2) + exit(-1); + + RNG_RNGInit(); + SECOID_Init(); +@@ -7066,11 +8369,19 @@ main(int argc, char **argv) + rng_mct(argv[3]); + } + } else if (strcmp(argv[1], "drbg") == 0) { + /* Variable Seed Test */ + drbg(argv[2]); + } else if (strcmp(argv[1], "ddrbg") == 0) { + debug = 1; + drbg(argv[2]); ++ } else if (strcmp(argv[1], "tls") == 0) { ++ tls(argv[2]); ++ } else if (strcmp(argv[1], "ikev1") == 0) { ++ ikev1(argv[2]); ++ } else if (strcmp(argv[1], "ikev1-psk") == 0) { ++ ikev1_psk(argv[2]); ++ } else if (strcmp(argv[1], "ikev2") == 0) { ++ ikev2(argv[2]); + } + return 0; + } +diff --git a/cmd/fipstest/hmac.sh b/cmd/fipstest/hmac.sh +deleted file mode 100755 +--- a/cmd/fipstest/hmac.sh ++++ /dev/null +@@ -1,36 +0,0 @@ +-#!/bin/sh +-# +-# 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/. +-# +-# A Bourne shell script for running the NIST HMAC Algorithm Validation Suite +-# +-# Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment +-# variables appropriately so that the fipstest command and the NSPR and NSS +-# shared libraries/DLLs are on the search path. Then run this script in the +-# directory where the REQUEST (.req) files reside. The script generates the +-# RESPONSE (.rsp) files in the same directory. +- +-BASEDIR=${1-.} +-TESTDIR=${BASEDIR}/HMAC +-COMMAND=${2-run} +-REQDIR=${TESTDIR}/req +-RSPDIR=${TESTDIR}/resp +- +-hmac_requests=" +-HMAC.req +-" +- +-if [ ${COMMAND} = "verify" ]; then +- for request in $hmac_requests; do +- sh ./validate1.sh ${TESTDIR} $request +- done +- exit 0 +-fi +-for request in $hmac_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest hmac ${REQDIR}/$request > ${RSPDIR}/$response +-done +- +diff --git a/cmd/fipstest/kas.sh b/cmd/fipstest/kas.sh +deleted file mode 100755 +--- a/cmd/fipstest/kas.sh ++++ /dev/null +@@ -1,84 +0,0 @@ +-#!/bin/sh +-# +-# 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/. +-# +-# A Bourne shell script for running the NIST DSA Validation System +-# +-# Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment +-# variables appropriately so that the fipstest command and the NSPR and NSS +-# shared libraries/DLLs are on the search path. Then run this script in the +-# directory where the REQUEST (.req) files reside. The script generates the +-# RESPONSE (.rsp) files in the same directory. +-BASEDIR=${1-.} +-TESTDIR=${BASEDIR}/KAS +-COMMAND=${2-run} +-REQDIR=${TESTDIR}/req +-RSPDIR=${TESTDIR}/resp +- +- +-# +-if [ ${COMMAND} = "verify" ]; then +-# +-# need verify for KAS tests +- +-# verify generated keys +-# name=KeyPair +-# echo ">>>>> $name" +-# fipstest dsa keyver ${RSPDIR}/$name.rsp | grep ^Result.=.F +-# verify generated pqg values +-# name=PQGGen +-# echo ">>>>> $name" +-# fipstest dsa pqgver ${RSPDIR}/$name.rsp | grep ^Result.=.F +-# verify PQGVer with known answer +-# sh ./validate1.sh ${TESTDIR} PQGVer.req ' ' '-e /^Result.=.F/s;.(.*);; -e /^Result.=.P/s;.(.*);;' +-# verify signatures +-# name=SigGen +-# echo ">>>>> $name" +-# fipstest dsa sigver ${RSPDIR}/$name.rsp | grep ^Result.=.F +-# verify SigVer with known answer +-# sh ./validate1.sh ${TESTDIR} SigVer.req ' ' '-e /^X.=/d -e /^Result.=.F/s;.(.*);;' +- exit 0 +-fi +- +-request=KASFunctionTest_ECCEphemeralUnified_NOKC_ZZOnly_init.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest ecdh init-func ${REQDIR}/$request > ${RSPDIR}/$response +- +-request=KASFunctionTest_ECCEphemeralUnified_NOKC_ZZOnly_resp.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest ecdh resp-func ${REQDIR}/$request > ${RSPDIR}/$response +- +-request=KASValidityTest_ECCEphemeralUnified_NOKC_ZZOnly_init.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest ecdh init-verify ${REQDIR}/$request > ${RSPDIR}/$response +- +-request=KASValidityTest_ECCEphemeralUnified_NOKC_ZZOnly_resp.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest ecdh resp-verify ${REQDIR}/$request > ${RSPDIR}/$response +- +-request=KASFunctionTest_FFCEphem_NOKC_ZZOnly_init.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest dh init-func ${REQDIR}/$request > ${RSPDIR}/$response +- +-request=KASFunctionTest_FFCEphem_NOKC_ZZOnly_resp.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest dh resp-func ${REQDIR}/$request > ${RSPDIR}/$response +- +-request=KASValidityTest_FFCEphem_NOKC_ZZOnly_init.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest dh init-verify ${REQDIR}/$request > ${RSPDIR}/$response +- +-request=KASValidityTest_FFCEphem_NOKC_ZZOnly_resp.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest dh resp-verify ${REQDIR}/$request > ${RSPDIR}/$response +- +diff --git a/cmd/fipstest/rng.sh b/cmd/fipstest/rng.sh +deleted file mode 100644 +--- a/cmd/fipstest/rng.sh ++++ /dev/null +@@ -1,34 +0,0 @@ +-#!/bin/sh +-# +-# 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/. +-# +-# A Bourne shell script for running the NIST RNG Validation Suite +-# +-# Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment +-# variables appropriately so that the fipstest command and the NSPR and NSS +-# shared libraries/DLLs are on the search path. Then run this script in the +-# directory where the REQUEST (.req) files reside. The script generates the +-# RESPONSE (.rsp) files in the same directory. +-BASEDIR=${1-.} +-TESTDIR=${BASEDIR}/DRBG800-90A +-COMMAND=${2-run} +-REQDIR=${TESTDIR}/req +-RSPDIR=${TESTDIR}/resp +- +-drbg_requests=" +-Hash_DRBG.req +-" +- +-if [ ${COMMAND} = "verify" ]; then +- for request in $drbg_requests; do +- sh ./validate1.sh ${TESTDIR} $request +- done +- exit 0 +-fi +-for request in $drbg_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest drbg ${REQDIR}/$request > ${RSPDIR}/$response +-done +diff --git a/cmd/fipstest/rsa.sh b/cmd/fipstest/rsa.sh +deleted file mode 100644 +--- a/cmd/fipstest/rsa.sh ++++ /dev/null +@@ -1,50 +0,0 @@ +-#!/bin/sh +-# +-# 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/. +-# +-# A Bourne shell script for running the NIST RSA Validation System +-# +-# Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment +-# variables appropriately so that the fipstest command and the NSPR and NSS +-# shared libraries/DLLs are on the search path. Then run this script in the +-# directory where the REQUEST (.req) files reside. The script generates the +-# RESPONSE (.rsp) files in the same directory. +-BASEDIR=${1-.} +-TESTDIR=${BASEDIR}/RSA2 +-COMMAND=${2-run} +-REQDIR=${TESTDIR}/req +-RSPDIR=${TESTDIR}/resp +- +-if [ ${COMMAND} = "verify" ]; then +-#verify the signatures. The fax file does not have any known answers, so +-#use our own verify function. +- name=SigGen15_186-3 +- echo ">>>>> $name" +- fipstest rsa sigver ${RSPDIR}/$name.rsp | grep ^Result.=.F +-# fipstest rsa sigver ${REQDIR}/SigVer15_186-3.req | grep ^Result.=.F +-#The Fax file has the private exponent and the salt value, remove it +-#also remove the false reason +- sh ./validate1.sh ${TESTDIR} SigVer15_186-3.req ' ' '-e /^SaltVal/d -e/^d.=/d -e /^p.=/d -e /^q.=/d -e /^EM.with/d -e /^Result.=.F/s;.(.*);;' +-# +-# currently don't have a way to verify the RSA keygen +-# +- exit 0 +-fi +- +-request=SigGen15_186-3.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest rsa siggen ${REQDIR}/$request > ${RSPDIR}/$response +- +-request=SigVer15_186-3.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest rsa sigver ${REQDIR}/$request > ${RSPDIR}/$response +- +-#request=KeyGen_186-3.req +-request=KeyGen_RandomProbablyPrime3_3.req +-response=`echo $request | sed -e "s/req/rsp/"` +-echo $request $response +-fipstest rsa keypair ${REQDIR}/$request > ${RSPDIR}/$response +diff --git a/cmd/fipstest/runtest.sh b/cmd/fipstest/runtest.sh +deleted file mode 100644 +--- a/cmd/fipstest/runtest.sh ++++ /dev/null +@@ -1,14 +0,0 @@ +-#!/bin/sh +-# +-# 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/. +-# +-TESTDIR=${1-.} +-COMMAND=${2-run} +-TESTS="aes aesgcm dsa ecdsa hmac kas tls rng rsa sha tdea" +-for i in $TESTS +-do +- echo "********************Running $i tests" +- sh ./${i}.sh ${TESTDIR} ${COMMAND} +-done +diff --git a/cmd/fipstest/sha.sh b/cmd/fipstest/sha.sh +deleted file mode 100644 +--- a/cmd/fipstest/sha.sh ++++ /dev/null +@@ -1,66 +0,0 @@ +-#!/bin/sh +-# +-# 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/. +-# +-# A Bourne shell script for running the NIST SHA Algorithm Validation Suite +-# +-# Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment +-# variables appropriately so that the fipstest command and the NSPR and NSS +-# shared libraries/DLLs are on the search path. Then run this script in the +-# directory where the REQUEST (.req) files reside. The script generates the +-# RESPONSE (.rsp) files in the same directory. +-BASEDIR=${1-.} +-TESTDIR=${BASEDIR}/SHA +-COMMAND=${2-run} +-REQDIR=${TESTDIR}/req +-RSPDIR=${TESTDIR}/resp +- +-sha_ShortMsg_requests=" +-SHA1ShortMsg.req +-SHA224ShortMsg.req +-SHA256ShortMsg.req +-SHA384ShortMsg.req +-SHA512ShortMsg.req +-" +- +-sha_LongMsg_requests=" +-SHA1LongMsg.req +-SHA224LongMsg.req +-SHA256LongMsg.req +-SHA384LongMsg.req +-SHA512LongMsg.req +-" +- +-sha_Monte_requests=" +-SHA1Monte.req +-SHA224Monte.req +-SHA256Monte.req +-SHA384Monte.req +-SHA512Monte.req +-" +- +-if [ ${COMMAND} = "verify" ]; then +- for request in $sha_ShortMsg_requests $sha_LongMsg_requests $sha_Monte_requests; do +- sh ./validate1.sh ${TESTDIR} $request +- done +- exit 0 +-fi +- +-for request in $sha_ShortMsg_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest sha ${REQDIR}/$request > ${RSPDIR}/$response +-done +-for request in $sha_LongMsg_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest sha ${REQDIR}/$request > ${RSPDIR}/$response +-done +-for request in $sha_Monte_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest sha ${REQDIR}/$request > ${RSPDIR}/$response +-done +- +diff --git a/cmd/fipstest/tdea.sh b/cmd/fipstest/tdea.sh +deleted file mode 100644 +--- a/cmd/fipstest/tdea.sh ++++ /dev/null +@@ -1,106 +0,0 @@ +-#!/bin/sh +-# +-# 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/. +-# +-# A Bourne shell script for running the NIST tdea Algorithm Validation Suite +-# +-# Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment +-# variables appropriately so that the fipstest command and the NSPR and NSS +-# shared libraries/DLLs are on the search path. Then run this script in the +-# directory where the REQUEST (.req) files reside. The script generates the +-# RESPONSE (.rsp) files in the same directory. +- +-BASEDIR=${1-.} +-TESTDIR=${BASEDIR}/TDES +-COMMAND=${2-run} +-REQDIR=${TESTDIR}/req +-RSPDIR=${TESTDIR}/resp +- +-#CBC_Known_Answer_tests +-#Initial Permutation KAT +-#Permutation Operation KAT +-#Subsitution Table KAT +-#Variable Key KAT +-#Variable PlainText KAT +-cbc_kat_requests=" +-TCBCinvperm.req +-TCBCpermop.req +-TCBCsubtab.req +-TCBCvarkey.req +-TCBCvartext.req +-" +- +-#CBC Monte Carlo KATs +-cbc_monte_requests=" +-TCBCMonte1.req +-TCBCMonte2.req +-TCBCMonte3.req +-" +-#Multi-block Message KATs +-cbc_mmt_requests=" +-TCBCMMT1.req +-TCBCMMT2.req +-TCBCMMT3.req +-" +- +-ecb_kat_requests=" +-TECBinvperm.req +-TECBpermop.req +-TECBsubtab.req +-TECBvarkey.req +-TECBvartext.req +-" +- +-ecb_monte_requests=" +-TECBMonte1.req +-TECBMonte2.req +-TECBMonte3.req +-" +- +-ecb_mmt_requests=" +-TECBMMT1.req +-TECBMMT2.req +-TECBMMT3.req +-" +- +- +-if [ ${COMMAND} = "verify" ]; then +- for request in $cbc_kat_requests $cbc_monte_requests $cbc_mmt_requests $ecb_kat_requests $ecb_monte_requests $ecb_mmt_requests +- do +- sh ./validate1.sh ${TESTDIR} $request "-e /^NumKeys/d" +- done +- exit 0 +-fi +- +-for request in $cbc_kat_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest tdea kat cbc ${REQDIR}/$request > ${RSPDIR}/$response +-done +-for request in $cbc_mmt_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest tdea mmt cbc ${REQDIR}/$request > ${RSPDIR}/$response +-done +-for request in $cbc_monte_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest tdea mct cbc ${REQDIR}/$request > ${RSPDIR}/$response +-done +-for request in $ecb_kat_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest tdea kat ecb ${REQDIR}/$request > ${RSPDIR}/$response +-done +-for request in $ecb_mmt_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest tdea mmt ecb ${REQDIR}/$request > ${RSPDIR}/$response +-done +-for request in $ecb_monte_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest tdea mct ecb ${REQDIR}/$request > ${RSPDIR}/$response +-done +diff --git a/cmd/fipstest/tls.sh b/cmd/fipstest/tls.sh +deleted file mode 100644 +--- a/cmd/fipstest/tls.sh ++++ /dev/null +@@ -1,34 +0,0 @@ +-#!/bin/sh +-# +-# 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/. +-# +-# A Bourne shell script for running the NIST RNG Validation Suite +-# +-# Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment +-# variables appropriately so that the fipstest command and the NSPR and NSS +-# shared libraries/DLLs are on the search path. Then run this script in the +-# directory where the REQUEST (.req) files reside. The script generates the +-# RESPONSE (.rsp) files in the same directory. +-BASEDIR=${1-.} +-TESTDIR=${BASEDIR}/KDF135 +-COMMAND=${2-run} +-REQDIR=${TESTDIR}/req +-RSPDIR=${TESTDIR}/resp +- +-drbg_requests=" +-tls.req +-" +- +-if [ ${COMMAND} = "verify" ]; then +- for request in $drbg_requests; do +- sh ./validate1.sh ${TESTDIR} $request +- done +- exit 0 +-fi +-for request in $drbg_requests; do +- response=`echo $request | sed -e "s/req/rsp/"` +- echo $request $response +- fipstest tls ${REQDIR}/$request > ${RSPDIR}/$response +-done +diff --git a/cmd/fipstest/validate.sh b/cmd/fipstest/validate.sh +deleted file mode 100644 +--- a/cmd/fipstest/validate.sh ++++ /dev/null +@@ -1,7 +0,0 @@ +-#!/bin/sh +-# +-# 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/. +-# +-sh ./runtest.sh ${1-.} verify +diff --git a/cmd/fipstest/validate1.sh b/cmd/fipstest/validate1.sh +deleted file mode 100644 +--- a/cmd/fipstest/validate1.sh ++++ /dev/null +@@ -1,30 +0,0 @@ +-#!/bin/sh +-# +-# 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/. +-# +-# Validate1.sh is a helper shell script that each of the base test shell +-# scripts call to help validate that the generated response (response) +-# matches the known answer response (fax). Sometimes (depending on the +-# individual tests) there are extraneous output in either or both response +-# and fax files. These allow the caller to pass in additional sed commands +-# to clear out those extraneous outputs before we compare the two files. +-# The sed line always clears out Windows line endings, replaces tabs with +-# spaces, and removed comments. +-# +-TESTDIR=${1-.} +-request=${2} +-extraneous_response=${3} +-extraneous_fax=${4} +-name=`basename $request .req` +-echo ">>>>> $name" +-sed -e 's; ;;g' -e 's; ; ;g' -e '/^#/d' $extraneous_response ${TESTDIR}/resp/${name}.rsp > /tmp/y1 +-# if we didn't generate any output, flag that as an error +-size=`sum /tmp/y1 | awk '{ print $NF }'` +-if [ $size -eq 0 ]; then +- echo "${TESTDIR}/resp/${name}.rsp: empty" +- exit 1; +-fi +-sed -e 's; ;;g' -e 's; ; ;g' -e '/^#/d' $extraneous_fax ${TESTDIR}/fax/${name}.fax > /tmp/y2 +-diff -i -w -B /tmp/y1 /tmp/y2 +diff --git a/lib/pk11wrap/pk11mech.c b/lib/pk11wrap/pk11mech.c +--- a/lib/pk11wrap/pk11mech.c ++++ b/lib/pk11wrap/pk11mech.c +@@ -234,16 +234,18 @@ PK11_GetKeyType(CK_MECHANISM_TYPE type, + case CKM_AES_CTS: + case CKM_AES_GCM: + case CKM_AES_MAC: + case CKM_AES_MAC_GENERAL: + case CKM_AES_CBC_PAD: + case CKM_AES_KEY_GEN: + case CKM_NETSCAPE_AES_KEY_WRAP: + case CKM_NETSCAPE_AES_KEY_WRAP_PAD: ++ case CKM_AES_XCBC_MAC: ++ case CKM_AES_XCBC_MAC_96: + return CKK_AES; + case CKM_DES_ECB: + case CKM_DES_CBC: + case CKM_DES_MAC: + case CKM_DES_MAC_GENERAL: + case CKM_DES_CBC_PAD: + case CKM_DES_KEY_GEN: + case CKM_KEY_WRAP_LYNKS: +diff --git a/lib/pk11wrap/pk11skey.c b/lib/pk11wrap/pk11skey.c +--- a/lib/pk11wrap/pk11skey.c ++++ b/lib/pk11wrap/pk11skey.c +@@ -1593,16 +1593,17 @@ PK11_DeriveWithTemplate(PK11SymKey *base + } else { + pk11_ExitKeyMonitor(symKey); + } + } + if (newBaseKey) + PK11_FreeSymKey(newBaseKey); + if (crv != CKR_OK) { + PK11_FreeSymKey(symKey); ++ PORT_SetError(PK11_MapError(crv)); + return NULL; + } + return symKey; + } + + /* Create a new key by concatenating base and data + */ + static PK11SymKey * +diff --git a/lib/softoken/fipstest.c b/lib/softoken/fipstest.c +--- a/lib/softoken/fipstest.c ++++ b/lib/softoken/fipstest.c +@@ -7,16 +7,17 @@ + + #ifndef NSS_FIPS_DISABLED + #include "seccomon.h" + #include "blapi.h" + #include "softoken.h" + #include "lowkeyi.h" + #include "secoid.h" + #include "secerr.h" ++#include "pkcs11i.h" + + /* + * different platforms have different ways of calling and initial entry point + * when the dll/.so is loaded. Most platforms support either a posix pragma + * or the GCC attribute. Some platforms suppor a pre-defined name, and some + * platforms have a link line way of invoking this function. + */ + +@@ -621,16 +622,20 @@ sftk_startup_tests(void) + return; + } + if (!BLAPI_SHVerify(libraryName, + (PRFuncPtr)&sftk_fips_RSA_PowerUpSelfTest)) { + /* something is wrong with the library, fail without enabling + * the token */ + return; + } ++ rv = sftk_fips_IKE_PowerUpSelfTests(); ++ if (rv != SECSuccess) { ++ return; ++ } + sftk_self_tests_success = PR_TRUE; + } + + /* + * this is called from nsc_Common_Initizialize entry points that gates access + * to * all other pkcs11 functions. This prevents softoken operation if our + * power on selftest failed. + */ +diff --git a/lib/softoken/manifest.mn b/lib/softoken/manifest.mn +--- a/lib/softoken/manifest.mn ++++ b/lib/softoken/manifest.mn +@@ -41,16 +41,17 @@ CSRCS = \ + lowpbe.c \ + padbuf.c \ + pkcs11.c \ + pkcs11c.c \ + pkcs11u.c \ + sdb.c \ + sftkdb.c \ + sftkhmac.c \ ++ sftkike.c \ + sftkpars.c \ + sftkpwd.c \ + softkver.c \ + tlsprf.c \ + jpakesftk.c \ + $(NULL) + + ifdef SQLITE_UNSAFE_THREADS +diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c +--- a/lib/softoken/pkcs11.c ++++ b/lib/softoken/pkcs11.c +@@ -323,16 +323,18 @@ static const struct mechanismList mechan + { CKM_AES_ECB, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE }, + { CKM_AES_CBC, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE }, + { CKM_AES_MAC, { 16, 32, CKF_SN_VR }, PR_TRUE }, + { CKM_AES_MAC_GENERAL, { 16, 32, CKF_SN_VR }, PR_TRUE }, + { CKM_AES_CBC_PAD, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE }, + { CKM_AES_CTS, { 16, 32, CKF_EN_DE }, PR_TRUE }, + { CKM_AES_CTR, { 16, 32, CKF_EN_DE }, PR_TRUE }, + { CKM_AES_GCM, { 16, 32, CKF_EN_DE }, PR_TRUE }, ++ { CKM_AES_XCBC_MAC_96, { 12, 12, CKF_SN_VR }, PR_TRUE }, ++ { CKM_AES_XCBC_MAC, { 16, 16, CKF_SN_VR }, PR_TRUE }, + /* ------------------------- Camellia Operations --------------------- */ + { CKM_CAMELLIA_KEY_GEN, { 16, 32, CKF_GENERATE }, PR_TRUE }, + { CKM_CAMELLIA_ECB, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE }, + { CKM_CAMELLIA_CBC, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE }, + { CKM_CAMELLIA_MAC, { 16, 32, CKF_SN_VR }, PR_TRUE }, + { CKM_CAMELLIA_MAC_GENERAL, { 16, 32, CKF_SN_VR }, PR_TRUE }, + { CKM_CAMELLIA_CBC_PAD, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE }, + /* ------------------------- SEED Operations --------------------------- */ +@@ -504,17 +506,21 @@ static const struct mechanismList mechan + { CKM_NSS_JPAKE_ROUND2_SHA384, { 0, 0, CKF_DERIVE }, PR_TRUE }, + { CKM_NSS_JPAKE_ROUND2_SHA512, { 0, 0, CKF_DERIVE }, PR_TRUE }, + { CKM_NSS_JPAKE_FINAL_SHA1, { 0, 0, CKF_DERIVE }, PR_TRUE }, + { CKM_NSS_JPAKE_FINAL_SHA256, { 0, 0, CKF_DERIVE }, PR_TRUE }, + { CKM_NSS_JPAKE_FINAL_SHA384, { 0, 0, CKF_DERIVE }, PR_TRUE }, + { CKM_NSS_JPAKE_FINAL_SHA512, { 0, 0, CKF_DERIVE }, PR_TRUE }, + /* -------------------- Constant Time TLS MACs ----------------------- */ + { CKM_NSS_HMAC_CONSTANT_TIME, { 0, 0, CKF_DIGEST }, PR_TRUE }, +- { CKM_NSS_SSL3_MAC_CONSTANT_TIME, { 0, 0, CKF_DIGEST }, PR_TRUE } ++ { CKM_NSS_SSL3_MAC_CONSTANT_TIME, { 0, 0, CKF_DIGEST }, PR_TRUE }, ++ /* --------------------IPSEC ----------------------- */ ++ { CKM_NSS_IKE_PRF_PLUS_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE }, ++ { CKM_NSS_IKE_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE }, ++ { CKM_NSS_IKE1_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE } + }; + static const CK_ULONG mechanismCount = sizeof(mechanisms) / sizeof(mechanisms[0]); + + /* sigh global so fipstokn can read it */ + PRBool nsc_init = PR_FALSE; + + #if defined(CHECK_FORK_PTHREAD) || defined(CHECK_FORK_MIXED) + +diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c +--- a/lib/softoken/pkcs11c.c ++++ b/lib/softoken/pkcs11c.c +@@ -94,49 +94,16 @@ sftk_Space(void *data, PRBool freeit) + PORT_Free(data); + } + + /* + * map all the SEC_ERROR_xxx error codes that may be returned by freebl + * functions to CKR_xxx. return CKR_DEVICE_ERROR by default for backward + * compatibility. + */ +-static CK_RV +-sftk_MapCryptError(int error) +-{ +- switch (error) { +- case SEC_ERROR_INVALID_ARGS: +- case SEC_ERROR_BAD_DATA: /* MP_RANGE gets mapped to this */ +- return CKR_ARGUMENTS_BAD; +- case SEC_ERROR_INPUT_LEN: +- return CKR_DATA_LEN_RANGE; +- case SEC_ERROR_OUTPUT_LEN: +- return CKR_BUFFER_TOO_SMALL; +- case SEC_ERROR_LIBRARY_FAILURE: +- return CKR_GENERAL_ERROR; +- case SEC_ERROR_NO_MEMORY: +- return CKR_HOST_MEMORY; +- case SEC_ERROR_BAD_SIGNATURE: +- return CKR_SIGNATURE_INVALID; +- case SEC_ERROR_INVALID_KEY: +- return CKR_KEY_SIZE_RANGE; +- case SEC_ERROR_BAD_KEY: /* an EC public key that fails validation */ +- return CKR_KEY_SIZE_RANGE; /* the closest error code */ +- case SEC_ERROR_UNSUPPORTED_EC_POINT_FORM: +- return CKR_TEMPLATE_INCONSISTENT; +- case SEC_ERROR_UNSUPPORTED_KEYALG: +- return CKR_MECHANISM_INVALID; +- case SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE: +- return CKR_DOMAIN_PARAMS_INVALID; +- /* key pair generation failed after max number of attempts */ +- case SEC_ERROR_NEED_RANDOM: +- return CKR_FUNCTION_FAILED; +- } +- return CKR_DEVICE_ERROR; +-} + + /* used by Decrypt and UnwrapKey (indirectly) */ + static CK_RV + sftk_MapDecryptError(int error) + { + switch (error) { + case SEC_ERROR_BAD_DATA: + return CKR_ENCRYPTED_DATA_INVALID; +@@ -2075,19 +2042,22 @@ sftk_InitCBCMac(CK_SESSION_HANDLE hSessi + CK_MECHANISM cbc_mechanism; + CK_ULONG mac_bytes = SFTK_INVALID_MAC_SIZE; + CK_RC2_CBC_PARAMS rc2_params; + #if NSS_SOFTOKEN_DOES_RC5 + CK_RC5_CBC_PARAMS rc5_params; + CK_RC5_MAC_GENERAL_PARAMS *rc5_mac; + #endif + unsigned char ivBlock[SFTK_MAX_BLOCK_SIZE]; ++ unsigned char k2[SFTK_MAX_BLOCK_SIZE]; ++ unsigned char k3[SFTK_MAX_BLOCK_SIZE]; + SFTKSessionContext *context; + CK_RV crv; + unsigned int blockSize; ++ PRBool isXCBC = PR_FALSE; + + switch (pMechanism->mechanism) { + case CKM_RC2_MAC_GENERAL: + if (!pMechanism->pParameter) { + return CKR_MECHANISM_PARAM_INVALID; + } + mac_bytes = + ((CK_RC2_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength; +@@ -2181,43 +2151,82 @@ sftk_InitCBCMac(CK_SESSION_HANDLE hSessi + /* fall through */ + case CKM_AES_MAC: + blockSize = 16; + PORT_Memset(ivBlock, 0, blockSize); + cbc_mechanism.mechanism = CKM_AES_CBC; + cbc_mechanism.pParameter = &ivBlock; + cbc_mechanism.ulParameterLen = blockSize; + break; ++ case CKM_AES_XCBC_MAC_96: ++ case CKM_AES_XCBC_MAC: ++ /* The only difference between CKM_AES_XCBC_MAC ++ * and CKM_AES_XCBC_MAC_96 is the size of the returned mac. */ ++ mac_bytes = pMechanism->mechanism == CKM_AES_XCBC_MAC_96 ? 12 : 16; ++ blockSize = 16; ++ PORT_Memset(ivBlock, 0, blockSize); ++ cbc_mechanism.mechanism = CKM_AES_CBC; ++ cbc_mechanism.pParameter = &ivBlock; ++ cbc_mechanism.ulParameterLen = blockSize; ++ /* is XCBC requires extra processing at the end of the operation */ ++ isXCBC = PR_TRUE; ++ /* The input key is used to generate k1, k2, and k3. k2 and k3 ++ * are used at the end in the pad step. k1 replaces the input ++ * key in the aes cbc mac */ ++ crv = sftk_aes_xcbc_new_keys(hSession, hKey, &hKey, k2, k3); ++ if (crv != CKR_OK) { ++ return crv; ++ } ++ break; + default: + return CKR_FUNCTION_NOT_SUPPORTED; + } + + /* if MAC size is externally supplied, it should be checked. + */ + if (mac_bytes == SFTK_INVALID_MAC_SIZE) + mac_bytes = blockSize >> 1; + else { +- if (mac_bytes > blockSize) +- return CKR_MECHANISM_PARAM_INVALID; ++ if (mac_bytes > blockSize) { ++ crv = CKR_MECHANISM_PARAM_INVALID; ++ goto fail; ++ } + } + + crv = sftk_CryptInit(hSession, &cbc_mechanism, hKey, + CKA_ENCRYPT, /* CBC mech is able to ENCRYPT, not SIGN/VERIFY */ + keyUsage, contextType, PR_TRUE); + if (crv != CKR_OK) +- return crv; ++ goto fail; + crv = sftk_GetContext(hSession, &context, contextType, PR_TRUE, NULL); + + /* this shouldn't happen! */ + PORT_Assert(crv == CKR_OK); + if (crv != CKR_OK) +- return crv; ++ goto fail; + context->blockSize = blockSize; + context->macSize = mac_bytes; ++ context->isXCBC = isXCBC; ++ if (isXCBC) { ++ /* save the xcbc specific parameters */ ++ PORT_Memcpy(context->k2, k2, blockSize); ++ PORT_Memcpy(context->k3, k3, blockSize); ++ PORT_Memset(k2, 0, blockSize); ++ PORT_Memset(k3, 0, blockSize); ++ /* get rid of the temp key now that the context has been created */ ++ NSC_DestroyObject(hSession, hKey); ++ } + return CKR_OK; ++fail: ++ if (isXCBC) { ++ PORT_Memset(k2, 0, blockSize); ++ PORT_Memset(k3, 0, blockSize); ++ NSC_DestroyObject(hSession, hKey); /* get rid of our temp key */ ++ } ++ return crv; + } + + /* + * encode RSA PKCS #1 Signature data before signing... + */ + static SECStatus + sftk_RSAHashSign(SFTKHashSignInfo *info, unsigned char *sig, + unsigned int *sigLen, unsigned int maxLen, +@@ -2823,16 +2832,23 @@ sftk_MACBlock(SFTKSessionContext *ctx, v + * + * Call once, then terminate MACing operation. + */ + static CK_RV + sftk_MACFinal(SFTKSessionContext *ctx) + { + unsigned int padLen = ctx->padDataLength; + /* pad and proceed the residual */ ++ if (ctx->isXCBC) { ++ CK_RV crv = sftk_xcbc_mac_pad(ctx->padBuf, padLen, ctx->blockSize, ++ ctx->k2, ctx->k3); ++ if (crv != CKR_OK) ++ return crv; ++ return sftk_MACBlock(ctx, ctx->padBuf); ++ } + if (padLen) { + /* shd clr ctx->padLen to make sftk_MACFinal idempotent */ + PORT_Memset(ctx->padBuf + padLen, 0, ctx->blockSize - padLen); + return sftk_MACBlock(ctx, ctx->padBuf); + } else + return CKR_OK; + } + +@@ -2861,31 +2877,31 @@ sftk_MACUpdate(CK_SESSION_HANDLE hSessio + + unsigned int blkSize = context->blockSize; + unsigned char *residual = /* free room in context->padBuf */ + context->padBuf + context->padDataLength; + unsigned int minInput = /* min input for MACing at least one block */ + blkSize - context->padDataLength; + + /* not enough data even for one block */ +- if (ulPartLen < minInput) { ++ if (ulPartLen <= minInput) { + PORT_Memcpy(residual, pPart, ulPartLen); + context->padDataLength += ulPartLen; + goto cleanup; + } + /* MACing residual */ + if (context->padDataLength) { + PORT_Memcpy(residual, pPart, minInput); + ulPartLen -= minInput; + pPart += minInput; + if (CKR_OK != (crv = sftk_MACBlock(context, context->padBuf))) + goto terminate; + } + /* MACing full blocks */ +- while (ulPartLen >= blkSize) { ++ while (ulPartLen > blkSize) { + if (CKR_OK != (crv = sftk_MACBlock(context, pPart))) + goto terminate; + ulPartLen -= blkSize; + pPart += blkSize; + } + /* save the residual */ + if ((context->padDataLength = ulPartLen)) + PORT_Memcpy(context->padBuf, pPart, ulPartLen); +@@ -6513,16 +6529,55 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession + if (att == NULL) { + sftk_FreeObject(key); + sftk_FreeObject(sourceKey); + return CKR_KEY_HANDLE_INVALID; + } + } + + switch (mechanism) { ++ case CKM_NSS_IKE_PRF_DERIVE: ++ if (pMechanism->ulParameterLen != ++ sizeof(CK_NSS_IKE_PRF_DERIVE_PARAMS)) { ++ crv = CKR_MECHANISM_PARAM_INVALID; ++ break; ++ } ++ crv = sftk_ike_prf(hSession, att, ++ (CK_NSS_IKE_PRF_DERIVE_PARAMS *)pMechanism->pParameter, key); ++ break; ++ case CKM_NSS_IKE1_PRF_DERIVE: ++ if (pMechanism->ulParameterLen != ++ sizeof(CK_NSS_IKE1_PRF_DERIVE_PARAMS)) { ++ crv = CKR_MECHANISM_PARAM_INVALID; ++ break; ++ } ++ crv = sftk_ike1_prf(hSession, att, ++ (CK_NSS_IKE1_PRF_DERIVE_PARAMS *)pMechanism->pParameter, ++ key, keySize); ++ break; ++ case CKM_NSS_IKE1_APP_B_PRF_DERIVE: ++ if (pMechanism->ulParameterLen != ++ sizeof(CK_MECHANISM_TYPE)) { ++ crv = CKR_MECHANISM_PARAM_INVALID; ++ break; ++ } ++ crv = sftk_ike1_appendix_b_prf(hSession, att, ++ (CK_MECHANISM_TYPE *)pMechanism->pParameter, ++ key, keySize); ++ break; ++ case CKM_NSS_IKE_PRF_PLUS_DERIVE: ++ if (pMechanism->ulParameterLen != ++ sizeof(CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS)) { ++ crv = CKR_MECHANISM_PARAM_INVALID; ++ break; ++ } ++ crv = sftk_ike_prf_plus(hSession, att, ++ (CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS *)pMechanism->pParameter, ++ key, keySize); ++ break; + /* + * generate the master secret + */ + case CKM_TLS12_MASTER_KEY_DERIVE: + case CKM_TLS12_MASTER_KEY_DERIVE_DH: + case CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256: + case CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256: + case CKM_TLS_MASTER_KEY_DERIVE: +diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h +--- a/lib/softoken/pkcs11i.h ++++ b/lib/softoken/pkcs11i.h +@@ -248,22 +248,25 @@ typedef enum { + * multi=0 hashInfo=0 PKC S/V one shot (w/o hashing) + * multi=0 hashInfo=X *** shouldn't happen *** + */ + struct SFTKSessionContextStr { + SFTKContextType type; + PRBool multi; /* is multipart */ + PRBool rsa; /* is rsa */ + PRBool doPad; /* use PKCS padding for block ciphers */ ++ PRBool isXCBC; /* xcbc, use special handling in final */ + unsigned int blockSize; /* blocksize for padding */ + unsigned int padDataLength; /* length of the valid data in padbuf */ + /** latest incomplete block of data for block cipher */ + unsigned char padBuf[SFTK_MAX_BLOCK_SIZE]; + /** result of MAC'ing of latest full block of data with block cipher */ + unsigned char macBuf[SFTK_MAX_BLOCK_SIZE]; ++ unsigned char k2[SFTK_MAX_BLOCK_SIZE]; ++ unsigned char k3[SFTK_MAX_BLOCK_SIZE]; + CK_ULONG macSize; /* size of a general block cipher mac*/ + void *cipherInfo; + void *hashInfo; + unsigned int cipherInfoLen; + CK_MECHANISM_TYPE currentMech; + SFTKCipher update; + SFTKHash hashUpdate; + SFTKEnd end; +@@ -600,16 +603,17 @@ extern CK_RV SFTK_SlotInit(char *configd + extern CK_RV SFTK_SlotReInit(SFTKSlot *slot, char *configdir, + char *updatedir, char *updateID, + sftk_token_parameters *params, int moduleIndex); + extern CK_RV SFTK_DestroySlotData(SFTKSlot *slot); + extern CK_RV SFTK_ShutdownSlot(SFTKSlot *slot); + extern CK_RV sftk_CloseAllSessions(SFTKSlot *slot, PRBool logout); + + /* internal utility functions used by pkcs11.c */ ++extern CK_RV sftk_MapCryptError(int error); + extern SFTKAttribute *sftk_FindAttribute(SFTKObject *object, + CK_ATTRIBUTE_TYPE type); + extern void sftk_FreeAttribute(SFTKAttribute *attribute); + extern CK_RV sftk_AddAttributeType(SFTKObject *object, CK_ATTRIBUTE_TYPE type, + const void *valPtr, CK_ULONG length); + extern CK_RV sftk_Attribute2SecItem(PLArenaPool *arena, SECItem *item, + SFTKObject *object, CK_ATTRIBUTE_TYPE type); + extern CK_RV sftk_MultipleAttribute2SecItem(PLArenaPool *arena, +@@ -681,16 +685,40 @@ extern void sftk_CleanupFreeLists(void); + extern NSSLOWKEYPublicKey *sftk_GetPubKey(SFTKObject *object, + CK_KEY_TYPE key_type, CK_RV *crvp); + extern NSSLOWKEYPrivateKey *sftk_GetPrivKey(SFTKObject *object, + CK_KEY_TYPE key_type, CK_RV *crvp); + extern void sftk_FormatDESKey(unsigned char *key, int length); + extern PRBool sftk_CheckDESKey(unsigned char *key); + extern PRBool sftk_IsWeakKey(unsigned char *key, CK_KEY_TYPE key_type); + ++/* ike and xcbc helpers */ ++extern CK_RV sftk_ike_prf(CK_SESSION_HANDLE hSession, ++ const SFTKAttribute *inKey, ++ const CK_NSS_IKE_PRF_DERIVE_PARAMS *params, SFTKObject *outKey); ++extern CK_RV sftk_ike1_prf(CK_SESSION_HANDLE hSession, ++ const SFTKAttribute *inKey, ++ const CK_NSS_IKE1_PRF_DERIVE_PARAMS *params, SFTKObject *outKey, ++ unsigned int keySize); ++extern CK_RV sftk_ike1_appendix_b_prf(CK_SESSION_HANDLE hSession, ++ const SFTKAttribute *inKey, ++ const CK_MECHANISM_TYPE *params, SFTKObject *outKey, ++ unsigned int keySize); ++extern CK_RV sftk_ike_prf_plus(CK_SESSION_HANDLE hSession, ++ const SFTKAttribute *inKey, ++ const CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS *params, SFTKObject *outKey, ++ unsigned int keySize); ++extern CK_RV sftk_aes_xcbc_new_keys(CK_SESSION_HANDLE hSession, ++ CK_OBJECT_HANDLE hKey, CK_OBJECT_HANDLE_PTR phKey, ++ unsigned char *k2, unsigned char *k3); ++extern CK_RV sftk_xcbc_mac_pad(unsigned char *padBuf, unsigned int bufLen, ++ int blockSize, const unsigned char *k2, ++ const unsigned char *k3); ++extern SECStatus sftk_fips_IKE_PowerUpSelfTests(void); ++ + /* mechanism allows this operation */ + extern CK_RV sftk_MechAllowsOperation(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE op); + + /* helper function which calls nsslowkey_FindKeyByPublicKey after safely + * acquiring a reference to the keydb from the slot */ + NSSLOWKEYPrivateKey *sftk_FindKeyByPublicKey(SFTKSlot *slot, SECItem *dbKey); + + /* +diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c +--- a/lib/softoken/pkcs11u.c ++++ b/lib/softoken/pkcs11u.c +@@ -10,16 +10,57 @@ + #include "secasn1.h" + #include "blapi.h" + #include "secerr.h" + #include "prnetdb.h" /* for PR_ntohl */ + #include "sftkdb.h" + #include "softoken.h" + + /* ++ * ******************** Error mapping ******************************* ++ */ ++/* ++ * map all the SEC_ERROR_xxx error codes that may be returned by freebl ++ * functions to CKR_xxx. return CKR_DEVICE_ERROR by default for backward ++ * compatibility. ++ */ ++CK_RV ++sftk_MapCryptError(int error) ++{ ++ switch (error) { ++ case SEC_ERROR_INVALID_ARGS: ++ case SEC_ERROR_BAD_DATA: /* MP_RANGE gets mapped to this */ ++ return CKR_ARGUMENTS_BAD; ++ case SEC_ERROR_INPUT_LEN: ++ return CKR_DATA_LEN_RANGE; ++ case SEC_ERROR_OUTPUT_LEN: ++ return CKR_BUFFER_TOO_SMALL; ++ case SEC_ERROR_LIBRARY_FAILURE: ++ return CKR_GENERAL_ERROR; ++ case SEC_ERROR_NO_MEMORY: ++ return CKR_HOST_MEMORY; ++ case SEC_ERROR_BAD_SIGNATURE: ++ return CKR_SIGNATURE_INVALID; ++ case SEC_ERROR_INVALID_KEY: ++ return CKR_KEY_SIZE_RANGE; ++ case SEC_ERROR_BAD_KEY: /* an EC public key that fails validation */ ++ return CKR_KEY_SIZE_RANGE; /* the closest error code */ ++ case SEC_ERROR_UNSUPPORTED_EC_POINT_FORM: ++ return CKR_TEMPLATE_INCONSISTENT; ++ case SEC_ERROR_UNSUPPORTED_KEYALG: ++ return CKR_MECHANISM_INVALID; ++ case SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE: ++ return CKR_DOMAIN_PARAMS_INVALID; ++ /* key pair generation failed after max number of attempts */ ++ case SEC_ERROR_NEED_RANDOM: ++ return CKR_FUNCTION_FAILED; ++ } ++ return CKR_DEVICE_ERROR; ++} ++/* + * ******************** Attribute Utilities ******************************* + */ + + /* + * create a new attribute with type, value, and length. Space is allocated + * to hold value. + */ + static SFTKAttribute * +diff --git a/lib/softoken/sftkike.c b/lib/softoken/sftkike.c +new file mode 100644 +--- /dev/null ++++ b/lib/softoken/sftkike.c +@@ -0,0 +1,1288 @@ ++/* 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/. */ ++/* ++ * This file implements PKCS 11 on top of our existing security modules ++ * ++ * For more information about PKCS 11 See PKCS 11 Token Inteface Standard. ++ * This implementation has two slots: ++ * slot 1 is our generic crypto support. It does not require login. ++ * It supports Public Key ops, and all they bulk ciphers and hashes. ++ * It can also support Private Key ops for imported Private keys. It does ++ * not have any token storage. ++ * slot 2 is our private key support. It requires a login before use. It ++ * can store Private Keys and Certs as token objects. Currently only private ++ * keys and their associated Certificates are saved on the token. ++ * ++ * In this implementation, session objects are only visible to the session ++ * that created or generated them. ++ */ ++#include "seccomon.h" ++#include "secitem.h" ++#include "secport.h" ++#include "blapi.h" ++#include "pkcs11.h" ++#include "pkcs11i.h" ++#include "pkcs1sig.h" ++#include "lowkeyi.h" ++#include "secder.h" ++#include "secdig.h" ++#include "lowpbe.h" /* We do PBE below */ ++#include "pkcs11t.h" ++#include "secoid.h" ++#include "alghmac.h" ++#include "softoken.h" ++#include "secasn1.h" ++#include "secerr.h" ++ ++#include "prprf.h" ++#include "prenv.h" ++ ++/* ++ * A common prfContext to handle both hmac and aes xcbc ++ * hash contexts have non-null hashObj and hmac, aes ++ * contexts have non-null aes */ ++typedef struct prfContextStr { ++ HASH_HashType hashType; ++ const SECHashObject *hashObj; ++ HMACContext *hmac; ++ AESContext *aes; ++ unsigned int nextChar; ++ unsigned char padBuf[AES_BLOCK_SIZE]; ++ unsigned char macBuf[AES_BLOCK_SIZE]; ++ unsigned char k1[AES_BLOCK_SIZE]; ++ unsigned char k2[AES_BLOCK_SIZE]; ++ unsigned char k3[AES_BLOCK_SIZE]; ++} prfContext; ++ ++/* iv full of zeros used in several places in aex xcbc */ ++static const unsigned char iv_zero[] = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++ ++/* ++ * Generate AES XCBC keys from the AES MAC key. ++ * k1 is used in the actual mac. ++ * k2 and k3 are used in the final pad step. ++ */ ++static CK_RV ++sftk_aes_xcbc_get_keys(const unsigned char *keyValue, unsigned int keyLen, ++ unsigned char *k1, unsigned char *k2, unsigned char *k3) ++{ ++ SECStatus rv; ++ CK_RV crv; ++ unsigned int tmpLen; ++ AESContext *aes_context = NULL; ++ unsigned char newKey[AES_BLOCK_SIZE]; ++ ++ /* AES XCBC keys. k1, k2, and k3 are derived by encrypting ++ * k1data, k2data, and k3data with the mac key. ++ */ ++ static const unsigned char k1data[] = { ++ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ++ }; ++ static const unsigned char k2data[] = { ++ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, ++ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 ++ }; ++ static const unsigned char k3data[] = { ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 ++ }; ++ ++ /* k1_0 = aes_ecb(0, k1data) */ ++ static const unsigned char k1_0[] = { ++ 0xe1, 0x4d, 0x5d, 0x0e, 0xe2, 0x77, 0x15, 0xdf, ++ 0x08, 0xb4, 0x15, 0x2b, 0xa2, 0x3d, 0xa8, 0xe0 ++ ++ }; ++ /* k2_0 = aes_ecb(0, k2data) */ ++ static const unsigned char k2_0[] = { ++ 0x5e, 0xba, 0x73, 0xf8, 0x91, 0x42, 0xc5, 0x48, ++ 0x80, 0xf6, 0x85, 0x94, 0x37, 0x3c, 0x5c, 0x37 ++ }; ++ /* k3_0 = aes_ecb(0, k3data) */ ++ static const unsigned char k3_0[] = { ++ 0x8d, 0x34, 0xef, 0xcb, 0x3b, 0xd5, 0x45, 0xca, ++ 0x06, 0x2a, 0xec, 0xdf, 0xef, 0x7c, 0x0b, 0xfa ++ }; ++ ++ /* first make sure out input key is the correct length ++ * rfc 4434. If key is shorter, pad with zeros to the ++ * the right. If key is longer newKey = aes_xcbc(0, key, keyLen). ++ */ ++ if (keyLen < AES_BLOCK_SIZE) { ++ PORT_Memcpy(newKey, keyValue, keyLen); ++ PORT_Memset(&newKey[keyLen], 0, AES_BLOCK_SIZE - keyLen); ++ keyValue = newKey; ++ } else if (keyLen > AES_BLOCK_SIZE) { ++ /* calculate our new key = aes_xcbc(0, key, keyLen). Because the ++ * key above is fixed (0), we can precalculate k1, k2, and k2. ++ * if this code ever needs to be more generic (support any xcbc ++ * function rather than just aes, we would probably want to just ++ * recurse here using our prf functions. This would be safe because ++ * the recurse case would have keyLen == blocksize and thus skip ++ * this conditional. ++ */ ++ aes_context = AES_CreateContext(k1_0, iv_zero, NSS_AES_CBC, ++ PR_TRUE, AES_BLOCK_SIZE, AES_BLOCK_SIZE); ++ /* we know the following loop will execute at least once */ ++ while (keyLen > AES_BLOCK_SIZE) { ++ rv = AES_Encrypt(aes_context, newKey, &tmpLen, AES_BLOCK_SIZE, ++ keyValue, AES_BLOCK_SIZE); ++ if (rv != SECSuccess) { ++ goto fail; ++ } ++ keyValue += AES_BLOCK_SIZE; ++ keyLen -= AES_BLOCK_SIZE; ++ } ++ PORT_Memcpy(newKey, keyValue, keyLen); ++ sftk_xcbc_mac_pad(newKey, keyLen, AES_BLOCK_SIZE, k2_0, k3_0); ++ rv = AES_Encrypt(aes_context, newKey, &tmpLen, AES_BLOCK_SIZE, ++ newKey, AES_BLOCK_SIZE); ++ if (rv != SECSuccess) { ++ goto fail; ++ } ++ keyValue = newKey; ++ AES_DestroyContext(aes_context, PR_TRUE); ++ } ++ /* the length of the key in keyValue is known to be AES_BLOCK_SIZE, ++ * either because it was on input, or it was shorter and extended, or ++ * because it was mac'd down using aes_xcbc_prf. ++ */ ++ aes_context = AES_CreateContext(keyValue, iv_zero, ++ NSS_AES, PR_TRUE, AES_BLOCK_SIZE, AES_BLOCK_SIZE); ++ if (aes_context == NULL) { ++ goto fail; ++ } ++ rv = AES_Encrypt(aes_context, k1, &tmpLen, AES_BLOCK_SIZE, ++ k1data, sizeof(k1data)); ++ if (rv != SECSuccess) { ++ goto fail; ++ } ++ rv = AES_Encrypt(aes_context, k2, &tmpLen, AES_BLOCK_SIZE, ++ k2data, sizeof(k2data)); ++ if (rv != SECSuccess) { ++ goto fail; ++ } ++ rv = AES_Encrypt(aes_context, k3, &tmpLen, AES_BLOCK_SIZE, ++ k3data, sizeof(k3data)); ++ if (rv != SECSuccess) { ++ goto fail; ++ } ++ AES_DestroyContext(aes_context, PR_TRUE); ++ PORT_Memset(newKey, 0, AES_BLOCK_SIZE); ++ return CKR_OK; ++fail: ++ crv = sftk_MapCryptError(PORT_GetError()); ++ if (aes_context) { ++ AES_DestroyContext(aes_context, PR_TRUE); ++ } ++ PORT_Memset(k1, 0, AES_BLOCK_SIZE); ++ PORT_Memset(k2, 0, AES_BLOCK_SIZE); ++ PORT_Memset(k3, 0, AES_BLOCK_SIZE); ++ PORT_Memset(newKey, 0, AES_BLOCK_SIZE); ++ return crv; ++} ++ ++/* encode the final pad block of aes xcbc, padBuf is modified */ ++CK_RV ++sftk_xcbc_mac_pad(unsigned char *padBuf, unsigned int bufLen, int blockSize, ++ const unsigned char *k2, const unsigned char *k3) ++{ ++ int i; ++ if (bufLen == blockSize) { ++ for (i = 0; i < blockSize; i++) { ++ padBuf[i] ^= k2[i]; ++ } ++ } else { ++ padBuf[bufLen++] = 0x80; ++ for (i = bufLen; i < blockSize; i++) { ++ padBuf[i] = 0x00; ++ } ++ for (i = 0; i < blockSize; i++) { ++ padBuf[i] ^= k3[i]; ++ } ++ } ++ return CKR_OK; ++} ++ ++/* Map the mechanism to the underlying hash. If the type is not a hash ++ * or HMAC, return HASH_AlgNULL. This can happen legitimately if ++ * we are doing AES XCBC */ ++static HASH_HashType ++sftk_map_hmac_to_hash(CK_MECHANISM_TYPE type) ++{ ++ switch (type) { ++ case CKM_SHA_1_HMAC: ++ case CKM_SHA_1: ++ return HASH_AlgSHA1; ++ case CKM_MD5_HMAC: ++ case CKM_MD5: ++ return HASH_AlgMD5; ++ case CKM_MD2_HMAC: ++ case CKM_MD2: ++ return HASH_AlgMD2; ++ case CKM_SHA224_HMAC: ++ case CKM_SHA224: ++ return HASH_AlgSHA224; ++ case CKM_SHA256_HMAC: ++ case CKM_SHA256: ++ return HASH_AlgSHA256; ++ case CKM_SHA384_HMAC: ++ case CKM_SHA384: ++ return HASH_AlgSHA384; ++ case CKM_SHA512_HMAC: ++ case CKM_SHA512: ++ return HASH_AlgSHA512; ++ } ++ return HASH_AlgNULL; ++} ++ ++/* ++ * Generally setup the context based on the mechanism. ++ * If the mech is HMAC, context->hashObj should be set ++ * Otherwise it is assumed to be AES XCBC. prf_setup ++ * checks these assumptions and will return an error ++ * if they are not met. NOTE: this function does not allocate ++ * anything, so there is no requirement to free context after ++ * prf_setup like there is if you call prf_init. ++ */ ++static CK_RV ++prf_setup(prfContext *context, CK_MECHANISM_TYPE mech) ++{ ++ context->hashType = sftk_map_hmac_to_hash(mech); ++ context->hashObj = NULL; ++ context->hmac = NULL; ++ context->aes = NULL; ++ if (context->hashType != HASH_AlgNULL) { ++ context->hashObj = HASH_GetRawHashObject(context->hashType); ++ if (context->hashObj == NULL) { ++ return CKR_GENERAL_ERROR; ++ } ++ return CKR_OK; ++ } else if (mech == CKM_AES_XCBC_MAC) { ++ return CKR_OK; ++ } ++ return CKR_MECHANISM_PARAM_INVALID; ++} ++ ++/* return the underlying prf length for this context. This will ++ * function once the context is setup */ ++static CK_RV ++prf_length(prfContext *context) ++{ ++ if (context->hashObj) { ++ return context->hashObj->length; ++ } ++ return AES_BLOCK_SIZE; /* AES */ ++} ++ ++/* set up the key for the prf. prf_update or prf_final should not be called if ++ * prf_init has not been called first. Once prf_init returns hmac and ++ * aes contexts should set and valid. ++ */ ++static CK_RV ++prf_init(prfContext *context, const unsigned char *keyValue, ++ unsigned int keyLen) ++{ ++ CK_RV crv; ++ ++ context->hmac = NULL; ++ if (context->hashObj) { ++ context->hmac = HMAC_Create(context->hashObj, ++ keyValue, keyLen, PR_FALSE); ++ if (context->hmac == NULL) { ++ return sftk_MapCryptError(PORT_GetError()); ++ } ++ HMAC_Begin(context->hmac); ++ } else { ++ crv = sftk_aes_xcbc_get_keys(keyValue, keyLen, context->k1, ++ context->k2, context->k3); ++ if (crv != CKR_OK) ++ return crv; ++ context->nextChar = 0; ++ context->aes = AES_CreateContext(context->k1, iv_zero, NSS_AES_CBC, ++ PR_TRUE, sizeof(context->k1), AES_BLOCK_SIZE); ++ if (context->aes == NULL) { ++ crv = sftk_MapCryptError(PORT_GetError()); ++ PORT_Memset(context->k1, 0, sizeof(context->k1)); ++ PORT_Memset(context->k2, 0, sizeof(context->k2)); ++ PORT_Memset(context->k3, 0, sizeof(context->k2)); ++ return crv; ++ } ++ } ++ return CKR_OK; ++} ++ ++/* ++ * process input to the prf ++ */ ++static CK_RV ++prf_update(prfContext *context, const unsigned char *buf, unsigned int len) ++{ ++ unsigned int tmpLen; ++ SECStatus rv; ++ ++ if (context->hmac) { ++ HMAC_Update(context->hmac, buf, len); ++ } else { ++ /* AES MAC XCBC*/ ++ /* We must keep the last block back so that it can be processed in ++ * final. This is why we only check that nextChar + len > blocksize, ++ * rather than checking that nextChar + len >= blocksize */ ++ while (context->nextChar + len > AES_BLOCK_SIZE) { ++ if (context->nextChar != 0) { ++ /* first handle fill in any partial blocks in the buffer */ ++ unsigned int left = AES_BLOCK_SIZE - context->nextChar; ++ /* note: left can be zero */ ++ PORT_Memcpy(context->padBuf + context->nextChar, buf, left); ++ /* NOTE: AES MAC XCBC xors the data with the previous block ++ * We don't do that step here because our AES_Encrypt mode ++ * is CBC, which does the xor automatically */ ++ rv = AES_Encrypt(context->aes, context->macBuf, &tmpLen, ++ sizeof(context->macBuf), context->padBuf, ++ sizeof(context->padBuf)); ++ if (rv != SECSuccess) { ++ return sftk_MapCryptError(PORT_GetError()); ++ } ++ context->nextChar = 0; ++ len -= left; ++ buf += left; ++ } else { ++ /* optimization. if we have complete blocks to write out ++ * (and will still have leftover blocks for padbuf in the end). ++ * we can mac directly out of our buffer without first copying ++ * them to padBuf */ ++ rv = AES_Encrypt(context->aes, context->macBuf, &tmpLen, ++ sizeof(context->macBuf), buf, AES_BLOCK_SIZE); ++ if (rv != SECSuccess) { ++ return sftk_MapCryptError(PORT_GetError()); ++ } ++ len -= AES_BLOCK_SIZE; ++ buf += AES_BLOCK_SIZE; ++ } ++ } ++ PORT_Memcpy(context->padBuf + context->nextChar, buf, len); ++ context->nextChar += len; ++ } ++ return CKR_OK; ++} ++ ++/* ++ * free the data associated with the prf. Clear any possible CSPs ++ * This can safely be called on any context after prf_setup. It can ++ * also be called an an already freed context. ++ * A free context can be reused by calling prf_init again without ++ * the need to call prf_setup. ++ */ ++static void ++prf_free(prfContext *context) ++{ ++ if (context->hmac) { ++ HMAC_Destroy(context->hmac, PR_TRUE); ++ context->hmac = NULL; ++ } ++ if (context->aes) { ++ PORT_Memset(context->k1, 0, sizeof(context->k1)); ++ PORT_Memset(context->k2, 0, sizeof(context->k2)); ++ PORT_Memset(context->k3, 0, sizeof(context->k2)); ++ PORT_Memset(context->padBuf, 0, sizeof(context->padBuf)); ++ PORT_Memset(context->macBuf, 0, sizeof(context->macBuf)); ++ AES_DestroyContext(context->aes, PR_TRUE); ++ context->aes = NULL; ++ } ++} ++ ++/* ++ * extract the final prf value. On success, this has the side effect of ++ * also freeing the context data and clearing the keys ++ */ ++static CK_RV ++prf_final(prfContext *context, unsigned char *buf, unsigned int len) ++{ ++ unsigned int tmpLen; ++ SECStatus rv; ++ ++ if (context->hmac) { ++ unsigned int outLen; ++ HMAC_Finish(context->hmac, buf, &outLen, len); ++ if (outLen != len) { ++ return CKR_GENERAL_ERROR; ++ } ++ } else { ++ /* prf_update had guarrenteed that the last full block is still in ++ * the padBuf if the input data is a multiple of the blocksize. This ++ * allows sftk_xcbc_mac_pad to process that pad buf accordingly */ ++ sftk_xcbc_mac_pad(context->padBuf, context->nextChar, AES_BLOCK_SIZE, ++ context->k2, context->k3); ++ rv = AES_Encrypt(context->aes, context->macBuf, &tmpLen, ++ sizeof(context->macBuf), context->padBuf, AES_BLOCK_SIZE); ++ if (rv != SECSuccess) { ++ return sftk_MapCryptError(PORT_GetError()); ++ } ++ PORT_Memcpy(buf, context->macBuf, len); ++ } ++ prf_free(context); ++ return CKR_OK; ++} ++ ++/* ++ * There are four flavors of ike prf functions here. ++ * ike_prf is used in both ikeV1 and ikeV2 to generate ++ * an initial key that all the other keys are generated with. ++ * ++ * These functions are called from NSC_DeriveKey with the inKey value ++ * already looked up, and it expects the CKA_VALUE for outKey to be set. ++ * ++ * Depending on usage it returns either: ++ * 1. prf(Ni|Nr, inKey); (bDataAsKey=TRUE, bRekey=FALSE) ++ * 2. prf(inKey, Ni|Nr); (bDataAsKkey=FALSE, bRekey=FALSE) ++ * 3. prf(inKey, newKey | Ni | Nr); (bDataAsKey=FALSE, bRekey=TRUE) ++ * The resulting output key is always the length of the underlying prf ++ * (as returned by prf_length()). ++ * The combination of bDataAsKey=TRUE and bRekey=TRUE is not allowed ++ * ++ * Case 1 is used in ++ * a. ikev2 (rfc5996) inKey is called g^ir, the output is called SKEYSEED ++ * b. ikev1 (rfc2409) inKey is called g^ir, the output is called SKEYID ++ * Case 2 is used in ikev1 (rfc2409) inkey is called pre-shared-key, output ++ * is called SKEYID ++ * Case 3 is used in ikev2 (rfc5996) rekey case, inKey is SK_d, newKey is ++ * g^ir (new), the output is called SKEYSEED ++ */ ++CK_RV ++sftk_ike_prf(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey, ++ const CK_NSS_IKE_PRF_DERIVE_PARAMS *params, SFTKObject *outKey) ++{ ++ SFTKAttribute *newKeyValue = NULL; ++ SFTKObject *newKeyObj = NULL; ++ unsigned char outKeyData[HASH_LENGTH_MAX]; ++ unsigned char *newInKey = NULL; ++ unsigned int newInKeySize; ++ unsigned int macSize; ++ CK_RV crv = CKR_OK; ++ prfContext context; ++ ++ crv = prf_setup(&context, params->prfMechanism); ++ if (crv != CKR_OK) { ++ return crv; ++ } ++ macSize = prf_length(&context); ++ if ((params->bDataAsKey) && (params->bRekey)) { ++ return CKR_ARGUMENTS_BAD; ++ } ++ if (params->bRekey) { ++ /* lookup the value of new key from the session and key handle */ ++ SFTKSession *session = sftk_SessionFromHandle(hSession); ++ if (session == NULL) { ++ return CKR_SESSION_HANDLE_INVALID; ++ } ++ newKeyObj = sftk_ObjectFromHandle(params->hNewKey, session); ++ sftk_FreeSession(session); ++ if (newKeyObj == NULL) { ++ return CKR_KEY_HANDLE_INVALID; ++ } ++ newKeyValue = sftk_FindAttribute(newKeyObj, CKA_VALUE); ++ if (newKeyValue == NULL) { ++ crv = CKR_KEY_HANDLE_INVALID; ++ goto fail; ++ } ++ } ++ if (params->bDataAsKey) { ++ /* The key is Ni || Np, so we need to concatenate them together first */ ++ newInKeySize = params->ulNiLen + params->ulNrLen; ++ newInKey = PORT_Alloc(newInKeySize); ++ if (newInKey == NULL) { ++ crv = CKR_HOST_MEMORY; ++ goto fail; ++ } ++ PORT_Memcpy(newInKey, params->pNi, params->ulNiLen); ++ PORT_Memcpy(newInKey + params->ulNiLen, params->pNr, params->ulNrLen); ++ crv = prf_init(&context, newInKey, newInKeySize); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ /* key as the data */ ++ crv = prf_update(&context, inKey->attrib.pValue, ++ inKey->attrib.ulValueLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ } else { ++ crv = prf_init(&context, inKey->attrib.pValue, ++ inKey->attrib.ulValueLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ if (newKeyValue) { ++ crv = prf_update(&context, newKeyValue->attrib.pValue, ++ newKeyValue->attrib.ulValueLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ } ++ crv = prf_update(&context, params->pNi, params->ulNiLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = prf_update(&context, params->pNr, params->ulNrLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ } ++ crv = prf_final(&context, outKeyData, macSize); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ ++ crv = sftk_forceAttribute(outKey, CKA_VALUE, outKeyData, macSize); ++fail: ++ if (newInKey) { ++ PORT_Free(newInKey); ++ } ++ if (newKeyValue) { ++ sftk_FreeAttribute(newKeyValue); ++ } ++ if (newKeyObj) { ++ sftk_FreeObject(newKeyObj); ++ } ++ PORT_Memset(outKeyData, 0, macSize); ++ prf_free(&context); ++ return crv; ++} ++ ++/* ++ * The second flavor of ike prf is ike1_prf. ++ * ++ * It is used by ikeV1 to generate the various session keys used in the ++ * connection. It uses the initial key, an optional previous key, and a one byte ++ * key number to generate a unique key for each of the various session ++ * functions (encryption, decryption, mac). These keys expect a key size ++ * (as they may vary in length based on usage). If no length is provided, ++ * it will default to the length of the prf. ++ * ++ * This function returns either: ++ * prf(inKey, gxyKey || CKYi || CKYr || key_number) ++ * or ++ * prf(inKey, prevkey || gxyKey || CKYi || CKYr || key_number) ++ * depending on the stats of bHasPrevKey ++ * ++ * This is defined in rfc2409. For each of the following keys. ++ * inKey is SKEYID, gxyKey is g^xy ++ * for outKey = SKEYID_d, bHasPrevKey = false, key_number = 0 ++ * for outKey = SKEYID_a, prevKey= SKEYID_d, key_number = 1 ++ * for outKey = SKEYID_e, prevKey= SKEYID_a, key_number = 2 ++ */ ++CK_RV ++sftk_ike1_prf(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey, ++ const CK_NSS_IKE1_PRF_DERIVE_PARAMS *params, SFTKObject *outKey, ++ unsigned int keySize) ++{ ++ SFTKAttribute *gxyKeyValue = NULL; ++ SFTKObject *gxyKeyObj = NULL; ++ SFTKAttribute *prevKeyValue = NULL; ++ SFTKObject *prevKeyObj = NULL; ++ SFTKSession *session; ++ unsigned char outKeyData[HASH_LENGTH_MAX]; ++ unsigned int macSize; ++ CK_RV crv; ++ prfContext context; ++ ++ crv = prf_setup(&context, params->prfMechanism); ++ if (crv != CKR_OK) { ++ return crv; ++ } ++ macSize = prf_length(&context); ++ if (keySize > macSize) { ++ return CKR_KEY_SIZE_RANGE; ++ } ++ if (keySize == 0) { ++ keySize = macSize; ++ } ++ ++ /* lookup the two keys from their passed in handles */ ++ session = sftk_SessionFromHandle(hSession); ++ if (session == NULL) { ++ return CKR_SESSION_HANDLE_INVALID; ++ } ++ gxyKeyObj = sftk_ObjectFromHandle(params->hKeygxy, session); ++ if (params->bHasPrevKey) { ++ prevKeyObj = sftk_ObjectFromHandle(params->hPrevKey, session); ++ } ++ sftk_FreeSession(session); ++ if ((gxyKeyObj == NULL) || ((params->bHasPrevKey) && ++ (prevKeyObj == NULL))) { ++ crv = CKR_KEY_HANDLE_INVALID; ++ goto fail; ++ } ++ gxyKeyValue = sftk_FindAttribute(gxyKeyObj, CKA_VALUE); ++ if (gxyKeyValue == NULL) { ++ crv = CKR_KEY_HANDLE_INVALID; ++ goto fail; ++ } ++ if (prevKeyObj) { ++ prevKeyValue = sftk_FindAttribute(prevKeyObj, CKA_VALUE); ++ if (prevKeyValue == NULL) { ++ crv = CKR_KEY_HANDLE_INVALID; ++ goto fail; ++ } ++ } ++ ++ /* outKey = prf(inKey, [prevKey|] gxyKey | CKYi | CKYr | keyNumber) */ ++ crv = prf_init(&context, inKey->attrib.pValue, inKey->attrib.ulValueLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ if (prevKeyValue) { ++ crv = prf_update(&context, prevKeyValue->attrib.pValue, ++ prevKeyValue->attrib.ulValueLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ } ++ crv = prf_update(&context, gxyKeyValue->attrib.pValue, ++ gxyKeyValue->attrib.ulValueLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = prf_update(&context, params->pCKYi, params->ulCKYiLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = prf_update(&context, params->pCKYr, params->ulCKYrLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = prf_update(&context, ¶ms->keyNumber, 1); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = prf_final(&context, outKeyData, macSize); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ ++ crv = sftk_forceAttribute(outKey, CKA_VALUE, outKeyData, keySize); ++fail: ++ if (gxyKeyValue) { ++ sftk_FreeAttribute(gxyKeyValue); ++ } ++ if (prevKeyValue) { ++ sftk_FreeAttribute(prevKeyValue); ++ } ++ if (gxyKeyObj) { ++ sftk_FreeObject(gxyKeyObj); ++ } ++ if (prevKeyObj) { ++ sftk_FreeObject(prevKeyObj); ++ } ++ PORT_Memset(outKeyData, 0, macSize); ++ prf_free(&context); ++ return crv; ++} ++ ++/* ++ * The third flavor of ike prf is ike1_appendix_b. ++ * ++ * It is used by ikeV1 to generate longer key material from skeyid_e. ++ * Unlike ike1_prf, if no length is provided, this function ++ * will generate a KEY_RANGE_ERROR. ++ * ++ * This function returns (from rfc2409 appendix b): ++ * Ka = K1 | K2 | K3 | K4 |... Kn ++ * where: ++ * K1 = prf(K, 0x00) ++ * K2 = prf(K, K1) ++ * K3 = prf(K, K2) ++ * K4 = prf(K, K3) ++ * . ++ * Kn = prf(K, K(n-1)) ++ * K = inKey ++ */ ++CK_RV ++sftk_ike1_appendix_b_prf(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey, ++ const CK_MECHANISM_TYPE *mech, SFTKObject *outKey, unsigned int keySize) ++{ ++ unsigned char *outKeyData = NULL; ++ unsigned char *thisKey = NULL; ++ unsigned char *lastKey = NULL; ++ unsigned int macSize; ++ unsigned int outKeySize; ++ unsigned int genKeySize; ++ CK_RV crv; ++ prfContext context; ++ ++ crv = prf_setup(&context, *mech); ++ if (crv != CKR_OK) { ++ return crv; ++ } ++ ++ macSize = prf_length(&context); ++ ++ if (keySize == 0) { ++ keySize = macSize; ++ } ++ ++ if (keySize <= inKey->attrib.ulValueLen) { ++ return sftk_forceAttribute(outKey, CKA_VALUE, ++ inKey->attrib.pValue, keySize); ++ } ++ outKeySize = PR_ROUNDUP(keySize, macSize); ++ outKeyData = PORT_Alloc(outKeySize); ++ if (outKeyData == NULL) { ++ crv = CKR_HOST_MEMORY; ++ goto fail; ++ } ++ ++ /* ++ * this loop generates on block of the prf, basically ++ * kn = prf(key, Kn-1) ++ * Kn is thisKey, Kn-1 is lastKey ++ * key is inKey ++ */ ++ thisKey = outKeyData; ++ for (genKeySize = 0; genKeySize <= keySize; genKeySize += macSize) { ++ crv = prf_init(&context, inKey->attrib.pValue, inKey->attrib.ulValueLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ if (lastKey == NULL) { ++ const unsigned char zero = 0; ++ crv = prf_update(&context, &zero, 1); ++ } else { ++ crv = prf_update(&context, lastKey, macSize); ++ } ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = prf_final(&context, thisKey, macSize); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ lastKey = thisKey; ++ thisKey += macSize; ++ } ++ crv = sftk_forceAttribute(outKey, CKA_VALUE, outKeyData, keySize); ++fail: ++ if (outKeyData) { ++ PORT_ZFree(outKeyData, outKeySize); ++ } ++ prf_free(&context); ++ return crv; ++} ++ ++/* ++ * The final flavor of ike prf is ike_prf_plus ++ * ++ * It is used by ikeV2 to generate the various session keys used in the ++ * connection. It uses the initial key and a feedback version of the prf ++ * to generate sufficient bytes to cover all the session keys. The application ++ * will then use CK_EXTRACT_KEY_FROM_KEY to pull out the various subkeys. ++ * This function expects a key size to be set by the application to cover ++ * all the keys. Unlike ike1_prf, if no length is provided, this function ++ * will generate a KEY_RANGE_ERROR ++ * ++ * This function returns (from rfc5996): ++ * prfplus = T1 | T2 | T3 | T4 |... Tn ++ * where: ++ * T1 = prf(K, S | 0x01) ++ * T2 = prf(K, T1 | S | 0x02) ++ * T3 = prf(K, T3 | S | 0x03) ++ * T4 = prf(K, T4 | S | 0x04) ++ * . ++ * Tn = prf(K, T(n-1) | n) ++ * K = inKey, S = seedKey | seedData ++ */ ++ ++CK_RV ++sftk_ike_prf_plus(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey, ++ const CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS *params, SFTKObject *outKey, ++ unsigned int keySize) ++{ ++ SFTKAttribute *seedValue = NULL; ++ SFTKObject *seedKeyObj = NULL; ++ unsigned char *outKeyData = NULL; ++ unsigned int outKeySize; ++ unsigned char *thisKey; ++ unsigned char *lastKey = NULL; ++ unsigned char currentByte = 0; ++ unsigned int getKeySize; ++ unsigned int macSize; ++ CK_RV crv; ++ prfContext context; ++ ++ if (keySize == 0) { ++ return CKR_KEY_SIZE_RANGE; ++ } ++ ++ crv = prf_setup(&context, params->prfMechanism); ++ if (crv != CKR_OK) { ++ return crv; ++ } ++ /* pull in optional seedKey */ ++ if (params->bHasSeedKey) { ++ SFTKSession *session = sftk_SessionFromHandle(hSession); ++ if (session == NULL) { ++ return CKR_SESSION_HANDLE_INVALID; ++ } ++ seedKeyObj = sftk_ObjectFromHandle(params->hSeedKey, session); ++ sftk_FreeSession(session); ++ if (seedKeyObj == NULL) { ++ return CKR_KEY_HANDLE_INVALID; ++ } ++ seedValue = sftk_FindAttribute(seedKeyObj, CKA_VALUE); ++ if (seedValue == NULL) { ++ crv = CKR_KEY_HANDLE_INVALID; ++ goto fail; ++ } ++ } else if (params->ulSeedDataLen == 0) { ++ crv = CKR_ARGUMENTS_BAD; ++ goto fail; ++ } ++ macSize = prf_length(&context); ++ outKeySize = PR_ROUNDUP(keySize, macSize); ++ outKeyData = PORT_Alloc(outKeySize); ++ if (outKeyData == NULL) { ++ crv = CKR_HOST_MEMORY; ++ goto fail; ++ } ++ ++ /* ++ * this loop generates on block of the prf, basically ++ * Tn = prf(key, Tn-1 | S | n) ++ * Tn is thisKey, Tn-2 is lastKey, S is seedKey || seedData, ++ * key is inKey. currentByte = n-1 on entry. ++ */ ++ thisKey = outKeyData; ++ for (getKeySize = 0; getKeySize < keySize; getKeySize += macSize) { ++ /* if currentByte is 255, we'll overflow when we increment it below. ++ * This can only happen if keysize > 255*macSize. In that case ++ * the application has asked for too much key material, so return ++ * an error */ ++ if (currentByte == 255) { ++ crv = CKR_KEY_SIZE_RANGE; ++ goto fail; ++ } ++ crv = prf_init(&context, inKey->attrib.pValue, ++ inKey->attrib.ulValueLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ ++ if (lastKey) { ++ crv = prf_update(&context, lastKey, macSize); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ } ++ /* prf the key first */ ++ if (seedValue) { ++ crv = prf_update(&context, seedValue->attrib.pValue, ++ seedValue->attrib.ulValueLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ } ++ /* then prf the data */ ++ if (params->ulSeedDataLen != 0) { ++ crv = prf_update(&context, params->pSeedData, ++ params->ulSeedDataLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ } ++ currentByte++; ++ crv = prf_update(&context, ¤tByte, 1); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = prf_final(&context, thisKey, macSize); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ lastKey = thisKey; ++ thisKey += macSize; ++ } ++ crv = sftk_forceAttribute(outKey, CKA_VALUE, outKeyData, keySize); ++fail: ++ if (outKeyData) { ++ PORT_ZFree(outKeyData, outKeySize); ++ } ++ if (seedValue) { ++ sftk_FreeAttribute(seedValue); ++ } ++ if (seedKeyObj) { ++ sftk_FreeObject(seedKeyObj); ++ } ++ prf_free(&context); ++ return crv; ++} ++ ++/* sftk_aes_xcbc_new_keys: ++ * ++ * aes xcbc creates 3 new keys from the input key. The first key will be the ++ * base key of the underlying cbc. The sign code hooks directly into encrypt ++ * so we'll have to create a full PKCS #11 key with handle for that key. The ++ * caller needs to delete the key when it's through setting up the context. ++ * ++ * The other two keys will be stored in the sign context until we need them ++ * at the end. ++ */ ++CK_RV ++sftk_aes_xcbc_new_keys(CK_SESSION_HANDLE hSession, ++ CK_OBJECT_HANDLE hKey, CK_OBJECT_HANDLE_PTR phKey, ++ unsigned char *k2, unsigned char *k3) ++{ ++ SFTKObject *key = NULL; ++ SFTKSession *session = NULL; ++ SFTKObject *inKeyObj = NULL; ++ SFTKAttribute *inKeyValue = NULL; ++ CK_KEY_TYPE key_type = CKK_AES; ++ CK_OBJECT_CLASS objclass = CKO_SECRET_KEY; ++ CK_BBOOL ck_true = CK_TRUE; ++ CK_RV crv = CKR_OK; ++ SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession); ++ unsigned char buf[AES_BLOCK_SIZE]; ++ ++ if (!slot) { ++ return CKR_SESSION_HANDLE_INVALID; ++ } ++ ++ /* get the session */ ++ session = sftk_SessionFromHandle(hSession); ++ if (session == NULL) { ++ crv = CKR_SESSION_HANDLE_INVALID; ++ goto fail; ++ } ++ ++ inKeyObj = sftk_ObjectFromHandle(hKey, session); ++ if (inKeyObj == NULL) { ++ crv = CKR_KEY_HANDLE_INVALID; ++ goto fail; ++ } ++ ++ inKeyValue = sftk_FindAttribute(inKeyObj, CKA_VALUE); ++ if (inKeyValue == NULL) { ++ crv = CKR_KEY_HANDLE_INVALID; ++ goto fail; ++ } ++ ++ crv = sftk_aes_xcbc_get_keys(inKeyValue->attrib.pValue, ++ inKeyValue->attrib.ulValueLen, buf, k2, k3); ++ ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ ++ /* ++ * now lets create an object to hang the attributes off of ++ */ ++ key = sftk_NewObject(slot); /* fill in the handle later */ ++ if (key == NULL) { ++ crv = CKR_HOST_MEMORY; ++ goto fail; ++ } ++ ++ /* make sure we don't have any class, key_type, or value fields */ ++ sftk_DeleteAttributeType(key, CKA_CLASS); ++ sftk_DeleteAttributeType(key, CKA_KEY_TYPE); ++ sftk_DeleteAttributeType(key, CKA_VALUE); ++ sftk_DeleteAttributeType(key, CKA_SIGN); ++ ++ /* Add the class, key_type, and value */ ++ crv = sftk_AddAttributeType(key, CKA_CLASS, &objclass, sizeof(CK_OBJECT_CLASS)); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &key_type, sizeof(CK_KEY_TYPE)); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = sftk_AddAttributeType(key, CKA_SIGN, &ck_true, sizeof(CK_BBOOL)); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = sftk_AddAttributeType(key, CKA_VALUE, buf, AES_BLOCK_SIZE); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ ++ /* ++ * finish filling in the key and link it with our global system. ++ */ ++ crv = sftk_handleObject(key, session); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ *phKey = key->handle; ++fail: ++ if (session) { ++ sftk_FreeSession(session); ++ } ++ ++ if (inKeyValue) { ++ sftk_FreeAttribute(inKeyValue); ++ } ++ if (inKeyObj) { ++ sftk_FreeObject(inKeyObj); ++ } ++ if (key) { ++ sftk_FreeObject(key); ++ } ++ /* clear our CSPs */ ++ if (crv != CKR_OK) { ++ PORT_Memset(k2, 0, AES_BLOCK_SIZE); ++ PORT_Memset(k3, 0, AES_BLOCK_SIZE); ++ } ++ return crv; ++} ++ ++/* ++ * Helper function that tests a single prf test vector ++ */ ++static SECStatus ++prf_test(CK_MECHANISM_TYPE mech, ++ const unsigned char *inKey, unsigned int inKeyLen, ++ const unsigned char *plainText, unsigned int plainTextLen, ++ const unsigned char *expectedResult, unsigned int expectedResultLen) ++{ ++ PRUint8 ike_computed_mac[HASH_LENGTH_MAX]; ++ prfContext context; ++ unsigned int macSize; ++ CK_RV crv; ++ ++ crv = prf_setup(&context, mech); ++ if (crv != CKR_OK) { ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); ++ return SECFailure; ++ } ++ macSize = prf_length(&context); ++ crv = prf_init(&context, inKey, inKeyLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = prf_update(&context, plainText, plainTextLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = prf_final(&context, ike_computed_mac, macSize); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ ++ if (macSize != expectedResultLen) { ++ goto fail; ++ } ++ if (PORT_Memcmp(expectedResult, ike_computed_mac, macSize) != 0) { ++ goto fail; ++ } ++ ++ /* only do the alignment if the plaintext is long enough */ ++ if (plainTextLen <= macSize) { ++ return SECSuccess; ++ } ++ /* do it again, but this time tweak with the alignment */ ++ crv = prf_init(&context, inKey, inKeyLen); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = prf_update(&context, plainText, 1); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = prf_update(&context, &plainText[1], macSize); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = prf_update(&context, &plainText[1 + macSize], plainTextLen - (macSize + 1)); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ crv = prf_final(&context, ike_computed_mac, macSize); ++ if (crv != CKR_OK) { ++ goto fail; ++ } ++ if (PORT_Memcmp(expectedResult, ike_computed_mac, macSize) != 0) { ++ goto fail; ++ } ++ return SECSuccess; ++fail: ++ prf_free(&context); ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); ++ return SECFailure; ++} ++ ++/* ++ * FIPS Power up Self Tests for IKE. This is in this function so it ++ * can access the private prf_ functions here. It's called out of fipstest.c ++ */ ++SECStatus ++sftk_fips_IKE_PowerUpSelfTests(void) ++{ ++ /* PRF known test vectors */ ++ static const PRUint8 ike_xcbc_known_key[] = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ++ }; ++ static const PRUint8 ike_xcbc_known_plain_text[] = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ++ }; ++ static const PRUint8 ike_xcbc_known_mac[] = { ++ 0xd2, 0xa2, 0x46, 0xfa, 0x34, 0x9b, 0x68, 0xa7, ++ 0x99, 0x98, 0xa4, 0x39, 0x4f, 0xf7, 0xa2, 0x63 ++ }; ++ /* test 2 uses the same key as test 1 */ ++ static const PRUint8 ike_xcbc_known_plain_text_2[] = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ++ 0x10, 0x11, 0x12, 0x13 ++ }; ++ static const PRUint8 ike_xcbc_known_mac_2[] = { ++ 0x47, 0xf5, 0x1b, 0x45, 0x64, 0x96, 0x62, 0x15, ++ 0xb8, 0x98, 0x5c, 0x63, 0x05, 0x5e, 0xd3, 0x08 ++ }; ++ static const PRUint8 ike_xcbc_known_key_3[] = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09 ++ }; ++ /* test 3 uses the same plaintest as test 2 */ ++ static const PRUint8 ike_xcbc_known_mac_3[] = { ++ 0x0f, 0xa0, 0x87, 0xaf, 0x7d, 0x86, 0x6e, 0x76, ++ 0x53, 0x43, 0x4e, 0x60, 0x2f, 0xdd, 0xe8, 0x35 ++ }; ++ static const PRUint8 ike_xcbc_known_key_4[] = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ++ 0xed, 0xcb ++ }; ++ /* test 4 uses the same plaintest as test 2 */ ++ static const PRUint8 ike_xcbc_known_mac_4[] = { ++ 0x8c, 0xd3, 0xc9, 0x3a, 0xe5, 0x98, 0xa9, 0x80, ++ 0x30, 0x06, 0xff, 0xb6, 0x7c, 0x40, 0xe9, 0xe4 ++ }; ++ static const PRUint8 ike_sha1_known_key[] = { ++ 0x59, 0x98, 0x2b, 0x5b, 0xa5, 0x7e, 0x62, 0xc0, ++ 0x46, 0x0d, 0xef, 0xc7, 0x1e, 0x18, 0x64, 0x63 ++ }; ++ static const PRUint8 ike_sha1_known_plain_text[] = { ++ 0x1c, 0x07, 0x32, 0x1a, 0x9a, 0x7e, 0x41, 0xcd, ++ 0x88, 0x0c, 0xa3, 0x7a, 0xdb, 0x10, 0xc7, 0x3b, ++ 0xf0, 0x0e, 0x7a, 0xe3, 0xcf, 0xc6, 0xfd, 0x8b, ++ 0x51, 0xbc, 0xe2, 0xb9, 0x90, 0xe6, 0xf2, 0x01 ++ }; ++ static const PRUint8 ike_sha1_known_mac[] = { ++ 0x0c, 0x2a, 0xf3, 0x42, 0x97, 0x15, 0x62, 0x1d, ++ 0x2a, 0xad, 0xc9, 0x94, 0x5a, 0x90, 0x26, 0xfa, ++ 0xc7, 0x91, 0xe2, 0x4b ++ }; ++ static const PRUint8 ike_sha256_known_key[] = { ++ 0x9d, 0xa2, 0xd5, 0x8f, 0x57, 0xf0, 0x39, 0xf9, ++ 0x20, 0x4e, 0x0d, 0xd0, 0xef, 0x04, 0xf3, 0x72 ++ }; ++ static const PRUint8 ike_sha256_known_plain_text[] = { ++ 0x33, 0xf1, 0x7a, 0xfc, 0xb6, 0x13, 0x4c, 0xbf, ++ 0x1c, 0xab, 0x59, 0x87, 0x7d, 0x42, 0xdb, 0x35, ++ 0x82, 0x22, 0x6e, 0xff, 0x74, 0xdd, 0x37, 0xeb, ++ 0x8b, 0x75, 0xe6, 0x75, 0x64, 0x5f, 0xc1, 0x69 ++ }; ++ static const PRUint8 ike_sha256_known_mac[] = { ++ 0x80, 0x4b, 0x4a, 0x1e, 0x0e, 0xc5, 0x93, 0xcf, 0xb6, ++ 0xe4, 0x54, 0x52, 0x41, 0x49, 0x39, 0x6d, 0xe2, 0x34, ++ 0xd0, 0xda, 0xe2, 0x9f, 0x34, 0xa8, 0xfd, 0xb5, 0xf9, ++ 0xaf, 0xe7, 0x6e, 0xa6, 0x52 ++ }; ++ static const PRUint8 ike_sha384_known_key[] = { ++ 0xce, 0xc8, 0x9d, 0x84, 0x5a, 0xdd, 0x83, 0xef, ++ 0xce, 0xbd, 0x43, 0xab, 0x71, 0xd1, 0x7d, 0xb9 ++ }; ++ static const PRUint8 ike_sha384_known_plain_text[] = { ++ 0x17, 0x24, 0xdb, 0xd8, 0x93, 0x52, 0x37, 0x64, ++ 0xbf, 0xef, 0x8c, 0x6f, 0xa9, 0x27, 0x85, 0x6f, ++ 0xcc, 0xfb, 0x77, 0xae, 0x25, 0x43, 0x58, 0xcc, ++ 0xe2, 0x9c, 0x27, 0x69, 0xa3, 0x29, 0x15, 0xc1 ++ }; ++ static const PRUint8 ike_sha384_known_mac[] = { ++ 0x6e, 0x45, 0x14, 0x61, 0x0b, 0xf8, 0x2d, 0x0a, ++ 0xb7, 0xbf, 0x02, 0x60, 0x09, 0x6f, 0x61, 0x46, ++ 0xa1, 0x53, 0xc7, 0x12, 0x07, 0x1a, 0xbb, 0x63, ++ 0x3c, 0xed, 0x81, 0x3c, 0x57, 0x21, 0x56, 0xc7, ++ 0x83, 0xe3, 0x68, 0x74, 0xa6, 0x5a, 0x64, 0x69, ++ 0x0c, 0xa7, 0x01, 0xd4, 0x0d, 0x56, 0xea, 0x18 ++ }; ++ static const PRUint8 ike_sha512_known_key[] = { ++ 0xac, 0xad, 0xc6, 0x31, 0x4a, 0x69, 0xcf, 0xcd, ++ 0x4e, 0x4a, 0xd1, 0x77, 0x18, 0xfe, 0xa7, 0xce ++ }; ++ static const PRUint8 ike_sha512_known_plain_text[] = { ++ 0xb1, 0x5a, 0x9c, 0xfc, 0xe8, 0xc8, 0xd7, 0xea, ++ 0xb8, 0x79, 0xd6, 0x24, 0x30, 0x29, 0xd4, 0x01, ++ 0x88, 0xd3, 0xb7, 0x40, 0x87, 0x5a, 0x6a, 0xc6, ++ 0x2f, 0x56, 0xca, 0xc4, 0x37, 0x7e, 0x2e, 0xdd ++ }; ++ static const PRUint8 ike_sha512_known_mac[] = { ++ 0xf0, 0x5a, 0xa0, 0x36, 0xdf, 0xce, 0x45, 0xa5, ++ 0x58, 0xd4, 0x04, 0x18, 0xde, 0xa9, 0x80, 0x96, ++ 0xe5, 0x19, 0xbc, 0x78, 0x41, 0xe3, 0xdb, 0x3d, ++ 0xd9, 0x36, 0x58, 0xd1, 0x18, 0xc3, 0xe8, 0x3b, ++ 0x50, 0x2f, 0x39, 0x8e, 0xcb, 0x13, 0x61, 0xec, ++ 0x77, 0xd3, 0x8a, 0x88, 0x55, 0xef, 0xff, 0x40, ++ 0x7f, 0x6f, 0x77, 0x2e, 0x5d, 0x65, 0xb5, 0x8e, ++ 0xb1, 0x13, 0x40, 0x96, 0xe8, 0x47, 0x8d, 0x2b ++ }; ++ SECStatus rv; ++ ++ rv = prf_test(CKM_AES_XCBC_MAC, ++ ike_xcbc_known_key, sizeof(ike_xcbc_known_key), ++ ike_xcbc_known_plain_text, sizeof(ike_xcbc_known_plain_text), ++ ike_xcbc_known_mac, sizeof(ike_xcbc_known_mac)); ++ if (rv != SECSuccess) ++ return rv; ++ rv = prf_test(CKM_AES_XCBC_MAC, ++ ike_xcbc_known_key, sizeof(ike_xcbc_known_key), ++ ike_xcbc_known_plain_text_2, sizeof(ike_xcbc_known_plain_text_2), ++ ike_xcbc_known_mac_2, sizeof(ike_xcbc_known_mac_2)); ++ if (rv != SECSuccess) ++ return rv; ++ rv = prf_test(CKM_AES_XCBC_MAC, ++ ike_xcbc_known_key_3, sizeof(ike_xcbc_known_key_3), ++ ike_xcbc_known_plain_text_2, sizeof(ike_xcbc_known_plain_text_2), ++ ike_xcbc_known_mac_3, sizeof(ike_xcbc_known_mac_3)); ++ if (rv != SECSuccess) ++ return rv; ++ rv = prf_test(CKM_AES_XCBC_MAC, ++ ike_xcbc_known_key_4, sizeof(ike_xcbc_known_key_4), ++ ike_xcbc_known_plain_text_2, sizeof(ike_xcbc_known_plain_text_2), ++ ike_xcbc_known_mac_4, sizeof(ike_xcbc_known_mac_4)); ++ if (rv != SECSuccess) ++ return rv; ++ rv = prf_test(CKM_SHA_1_HMAC, ++ ike_sha1_known_key, sizeof(ike_sha1_known_key), ++ ike_sha1_known_plain_text, sizeof(ike_sha1_known_plain_text), ++ ike_sha1_known_mac, sizeof(ike_sha1_known_mac)); ++ if (rv != SECSuccess) ++ return rv; ++ rv = prf_test(CKM_SHA256_HMAC, ++ ike_sha256_known_key, sizeof(ike_sha256_known_key), ++ ike_sha256_known_plain_text, ++ sizeof(ike_sha256_known_plain_text), ++ ike_sha256_known_mac, sizeof(ike_sha256_known_mac)); ++ if (rv != SECSuccess) ++ return rv; ++ rv = prf_test(CKM_SHA384_HMAC, ++ ike_sha384_known_key, sizeof(ike_sha384_known_key), ++ ike_sha384_known_plain_text, ++ sizeof(ike_sha384_known_plain_text), ++ ike_sha384_known_mac, sizeof(ike_sha384_known_mac)); ++ if (rv != SECSuccess) ++ return rv; ++ rv = prf_test(CKM_SHA512_HMAC, ++ ike_sha512_known_key, sizeof(ike_sha512_known_key), ++ ike_sha512_known_plain_text, ++ sizeof(ike_sha512_known_plain_text), ++ ike_sha512_known_mac, sizeof(ike_sha512_known_mac)); ++ return rv; ++} +diff --git a/lib/softoken/softoken.gyp b/lib/softoken/softoken.gyp +--- a/lib/softoken/softoken.gyp ++++ b/lib/softoken/softoken.gyp +@@ -53,16 +53,17 @@ + 'lowpbe.c', + 'padbuf.c', + 'pkcs11.c', + 'pkcs11c.c', + 'pkcs11u.c', + 'sdb.c', + 'sftkdb.c', + 'sftkhmac.c', ++ 'sftkike.c', + 'sftkpars.c', + 'sftkpwd.c', + 'softkver.c', + 'tlsprf.c' + ], + }, + }, + { +diff --git a/lib/util/pkcs11n.h b/lib/util/pkcs11n.h +--- a/lib/util/pkcs11n.h ++++ b/lib/util/pkcs11n.h +@@ -147,16 +147,22 @@ + #define CKM_NSS_AES_KEY_WRAP_PAD (CKM_NSS + 2) + + /* HKDF key derivation mechanisms. See CK_NSS_HKDFParams for documentation. */ + #define CKM_NSS_HKDF_SHA1 (CKM_NSS + 3) + #define CKM_NSS_HKDF_SHA256 (CKM_NSS + 4) + #define CKM_NSS_HKDF_SHA384 (CKM_NSS + 5) + #define CKM_NSS_HKDF_SHA512 (CKM_NSS + 6) + ++/* IKE mechanism (to be proposed to PKCS #11 */ ++#define CKM_NSS_IKE_PRF_PLUS_DERIVE (CKM_NSS + 7) ++#define CKM_NSS_IKE_PRF_DERIVE (CKM_NSS + 8) ++#define CKM_NSS_IKE1_PRF_DERIVE (CKM_NSS + 9) ++#define CKM_NSS_IKE1_APP_B_PRF_DERIVE (CKM_NSS + 10) ++ + /* J-PAKE round 1 key generation mechanisms. + * + * Required template attributes: CKA_PRIME, CKA_SUBPRIME, CKA_BASE, + * CKA_NSS_JPAKE_SIGNERID + * Output key type: CKK_NSS_JPAKE_ROUND1 + * Output key class: CKO_PRIVATE_KEY + * Parameter type: CK_NSS_JPAKERound1Params + * +@@ -337,16 +343,82 @@ typedef struct CK_NSS_HKDFParams { + CK_BYTE_PTR pSalt; + CK_ULONG ulSaltLen; + CK_BBOOL bExpand; + CK_BYTE_PTR pInfo; + CK_ULONG ulInfoLen; + } CK_NSS_HKDFParams; + + /* ++ * CK_NSS_IKE_PRF_PLUS_PARAMS is a structure that provides the parameters to ++ * the CKM_NSS_IKE_PRF_PLUS_DERIVE mechanism. ++ * The fields of the structure have the following meanings: ++ * prfMechanism underlying MAC mechanism used to generate the prf. ++ * bHasSeedKey hSeed key is present. ++ * hSeedKey optional seed from key ++ * pSeedData optional seed from data. ++ * ulSeedDataLen length of optional seed data. ++ * If no seed data is present this value is NULL. ++ */ ++typedef struct CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS { ++ CK_MECHANISM_TYPE prfMechanism; ++ CK_BBOOL bHasSeedKey; ++ CK_OBJECT_HANDLE hSeedKey; ++ CK_BYTE_PTR pSeedData; ++ CK_ULONG ulSeedDataLen; ++} CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS; ++ ++/* CK_NSS_IKE_PRF_DERIVE_PARAMS is a structure that provides the parameters to ++ * the CKM_NSS_IKE_PRF_DERIVE mechanism. ++ * ++ * The fields of the structure have the following meanings: ++ * prfMechanism underlying MAC mechanism used to generate the prf. ++ * bRekey hNewKey is present. ++ * pNi Ni value ++ * ulNiLen length of Ni ++ * pNr Nr value ++ * ulNrLen length of Nr ++ * hNewKey New key value to drive the rekey. ++ */ ++typedef struct CK_NSS_IKE_PRF_DERIVE_PARAMS { ++ CK_MECHANISM_TYPE prfMechanism; ++ CK_BBOOL bDataAsKey; ++ CK_BBOOL bRekey; ++ CK_BYTE_PTR pNi; ++ CK_ULONG ulNiLen; ++ CK_BYTE_PTR pNr; ++ CK_ULONG ulNrLen; ++ CK_OBJECT_HANDLE hNewKey; ++} CK_NSS_IKE_PRF_DERIVE_PARAMS; ++ ++/* CK_NSS_IKE1_PRF_DERIVE_PARAMS is a structure that provides the parameters ++ * to the CKM_NSS_IKE_PRF_DERIVE mechanism. ++ * ++ * The fields of the structure have the following meanings: ++ * prfMechanism underlying MAC mechanism used to generate the prf. ++ * bRekey hNewKey is present. ++ * pCKYi CKYi value ++ * ulCKYiLen length of CKYi ++ * pCKYr CKYr value ++ * ulCKYrLen length of CKYr ++ * hNewKey New key value to drive the rekey. ++ */ ++typedef struct CK_NSS_IKE1_PRF_DERIVE_PARAMS { ++ CK_MECHANISM_TYPE prfMechanism; ++ CK_BBOOL bHasPrevKey; ++ CK_OBJECT_HANDLE hKeygxy; ++ CK_OBJECT_HANDLE hPrevKey; ++ CK_BYTE_PTR pCKYi; ++ CK_ULONG ulCKYiLen; ++ CK_BYTE_PTR pCKYr; ++ CK_ULONG ulCKYrLen; ++ CK_BYTE keyNumber; ++} CK_NSS_IKE1_PRF_DERIVE_PARAMS; ++ ++/* + * Parameter for the TLS extended master secret key derivation mechanisms: + * + * * CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE + * * CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH + * + * For the TLS 1.2 PRF, the prfHashMechanism parameter determines the hash + * function used. For earlier versions of the PRF, set the prfHashMechanism + * value to CKM_TLS_PRF. +diff --git a/lib/util/pkcs11t.h b/lib/util/pkcs11t.h +--- a/lib/util/pkcs11t.h ++++ b/lib/util/pkcs11t.h +@@ -877,16 +877,18 @@ typedef CK_ULONG CK_MECHANISM_TYPE; + #define CKM_AES_MAC_GENERAL 0x00001084 + #define CKM_AES_CBC_PAD 0x00001085 + /* new for v2.20 amendment 3 */ + #define CKM_AES_CTR 0x00001086 + /* new for v2.30 */ + #define CKM_AES_GCM 0x00001087 + #define CKM_AES_CCM 0x00001088 + #define CKM_AES_CTS 0x00001089 ++#define CKM_AES_XCBC_MAC 0x0000108C ++#define CKM_AES_XCBC_MAC_96 0x0000108D + + /* BlowFish and TwoFish are new for v2.20 */ + #define CKM_BLOWFISH_KEY_GEN 0x00001090 + #define CKM_BLOWFISH_CBC 0x00001091 + #define CKM_TWOFISH_KEY_GEN 0x00001092 + #define CKM_TWOFISH_CBC 0x00001093 + + /* Camellia is proposed for v2.20 Amendment 3 */ +diff --git a/tests/common/init.sh b/tests/common/init.sh +--- a/tests/common/init.sh ++++ b/tests/common/init.sh +@@ -646,18 +646,21 @@ if [ -z "${INIT_SOURCED}" -o "${INIT_SOU + + TOTAL_CRL_RANGE=`expr ${CRL_GRP_1_RANGE} + ${CRL_GRP_2_RANGE} + \ + ${CRL_GRP_3_RANGE}` + + TOTAL_GRP_NUM=3 + + RELOAD_CRL=1 + +- NSS_DEFAULT_DB_TYPE="dbm" +- export NSS_DEFAULT_DB_TYPE ++ # if test mode isn't set, test scripts default to expecting dbm ++ if [ "${TEST_MODE}" = "" ]; then ++ NSS_DEFAULT_DB_TYPE="dbm" ++ export NSS_DEFAULT_DB_TYPE ++ fi + + MSG_ID=0 + + ################################################# + # Interoperability testing constatnts + # + # if suite is setup for testing, IOPR_HOSTADDR_LIST should have + # at least one host name(FQDN) +diff --git a/tests/fips/fips.sh b/tests/fips/fips.sh +--- a/tests/fips/fips.sh ++++ b/tests/fips/fips.sh +@@ -40,27 +40,31 @@ fips_init() + SCRIPTNAME=fips.sh + html_head "FIPS 140 Compliance Tests" + + grep "SUCCESS: FIPS passed" $CERT_LOG_FILE >/dev/null || { + Exit 15 "Fatal - FIPS of cert.sh needs to pass first" + } + + COPYDIR=${FIPSDIR}/copydir ++ CAVSDIR=${FIPSDIR}/cavs/tests ++ CAVSRUNDIR=${FIPSDIR}/cavs/scripts + + R_FIPSDIR=../fips + P_R_FIPSDIR=../fips + R_COPYDIR=../fips/copydir + + if [ -n "${MULTIACCESS_DBM}" ]; then + P_R_FIPSDIR="multiaccess:${D_FIPS}" + fi + + mkdir -p ${FIPSDIR} + mkdir -p ${COPYDIR} ++ mkdir -p ${CAVSDIR} ++ mkdir -p ${CAVSRUNDIR} + + cd ${FIPSDIR} + } + + ############################## fips_140 ############################## + # local shell function to test basic functionality of NSS while in + # FIPS 140 compliant mode + ######################################################################## +@@ -269,25 +273,51 @@ fips_140() + fi + + html_msg ${RESULT} 46 "Init NSS with a corrupted library (dbtest -r)" "." + else + html_failed "Mangle ${DLL_PREFIX}softokn3.${DLL_SUFFIX}" + fi + } + ++fips_cavs() ++{ ++ if [ "${CAVS_VECTORS}" = "all" ]; then ++ VECTORS= ++ elif [ "${CAVS_VECTORS}" = "" ]; then ++ VECTORS="aesgcm ecdsa hmac kas tls ike rng sha" ++ else ++ VECTORS=${CAVS_VECTORS} ++ fi ++ echo "Copying CAVS vectors" ++ cp -r ${QADIR}/fips/cavs_samples/* ${CAVSDIR} ++# we copy the scripts to the test directory because they are designed to run from their ++# own directory and we want any resulting core dumps to wind up in the test_results directory. ++ echo "Copying CAVS scripts" ++ cp -r ${QADIR}/fips/cavs_scripts/* ${CAVSRUNDIR} ++ echo "cd ${CAVSRUNDIR}" ++ cd ${CAVSRUNDIR} ++ echo "Running CAVS tests in ${CAVSDIR}" ++ ./runtest.sh ${CAVSDIR} run ${VECTORS} ++ echo "Verifying CAVS results in ${CAVSDIR}" ++ ./runtest.sh ${CAVSDIR} verify ${VECTORS} ++ RESULT=$? ++ html_msg $RESULT 0 "NIST CAVS test" "${CAVSDIR}" ++} ++ + ############################## fips_cleanup ############################ + # local shell function to finish this script (no exit since it might be + # sourced) + ######################################################################## + fips_cleanup() + { + html "
" + cd ${QADIR} + . common/cleanup.sh + } + + ################## main ################################################# + + fips_init + fips_140 ++fips_cavs + fips_cleanup + echo "fips.sh done" diff --git a/SOURCES/nss-input-check.patch b/SOURCES/nss-input-check.patch new file mode 100644 index 0000000..366b793 --- /dev/null +++ b/SOURCES/nss-input-check.patch @@ -0,0 +1,127 @@ +# HG changeset patch +# User Martin Thomson +# Date 1560498951 0 +# Fri Jun 14 07:55:51 2019 +0000 +# Branch NSS_3_44_BRANCH +# Node ID fb9932d6e083322e7b5dfcd3d6e67477e0bb075a +# Parent 876bca2723a1f969422edc93e7504420d8331d3c +Bug 1515342 - More thorough input checking, r=jcj + +All part of applying better discipline throughout. + +Differential Revision: https://phabricator.services.mozilla.com/D33736 + +diff --git a/lib/cryptohi/seckey.c b/lib/cryptohi/seckey.c +--- a/lib/cryptohi/seckey.c ++++ b/lib/cryptohi/seckey.c +@@ -639,6 +639,11 @@ seckey_ExtractPublicKey(const CERTSubjec + return pubk; + break; + case SEC_OID_ANSIX962_EC_PUBLIC_KEY: ++ /* A basic sanity check on inputs. */ ++ if (spki->algorithm.parameters.len == 0 || newOs.len == 0) { ++ PORT_SetError(SEC_ERROR_INPUT_LEN); ++ break; ++ } + pubk->keyType = ecKey; + pubk->u.ec.size = 0; + +diff --git a/lib/freebl/dh.c b/lib/freebl/dh.c +--- a/lib/freebl/dh.c ++++ b/lib/freebl/dh.c +@@ -210,7 +210,8 @@ DH_Derive(SECItem *publicValue, + unsigned int len = 0; + unsigned int nb; + unsigned char *secret = NULL; +- if (!publicValue || !prime || !privateValue || !derivedSecret) { ++ if (!publicValue || !publicValue->len || !prime || !prime->len || ++ !privateValue || !privateValue->len || !derivedSecret) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } +diff --git a/lib/freebl/ec.c b/lib/freebl/ec.c +--- a/lib/freebl/ec.c ++++ b/lib/freebl/ec.c +@@ -202,8 +202,8 @@ ec_NewKey(ECParams *ecParams, ECPrivateK + #endif + MP_DIGITS(&k) = 0; + +- if (!ecParams || !privKey || !privKeyBytes || (privKeyLen < 0) || +- !ecParams->name) { ++ if (!ecParams || ecParams->name == ECCurve_noName || ++ !privKey || !privKeyBytes || privKeyLen <= 0) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } +@@ -391,7 +391,7 @@ EC_NewKey(ECParams *ecParams, ECPrivateK + int len; + unsigned char *privKeyBytes = NULL; + +- if (!ecParams) { ++ if (!ecParams || ecParams->name == ECCurve_noName || !privKey) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } +@@ -430,7 +430,8 @@ EC_ValidatePublicKey(ECParams *ecParams, + mp_err err = MP_OKAY; + int len; + +- if (!ecParams || !publicValue || !ecParams->name) { ++ if (!ecParams || ecParams->name == ECCurve_noName || ++ !publicValue || !publicValue->len) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } +@@ -536,8 +537,9 @@ ECDH_Derive(SECItem *publicValue, + int i; + #endif + +- if (!publicValue || !ecParams || !privateValue || !derivedSecret || +- !ecParams->name) { ++ if (!publicValue || !publicValue->len || ++ !ecParams || ecParams->name == ECCurve_noName || ++ !privateValue || !privateValue->len || !derivedSecret) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } +diff --git a/lib/util/quickder.c b/lib/util/quickder.c +--- a/lib/util/quickder.c ++++ b/lib/util/quickder.c +@@ -757,6 +757,13 @@ DecodeItem(void* dest, + } + + case SEC_ASN1_BIT_STRING: { ++ /* Can't be 8 or more spare bits, or any spare bits ++ * if there are no octets. */ ++ if (temp.data[0] >= 8 || (temp.data[0] > 0 && temp.len == 1)) { ++ PORT_SetError(SEC_ERROR_BAD_DER); ++ rv = SECFailure; ++ break; ++ } + /* change the length in the SECItem to be the number + of bits */ + temp.len = (temp.len - 1) * 8 - (temp.data[0] & 0x7); +# HG changeset patch +# User Kevin Jacobs +# Date 1561145635 0 +# Fri Jun 21 19:33:55 2019 +0000 +# Branch NSS_3_44_BRANCH +# Node ID 416a8f7cf8986103b4d74694aac1198edbb08b3e +# Parent fb9932d6e083322e7b5dfcd3d6e67477e0bb075a +Bug 1515342 - Ignore spki decode failures on negative (expect_fail) tests. r=jcj + +Differential Revision: https://phabricator.services.mozilla.com/D35565 + +diff --git a/gtests/pk11_gtest/pk11_curve25519_unittest.cc b/gtests/pk11_gtest/pk11_curve25519_unittest.cc +--- a/gtests/pk11_gtest/pk11_curve25519_unittest.cc ++++ b/gtests/pk11_gtest/pk11_curve25519_unittest.cc +@@ -40,6 +40,9 @@ class Pkcs11Curve25519Test + + ScopedCERTSubjectPublicKeyInfo certSpki( + SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem)); ++ if (!expect_success && !certSpki) { ++ return; ++ } + ASSERT_TRUE(certSpki); + + ScopedSECKEYPublicKey pubKey(SECKEY_ExtractPublicKey(certSpki.get())); diff --git a/SOURCES/nss-leading-zero.patch b/SOURCES/nss-leading-zero.patch new file mode 100644 index 0000000..4ea008c --- /dev/null +++ b/SOURCES/nss-leading-zero.patch @@ -0,0 +1,143 @@ +# HG changeset patch +# User Kevin Jacobs +# Date 1560499074 0 +# Fri Jun 14 07:57:54 2019 +0000 +# Branch NSS_3_44_BRANCH +# Node ID 876bca2723a1f969422edc93e7504420d8331d3c +# Parent 20671f860c2619dc27208d64a84a759fdffc5ed1 +Bug 1540541 - Don't unnecessarily strip leading 0's from key material during PKCS11 import. r=jcj,mt + +Differential Revision: https://phabricator.services.mozilla.com/D31671 + +diff --git a/lib/freebl/ecl/ecp_25519.c b/lib/freebl/ecl/ecp_25519.c +--- a/lib/freebl/ecl/ecp_25519.c ++++ b/lib/freebl/ecl/ecp_25519.c +@@ -114,6 +114,9 @@ ec_Curve25519_pt_mul(SECItem *X, SECItem + } + px = P->data; + } ++ if (k->len != 32) { ++ return SECFailure; ++ } + + SECStatus rv = ec_Curve25519_mul(X->data, k->data, px); + if (NSS_SecureMemcmpZero(X->data, X->len) == 0) { +diff --git a/lib/pk11wrap/pk11akey.c b/lib/pk11wrap/pk11akey.c +--- a/lib/pk11wrap/pk11akey.c ++++ b/lib/pk11wrap/pk11akey.c +@@ -190,7 +190,6 @@ PK11_ImportPublicKey(PK11SlotInfo *slot, + attrs++; + PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL)); + attrs++; +- signedattr = attrs; + PK11_SETATTRS(attrs, CKA_EC_PARAMS, + pubKey->u.ec.DEREncodedParams.data, + pubKey->u.ec.DEREncodedParams.len); +@@ -222,12 +221,14 @@ PK11_ImportPublicKey(PK11SlotInfo *slot, + PORT_SetError(SEC_ERROR_BAD_KEY); + return CK_INVALID_HANDLE; + } +- + templateCount = attrs - theTemplate; +- signedcount = attrs - signedattr; + PORT_Assert(templateCount <= (sizeof(theTemplate) / sizeof(CK_ATTRIBUTE))); +- for (attrs = signedattr; signedcount; attrs++, signedcount--) { +- pk11_SignedToUnsigned(attrs); ++ if (pubKey->keyType != ecKey) { ++ PORT_Assert(signedattr); ++ signedcount = attrs - signedattr; ++ for (attrs = signedattr; signedcount; attrs++, signedcount--) { ++ pk11_SignedToUnsigned(attrs); ++ } + } + rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, theTemplate, + templateCount, isToken, &objectID); +@@ -1074,9 +1075,13 @@ pk11_loadPrivKeyWithFlags(PK11SlotInfo * + &cktrue, &ckfalse); + + /* Not everyone can handle zero padded key values, give +- * them the raw data as unsigned */ +- for (ap = attrs; extra_count; ap++, extra_count--) { +- pk11_SignedToUnsigned(ap); ++ * them the raw data as unsigned. The exception is EC, ++ * where the values are encoded or zero-preserving ++ * per-RFC5915 */ ++ if (privKey->keyType != ecKey) { ++ for (ap = attrs; extra_count; ap++, extra_count--) { ++ pk11_SignedToUnsigned(ap); ++ } + } + + /* now Store the puppies */ +diff --git a/lib/pk11wrap/pk11cert.c b/lib/pk11wrap/pk11cert.c +--- a/lib/pk11wrap/pk11cert.c ++++ b/lib/pk11wrap/pk11cert.c +@@ -184,7 +184,9 @@ PK11_IsUserCert(PK11SlotInfo *slot, CERT + SECKEY_DestroyPublicKey(pubKey); + return PR_FALSE; + } +- pk11_SignedToUnsigned(&theTemplate); ++ if (pubKey->keyType != ecKey) { ++ pk11_SignedToUnsigned(&theTemplate); ++ } + if (pk11_FindObjectByTemplate(slot, &theTemplate, 1) != CK_INVALID_HANDLE) { + SECKEY_DestroyPublicKey(pubKey); + return PR_TRUE; +diff --git a/lib/pk11wrap/pk11pk12.c b/lib/pk11wrap/pk11pk12.c +--- a/lib/pk11wrap/pk11pk12.c ++++ b/lib/pk11wrap/pk11pk12.c +@@ -505,7 +505,7 @@ PK11_ImportAndReturnPrivateKey(PK11SlotI + } + PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); + attrs++; +- signedattr = attrs; ++ /* No signed attrs for EC */ + /* curveOID always is a copy of AlgorithmID.parameters. */ + PK11_SETATTRS(attrs, CKA_EC_PARAMS, lpk->u.ec.curveOID.data, + lpk->u.ec.curveOID.len); +@@ -523,11 +523,12 @@ PK11_ImportAndReturnPrivateKey(PK11SlotI + } + templateCount = attrs - theTemplate; + PORT_Assert(templateCount <= sizeof(theTemplate) / sizeof(CK_ATTRIBUTE)); +- PORT_Assert(signedattr != NULL); +- signedcount = attrs - signedattr; +- +- for (ap = signedattr; signedcount; ap++, signedcount--) { +- pk11_SignedToUnsigned(ap); ++ if (lpk->keyType != ecKey) { ++ PORT_Assert(signedattr); ++ signedcount = attrs - signedattr; ++ for (ap = signedattr; signedcount; ap++, signedcount--) { ++ pk11_SignedToUnsigned(ap); ++ } + } + + rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, +diff --git a/lib/softoken/legacydb/lgattr.c b/lib/softoken/legacydb/lgattr.c +--- a/lib/softoken/legacydb/lgattr.c ++++ b/lib/softoken/legacydb/lgattr.c +@@ -950,9 +950,9 @@ lg_FindECPrivateKeyAttribute(NSSLOWKEYPr + case CKA_UNWRAP: + return LG_CLONE_ATTR(attribute, type, lg_StaticFalseAttr); + case CKA_VALUE: +- return lg_CopyPrivAttrSigned(attribute, type, +- key->u.ec.privateValue.data, +- key->u.ec.privateValue.len, sdbpw); ++ return lg_CopyPrivAttribute(attribute, type, ++ key->u.ec.privateValue.data, ++ key->u.ec.privateValue.len, sdbpw); + case CKA_EC_PARAMS: + return lg_CopyAttributeSigned(attribute, type, + key->u.ec.ecParams.DEREncoding.data, +diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c +--- a/lib/softoken/pkcs11c.c ++++ b/lib/softoken/pkcs11c.c +@@ -7747,7 +7747,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession + + rv = ECDH_Derive(&ecPoint, &privKey->u.ec.ecParams, &ecScalar, + withCofactor, &tmp); +- PORT_Free(ecScalar.data); ++ PORT_ZFree(ecScalar.data, ecScalar.len); + ecScalar.data = NULL; + if (privKey != sourceKey->objectInfo) { + nsslowkey_DestroyPrivateKey(privKey); diff --git a/SOURCES/nss-manpage-fixes.patch b/SOURCES/nss-manpage-fixes.patch deleted file mode 100644 index ae2b2fd..0000000 --- a/SOURCES/nss-manpage-fixes.patch +++ /dev/null @@ -1,170 +0,0 @@ -# HG changeset patch -# User Daiki Ueno -# Date 1544699159 -3600 -# Thu Dec 13 12:05:59 2018 +0100 -# Node ID 0124a811bdf7abfe4bcf135ccc8c719b14db0580 -# Parent 5b2efc615899a283c1ab2e26ddb41684aeae60f0 -Add manual for nss-policy-check - -diff --git a/doc/Makefile b/doc/Makefile ---- a/doc/Makefile -+++ b/doc/Makefile -@@ -21,7 +21,7 @@ all: prepare all-man all-html - prepare: date-and-version - mkdir -p html - mkdir -p nroff -- -+ - clean: - rm -f date.xml version.xml *.tar.bz2 - rm -f html/*.proc -@@ -45,11 +45,11 @@ version.xml: - - nroff/%.1 : %.xml - $(COMPILE.1) $< -- -+ - MANPAGES = \ - nroff/certutil.1 nroff/cmsutil.1 nroff/crlutil.1 nroff/pk12util.1 \ - nroff/modutil.1 nroff/ssltap.1 nroff/derdump.1 nroff/signtool.1 nroff/signver.1 \ --nroff/pp.1 nroff/vfychain.1 nroff/vfyserv.1 -+nroff/pp.1 nroff/vfychain.1 nroff/vfyserv.1 nroff/nss-policy-check.1 - - all-man: prepare $(MANPAGES) - -@@ -64,6 +64,6 @@ html/%.html : %.xml - HTMLPAGES = \ - html/certutil.html html/cmsutil.html html/crlutil.html html/pk12util.html html/modutil.html \ - html/ssltap.html html/derdump.html html/signtool.html html/signver.html html/pp.html \ --html/vfychain.html html/vfyserv.html -+html/vfychain.html html/vfyserv.html html/nss-policy-check.html - - all-html: prepare $(HTMLPAGES) -diff --git a/doc/certutil.xml b/doc/certutil.xml ---- a/doc/certutil.xml -+++ b/doc/certutil.xml -@@ -180,6 +180,10 @@ For certificate requests, ASCII output d - - - -+ --simple-self-signed -+ When printing the certificate chain, don't search for a chain if issuer name equals to subject name. -+ -+ - -b validity-time - Specify a time at which a certificate is required to be valid. Use when checking certificate validity with the option. The format of the validity-time argument is YYMMDDHHMMSS[+HHMM|-HHMM|Z], which allows offsets to be set relative to the validity end time. Specifying seconds (SS) is optional. When specifying an explicit time, use a Z at the end of the term, YYMMDDHHMMSSZ, to close it. When specifying an offset time, use YYMMDDHHMMSS+HHMM or YYMMDDHHMMSS-HHMM for adding or subtracting time, respectively. - -diff --git a/doc/nss-policy-check.xml b/doc/nss-policy-check.xml -new file mode 100644 ---- /dev/null -+++ b/doc/nss-policy-check.xml -@@ -0,0 +1,97 @@ -+ -+ -+ -+]> -+ -+ -+ -+ -+ &date; -+ NSS Security Tools -+ nss-tools -+ &version; -+ -+ -+ -+ NSS-POLICY-CHECK -+ 1 -+ -+ -+ -+ nss-policy-check -+ nss-policy-check policy-file -+ -+ -+ -+ -+ nss-policy-check -+ -+ -+ -+ -+ Description -+ nss-policy-check verifies crypto-policy configuration that controls certain crypto algorithms are allowed/disallowed to use in the NSS library. -+ -+ The crypto-policy configuration can be stored in either a system-wide configuration file, specified with the POLICY_PATH and POLICY_FILE build options, or in the pkcs11.txt in NSS database. -+ -+ -+ -+ Usage and Examples -+ To check the global crypto-policy configuration in /etc/crypto-policies/back-ends/nss.config: -+ -+ $ nss-policy-check /etc/crypto-policies/back-ends/nss.config -+NSS-POLICY-INFO: LOADED-SUCCESSFULLY -+NSS-POLICY-INFO: PRIME256V1 is enabled for KX -+NSS-POLICY-INFO: PRIME256V1 is enabled for CERT-SIGNATURE -+NSS-POLICY-INFO: SECP256R1 is enabled for KX -+NSS-POLICY-INFO: SECP256R1 is enabled for CERT-SIGNATURE -+NSS-POLICY-INFO: SECP384R1 is enabled for KX -+NSS-POLICY-INFO: SECP384R1 is enabled for CERT-SIGNATURE -+... -+NSS-POLICY-INFO: NUMBER-OF-SSL-ALG-KX: 13 -+NSS-POLICY-INFO: NUMBER-OF-SSL-ALG: 9 -+NSS-POLICY-INFO: NUMBER-OF-CERT-SIG: 9 -+... -+NSS-POLICY-INFO: ciphersuite TLS_AES_128_GCM_SHA256 is enabled -+NSS-POLICY-INFO: ciphersuite TLS_CHACHA20_POLY1305_SHA256 is enabled -+NSS-POLICY-INFO: ciphersuite TLS_AES_256_GCM_SHA384 is enabled -+... -+NSS-POLICY-INFO: NUMBER-OF-CIPHERSUITES: 24 -+NSS-POLICY-INFO: NUMBER-OF-TLS-VERSIONS: 3 -+NSS-POLICY-INFO: NUMBER-OF-DTLS-VERSIONS: 2 -+ -+ If there is a failure or warning, it will be prefixed with -+ NSS-POLICY-FAIL or NSS-POLICY_WARN. -+ -+ nss-policy-check exits with 2 if any -+ failure is found, 1 if any warning is found, or 0 if no errors are -+ found. -+ -+ -+ -+ -+ Additional Resources -+ For information about NSS and other tools related to NSS (like JSS), check out the NSS project wiki at http://www.mozilla.org/projects/security/pki/nss/. The NSS site relates directly to NSS code changes and releases. -+ Mailing lists: https://lists.mozilla.org/listinfo/dev-tech-crypto -+ IRC: Freenode at #dogtag-pki -+ -+ -+ -+ -+ Authors -+ The NSS tools were written and maintained by developers with Netscape, Red Hat, Sun, Oracle, Mozilla, and Google. -+ -+ Authors: Elio Maldonado <emaldona@redhat.com>, Deon Lackey <dlackey@redhat.com>. -+ -+ -+ -+ -+ -+ LICENSE -+ Licensed under 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/. -+ -+ -+ -+ -diff --git a/doc/pk12util.xml b/doc/pk12util.xml ---- a/doc/pk12util.xml -+++ b/doc/pk12util.xml -@@ -108,7 +108,7 @@ - - - -- -n | --cert-key-len certKeyLength -+ --cert-key-len certKeyLength - Specify the desired length of the symmetric key to be used to encrypt the certificates and other meta-data. - - diff --git a/SOURCES/nss-module-leak.patch b/SOURCES/nss-module-leak.patch new file mode 100644 index 0000000..7acf3f3 --- /dev/null +++ b/SOURCES/nss-module-leak.patch @@ -0,0 +1,35 @@ +# HG changeset patch +# User Daiki Ueno +# Date 1557150127 -7200 +# Mon May 06 15:42:07 2019 +0200 +# Node ID 438ac983bda9ec7944990d22a37877e9111caa90 +# Parent b018f3e84d87cce99a1fd81feeecb31123058687 +pk11slot: reference module from slot for finalization + +diff --git a/lib/pk11wrap/pk11slot.c b/lib/pk11wrap/pk11slot.c +--- a/lib/pk11wrap/pk11slot.c ++++ b/lib/pk11wrap/pk11slot.c +@@ -1439,6 +1439,11 @@ PK11_InitSlot(SECMODModule *mod, CK_SLOT + slot->slotID = slotID; + slot->isThreadSafe = mod->isThreadSafe; + slot->hasRSAInfo = PR_FALSE; ++ slot->module = mod; /* NOTE: we don't make a reference here because ++ * modules have references to their slots. This ++ * works because modules keep implicit references ++ * from their slots, and won't unload and disappear ++ * until all their slots have been freed */ + + if (PK11_GETTAB(slot)->C_GetSlotInfo(slotID, &slotInfo) != CKR_OK) { + slot->disabled = PR_TRUE; +@@ -1448,11 +1453,6 @@ PK11_InitSlot(SECMODModule *mod, CK_SLOT + + /* test to make sure claimed mechanism work */ + slot->needTest = mod->internal ? PR_FALSE : PR_TRUE; +- slot->module = mod; /* NOTE: we don't make a reference here because +- * modules have references to their slots. This +- * works because modules keep implicit references +- * from their slots, and won't unload and disappear +- * until all their slots have been freed */ + (void)PK11_MakeString(NULL, slot->slot_name, + (char *)slotInfo.slotDescription, sizeof(slotInfo.slotDescription)); + slot->isHW = (PRBool)((slotInfo.flags & CKF_HW_SLOT) == CKF_HW_SLOT); diff --git a/SOURCES/nss-mpi-loop.patch b/SOURCES/nss-mpi-loop.patch new file mode 100644 index 0000000..d919a5e --- /dev/null +++ b/SOURCES/nss-mpi-loop.patch @@ -0,0 +1,24 @@ +# HG changeset patch +# User Greg Rubin +# Date 1558464083 25200 +# Tue May 21 11:41:23 2019 -0700 +# Branch NSS_3_44_BRANCH +# Node ID 1eac9016c021055018389a5cb117678ecc61782a +# Parent 416a8f7cf8986103b4d74694aac1198edbb08b3e +Bug 1554336 - Optimize away unneeded loop in mpi.c r=kevinjacobs,jcj + +diff --git a/lib/freebl/mpi/mpi.c b/lib/freebl/mpi/mpi.c +--- a/lib/freebl/mpi/mpi.c ++++ b/lib/freebl/mpi/mpi.c +@@ -2063,7 +2063,10 @@ s_mp_almost_inverse(const mp_int *a, con + } + } + if (res >= 0) { +- while (MP_SIGN(c) != MP_ZPOS) { ++ if (mp_cmp_mag(c, p) >= 0) { ++ MP_CHECKOK(mp_div(c, p, NULL, c)); ++ } ++ if (MP_SIGN(c) != MP_ZPOS) { + MP_CHECKOK(mp_add(c, p, c)); + } + res = k; diff --git a/SOURCES/nss-post-handshake-auth-with-tickets.patch b/SOURCES/nss-post-handshake-auth-with-tickets.patch new file mode 100644 index 0000000..ac51f07 --- /dev/null +++ b/SOURCES/nss-post-handshake-auth-with-tickets.patch @@ -0,0 +1,96 @@ +# HG changeset patch +# User Daiki Ueno +# Date 1559121620 -7200 +# Wed May 29 11:20:20 2019 +0200 +# Node ID 29a48b604602a523defd6f9322a5adeca7e284a5 +# Parent 43a7fb4f994a31222c308113b0fccdd5480d5b8e +Bug 1553443, send session ticket only after handshake is marked as finished + +Reviewers: mt + +Reviewed By: mt + +Bug #: 1553443 + +Differential Revision: https://phabricator.services.mozilla.com/D32128 + +diff --git a/gtests/ssl_gtest/ssl_auth_unittest.cc b/gtests/ssl_gtest/ssl_auth_unittest.cc +--- a/gtests/ssl_gtest/ssl_auth_unittest.cc ++++ b/gtests/ssl_gtest/ssl_auth_unittest.cc +@@ -537,6 +537,40 @@ TEST_F(TlsConnectStreamTls13, PostHandsh + capture_cert_req->buffer().len())); + } + ++// Check if post-handshake auth still works when session tickets are enabled: ++// https://bugzilla.mozilla.org/show_bug.cgi?id=1553443 ++TEST_F(TlsConnectStreamTls13, PostHandshakeAuthWithSessionTicketsEnabled) { ++ EnsureTlsSetup(); ++ client_->SetupClientAuth(); ++ EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(), ++ SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE)); ++ EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(), ++ SSL_ENABLE_SESSION_TICKETS, PR_TRUE)); ++ EXPECT_EQ(SECSuccess, SSL_OptionSet(server_->ssl_fd(), ++ SSL_ENABLE_SESSION_TICKETS, PR_TRUE)); ++ size_t called = 0; ++ server_->SetAuthCertificateCallback( ++ [&called](TlsAgent*, PRBool, PRBool) -> SECStatus { ++ called++; ++ return SECSuccess; ++ }); ++ Connect(); ++ EXPECT_EQ(0U, called); ++ // Send CertificateRequest. ++ EXPECT_EQ(SECSuccess, SSL_GetClientAuthDataHook( ++ client_->ssl_fd(), GetClientAuthDataHook, nullptr)); ++ EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd())) ++ << "Unexpected error: " << PORT_ErrorToName(PORT_GetError()); ++ server_->SendData(50); ++ client_->ReadBytes(50); ++ client_->SendData(50); ++ server_->ReadBytes(50); ++ EXPECT_EQ(1U, called); ++ ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd())); ++ ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd())); ++ EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert)); ++} ++ + // In TLS 1.3, the client sends its cert rejection on the + // second flight, and since it has already received the + // server's Finished, it transitions to complete and +diff --git a/lib/ssl/tls13con.c b/lib/ssl/tls13con.c +--- a/lib/ssl/tls13con.c ++++ b/lib/ssl/tls13con.c +@@ -4561,6 +4561,11 @@ tls13_ServerHandleFinished(sslSocket *ss + return SECFailure; + } + ++ rv = tls13_FinishHandshake(ss); ++ if (rv != SECSuccess) { ++ return SECFailure; ++ } ++ + ssl_GetXmitBufLock(ss); + if (ss->opt.enableSessionTickets) { + rv = tls13_SendNewSessionTicket(ss, NULL, 0); +@@ -4573,8 +4578,7 @@ tls13_ServerHandleFinished(sslSocket *ss + } + } + ssl_ReleaseXmitBufLock(ss); +- +- return tls13_FinishHandshake(ss); ++ return SECSuccess; + + loser: + ssl_ReleaseXmitBufLock(ss); +diff --git a/tests/ssl/sslauth.txt b/tests/ssl/sslauth.txt +--- a/tests/ssl/sslauth.txt ++++ b/tests/ssl/sslauth.txt +@@ -42,6 +42,7 @@ + noECC 0 -r_-r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_TestUser_-w_nss TLS 1.3 Require client auth on post hs (client auth) + noECC 0 -r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_none_-w_nss TLS 1.3 Request don't require client auth on post hs (client does not provide auth) + noECC 1 -r_-r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_none_-w_nss TLS 1.3 Require client auth on post hs (client does not provide auth) ++ noECC 0 -r_-r_-r_-E_-u -V_tls1.3:tls1.3_-E_-n_TestUser_-w_nss TLS 1.3 Request don't require client auth on post hs with session ticket (client auth) + # + # Use EC cert for client authentication + # diff --git a/SOURCES/nss-skip-sysinit-gtests.patch b/SOURCES/nss-skip-sysinit-gtests.patch new file mode 100644 index 0000000..4c3ea29 --- /dev/null +++ b/SOURCES/nss-skip-sysinit-gtests.patch @@ -0,0 +1,11 @@ +diff -up nss/gtests/manifest.mn.skip-sysinit-gtests nss/gtests/manifest.mn +--- nss/gtests/manifest.mn.skip-sysinit-gtests 2019-04-26 12:55:05.979302035 +0200 ++++ nss/gtests/manifest.mn 2019-04-26 12:55:09.507228984 +0200 +@@ -27,7 +27,6 @@ NSS_SRCDIRS = \ + smime_gtest \ + softoken_gtest \ + ssl_gtest \ +- $(SYSINIT_GTEST) \ + nss_bogo_shim \ + $(NULL) + endif diff --git a/SOURCES/nss-skip-tls13-fips.patch b/SOURCES/nss-skip-tls13-fips.patch new file mode 100644 index 0000000..4a7c707 --- /dev/null +++ b/SOURCES/nss-skip-tls13-fips.patch @@ -0,0 +1,27 @@ +# HG changeset patch +# User Daiki Ueno +# Date 1558341826 -7200 +# Mon May 20 10:43:46 2019 +0200 +# Node ID b447f0046807b718d2928d0e33313620d38a287a +# Parent 02ea5f29ac3c1f1c6e6eb4b655afd9b4fc075a9e +tests: skip TLS 1.3 tests under FIPS mode + +diff --git a/tests/ssl/ssl.sh b/tests/ssl/ssl.sh +--- a/tests/ssl/ssl.sh ++++ b/tests/ssl/ssl.sh +@@ -393,6 +393,15 @@ ssl_auth() + echo "${testname}" | grep "TLS 1.3" > /dev/null + TLS13=$? + ++ # Currently TLS 1.3 tests are known to fail under FIPS mode, ++ # because HKDF is implemented using the PKCS #11 functions ++ # prohibited under FIPS mode. ++ if [ "${TLS13}" -eq 0 ] && \ ++ [ "$SERVER_MODE" = "fips" -o "$CLIENT_MODE" = "fips" ] ; then ++ echo "$SCRIPTNAME: skipping $testname (non-FIPS only)" ++ continue ++ fi ++ + if [ "${CLIENT_MODE}" = "fips" -a "${CAUTH}" -eq 0 ] ; then + echo "$SCRIPTNAME: skipping $testname (non-FIPS only)" + elif [ "$ectype" = "SNI" -a "$NORM_EXT" = "Extended Test" ] ; then diff --git a/SOURCES/nss-softokn-fips-update.patch b/SOURCES/nss-softokn-fips-update.patch new file mode 100644 index 0000000..604b947 --- /dev/null +++ b/SOURCES/nss-softokn-fips-update.patch @@ -0,0 +1,1148 @@ +diff --git a/lib/freebl/fipsfreebl.c b/lib/freebl/fipsfreebl.c +--- a/lib/freebl/fipsfreebl.c ++++ b/lib/freebl/fipsfreebl.c +@@ -10,18 +10,20 @@ + #ifdef FREEBL_NO_DEPEND + #include "stubs.h" + #endif + + #include "blapi.h" + #include "seccomon.h" /* Required for RSA and DSA. */ + #include "secerr.h" + #include "prtypes.h" ++#include "secitem.h" ++#include "pkcs11t.h" + +-#include "ec.h" /* Required for ECDSA */ ++#include "ec.h" /* Required for EC */ + + /* + * different platforms have different ways of calling and initial entry point + * when the dll/.so is loaded. Most platforms support either a posix pragma + * or the GCC attribute. Some platforms suppor a pre-defined name, and some + * platforms have a link line way of invoking this function. + */ + +@@ -283,61 +285,88 @@ freebl_fips_AES_PowerUpSelfTest(int aes_ + + /* AES-CBC Known Initialization Vector (128-bits). */ + static const PRUint8 aes_cbc_known_initialization_vector[] = + { "SecurityytiruceS" }; + + /* AES Known Plaintext (128-bits). (blocksize is 128-bits) */ + static const PRUint8 aes_known_plaintext[] = { "NetscapeepacsteN" }; + ++ static const PRUint8 aes_gcm_known_aad[] = { "MozillaallizoM" }; ++ + /* AES Known Ciphertext (128-bit key). */ + static const PRUint8 aes_ecb128_known_ciphertext[] = { + 0x3c, 0xa5, 0x96, 0xf3, 0x34, 0x6a, 0x96, 0xc1, + 0x03, 0x88, 0x16, 0x7b, 0x20, 0xbf, 0x35, 0x47 + }; + + static const PRUint8 aes_cbc128_known_ciphertext[] = { + 0xcf, 0x15, 0x1d, 0x4f, 0x96, 0xe4, 0x4f, 0x63, + 0x15, 0x54, 0x14, 0x1d, 0x4e, 0xd8, 0xd5, 0xea + }; + ++ static const PRUint8 aes_gcm128_known_ciphertext[] = { ++ 0x63, 0xf4, 0x95, 0x28, 0xe6, 0x78, 0xee, 0x6e, ++ 0x4f, 0xe0, 0xfc, 0x8d, 0xd7, 0xa2, 0xb1, 0xff, ++ 0x0c, 0x97, 0x1b, 0x0a, 0xdd, 0x97, 0x75, 0xed, ++ 0x8b, 0xde, 0xbf, 0x16, 0x5e, 0x57, 0x6b, 0x4f ++ }; ++ + /* AES Known Ciphertext (192-bit key). */ + static const PRUint8 aes_ecb192_known_ciphertext[] = { + 0xa0, 0x18, 0x62, 0xed, 0x88, 0x19, 0xcb, 0x62, + 0x88, 0x1d, 0x4d, 0xfe, 0x84, 0x02, 0x89, 0x0e + }; + + static const PRUint8 aes_cbc192_known_ciphertext[] = { + 0x83, 0xf7, 0xa4, 0x76, 0xd1, 0x6f, 0x07, 0xbe, + 0x07, 0xbc, 0x43, 0x2f, 0x6d, 0xad, 0x29, 0xe1 + }; + ++ static const PRUint8 aes_gcm192_known_ciphertext[] = { ++ 0xc1, 0x0b, 0x92, 0x1d, 0x68, 0x21, 0xf4, 0x25, ++ 0x41, 0x61, 0x20, 0x2d, 0x59, 0x7f, 0x53, 0xde, ++ 0x93, 0x39, 0xab, 0x09, 0x76, 0x41, 0x57, 0x2b, ++ 0x90, 0x2e, 0x44, 0xbb, 0x52, 0x03, 0xe9, 0x07 ++ }; ++ + /* AES Known Ciphertext (256-bit key). */ + static const PRUint8 aes_ecb256_known_ciphertext[] = { + 0xdb, 0xa6, 0x52, 0x01, 0x8a, 0x70, 0xae, 0x66, + 0x3a, 0x99, 0xd8, 0x95, 0x7f, 0xfb, 0x01, 0x67 + }; + + static const PRUint8 aes_cbc256_known_ciphertext[] = { + 0x37, 0xea, 0x07, 0x06, 0x31, 0x1c, 0x59, 0x27, + 0xc5, 0xc5, 0x68, 0x71, 0x6e, 0x34, 0x40, 0x16 + }; + ++ static const PRUint8 aes_gcm256_known_ciphertext[] = { ++ 0x5d, 0x9e, 0xd2, 0xa2, 0x74, 0x9c, 0xd9, 0x1c, ++ 0xd1, 0xc9, 0xee, 0x5d, 0xb6, 0xf2, 0xc9, 0xb6, ++ 0x79, 0x27, 0x53, 0x02, 0xa3, 0xdc, 0x22, 0xce, ++ 0xf4, 0xb0, 0xc1, 0x8c, 0x86, 0x51, 0xf5, 0xa1 ++ }; ++ + const PRUint8 *aes_ecb_known_ciphertext = + (aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_ecb128_known_ciphertext : (aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_ecb192_known_ciphertext : aes_ecb256_known_ciphertext; + + const PRUint8 *aes_cbc_known_ciphertext = + (aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_cbc128_known_ciphertext : (aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_cbc192_known_ciphertext : aes_cbc256_known_ciphertext; + ++ const PRUint8 *aes_gcm_known_ciphertext = ++ (aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_gcm128_known_ciphertext : (aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_gcm192_known_ciphertext : aes_gcm256_known_ciphertext; ++ + /* AES variables. */ +- PRUint8 aes_computed_ciphertext[FIPS_AES_ENCRYPT_LENGTH]; +- PRUint8 aes_computed_plaintext[FIPS_AES_DECRYPT_LENGTH]; ++ PRUint8 aes_computed_ciphertext[FIPS_AES_ENCRYPT_LENGTH * 2]; ++ PRUint8 aes_computed_plaintext[FIPS_AES_DECRYPT_LENGTH * 2]; + AESContext *aes_context; + unsigned int aes_bytes_encrypted; + unsigned int aes_bytes_decrypted; ++ CK_GCM_PARAMS gcmParams; + SECStatus aes_status; + + /*check if aes_key_size is 128, 192, or 256 bits */ + if ((aes_key_size != FIPS_AES_128_KEY_SIZE) && + (aes_key_size != FIPS_AES_192_KEY_SIZE) && + (aes_key_size != FIPS_AES_256_KEY_SIZE)) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return (SECFailure); +@@ -450,16 +479,79 @@ freebl_fips_AES_PowerUpSelfTest(int aes_ + if ((aes_status != SECSuccess) || + (aes_bytes_decrypted != FIPS_AES_DECRYPT_LENGTH) || + (PORT_Memcmp(aes_computed_plaintext, aes_known_plaintext, + FIPS_AES_DECRYPT_LENGTH) != 0)) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return (SECFailure); + } + ++ /******************************************************/ ++ /* AES-GCM Single-Round Known Answer Encryption Test. */ ++ /******************************************************/ ++ ++ gcmParams.pIv = (PRUint8 *)aes_cbc_known_initialization_vector; ++ gcmParams.ulIvLen = FIPS_AES_BLOCK_SIZE; ++ gcmParams.pAAD = (PRUint8 *)aes_gcm_known_aad; ++ gcmParams.ulAADLen = sizeof(aes_gcm_known_aad); ++ gcmParams.ulTagBits = FIPS_AES_BLOCK_SIZE * 8; ++ aes_context = AES_CreateContext(aes_known_key, ++ (PRUint8 *)&gcmParams, ++ NSS_AES_GCM, PR_TRUE, aes_key_size, ++ FIPS_AES_BLOCK_SIZE); ++ ++ if (aes_context == NULL) { ++ PORT_SetError(SEC_ERROR_NO_MEMORY); ++ return (SECFailure); ++ } ++ ++ aes_status = AES_Encrypt(aes_context, aes_computed_ciphertext, ++ &aes_bytes_encrypted, FIPS_AES_ENCRYPT_LENGTH * 2, ++ aes_known_plaintext, ++ FIPS_AES_DECRYPT_LENGTH); ++ ++ AES_DestroyContext(aes_context, PR_TRUE); ++ ++ if ((aes_status != SECSuccess) || ++ (aes_bytes_encrypted != FIPS_AES_ENCRYPT_LENGTH * 2) || ++ (PORT_Memcmp(aes_computed_ciphertext, aes_gcm_known_ciphertext, ++ FIPS_AES_ENCRYPT_LENGTH * 2) != 0)) { ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); ++ return (SECFailure); ++ } ++ ++ /******************************************************/ ++ /* AES-GCM Single-Round Known Answer Decryption Test. */ ++ /******************************************************/ ++ ++ aes_context = AES_CreateContext(aes_known_key, ++ (PRUint8 *)&gcmParams, ++ NSS_AES_GCM, PR_FALSE, aes_key_size, ++ FIPS_AES_BLOCK_SIZE); ++ ++ if (aes_context == NULL) { ++ PORT_SetError(SEC_ERROR_NO_MEMORY); ++ return (SECFailure); ++ } ++ ++ aes_status = AES_Decrypt(aes_context, aes_computed_plaintext, ++ &aes_bytes_decrypted, FIPS_AES_DECRYPT_LENGTH * 2, ++ aes_gcm_known_ciphertext, ++ FIPS_AES_ENCRYPT_LENGTH * 2); ++ ++ AES_DestroyContext(aes_context, PR_TRUE); ++ ++ if ((aes_status != SECSuccess) || ++ (aes_bytes_decrypted != FIPS_AES_DECRYPT_LENGTH) || ++ (PORT_Memcmp(aes_computed_plaintext, aes_known_plaintext, ++ FIPS_AES_DECRYPT_LENGTH) != 0)) { ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); ++ return (SECFailure); ++ } ++ + return (SECSuccess); + } + + /* Known Hash Message (512-bits). Used for all hashes (incl. SHA-N [N>1]). */ + static const PRUint8 known_hash_message[] = { + "The test message for the MD2, MD5, and SHA-1 hashing algorithms." + }; + +@@ -1089,17 +1181,17 @@ freebl_fips_ECDSA_Test(ECParams *ecparam + 0x7b, 0x5a, 0x3b, 0x76, 0x4e, 0x7b, 0x7c, 0xbc, + 0xf2, 0x76, 0x1c, 0x1c, 0x7f, 0xc5, 0x53, 0x2f + }; + + static const PRUint8 msg[] = { + "Firefox and ThunderBird are awesome!" + }; + +- unsigned char sha1[SHA1_LENGTH]; /* SHA-1 hash (160 bits) */ ++ unsigned char sha256[SHA256_LENGTH]; /* SHA-256 hash (256 bits) */ + unsigned char sig[2 * MAX_ECKEY_LEN]; + SECItem signature, digest; + ECPrivateKey *ecdsa_private_key = NULL; + ECPublicKey ecdsa_public_key; + SECStatus ecdsaStatus = SECSuccess; + + /* Generates a new EC key pair. The private key is a supplied + * random value (in seed) and the public key is the result of +@@ -1131,23 +1223,23 @@ freebl_fips_ECDSA_Test(ECParams *ecparam + if (ecdsaStatus != SECSuccess) { + goto loser; + } + + /***************************************************/ + /* ECDSA Single-Round Known Answer Signature Test. */ + /***************************************************/ + +- ecdsaStatus = SHA1_HashBuf(sha1, msg, sizeof msg); ++ ecdsaStatus = SHA256_HashBuf(sha256, msg, sizeof msg); + if (ecdsaStatus != SECSuccess) { + goto loser; + } + digest.type = siBuffer; +- digest.data = sha1; +- digest.len = SHA1_LENGTH; ++ digest.data = sha256; ++ digest.len = SHA256_LENGTH; + + memset(sig, 0, sizeof sig); + signature.type = siBuffer; + signature.data = sig; + signature.len = sizeof sig; + + ecdsaStatus = ECDSA_SignDigestWithSeed(ecdsa_private_key, &signature, + &digest, ecdsa_Known_Seed, sizeof ecdsa_Known_Seed); +@@ -1176,20 +1268,93 @@ loser: + if (ecdsaStatus != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return (SECFailure); + } + return (SECSuccess); + } + + static SECStatus +-freebl_fips_ECDSA_PowerUpSelfTest() ++freebl_fips_ECDH_Test(ECParams *ecparams) + { + +- /* ECDSA Known curve nistp256 == ECCCurve_X9_62_PRIME_256V1 params */ ++ /* ECDH Known result (reused old CAVS vector) */ ++ static const PRUint8 ecdh_known_pub_key_1[] = { ++ EC_POINT_FORM_UNCOMPRESSED, ++ /* pubX */ ++ 0x16, 0x81, 0x32, 0x86, 0xc8, 0xe4, 0x3a, 0x1f, ++ 0x5d, 0xe3, 0x06, 0x22, 0x8b, 0x99, 0x14, 0x25, ++ 0xf7, 0x9c, 0x5b, 0x1e, 0x96, 0x84, 0x85, 0x3b, ++ 0x17, 0xfe, 0xf3, 0x1c, 0x0e, 0xed, 0xc4, 0xce, ++ /* pubY */ ++ 0x7a, 0x44, 0xfe, 0xbd, 0x91, 0x71, 0x7d, 0x73, ++ 0xd9, 0x45, 0xea, 0xae, 0x66, 0x78, 0xfa, 0x6e, ++ 0x46, 0xcd, 0xfa, 0x95, 0x15, 0x47, 0x62, 0x5d, ++ 0xbb, 0x1b, 0x9f, 0xe6, 0x39, 0xfc, 0xfd, 0x47 ++ }; ++ static const PRUint8 ecdh_known_priv_key_2[] = { ++ 0xb4, 0x2a, 0xe3, 0x69, 0x19, 0xec, 0xf0, 0x42, ++ 0x6d, 0x45, 0x8c, 0x94, 0x4a, 0x26, 0xa7, 0x5c, ++ 0xea, 0x9d, 0xd9, 0x0f, 0x59, 0xe0, 0x1a, 0x9d, ++ 0x7c, 0xb7, 0x1c, 0x04, 0x53, 0xb8, 0x98, 0x5a ++ }; ++ static const PRUint8 ecdh_known_hash_result[] = { ++ 0x16, 0xf3, 0x85, 0xa2, 0x41, 0xf3, 0x7f, 0xc4, ++ 0x0b, 0x56, 0x47, 0xee, 0xa7, 0x74, 0xb9, 0xdb, ++ 0xe1, 0xfa, 0x22, 0xe9, 0x04, 0xf1, 0xb6, 0x12, ++ 0x4b, 0x44, 0x8a, 0xbb, 0xbc, 0x08, 0x2b, 0xa7, ++ }; ++ ++ SECItem ecdh_priv_2, ecdh_pub_1; ++ SECItem ZZ = { 0, 0, 0 }; ++ SECStatus ecdhStatus = SECSuccess; ++ PRUint8 computed_hash_result[HASH_LENGTH_MAX]; ++ ++ ecdh_priv_2.data = (PRUint8 *)ecdh_known_priv_key_2; ++ ecdh_priv_2.len = sizeof(ecdh_known_priv_key_2); ++ ecdh_pub_1.data = (PRUint8 *)ecdh_known_pub_key_1; ++ ecdh_pub_1.len = sizeof(ecdh_known_pub_key_1); ++ ++ /* Generates a new EC key pair. The private key is a supplied ++ * random value (in seed) and the public key is the result of ++ * performing a scalar point multiplication of that value with ++ * the curve's base point. ++ */ ++ ecdhStatus = ECDH_Derive(&ecdh_pub_1, ecparams, &ecdh_priv_2, PR_FALSE, &ZZ); ++ if (ecdhStatus != SECSuccess) { ++ goto loser; ++ } ++ ecdhStatus = SHA256_HashBuf(computed_hash_result, ZZ.data, ZZ.len); ++ if (ecdhStatus != SECSuccess) { ++ goto loser; ++ } ++ ++ if (PORT_Memcmp(computed_hash_result, ecdh_known_hash_result, ++ sizeof(ecdh_known_hash_result)) != 0) { ++ ecdhStatus = SECFailure; ++ goto loser; ++ } ++ ++loser: ++ if (ZZ.data) { ++ SECITEM_FreeItem(&ZZ, PR_FALSE); ++ } ++ ++ if (ecdhStatus != SECSuccess) { ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); ++ return (SECFailure); ++ } ++ return (SECSuccess); ++} ++ ++static SECStatus ++freebl_fips_EC_PowerUpSelfTest() ++{ ++ ++ /* EC Known curve nistp256 == ECCCurve_X9_62_PRIME_256V1 params */ + static const unsigned char p256_prime[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + static const unsigned char p256_a[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +@@ -1212,17 +1377,17 @@ freebl_fips_ECDSA_PowerUpSelfTest() + static const unsigned char p256_order[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9, + 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51 + }; + static const unsigned char p256_encoding[] = { + 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07 + }; +- static const ECParams ecdsa_known_P256_Params = { ++ static const ECParams ec_known_P256_Params = { + NULL, ec_params_named, /* arena, type */ + /* fieldID */ + { 256, ec_field_GFp, /* size and type */ + { { siBuffer, (unsigned char *)p256_prime, sizeof(p256_prime) } }, /* u.prime */ + 0, + 0, + 0 }, + /* curve */ +@@ -1245,34 +1410,39 @@ freebl_fips_ECDSA_PowerUpSelfTest() + { siBuffer, (unsigned char *)(p256_encoding) + 2, sizeof(p256_encoding) - 2 }, + }; + + static const PRUint8 ecdsa_known_P256_signature[] = { + 0x07, 0xb1, 0xcb, 0x57, 0x20, 0xa7, 0x10, 0xd6, + 0x9d, 0x37, 0x4b, 0x1c, 0xdc, 0x35, 0x90, 0xff, + 0x1a, 0x2d, 0x98, 0x95, 0x1b, 0x2f, 0xeb, 0x7f, + 0xbb, 0x81, 0xca, 0xc0, 0x69, 0x75, 0xea, 0xc5, +- 0x59, 0x6a, 0x62, 0x49, 0x3d, 0x50, 0xc9, 0xe1, +- 0x27, 0x3b, 0xff, 0x9b, 0x13, 0x66, 0x67, 0xdd, +- 0x7d, 0xd1, 0x0d, 0x2d, 0x7c, 0x44, 0x04, 0x1b, +- 0x16, 0x21, 0x12, 0xc5, 0xcb, 0xbd, 0x9e, 0x75 ++ 0xa7, 0xd2, 0x20, 0xdd, 0x45, 0xf9, 0x2b, 0xdd, ++ 0xda, 0x98, 0x99, 0x5b, 0x1c, 0x02, 0x3a, 0x27, ++ 0x8b, 0x7d, 0xb6, 0xed, 0x0e, 0xe0, 0xa7, 0xac, ++ 0xaa, 0x36, 0x2c, 0xfa, 0x1a, 0xdf, 0x0d, 0xe1, + }; + + ECParams ecparams; + + SECStatus rv; + + /* ECDSA GF(p) prime field curve test */ +- ecparams = ecdsa_known_P256_Params; ++ ecparams = ec_known_P256_Params; + rv = freebl_fips_ECDSA_Test(&ecparams, + ecdsa_known_P256_signature, + sizeof ecdsa_known_P256_signature); + if (rv != SECSuccess) { + return (SECFailure); + } ++ /* ECDH GF(p) prime field curve test */ ++ rv = freebl_fips_ECDH_Test(&ecparams); ++ if (rv != SECSuccess) { ++ return (SECFailure); ++ } + + return (SECSuccess); + } + + static SECStatus + freebl_fips_DSA_PowerUpSelfTest(void) + { + /* DSA Known P (1024-bits), Q (160-bits), and G (1024-bits) Values. */ +@@ -1413,16 +1583,148 @@ freebl_fips_DSA_PowerUpSelfTest(void) + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + return (SECSuccess); + } + + static SECStatus ++freebl_fips_DH_PowerUpSelfTest(void) ++{ ++ /* DH Known P (2048-bits) */ ++ static const PRUint8 dh_known_P[] = { ++ 0xc2, 0x79, 0xbb, 0x76, 0x32, 0x0d, 0x43, 0xfd, ++ 0x1b, 0x8c, 0xa2, 0x3c, 0x00, 0xdd, 0x6d, 0xef, ++ 0xf8, 0x1a, 0xd9, 0xc1, 0xa2, 0xf5, 0x73, 0x2b, ++ 0xdb, 0x1a, 0x3e, 0x84, 0x90, 0xeb, 0xe7, 0x8e, ++ 0x5f, 0x5c, 0x6b, 0xb6, 0x61, 0x89, 0xd1, 0x03, ++ 0xb0, 0x5f, 0x91, 0xe4, 0xd2, 0x82, 0x90, 0xfc, ++ 0x3c, 0x49, 0x69, 0x59, 0xc1, 0x51, 0x6a, 0x85, ++ 0x71, 0xe7, 0x5d, 0x72, 0x5a, 0x45, 0xad, 0x01, ++ 0x6f, 0x82, 0xae, 0xec, 0x91, 0x08, 0x2e, 0x7c, ++ 0x64, 0x93, 0x46, 0x1c, 0x68, 0xef, 0xc2, 0x03, ++ 0x28, 0x1d, 0x75, 0x3a, 0xeb, 0x9c, 0x46, 0xf0, ++ 0xc9, 0xdb, 0x99, 0x95, 0x13, 0x66, 0x4d, 0xd5, ++ 0x1a, 0x78, 0x92, 0x51, 0x89, 0x72, 0x28, 0x7f, ++ 0x20, 0x70, 0x41, 0x49, 0xa2, 0x86, 0xe9, 0xf9, ++ 0x78, 0x5f, 0x8d, 0x2e, 0x5d, 0xfa, 0xdb, 0x57, ++ 0xd4, 0x71, 0xdf, 0x66, 0xe3, 0x9e, 0x88, 0x70, ++ 0xa4, 0x21, 0x44, 0x6a, 0xc7, 0xae, 0x30, 0x2c, ++ 0x9c, 0x1f, 0x91, 0x57, 0xc8, 0x24, 0x34, 0x2d, ++ 0x7a, 0x4a, 0x43, 0xc2, 0x5f, 0xab, 0x64, 0x2e, ++ 0xaa, 0x28, 0x32, 0x95, 0x42, 0x7b, 0xa0, 0xcc, ++ 0xdf, 0xfd, 0x22, 0xc8, 0x56, 0x84, 0xc1, 0x62, ++ 0x15, 0xb2, 0x77, 0x86, 0x81, 0xfc, 0xa5, 0x12, ++ 0x3c, 0xca, 0x28, 0x17, 0x8f, 0x03, 0x16, 0x6e, ++ 0xb8, 0x24, 0xfa, 0x1b, 0x15, 0x02, 0xfd, 0x8b, ++ 0xb6, 0x0a, 0x1a, 0xf7, 0x47, 0x41, 0xc5, 0x2b, ++ 0x37, 0x3e, 0xa1, 0xbf, 0x68, 0xda, 0x1c, 0x55, ++ 0x44, 0xc3, 0xee, 0xa1, 0x63, 0x07, 0x11, 0x3b, ++ 0x5f, 0x00, 0x84, 0xb4, 0xc4, 0xe4, 0xa7, 0x97, ++ 0x29, 0xf8, 0xce, 0xab, 0xfc, 0x27, 0x3e, 0x34, ++ 0xe4, 0xc7, 0x81, 0x52, 0x32, 0x0e, 0x27, 0x3c, ++ 0xa6, 0x70, 0x3f, 0x4a, 0x54, 0xda, 0xdd, 0x60, ++ 0x26, 0xb3, 0x6e, 0x45, 0x26, 0x19, 0x41, 0x6f ++ }; ++ ++ static const PRUint8 dh_known_Y_1[] = { ++ 0xb4, 0xc7, 0x85, 0xba, 0xa6, 0x98, 0xb3, 0x77, ++ 0x41, 0x2b, 0xd9, 0x9a, 0x72, 0x90, 0xa4, 0xac, ++ 0xc4, 0xf7, 0xc2, 0x23, 0x9a, 0x68, 0xe2, 0x7d, ++ 0x3a, 0x54, 0x45, 0x91, 0xc1, 0xd7, 0x8a, 0x17, ++ 0x54, 0xd3, 0x37, 0xaa, 0x0c, 0xcd, 0x0b, 0xe2, ++ 0xf2, 0x34, 0x0f, 0x17, 0xa8, 0x07, 0x88, 0xaf, ++ 0xed, 0xc1, 0x02, 0xd4, 0xdb, 0xdc, 0x0f, 0x22, ++ 0x51, 0x23, 0x40, 0xb9, 0x65, 0x6d, 0x39, 0xf4, ++ 0xe1, 0x8b, 0x57, 0x7d, 0xb6, 0xd3, 0xf2, 0x6b, ++ 0x02, 0xa9, 0x36, 0xf0, 0x0d, 0xe3, 0xdb, 0x9a, ++ 0xbf, 0x20, 0x00, 0x4d, 0xec, 0x6f, 0x68, 0x95, ++ 0xee, 0x59, 0x4e, 0x3c, 0xb6, 0xda, 0x7b, 0x19, ++ 0x08, 0x9a, 0xef, 0x61, 0x43, 0xf5, 0xfb, 0x25, ++ 0x70, 0x19, 0xc1, 0x5f, 0x0e, 0x0f, 0x6a, 0x63, ++ 0x44, 0xe9, 0xcf, 0x33, 0xce, 0x13, 0x4f, 0x34, ++ 0x3c, 0x94, 0x40, 0x8d, 0xf2, 0x65, 0x42, 0xef, ++ 0x70, 0x54, 0xdd, 0x5f, 0xc1, 0xd7, 0x0b, 0xa6, ++ 0x06, 0xd5, 0xa6, 0x47, 0xae, 0x2c, 0x1f, 0x5a, ++ 0xa6, 0xb3, 0xc1, 0x38, 0x3a, 0x3b, 0x60, 0x94, ++ 0xa2, 0x95, 0xab, 0xb2, 0x86, 0x82, 0xc5, 0x3b, ++ 0xb8, 0x6f, 0x3e, 0x55, 0x86, 0x84, 0xe0, 0x00, ++ 0xe5, 0xef, 0xca, 0x5c, 0xec, 0x7e, 0x38, 0x0f, ++ 0x82, 0xa2, 0xb1, 0xee, 0x48, 0x1b, 0x32, 0xbb, ++ 0x5a, 0x33, 0xa5, 0x01, 0xba, 0xca, 0xa6, 0x64, ++ 0x61, 0xb6, 0xe5, 0x5c, 0x0e, 0x5f, 0x2c, 0x66, ++ 0x0d, 0x01, 0x6a, 0x20, 0x04, 0x70, 0x68, 0x82, ++ 0x93, 0x29, 0x15, 0x3b, 0x7a, 0x06, 0xb2, 0x92, ++ 0x61, 0xcd, 0x7e, 0xa4, 0xc1, 0x15, 0x64, 0x3b, ++ 0x3c, 0x51, 0x10, 0x4c, 0x87, 0xa6, 0xaf, 0x07, ++ 0xce, 0x46, 0x82, 0x75, 0xf3, 0x90, 0xf3, 0x21, ++ 0x55, 0x74, 0xc2, 0xe4, 0x96, 0x7d, 0xc3, 0xe6, ++ 0x33, 0xa5, 0xc6, 0x51, 0xef, 0xec, 0x90, 0x08 ++ }; ++ ++ static const PRUint8 dh_known_x_2[] = { ++ 0x9e, 0x9b, 0xc3, 0x25, 0x53, 0xf9, 0xfc, 0x92, ++ 0xb6, 0xae, 0x54, 0x8e, 0x23, 0x4c, 0x94, 0xba, ++ 0x41, 0xe6, 0x29, 0x33, 0xb9, 0xdb, 0xff, 0x6d, ++ 0xa8, 0xb8, 0x48, 0x49, 0x66, 0x11, 0xa6, 0x13 ++ }; ++ ++ static const PRUint8 dh_known_hash_result[] = { ++ 0x93, 0xa2, 0x89, 0x1c, 0x8a, 0xc3, 0x70, 0xbf, ++ 0xa7, 0xdf, 0xb6, 0xd7, 0x82, 0xfb, 0x87, 0x81, ++ 0x09, 0x47, 0xf3, 0x9f, 0x5a, 0xbf, 0x4f, 0x3f, ++ 0x8e, 0x5e, 0x06, 0xca, 0x30, 0xa7, 0xaf, 0x10 ++ }; ++ ++ /* DH variables. */ ++ SECStatus dhStatus; ++ SECItem dh_prime; ++ SECItem dh_pub_key_1; ++ SECItem dh_priv_key_2; ++ SECItem ZZ = { 0, 0, 0 }; ++ PRUint8 computed_hash_result[HASH_LENGTH_MAX]; ++ ++ dh_prime.data = (PRUint8 *)dh_known_P; ++ dh_prime.len = sizeof(dh_known_P); ++ dh_pub_key_1.data = (PRUint8 *)dh_known_Y_1; ++ dh_pub_key_1.len = sizeof(dh_known_Y_1); ++ dh_priv_key_2.data = (PRUint8 *)dh_known_x_2; ++ dh_priv_key_2.len = sizeof(dh_known_x_2); ++ ++ /* execute the derive */ ++ dhStatus = DH_Derive(&dh_pub_key_1, &dh_prime, &dh_priv_key_2, &ZZ, dh_prime.len); ++ if (dhStatus != SECSuccess) { ++ goto loser; ++ } ++ ++ dhStatus = SHA256_HashBuf(computed_hash_result, ZZ.data, ZZ.len); ++ if (dhStatus != SECSuccess) { ++ goto loser; ++ } ++ ++ if (PORT_Memcmp(computed_hash_result, dh_known_hash_result, ++ sizeof(dh_known_hash_result)) != 0) { ++ dhStatus = SECFailure; ++ goto loser; ++ } ++ ++loser: ++ if (ZZ.data) { ++ SECITEM_FreeItem(&ZZ, PR_FALSE); ++ } ++ ++ if (dhStatus != SECSuccess) { ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); ++ return (SECFailure); ++ } ++ return (SECSuccess); ++} ++ ++static SECStatus + freebl_fips_RNG_PowerUpSelfTest(void) + { + static const PRUint8 Q[] = { + 0x85, 0x89, 0x9c, 0x77, 0xa3, 0x79, 0xff, 0x1a, + 0x86, 0x6f, 0x2f, 0x3e, 0x2e, 0xf9, 0x8c, 0x9c, + 0x9d, 0xef, 0xeb, 0xed + }; + static const PRUint8 GENX[] = { +@@ -1536,31 +1838,37 @@ freebl_fipsPowerUpSelfTest(unsigned int + + /* HMAC SHA-X Power-Up SelfTest(s). */ + rv = freebl_fips_HMAC_PowerUpSelfTest(); + + if (rv != SECSuccess) + return rv; + + /* NOTE: RSA can only be tested in full freebl. It requires access to +- * the locking primitives */ ++ * the locking primitives */ + /* RSA Power-Up SelfTest(s). */ + rv = freebl_fips_RSA_PowerUpSelfTest(); + + if (rv != SECSuccess) + return rv; + + /* DSA Power-Up SelfTest(s). */ + rv = freebl_fips_DSA_PowerUpSelfTest(); + + if (rv != SECSuccess) + return rv; + +- /* ECDSA Power-Up SelfTest(s). */ +- rv = freebl_fips_ECDSA_PowerUpSelfTest(); ++ /* DH Power-Up SelfTest(s). */ ++ rv = freebl_fips_DH_PowerUpSelfTest(); ++ ++ if (rv != SECSuccess) ++ return rv; ++ ++ /* EC Power-Up SelfTest(s). */ ++ rv = freebl_fips_EC_PowerUpSelfTest(); + + if (rv != SECSuccess) + return rv; + } + /* Passed Power-Up SelfTest(s). */ + return (SECSuccess); + } + +diff --git a/lib/freebl/intel-gcm-wrap.c b/lib/freebl/intel-gcm-wrap.c +--- a/lib/freebl/intel-gcm-wrap.c ++++ b/lib/freebl/intel-gcm-wrap.c +@@ -138,16 +138,17 @@ intel_AES_GCM_CreateContext(void *contex + loser: + PORT_Free(gcm); + return NULL; + } + + void + intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit) + { ++ PORT_Memset(gcm, 0, sizeof(intel_AES_GCMContext)); + if (freeit) { + PORT_Free(gcm); + } + } + + SECStatus + intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm, + unsigned char *outbuf, +diff --git a/lib/freebl/pqg.c b/lib/freebl/pqg.c +--- a/lib/freebl/pqg.c ++++ b/lib/freebl/pqg.c +@@ -486,21 +486,21 @@ cleanup: + ** Perform steps from FIPS 186-3, Appendix A.1.2.1 and Appendix C.6 + ** + ** This generates a provable prime from two smaller prime. The resulting + ** prime p will have q0 as a multiple of p-1. q0 can be 1. + ** + ** This implments steps 4 thorough 22 of FIPS 186-3 A.1.2.1 and + ** steps 16 through 34 of FIPS 186-2 C.6 + */ +-#define MAX_ST_SEED_BITS (HASH_LENGTH_MAX * PR_BITS_PER_BYTE) + static SECStatus + makePrimefromPrimesShaweTaylor( + HASH_HashType hashtype, /* selected Hashing algorithm */ + unsigned int length, /* input. Length of prime in bits. */ ++ unsigned int seedlen, /* input seed length in bits */ + mp_int *c0, /* seed prime */ + mp_int *q, /* sub prime, can be 1 */ + mp_int *prime, /* output. */ + SECItem *prime_seed, /* input/output. */ + unsigned int *prime_gen_counter) /* input/output. */ + { + mp_int c; + mp_int c0_2; +@@ -552,33 +552,32 @@ makePrimefromPrimesShaweTaylor( + */ + + /* Step 4/16 iterations = ceiling(length/outlen)-1 */ + iterations = (length + outlen - 1) / outlen; /* NOTE: iterations +1 */ + /* Step 5/17 old_counter = prime_gen_counter */ + old_counter = *prime_gen_counter; + /* + ** Comment: Generate a pseudorandom integer x in the interval +- ** [2**(lenght-1), 2**length]. ++ ** [2**(length-1), 2**length]. + ** + ** Step 6/18 x = 0 + */ + PORT_Memset(x, 0, sizeof(x)); + /* + ** Step 7/19 for i = 0 to iterations do + ** x = x + (HASH(prime_seed + i) * 2^(i*outlen)) + */ + for (i = 0; i < iterations; i++) { + /* is bigger than prime_seed should get to */ + CHECK_SEC_OK(addToSeedThenHash(hashtype, prime_seed, i, +- MAX_ST_SEED_BITS, &x[(iterations - i - 1) * hashlen])); ++ seedlen, &x[(iterations - i - 1) * hashlen])); + } + /* Step 8/20 prime_seed = prime_seed + iterations + 1 */ +- CHECK_SEC_OK(addToSeed(prime_seed, iterations, MAX_ST_SEED_BITS, +- prime_seed)); ++ CHECK_SEC_OK(addToSeed(prime_seed, iterations, seedlen, prime_seed)); + /* + ** Step 9/21 x = 2 ** (length-1) + x mod 2 ** (length-1) + ** + ** This step mathematically sets the high bit and clears out + ** all the other bits higher than length. 'x' is stored + ** in the x array, MSB first. The above formula gives us an 'x' + ** which is length bytes long and has the high bit set. We also know + ** that length <= iterations*outlen since +@@ -590,17 +589,17 @@ makePrimefromPrimesShaweTaylor( + * multiple of 8,*/ + bit = 1 << ((length - 1) & 0x7); /* select the proper bit in the byte */ + /* we need to zero out the rest of the bits in the byte above */ + mask = (bit - 1); + /* now we set it */ + x[offset] = (mask & x[offset]) | bit; + /* + ** Comment: Generate a candidate prime c in the interval +- ** [2**(lenght-1), 2**length]. ++ ** [2**(length-1), 2**length]. + ** + ** Step 10 t = ceiling(x/(2q(p0))) + ** Step 22 t = ceiling(x/(2(c0))) + */ + CHECK_MPI_OK(mp_read_unsigned_octets(&t, &x[offset], + hashlen * iterations - offset)); /* t = x */ + CHECK_MPI_OK(mp_mul(c0, q, &c0_2)); /* c0_2 is now c0*q */ + CHECK_MPI_OK(mp_add(&c0_2, &c0_2, &c0_2)); /* c0_2 is now 2*q*c0 */ +@@ -619,17 +618,17 @@ makePrimefromPrimesShaweTaylor( + step_23: + CHECK_MPI_OK(mp_mul(&t, &c0_2, &c)); /* c = t*2qc0 */ + CHECK_MPI_OK(mp_add_d(&c, (mp_digit)1, &c)); /* c= 2tqc0 + 1*/ + if (mpl_significant_bits(&c) > length) { /* if c > 2**length */ + CHECK_MPI_OK(mp_sub_d(&c0_2, (mp_digit)1, &t)); /* t = 2qc0-1 */ + /* t = 2**(length-1) + 2qc0 -1 */ + CHECK_MPI_OK(mp_add(&two_length_minus_1, &t, &t)); + /* t = floor((2**(length-1)+2qc0 -1)/2qco) +- * = ceil(2**(lenght-2)/2qc0) */ ++ * = ceil(2**(length-2)/2qc0) */ + CHECK_MPI_OK(mp_div(&t, &c0_2, &t, NULL)); + CHECK_MPI_OK(mp_mul(&t, &c0_2, &c)); + CHECK_MPI_OK(mp_add_d(&c, (mp_digit)1, &c)); /* c= 2tqc0 + 1*/ + } + /* Step 13/25 prime_gen_counter = prime_gen_counter + 1*/ + (*prime_gen_counter)++; + /* + ** Comment: Test the candidate prime c for primality; first pick an +@@ -640,23 +639,21 @@ step_23: + PORT_Memset(x, 0, sizeof(x)); /* use x for a */ + /* + ** Step 15/27 for i = 0 to iterations do + ** a = a + (HASH(prime_seed + i) * 2^(i*outlen)) + ** + ** NOTE: we reuse the x array for 'a' initially. + */ + for (i = 0; i < iterations; i++) { +- /* MAX_ST_SEED_BITS is bigger than prime_seed should get to */ + CHECK_SEC_OK(addToSeedThenHash(hashtype, prime_seed, i, +- MAX_ST_SEED_BITS, &x[(iterations - i - 1) * hashlen])); ++ seedlen, &x[(iterations - i - 1) * hashlen])); + } + /* Step 16/28 prime_seed = prime_seed + iterations + 1 */ +- CHECK_SEC_OK(addToSeed(prime_seed, iterations, MAX_ST_SEED_BITS, +- prime_seed)); ++ CHECK_SEC_OK(addToSeed(prime_seed, iterations, seedlen, prime_seed)); + /* Step 17/29 a = 2 + (a mod (c-3)). */ + CHECK_MPI_OK(mp_read_unsigned_octets(&a, x, iterations * hashlen)); + CHECK_MPI_OK(mp_sub_d(&c, (mp_digit)3, &z)); /* z = c -3 */ + CHECK_MPI_OK(mp_mod(&a, &z, &a)); /* a = a mod c -3 */ + CHECK_MPI_OK(mp_add_d(&a, (mp_digit)2, &a)); /* a = 2 + a mod c -3 */ + /* + ** Step 18 z = a**(2tq) mod p. + ** Step 30 z = a**(2t) mod c. +@@ -737,16 +734,17 @@ makePrimefromSeedShaweTaylor( + { + mp_int c; + mp_int c0; + mp_int one; + SECStatus rv = SECFailure; + int hashlen = HASH_ResultLen(hashtype); + int outlen = hashlen * PR_BITS_PER_BYTE; + int offset; ++ int seedlen = input_seed->len * 8; /*seedlen is in bits */ + unsigned char bit, mask; + unsigned char x[HASH_LENGTH_MAX * 2]; + mp_digit dummy; + mp_err err = MP_OKAY; + int i; + + MP_DIGITS(&c) = 0; + MP_DIGITS(&c0) = 0; +@@ -770,30 +768,29 @@ makePrimefromSeedShaweTaylor( + */ + rv = makePrimefromSeedShaweTaylor(hashtype, (length + 1) / 2 + 1, + input_seed, &c0, prime_seed, prime_gen_counter); + /* Step 15 if FAILURE is returned, return (FAILURE, 0, 0, 0). */ + if (rv != SECSuccess) { + goto cleanup; + } + /* Steps 16-34 */ +- rv = makePrimefromPrimesShaweTaylor(hashtype, length, &c0, &one, ++ rv = makePrimefromPrimesShaweTaylor(hashtype, length, seedlen, &c0, &one, + prime, prime_seed, prime_gen_counter); + goto cleanup; /* we're done, one way or the other */ + } + /* Step 3 prime_seed = input_seed */ + CHECK_SEC_OK(SECITEM_CopyItem(NULL, prime_seed, input_seed)); + /* Step 4 prime_gen_count = 0 */ + *prime_gen_counter = 0; + + step_5: + /* Step 5 c = Hash(prime_seed) xor Hash(prime_seed+1). */ + CHECK_SEC_OK(HASH_HashBuf(hashtype, x, prime_seed->data, prime_seed->len)); +- CHECK_SEC_OK(addToSeedThenHash(hashtype, prime_seed, 1, +- MAX_ST_SEED_BITS, &x[hashlen])); ++ CHECK_SEC_OK(addToSeedThenHash(hashtype, prime_seed, 1, seedlen, &x[hashlen])); + for (i = 0; i < hashlen; i++) { + x[i] = x[i] ^ x[i + hashlen]; + } + /* Step 6 c = 2**length-1 + c mod 2**length-1 */ + /* This step mathematically sets the high bit and clears out + ** all the other bits higher than length. Right now c is stored + ** in the x array, MSB first. The above formula gives us a c which + ** is length bytes long and has the high bit set. We also know that +@@ -812,17 +809,17 @@ step_5: + /* Step 7 c = c*floor(c/2) + 1 */ + /* set the low bit. much easier to find (the end of the array) */ + x[hashlen - 1] |= 1; + /* now that we've set our bits, we can create our candidate "c" */ + CHECK_MPI_OK(mp_read_unsigned_octets(&c, &x[offset], hashlen - offset)); + /* Step 8 prime_gen_counter = prime_gen_counter + 1 */ + (*prime_gen_counter)++; + /* Step 9 prime_seed = prime_seed + 2 */ +- CHECK_SEC_OK(addToSeed(prime_seed, 2, MAX_ST_SEED_BITS, prime_seed)); ++ CHECK_SEC_OK(addToSeed(prime_seed, 2, seedlen, prime_seed)); + /* Step 10 Perform deterministic primality test on c. For example, since + ** c is small, it's primality can be tested by trial division, See + ** See Appendic C.7. + ** + ** We in fact test with trial division. mpi has a built int trial divider + ** that divides all divisors up to 2^16. + */ + if (prime_tab[prime_tab_size - 1] < 0xFFF1) { +@@ -885,17 +882,18 @@ findQfromSeed( + unsigned int L, /* input. Length of p in bits. */ + unsigned int N, /* input. Length of q in bits. */ + unsigned int g, /* input. Length of seed in bits. */ + const SECItem *seed, /* input. */ + mp_int *Q, /* input. */ + mp_int *Q_, /* output. */ + unsigned int *qseed_len, /* output */ + HASH_HashType *hashtypePtr, /* output. Hash uses */ +- pqgGenType *typePtr) /* output. Generation Type used */ ++ pqgGenType *typePtr, /* output. Generation Type used */ ++ unsigned int *qgen_counter) /* output. q_counter */ + { + HASH_HashType hashtype; + SECItem firstseed = { 0, 0, 0 }; + SECItem qseed = { 0, 0, 0 }; + SECStatus rv; + + *qseed_len = 0; /* only set if FIPS186_3_ST_TYPE */ + +@@ -959,16 +957,17 @@ findQfromSeed( + * accident, someone has been tweeking with the seeds, just + * fail a this point. */ + SECITEM_FreeItem(&qseed, PR_FALSE); + return SECFailure; + } + *qseed_len = qseed.len; + *hashtypePtr = hashtype; + *typePtr = FIPS186_3_ST_TYPE; ++ *qgen_counter = count; + SECITEM_FreeItem(&qseed, PR_FALSE); + return SECSuccess; + } + SECITEM_FreeItem(&qseed, PR_FALSE); + } + /* no hash algorithms found which match seed to Q, fail */ + return SECFailure; + } +@@ -1383,29 +1382,33 @@ step_5: + CHECK_SEC_OK(makePrimefromSeedShaweTaylor(hashtype, N, &firstseed, &Q, + &qseed, &qgen_counter)); + /* Step 3. Use floor(L/2+1) and qseed to generate random prime p0 + * using Appendix C.6 */ + pgen_counter = 0; + CHECK_SEC_OK(makePrimefromSeedShaweTaylor(hashtype, (L + 1) / 2 + 1, + &qseed, &p0, &pseed, &pgen_counter)); + /* Steps 4-22 FIPS 186-3 appendix A.1.2.1.2 */ +- CHECK_SEC_OK(makePrimefromPrimesShaweTaylor(hashtype, L, ++ CHECK_SEC_OK(makePrimefromPrimesShaweTaylor(hashtype, L, seedBytes * 8, + &p0, &Q, &P, &pseed, &pgen_counter)); + + /* combine all the seeds */ +- seed->len = firstseed.len + qseed.len + pseed.len; ++ if ((qseed.len > firstseed.len) || (pseed.len > firstseed.len)) { ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); /* shouldn't happen */ ++ goto cleanup; ++ } ++ seed->len = firstseed.len * 3; /*handle leading zeros in pseed and qseed*/ + seed->data = PORT_ArenaZAlloc(verify->arena, seed->len); + if (seed->data == NULL) { + goto cleanup; + } + PORT_Memcpy(seed->data, firstseed.data, firstseed.len); +- PORT_Memcpy(seed->data + firstseed.len, pseed.data, pseed.len); +- PORT_Memcpy(seed->data + firstseed.len + pseed.len, qseed.data, qseed.len); +- counter = 0; /* (qgen_counter << 16) | pgen_counter; */ ++ PORT_Memcpy(seed->data + 2 * firstseed.len - pseed.len, pseed.data, pseed.len); ++ PORT_Memcpy(seed->data + 3 * firstseed.len - qseed.len, qseed.data, qseed.len); ++ counter = (qgen_counter << 16) | pgen_counter; + + /* we've generated both P and Q now, skip to generating G */ + goto generate_G; + } + /* ****************************************************************** + ** Step 8. (Step 4 in 186-1) + ** "Use a robust primality testing algorithm to test whether q is prime." + ** +@@ -1615,16 +1618,17 @@ PQG_VerifyParams(const PQGParams *params + { + SECStatus rv = SECSuccess; + unsigned int g, n, L, N, offset, outlen; + mp_int p0, P, Q, G, P_, Q_, G_, r, h; + mp_err err = MP_OKAY; + int j; + unsigned int counter_max = 0; /* handle legacy L < 1024 */ + unsigned int qseed_len; ++ unsigned int qgen_counter_ = 0; + SECItem pseed_ = { 0, 0, 0 }; + HASH_HashType hashtype; + pqgGenType type; + + #define CHECKPARAM(cond) \ + if (!(cond)) { \ + *result = SECFailure; \ + goto cleanup; \ +@@ -1694,77 +1698,104 @@ PQG_VerifyParams(const PQGParams *params + CHECKPARAM(mp_cmp_d(&r, 1) == 0); + /* 5. Q is prime */ + CHECKPARAM(mpp_pprime(&Q, prime_testcount_q(L, N)) == MP_YES); + /* 6. P is prime */ + CHECKPARAM(mpp_pprime(&P, prime_testcount_p(L, N)) == MP_YES); + /* Steps 7-12 are done only if the optional PQGVerify is supplied. */ + /* continue processing P */ + /* 7. counter < 4*L */ +- CHECKPARAM((vfy->counter == -1) || (vfy->counter < counter_max)); + /* 8. g >= N and g < 2*L (g is length of seed in bits) */ +- g = vfy->seed.len * 8; +- CHECKPARAM(g >= N && g < counter_max / 2); ++ /* step 7 and 8 are delayed until we determine which type of generation ++ * was used */ + /* 9. Q generated from SEED matches Q in PQGParams. */ + /* This function checks all possible hash and generation types to + * find a Q_ which matches Q. */ ++ g = vfy->seed.len * 8; + CHECKPARAM(findQfromSeed(L, N, g, &vfy->seed, &Q, &Q_, &qseed_len, +- &hashtype, &type) == SECSuccess); ++ &hashtype, &type, &qgen_counter_) == SECSuccess); + CHECKPARAM(mp_cmp(&Q, &Q_) == 0); ++ /* now we can do steps 7 & 8*/ ++ if ((type == FIPS186_1_TYPE) || (type == FIPS186_3_TYPE)) { ++ CHECKPARAM((vfy->counter == -1) || (vfy->counter < counter_max)); ++ CHECKPARAM(g >= N && g < counter_max / 2); ++ } + if (type == FIPS186_3_ST_TYPE) { + SECItem qseed = { 0, 0, 0 }; + SECItem pseed = { 0, 0, 0 }; + unsigned int first_seed_len; +- unsigned int pgen_counter = 0; ++ unsigned int pgen_counter_ = 0; ++ unsigned int qgen_counter = (vfy->counter >> 16) & 0xffff; ++ unsigned int pgen_counter = (vfy->counter) & 0xffff; + + /* extract pseed and qseed from domain_parameter_seed, which is + * first_seed || pseed || qseed. qseed is first_seed + small_integer +- * pseed is qseed + small_integer. This means most of the time ++ * mod the length of first_seed. pseed is qseed + small_integer mod ++ * the length of first_seed. This means most of the time + * first_seed.len == qseed.len == pseed.len. Rarely qseed.len and/or +- * pseed.len will be one greater than first_seed.len, so we can +- * depend on the fact that +- * first_seed.len = floor(domain_parameter_seed.len/3). +- * findQfromSeed returned qseed.len, so we can calculate pseed.len as +- * pseed.len = domain_parameter_seed.len - first_seed.len - qseed.len +- * this is probably over kill, since 99.999% of the time they will all +- * be equal. +- * +- * With the lengths, we can now find the offsets; ++ * pseed.len will be smaller because mpi clamps them. pqgGen ++ * automatically adds the zero pad back though, so we can depend ++ * domain_parameter_seed.len to be a multiple of three. We only have ++ * to deal with the fact that the returned seeds from our functions ++ * could be shorter. ++ * first_seed.len = domain_parameter_seed.len/3 ++ * We can now find the offsets; + * first_seed.data = domain_parameter_seed.data + 0 + * pseed.data = domain_parameter_seed.data + first_seed.len + * qseed.data = domain_parameter_seed.data + * + domain_paramter_seed.len - qseed.len +- * ++ * We deal with pseed possibly having zero pad in the pseed check later. + */ + first_seed_len = vfy->seed.len / 3; + CHECKPARAM(qseed_len < vfy->seed.len); + CHECKPARAM(first_seed_len * 8 > N - 1); +- CHECKPARAM(first_seed_len + qseed_len < vfy->seed.len); ++ CHECKPARAM(first_seed_len * 8 < counter_max / 2); ++ CHECKPARAM(first_seed_len >= qseed_len); + qseed.len = qseed_len; + qseed.data = vfy->seed.data + vfy->seed.len - qseed.len; +- pseed.len = vfy->seed.len - (first_seed_len + qseed_len); ++ pseed.len = first_seed_len; + pseed.data = vfy->seed.data + first_seed_len; + + /* + * now complete FIPS 186-3 A.1.2.1.2. Step 1 was completed + * above in our initial checks, Step 2 was completed by + * findQfromSeed */ + + /* Step 3 (status, c0, prime_seed, prime_gen_counter) = + ** (ST_Random_Prime((ceil(length/2)+1, input_seed) + */ + CHECK_SEC_OK(makePrimefromSeedShaweTaylor(hashtype, (L + 1) / 2 + 1, +- &qseed, &p0, &pseed_, &pgen_counter)); ++ &qseed, &p0, &pseed_, &pgen_counter_)); + /* Steps 4-22 FIPS 186-3 appendix A.1.2.1.2 */ +- CHECK_SEC_OK(makePrimefromPrimesShaweTaylor(hashtype, L, +- &p0, &Q_, &P_, &pseed_, &pgen_counter)); ++ CHECK_SEC_OK(makePrimefromPrimesShaweTaylor(hashtype, L, first_seed_len * 8, ++ &p0, &Q_, &P_, &pseed_, &pgen_counter_)); + CHECKPARAM(mp_cmp(&P, &P_) == 0); + /* make sure pseed wasn't tampered with (since it is part of + * calculating G) */ ++ if (pseed.len > pseed_.len) { ++ /* handle the case of zero pad for pseed */ ++ int extra = pseed.len - pseed_.len; ++ int i; ++ for (i = 0; i < extra; i++) { ++ if (pseed.data[i] != 0) { ++ *result = SECFailure; ++ goto cleanup; ++ } ++ } ++ pseed.data += extra; ++ pseed.len -= extra; ++ /* the rest is handled in the normal compare below */ ++ } + CHECKPARAM(SECITEM_CompareItem(&pseed, &pseed_) == SECEqual); ++ if (vfy->counter != -1) { ++ CHECKPARAM(pgen_counter < counter_max); ++ CHECKPARAM(qgen_counter < counter_max); ++ CHECKPARAM((pgen_counter_ == pgen_counter)); ++ CHECKPARAM((qgen_counter_ == qgen_counter)); ++ } + } else if (vfy->counter == -1) { + /* If counter is set to -1, we are really only verifying G, skip + * the remainder of the checks for P */ + CHECKPARAM(type != FIPS186_1_TYPE); /* we only do this for DSA2 */ + } else { + /* 10. P generated from (L, counter, g, SEED, Q) matches P + * in PQGParams. */ + outlen = HASH_ResultLen(hashtype) * PR_BITS_PER_BYTE; +diff --git a/lib/freebl/rijndael.c b/lib/freebl/rijndael.c +--- a/lib/freebl/rijndael.c ++++ b/lib/freebl/rijndael.c +@@ -1027,23 +1027,25 @@ AES_CreateContext(const unsigned char *k + * AES_DestroyContext + * + * Zero an AES cipher context. If freeit is true, also free the pointer + * to the context. + */ + void + AES_DestroyContext(AESContext *cx, PRBool freeit) + { ++ void *mem = cx->mem; + if (cx->worker_cx && cx->destroy) { + (*cx->destroy)(cx->worker_cx, PR_TRUE); + cx->worker_cx = NULL; + cx->destroy = NULL; + } ++ PORT_Memset(cx, 0, sizeof(AESContext)); + if (freeit) { +- PORT_Free(cx->mem); ++ PORT_Free(mem); + } + } + + /* + * AES_Encrypt + * + * Encrypt an arbitrary-length buffer. The output buffer must already be + * allocated to at least inputLen. +diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c +--- a/lib/softoken/pkcs11c.c ++++ b/lib/softoken/pkcs11c.c +@@ -4708,16 +4708,24 @@ sftk_PairwiseConsistencyCheck(CK_SESSION + pairwise_digest_length, + signature, + &signature_length); + if (crv != CKR_OK) { + PORT_Free(signature); + return crv; + } + ++ /* detect trivial signing transforms */ ++ if (signature_length >= pairwise_digest_length) { ++ if (PORT_Memcmp(known_digest, signature + (signature_length - pairwise_digest_length), pairwise_digest_length) == 0) { ++ PORT_Free(signature); ++ return CKR_DEVICE_ERROR; ++ } ++ } ++ + /* Verify the known hash using the public key. */ + crv = NSC_VerifyInit(hSession, &mech, publicKey->handle); + if (crv != CKR_OK) { + PORT_Free(signature); + return crv; + } + + crv = NSC_Verify(hSession, +@@ -7543,40 +7551,55 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession + SHA512_HashBuf(key_block, (const unsigned char *)att->attrib.pValue, + att->attrib.ulValueLen); + + crv = sftk_forceAttribute(key, CKA_VALUE, key_block, keySize); + break; + + case CKM_DH_PKCS_DERIVE: { + SECItem derived, dhPublic; +- SECItem dhPrime, dhValue; ++ SECItem dhPrime, dhSubPrime, dhValue; + /* sourceKey - values for the local existing low key */ + /* get prime and value attributes */ + crv = sftk_Attribute2SecItem(NULL, &dhPrime, sourceKey, CKA_PRIME); +- if (crv != SECSuccess) ++ if (crv != CKR_OK) + break; + crv = sftk_Attribute2SecItem(NULL, &dhValue, sourceKey, CKA_VALUE); +- if (crv != SECSuccess) { ++ if (crv != CKR_OK) { + PORT_Free(dhPrime.data); + break; + } + + dhPublic.data = pMechanism->pParameter; + dhPublic.len = pMechanism->ulParameterLen; + ++ /* if the caller bothered to provide Q, use Q to validate. ++ * the public key */ ++ crv = sftk_Attribute2SecItem(NULL, &dhSubPrime, sourceKey, CKA_SUBPRIME); ++ if (crv == CKR_OK) { ++ rv = KEA_Verify(&dhPublic, &dhPrime, &dhSubPrime); ++ PORT_Free(dhSubPrime.data); ++ if (rv != SECSuccess) { ++ crv = CKR_ARGUMENTS_BAD; ++ PORT_Free(dhPrime.data); ++ PORT_Free(dhValue.data); ++ break; ++ } ++ } ++ + /* calculate private value - oct */ + rv = DH_Derive(&dhPublic, &dhPrime, &dhValue, &derived, keySize); + + PORT_Free(dhPrime.data); + PORT_Free(dhValue.data); + + if (rv == SECSuccess) { + sftk_forceAttribute(key, CKA_VALUE, derived.data, derived.len); + PORT_ZFree(derived.data, derived.len); ++ crv = CKR_OK; + } else + crv = CKR_HOST_MEMORY; + + break; + } + + case CKM_ECDH1_DERIVE: + case CKM_ECDH1_COFACTOR_DERIVE: { diff --git a/SOURCES/nss-softokn-prelink.conf b/SOURCES/nss-softokn-prelink.conf deleted file mode 100644 index 11d7fb0..0000000 --- a/SOURCES/nss-softokn-prelink.conf +++ /dev/null @@ -1,6 +0,0 @@ --b /lib{,64}/libfreeblpriv3.so --b /lib{,64}/libsoftokn3.so --b /lib{,64}/libnssdbm3.so --b /usr/lib{,64}/libfreeblpriv3.so --b /usr/lib{,64}/libsoftokn3.so --b /usr/lib{,64}/libnssdbm3.so diff --git a/SOURCES/nss-sysinit-userdb.patch b/SOURCES/nss-sysinit-userdb.patch new file mode 100644 index 0000000..7347260 --- /dev/null +++ b/SOURCES/nss-sysinit-userdb.patch @@ -0,0 +1,106 @@ +Index: nss/lib/sysinit/nsssysinit.c +=================================================================== +--- nss.orig/lib/sysinit/nsssysinit.c ++++ nss/lib/sysinit/nsssysinit.c +@@ -36,41 +36,9 @@ testdir(char *dir) + return S_ISDIR(buf.st_mode); + } + +-/** +- * Append given @dir to @path and creates the directory with mode @mode. +- * Returns 0 if successful, -1 otherwise. +- * Assumes that the allocation for @path has sufficient space for @dir +- * to be added. +- */ +-static int +-appendDirAndCreate(char *path, char *dir, mode_t mode) +-{ +- PORT_Strcat(path, dir); +- if (!testdir(path)) { +- if (mkdir(path, mode)) { +- return -1; +- } +- } +- return 0; +-} +- +-#define XDG_NSS_USER_PATH1 "/.local" +-#define XDG_NSS_USER_PATH2 "/share" +-#define XDG_NSS_USER_PATH3 "/pki" +- + #define NSS_USER_PATH1 "/.pki" + #define NSS_USER_PATH2 "/nssdb" +- +-/** +- * Return the path to user's NSS database. +- * We search in the following dirs in order: +- * (1) $HOME/.pki/nssdb; +- * (2) $XDG_DATA_HOME/pki/nssdb if XDG_DATA_HOME is set; +- * (3) $HOME/.local/share/pki/nssdb (default XDG_DATA_HOME value). +- * If (1) does not exist, then the returned dir will be set to either +- * (2) or (3), depending if XDG_DATA_HOME is set. +- */ +-char * ++static char * + getUserDB(void) + { + char *userdir = PR_GetEnvSecure("HOME"); +@@ -81,47 +49,22 @@ getUserDB(void) + } + + nssdir = PORT_Alloc(strlen(userdir) + sizeof(NSS_USER_PATH1) + sizeof(NSS_USER_PATH2)); ++ if (nssdir == NULL) { ++ return NULL; ++ } + PORT_Strcpy(nssdir, userdir); +- PORT_Strcat(nssdir, NSS_USER_PATH1 NSS_USER_PATH2); +- if (testdir(nssdir)) { +- /* $HOME/.pki/nssdb exists */ +- return nssdir; +- } else { +- /* either $HOME/.pki or $HOME/.pki/nssdb does not exist */ ++ /* verify it exists */ ++ if (!testdir(nssdir)) { + PORT_Free(nssdir); +- } +- int size = 0; +- char *xdguserdatadir = PR_GetEnvSecure("XDG_DATA_HOME"); +- if (xdguserdatadir) { +- size = strlen(xdguserdatadir); +- } else { +- size = strlen(userdir) + sizeof(XDG_NSS_USER_PATH1) + sizeof(XDG_NSS_USER_PATH2); +- } +- size += sizeof(XDG_NSS_USER_PATH3) + sizeof(NSS_USER_PATH2); +- +- nssdir = PORT_Alloc(size); +- if (nssdir == NULL) { + return NULL; + } +- +- if (xdguserdatadir) { +- PORT_Strcpy(nssdir, xdguserdatadir); +- if (!testdir(nssdir)) { +- PORT_Free(nssdir); +- return NULL; +- } +- +- } else { +- PORT_Strcpy(nssdir, userdir); +- if (appendDirAndCreate(nssdir, XDG_NSS_USER_PATH1, 0755) || +- appendDirAndCreate(nssdir, XDG_NSS_USER_PATH2, 0755)) { +- PORT_Free(nssdir); +- return NULL; +- } ++ PORT_Strcat(nssdir, NSS_USER_PATH1); ++ if (!testdir(nssdir) && mkdir(nssdir, 0760)) { ++ PORT_Free(nssdir); ++ return NULL; + } +- /* ${XDG_DATA_HOME:-$HOME/.local/share}/pki/nssdb */ +- if (appendDirAndCreate(nssdir, XDG_NSS_USER_PATH3, 0760) || +- appendDirAndCreate(nssdir, NSS_USER_PATH2, 0760)) { ++ PORT_Strcat(nssdir, NSS_USER_PATH2); ++ if (!testdir(nssdir) && mkdir(nssdir, 0760)) { + PORT_Free(nssdir); + return NULL; + } diff --git a/SPECS/nss.spec b/SPECS/nss.spec index ddbb575..194c7ac 100644 --- a/SPECS/nss.spec +++ b/SPECS/nss.spec @@ -1,12 +1,14 @@ -%global nspr_version 4.20.0 -%global nss_version 3.41.0 +%global nspr_version 4.21.0 +%global nss_version 3.44.0 %global unsupported_tools_directory %{_libdir}/nss/unsupported-tools %global saved_files_dir %{_libdir}/nss/saved -%global prelink_conf_dir %{_sysconfdir}/prelink.conf.d/ %global dracutlibdir %{_prefix}/lib/dracut %global dracut_modules_dir %{dracutlibdir}/modules.d/05nss-softokn/ %global dracut_conf_dir %{dracutlibdir}/dracut.conf.d +# The timestamp of our downstream manual pages, e.g., nss-config.1 +%global manual_date "Nov 13 2013" + %bcond_without tests # Produce .chk files for the final stripped binaries @@ -44,7 +46,7 @@ rpm.define(string.format("nss_release_tag NSS_%s_RTM", Summary: Network Security Services Name: nss Version: %{nss_version} -Release: 5%{?dist} +Release: 7%{?dist} License: MPLv2.0 URL: http://www.mozilla.org/projects/security/pki/nss/ Requires: nspr >= %{nspr_version} @@ -70,7 +72,6 @@ Source1: nss-util.pc.in Source2: nss-util-config.in Source3: nss-softokn.pc.in Source4: nss-softokn-config.in -Source5: nss-softokn-prelink.conf Source6: nss-softokn-dracut-module-setup.sh Source7: nss-softokn-dracut.conf Source8: nss.pc.in @@ -91,11 +92,14 @@ Source25: key3.db.xml Source26: key4.db.xml Source27: secmod.db.xml Source28: nss-p11-kit.config +Source29: nss-softokn-cavs-1.0.tar.gz # To inject hardening flags for DSO Patch1: nss-dso-ldflags.patch # Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=617723 Patch2: nss-539183.patch +# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=1549382 +Patch3: nss-module-leak.patch # This patch uses the GCC -iquote option documented at # http://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html#Directory-Options # to give the in-tree headers a higher priority over the system headers, @@ -108,17 +112,41 @@ Patch2: nss-539183.patch # Once the buildroot aha been bootstrapped the patch may be removed # but it doesn't hurt to keep it. Patch4: iquote.patch -# Local patch for enabling FIPS when the system is in FIPS mode: -# https://bugzilla.redhat.com/show_bug.cgi?id=852023 -Patch55: enable-fips-when-system-is-in-fips-mode.patch +# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=1552767 +Patch5: nss-skip-tls13-fips.patch +# TLS 1.3 currently doesn't work under FIPS mode: +# https://bugzilla.redhat.com/show_bug.cgi?id=1710372 +Patch6: nss-fips-disable-tls13.patch +# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=1552208 +Patch7: nss-disable-pkcs1-sigalgs-tls13.patch +# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=1553443 +Patch8: nss-post-handshake-auth-with-tickets.patch +# To revert the change in: +# https://bugzilla.mozilla.org/show_bug.cgi?id=818686 +Patch9: nss-sysinit-userdb.patch +# Disable nss-sysinit test which is sorely to test the above change +Patch10: nss-skip-sysinit-gtests.patch +# Upstream patch didn't make 3.44 +# https://bugzilla.mozilla.org/show_bug.cgi?id=1546229 +Patch200: nss-ike-patch.patch +# https://bugzilla.mozilla.org/show_bug.cgi?id=1546477 +Patch201: nss-softokn-fips-update.patch # Local patch for TLS_ECDHE_{ECDSA|RSA}_WITH_3DES_EDE_CBC_SHA ciphers Patch58: rhbz1185708-enable-ecc-3des-ciphers-by-default.patch -# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=1493936 -Patch129: nss-dsa.patch -# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=1496124 -Patch150: nss-3.39-create-public-key-on-private-import.patch -# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=1513909 -Patch151: nss-manpage-fixes.patch +# https://bugzilla.mozilla.org/show_bug.cgi?id=1473806 +Patch202: nss-8-fix-public-key-from-priv.patch +Patch204: nss-8-add-ipsec-usage-to-manpage.patch +# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=1560329 +Patch205: nss-drbg-continuous.patch +# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=1559906 +Patch206: nss-fipstest-tls12-prf.patch +# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=1554336 +Patch210: nss-mpi-loop.patch +# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=1540541 +Patch211: nss-leading-zero.patch +# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=1515342 +Patch212: nss-input-check.patch + %description Network Security Services (NSS) is a set of libraries designed to @@ -213,7 +241,6 @@ Requires: nspr >= 4.12 # For NSS_SecureMemcmpZero() from nss-util >= 3.33 Requires: nss-util >= 3.33 Conflicts: nss < 3.12.2.99.3-5 -Conflicts: prelink < 0.4.3 Conflicts: filesystem < 3 %description softokn-freebl @@ -247,11 +274,15 @@ Header and library files for doing development with Network Security Services. %prep -%setup -q -n %{name}-%{nss_archive_version} +#autosetup -N -S quilt -n %{name}-%{nss_archive_version} +%autosetup -N -n %{name}-%{nss_archive_version} -a 29 pushd nss %autopatch -p1 popd +# https://bugzilla.redhat.com/show_bug.cgi?id=1247353 +find nss/lib/libpkix -perm /u+x -type f -exec chmod -x {} \; + %build @@ -292,6 +323,8 @@ export NSS_USE_SYSTEM_SQLITE=1 export NSS_ALLOW_SSLKEYLOGFILE=1 +export NSS_SEED_ONLY_DEV_URANDOM=1 + %ifnarch noarch %if 0%{__isa_bits} == 64 export USE_64=1 @@ -311,8 +344,12 @@ export POLICY_PATH="/etc/crypto-policies/back-ends" make -C ./nss # build the man pages clean -pushd ./nss -make clean_docs build_docs +pushd ./nss/doc +rm -rf ./nroff +make clean +echo -n %{manual_date} > date.xml +echo -n %{version} > version.xml +make popd # and copy them to the dist directory for %%install to find them @@ -493,35 +530,6 @@ pushd nss/tests HOST=localhost DOMSUF=localdomain PORT=$MYRAND NSS_CYCLES=%{?nss_cycles} NSS_TESTS=%{?nss_tests} NSS_SSL_TESTS=%{?nss_ssl_tests} NSS_SSL_RUN=%{?nss_ssl_run} ./all.sh popd -# Normally, the grep exit status is 0 if selected lines are found and 1 otherwise, -# Grep exits with status greater than 1 if an error ocurred. -# If there are test failures we expect TEST_FAILURES > 0 and GREP_EXIT_STATUS = 0, -# With no test failures we expect TEST_FAILURES = 0 and GREP_EXIT_STATUS = 1, whereas -# GREP_EXIT_STATUS > 1 would indicate an error in grep such as failure to find the log file. -killall $RANDSERV || : - -TEST_FAILURES=$(grep -c -- '- FAILED$' ./tests_results/security/localhost.1/output.log) || GREP_EXIT_STATUS=$? - -if [ ${GREP_EXIT_STATUS:-0} -eq 1 ]; then - echo "okay: test suite detected no failures" -else - if [ ${GREP_EXIT_STATUS:-0} -eq 0 ]; then - # while a situation in which grep return status is 0 and it doesn't output - # anything shouldn't happen, set the default to something that is - # obviously wrong (-1) - echo "error: test suite had ${TEST_FAILURES:--1} test failure(s)" - exit 1 - else - if [ ${GREP_EXIT_STATUS:-0} -eq 2 ]; then - echo "error: grep has not found log file" - exit 1 - else - echo "error: grep failed with exit code: ${GREP_EXIT_STATUS}" - exit 1 - fi - fi -fi -echo "test suite completed" %endif %install @@ -535,7 +543,6 @@ mkdir -p $RPM_BUILD_ROOT/%{_libdir} mkdir -p $RPM_BUILD_ROOT/%{unsupported_tools_directory} mkdir -p $RPM_BUILD_ROOT/%{_libdir}/pkgconfig mkdir -p $RPM_BUILD_ROOT/%{saved_files_dir} -mkdir -p $RPM_BUILD_ROOT/%{prelink_conf_dir} mkdir -p $RPM_BUILD_ROOT/%{dracut_modules_dir} mkdir -p $RPM_BUILD_ROOT/%{dracut_conf_dir} mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/crypto-policies/local.d @@ -546,7 +553,6 @@ mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/crypto-policies/local.d mkdir -p $RPM_BUILD_ROOT%{_datadir}/doc/nss-tools %endif -install -m 644 %{SOURCE5} $RPM_BUILD_ROOT/%{prelink_conf_dir} install -m 755 %{SOURCE6} $RPM_BUILD_ROOT/%{dracut_modules_dir}/module-setup.sh install -m 644 %{SOURCE7} $RPM_BUILD_ROOT/%{dracut_conf_dir}/50-nss-softokn.conf @@ -657,10 +663,10 @@ install -p -m 644 %{SOURCE28} $RPM_BUILD_ROOT/%{_sysconfdir}/crypto-policies/loc /usr/bin/setup-nsssysinit.sh on %post -update-crypto-policies --no-reload +update-crypto-policies --no-reload &> /dev/null || : %postun -update-crypto-policies --no-reload +update-crypto-policies --no-reload &> /dev/null || : %files @@ -880,8 +886,6 @@ update-crypto-policies --no-reload %{_libdir}/libfreeblpriv3.so %{_libdir}/libfreeblpriv3.chk #shared -%dir %{prelink_conf_dir} -%{prelink_conf_dir}/nss-softokn-prelink.conf %dir %{dracut_modules_dir} %{dracut_modules_dir}/module-setup.sh %{dracut_conf_dir}/50-nss-softokn.conf @@ -915,6 +919,43 @@ update-crypto-policies --no-reload %changelog +* Wed Jul 3 2019 Daiki Ueno - 3.44.0-7 +- Backport fixes from 3.44.1 + +* Wed Jun 26 2019 Daiki Ueno - 3.44.0-6 +- Add continuous RNG test required by FIPS +- fipstest: use CKM_TLS12_MASTER_KEY_DERIVE instead of vendor specific mechanism + +* Mon Jun 10 2019 Daiki Ueno - 3.44.0-5 +- Rebuild with the correct build target + +*Fri Jun 7 2019 Bob Relyea - 3.44.0-4.1 +- rebuild to try to retrigger CI tests + +*Wed Jun 5 2019 Bob Relyea - 3.44.0-4 +- Fix certutil man page +- Fix extracting a public key from a private key for dh, ec, and dsa + +* Thu May 30 2019 Daiki Ueno - 3.44.0-3 +- Disable TLS 1.3 under FIPS mode +- Disable RSASSA-PKCS1-v1_5 in TLS 1.3 +- Fix post-handshake auth transcript calculation if + SSL_ENABLE_SESSION_TICKETS is set +- Revert the change to use XDG basedirs (mozilla#818686) + +* Fri May 24 2019 Bob Relyea - 3.44.0-2 +- Add ike mechanisms in softokn +- Add FIPS checks in softoken + +* Fri May 24 2019 Daiki Ueno - 3.44.0-1 +- Update to NSS 3.44 +- Define NSS_SEED_ONLY_DEV_URANDOM=1 to exclusively use getentropy +- Use %%autosetup +- Clean up manual pages generation +- Clean up %%check +- Remove prelink dependency, which is not available in RHEL-8 +- Remove upstreamed patches + * Mon Dec 17 2018 Daiki Ueno - 3.41.0-5 - Update manual pages to reflect recent changes in commands