diff --git a/mozilla-nss.changes b/mozilla-nss.changes index a171bf6..ffacb5b 100644 --- a/mozilla-nss.changes +++ b/mozilla-nss.changes @@ -1,3 +1,62 @@ +------------------------------------------------------------------- +Sat Jun 27 21:16:07 UTC 2020 - Wolfgang Rosenauer + +- add FIPS mode patches from SLE stream + nss-fips-aes-keywrap-post.patch + nss-fips-approved-crypto-non-ec.patch + nss-fips-cavs-dsa-fixes.patch + nss-fips-cavs-general.patch + nss-fips-cavs-kas-ecc.patch + nss-fips-cavs-kas-ffc.patch + nss-fips-cavs-keywrap.patch + nss-fips-cavs-rsa-fixes.patch + nss-fips-combined-hash-sign-dsa-ecdsa.patch + nss-fips-constructor-self-tests.patch + nss-fips-detect-fips-mode-fixes.patch + nss-fips-dsa-kat.patch + nss-fips-gcm-ctr.patch + nss-fips-pairwise-consistency-check.patch + nss-fips-rsa-keygen-strictness.patch + nss-fips-tls-allow-md5-prf.patch + nss-fips-use-getrandom.patch + nss-fips-use-strong-random-pool.patch + nss-fips-zeroization.patch + nss-fix-dh-pkcs-derive-inverted-logic.patch + +------------------------------------------------------------------- +Tue Jun 23 05:40:12 UTC 2020 - Wolfgang Rosenauer + +- update to NSS 3.53.1 + * required for Firefox 78 + * CVE-2020-12402 - Use constant-time GCD and modular inversion in MPI. + (bmo#1631597, bsc#1173032) + +------------------------------------------------------------------- +Sun Jun 21 04:44:40 UTC 2020 - Michel Normand + +- Add ppc-old-abi-v3.patch as per upstream bug + https://bugzilla.mozilla.org/show_bug.cgi?id=1642174 + +------------------------------------------------------------------- +Thu Jun 11 20:09:44 UTC 2020 - Wolfgang Rosenauer + +- update to NSS 3.53 + Notable changes + * SEED is now moved into a new freebl directory freebl/deprecated + bmo#1636389 + * SEED will be disabled by default in a future release of NSS. At + that time, users will need to set the compile-time flag + (bmo#1622033) to disable that deprecation in order to use the + algorithm. + * Algorithms marked as deprecated will ultimately be removed + * Several root certificates in the Mozilla program now set the + CKA_NSS_SERVER_DISTRUST_AFTER attribute, which NSS consumers + can query to further refine trust decisions. (bmo#1618404, + bmo#1621159). If a builtin certificate has a + CKA_NSS_SERVER_DISTRUST_AFTER timestamp before the SCT or + NotBefore date of a certificate that builtin issued, then clients + can elect not to trust it. + ------------------------------------------------------------------- Tue May 26 09:08:26 UTC 2020 - Wolfgang Rosenauer diff --git a/mozilla-nss.spec b/mozilla-nss.spec index af462a6..7e664b3 100644 --- a/mozilla-nss.spec +++ b/mozilla-nss.spec @@ -17,14 +17,14 @@ # -%global nss_softokn_fips_version 3.52 +%global nss_softokn_fips_version 3.53 %define NSPR_min_version 4.25 %define nspr_ver %(rpm -q --queryformat '%%{VERSION}' mozilla-nspr) %define nssdbdir %{_sysconfdir}/pki/nssdb Name: mozilla-nss -Version: 3.52.1 +Version: 3.53.1 Release: 0 -%define underscore_version 3_52_1 +%define underscore_version 3_53_1 Summary: Network Security Services License: MPL-2.0 Group: System/Libraries @@ -49,7 +49,33 @@ Patch4: add-relro-linker-option.patch Patch5: malloc.patch Patch6: bmo-1400603.patch Patch7: nss-sqlitename.patch +Patch8: ppc-old-abi-v3.patch +Patch11: nss-fips-use-getrandom.patch +Patch13: nss-fips-dsa-kat.patch +Patch15: nss-fips-pairwise-consistency-check.patch +Patch16: nss-fips-rsa-keygen-strictness.patch +Patch19: nss-fips-cavs-keywrap.patch +Patch20: nss-fips-cavs-kas-ffc.patch +Patch21: nss-fips-cavs-kas-ecc.patch +Patch22: nss-fips-gcm-ctr.patch +Patch23: nss-fips-constructor-self-tests.patch +Patch24: nss-fips-cavs-general.patch +Patch25: nss-fips-cavs-dsa-fixes.patch +Patch26: nss-fips-cavs-rsa-fixes.patch +Patch27: nss-fips-approved-crypto-non-ec.patch +Patch29: nss-fips-zeroization.patch +Patch30: nss-fips-tls-allow-md5-prf.patch +Patch31: nss-fips-use-strong-random-pool.patch +Patch32: nss-fips-detect-fips-mode-fixes.patch +Patch34: nss-fips-combined-hash-sign-dsa-ecdsa.patch +Patch35: nss-fix-dh-pkcs-derive-inverted-logic.patch +Patch36: nss-fips-aes-keywrap-post.patch +%if 0%{?sle_version} >= 120000 && 0%{?sle_version} < 150000 +# aarch64 + gcc4.8 fails to build on SLE-12 due to undefined references +BuildRequires: gcc9-c++ +%else BuildRequires: gcc-c++ +%endif BuildRequires: pkgconfig BuildRequires: pkgconfig(nspr) >= %{NSPR_min_version} BuildRequires: pkgconfig(sqlite3) @@ -179,6 +205,30 @@ cd nss %endif %patch6 -p1 %patch7 -p1 +%patch8 -p1 + +# FIPS patches +%patch11 -p1 +%patch13 -p1 +%patch15 -p1 +%patch16 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 +%patch29 -p1 +%patch30 -p1 +%patch31 -p1 +%patch32 -p1 +%patch34 -p1 +%patch35 -p1 +%patch36 -p1 + # additional CA certificates #cd security/nss/lib/ckfw/builtins #cat %{SOURCE2} >> certdata.txt @@ -191,6 +241,12 @@ cd nss %else %global _lto_cflags %{_lto_cflags} -ffat-lto-objects %endif +%if 0%{?sle_version} >= 120000 && 0%{?sle_version} < 150000 +export CC=gcc-9 +# Yes, they use both... +export CXX=g++-9 +export CCC=g++-9 +%endif cd nss modified="$(sed -n '/^----/n;s/ - .*$//;p;q' "%{SOURCE99}")" DATE="\"$(date -d "${modified}" "+%%b %%e %%Y")\"" @@ -211,7 +267,7 @@ export USE_64=1 export NSS_USE_SYSTEM_SQLITE=1 #export SQLITE_LIB_NAME=nsssqlite3 MAKE_FLAGS="BUILD_OPT=1" -make --jobs=1 nss_build_all $MAKE_FLAGS +make %{?_smp_mflags} nss_build_all $MAKE_FLAGS # run testsuite %if 0%{?run_testsuite} export BUILD_OPT=1 diff --git a/nss-3.52.1.tar.gz b/nss-3.52.1.tar.gz deleted file mode 100644 index 0ca6356..0000000 --- a/nss-3.52.1.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bcc81ac33aeb4ecad182dc21e34d2c97bcc148fd7b9e76f85bebb892405a9278 -size 81222116 diff --git a/nss-3.53.1.tar.gz b/nss-3.53.1.tar.gz new file mode 100644 index 0000000..74727a1 --- /dev/null +++ b/nss-3.53.1.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2dccde67079b25c4e95ac3121f11b2819c37cf8c48ca263a45d8f83f7a315316 +size 81297900 diff --git a/nss-fips-aes-keywrap-post.patch b/nss-fips-aes-keywrap-post.patch new file mode 100644 index 0000000..ed22462 --- /dev/null +++ b/nss-fips-aes-keywrap-post.patch @@ -0,0 +1,127 @@ +# HG changeset patch +# User M. Sirringhaus +# Date 1589854460 -7200 +# Tue May 19 04:14:20 2020 +0200 +# Node ID ce99bba6375432c55a73c1367f619dfef7c7e9fc +# Parent 2b4f407fb1f8824fed4df9c4c3f15a2493e71677 +commit e78f5a6a2124ce88002796d6aaefc6232f132526 +Author: Hans Petter Jansson + AES Keywrap POST. + +diff --git a/lib/freebl/fipsfreebl.c b/lib/freebl/fipsfreebl.c +--- a/lib/freebl/fipsfreebl.c ++++ b/lib/freebl/fipsfreebl.c +@@ -110,6 +110,9 @@ + #define FIPS_AES_192_KEY_SIZE 24 /* 192-bits */ + #define FIPS_AES_256_KEY_SIZE 32 /* 256-bits */ + ++/* FIPS preprocessor directives for AES Keywrap */ ++#define FIPS_AES_KEYWRAP_KNOWN_CIPHERTEXT_SIZE 24 /* 192-bits */ ++ + /* FIPS preprocessor directives for message digests */ + #define FIPS_KNOWN_HASH_MESSAGE_LENGTH 64 /* 512-bits */ + +@@ -299,6 +302,9 @@ + + static const PRUint8 aes_gcm_known_aad[] = { "MozillaallizoM" }; + ++ /* AES Keywrap Known Initialization Vector (64 bits) */ ++ static const PRUint8 aes_key_wrap_iv[] = { "WrapparW" }; ++ + /* AES Known Ciphertext (128-bit key). */ + static const PRUint8 aes_ecb128_known_ciphertext[] = { + 0x3c, 0xa5, 0x96, 0xf3, 0x34, 0x6a, 0x96, 0xc1, +@@ -353,6 +359,25 @@ + 0xf4, 0xb0, 0xc1, 0x8c, 0x86, 0x51, 0xf5, 0xa1 + }; + ++ /* AES Keywrap Known Ciphertexts. */ ++ static const PRUint8 aes_kw128_known_ciphertext[] = { ++ 0xd7, 0xec, 0x33, 0x3a, 0x35, 0x50, 0x91, 0x4d, ++ 0x04, 0x69, 0x1f, 0xbc, 0x9b, 0x3a, 0x51, 0x9d, ++ 0xf3, 0x45, 0x01, 0xec, 0xaa, 0x43, 0x33, 0x42 ++ }; ++ ++ static const PRUint8 aes_kw192_known_ciphertext[] = { ++ 0x18, 0x44, 0xab, 0x72, 0xbd, 0x35, 0x6c, 0x8f, ++ 0x34, 0x34, 0x2e, 0x0b, 0xb0, 0x19, 0xd3, 0x46, ++ 0x3e, 0x53, 0x4f, 0x2f, 0x43, 0xcc, 0xf5, 0x8c ++ }; ++ ++ static const PRUint8 aes_kw256_known_ciphertext[] = { ++ 0x3e, 0xaf, 0xf3, 0x36, 0xaf, 0xc3, 0x68, 0xab, ++ 0x5a, 0x07, 0xed, 0x64, 0x5b, 0xf8, 0x81, 0x0d, ++ 0x9e, 0x67, 0x75, 0xbd, 0x66, 0xe1, 0x52, 0xdc ++ }; ++ + 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; + +@@ -362,10 +387,14 @@ + 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; + ++ const PRUint8 *aes_keywrap_known_ciphertext = ++ (aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_kw128_known_ciphertext : (aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_kw192_known_ciphertext : aes_kw256_known_ciphertext; ++ + /* AES variables. */ + PRUint8 aes_computed_ciphertext[FIPS_AES_ENCRYPT_LENGTH * 2]; + PRUint8 aes_computed_plaintext[FIPS_AES_DECRYPT_LENGTH * 2]; + AESContext *aes_context; ++ AESKeyWrapContext *aes_keywrap_context; + unsigned int aes_bytes_encrypted; + unsigned int aes_bytes_decrypted; + CK_NSS_GCM_PARAMS gcmParams; +@@ -554,6 +583,52 @@ + return (SECFailure); + } + ++ /********************************/ ++ /* AES Keywrap En/Decrypt Test. */ ++ /********************************/ ++ ++ /* Create encryption context */ ++ aes_keywrap_context = AESKeyWrap_CreateContext(aes_known_key, aes_key_wrap_iv, PR_TRUE, ++ aes_key_size); ++ if (aes_keywrap_context == NULL) { ++ PORT_SetError(SEC_ERROR_NO_MEMORY); ++ return (SECFailure); ++ } ++ ++ aes_status = AESKeyWrap_Encrypt(aes_keywrap_context, ++ aes_computed_ciphertext, &aes_bytes_encrypted, ++ FIPS_AES_ENCRYPT_LENGTH * 2, ++ aes_known_plaintext, FIPS_AES_ENCRYPT_LENGTH); ++ ++ AESKeyWrap_DestroyContext(aes_keywrap_context, PR_TRUE); ++ ++ if ((aes_status != SECSuccess) || ++ (aes_bytes_encrypted != FIPS_AES_KEYWRAP_KNOWN_CIPHERTEXT_SIZE) || ++ (PORT_Memcmp (aes_computed_ciphertext, aes_keywrap_known_ciphertext, ++ FIPS_AES_KEYWRAP_KNOWN_CIPHERTEXT_SIZE) != 0)) { ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); ++ return (SECFailure); ++ } ++ ++ /* Create decryption context */ ++ aes_keywrap_context = AESKeyWrap_CreateContext(aes_known_key, aes_key_wrap_iv, PR_FALSE, ++ aes_key_size); ++ ++ aes_status = AESKeyWrap_Decrypt(aes_keywrap_context, ++ aes_computed_plaintext, &aes_bytes_decrypted, ++ FIPS_AES_ENCRYPT_LENGTH, ++ aes_computed_ciphertext, aes_bytes_encrypted); ++ ++ AESKeyWrap_DestroyContext(aes_keywrap_context, PR_TRUE); ++ ++ if ((aes_status != SECSuccess) || ++ (aes_bytes_decrypted != FIPS_AES_ENCRYPT_LENGTH) || ++ (PORT_Memcmp (aes_computed_plaintext, aes_known_plaintext, ++ FIPS_AES_ENCRYPT_LENGTH) != 0)) { ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); ++ return (SECFailure); ++ } ++ + return (SECSuccess); + } + diff --git a/nss-fips-approved-crypto-non-ec.patch b/nss-fips-approved-crypto-non-ec.patch new file mode 100644 index 0000000..ec3cd50 --- /dev/null +++ b/nss-fips-approved-crypto-non-ec.patch @@ -0,0 +1,488 @@ +# HG changeset patch +# User M. Sirringhaus +# Date 1590413430 -7200 +# Mon May 25 15:30:30 2020 +0200 +# Node ID 2d4483f4a1259f965f32ff4c65436e92aef83be7 +# Parent 3f4d682c9a1e8b3d939c744ee249e23179db5191 +imported patch nss-fips-approved-crypto-non-ec.patch + +diff --git a/lib/freebl/alg2268.c b/lib/freebl/alg2268.c +--- a/lib/freebl/alg2268.c ++++ b/lib/freebl/alg2268.c +@@ -16,6 +16,8 @@ + #include /* for ptrdiff_t */ + #endif + ++#include "fips.h" ++ + /* + ** RC2 symmetric block cypher + */ +@@ -119,6 +121,7 @@ + RC2Context * + RC2_AllocateContext(void) + { ++ IN_FIPS_RETURN(NULL); + return PORT_ZNew(RC2Context); + } + SECStatus +@@ -133,6 +136,8 @@ + #endif + PRUint8 tmpB; + ++ IN_FIPS_RETURN(SECFailure); ++ + if (!key || !cx || !len || len > (sizeof cx->B) || + efLen8 > (sizeof cx->B)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); +@@ -204,7 +209,11 @@ + RC2_CreateContext(const unsigned char *key, unsigned int len, + const unsigned char *iv, int mode, unsigned efLen8) + { +- RC2Context *cx = PORT_ZNew(RC2Context); ++ RC2Context *cx; ++ ++ IN_FIPS_RETURN(NULL); ++ ++ cx = PORT_ZNew(RC2Context); + if (cx) { + SECStatus rv = RC2_InitContext(cx, key, len, iv, mode, efLen8, 0); + if (rv != SECSuccess) { +@@ -456,7 +465,11 @@ + unsigned int *outputLen, unsigned int maxOutputLen, + const unsigned char *input, unsigned int inputLen) + { +- SECStatus rv = SECSuccess; ++ SECStatus rv; ++ ++ IN_FIPS_RETURN(SECFailure); ++ ++ rv = SECSuccess; + if (inputLen) { + if (inputLen % RC2_BLOCK_SIZE) { + PORT_SetError(SEC_ERROR_INPUT_LEN); +@@ -490,7 +503,11 @@ + unsigned int *outputLen, unsigned int maxOutputLen, + const unsigned char *input, unsigned int inputLen) + { +- SECStatus rv = SECSuccess; ++ SECStatus rv; ++ ++ IN_FIPS_RETURN(SECFailure); ++ ++ rv = SECSuccess; + if (inputLen) { + if (inputLen % RC2_BLOCK_SIZE) { + PORT_SetError(SEC_ERROR_INPUT_LEN); +diff --git a/lib/freebl/arcfour.c b/lib/freebl/arcfour.c +--- a/lib/freebl/arcfour.c ++++ b/lib/freebl/arcfour.c +@@ -13,6 +13,7 @@ + + #include "prtypes.h" + #include "blapi.h" ++#include "fips.h" + + /* Architecture-dependent defines */ + +@@ -108,6 +109,7 @@ + RC4Context * + RC4_AllocateContext(void) + { ++ IN_FIPS_RETURN(NULL); + return PORT_ZNew(RC4Context); + } + +@@ -121,6 +123,8 @@ + PRUint8 K[256]; + PRUint8 *L; + ++ IN_FIPS_RETURN(SECFailure); ++ + /* verify the key length. */ + PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE); + if (len == 0 || len >= ARCFOUR_STATE_SIZE) { +@@ -162,7 +166,11 @@ + RC4Context * + RC4_CreateContext(const unsigned char *key, int len) + { +- RC4Context *cx = RC4_AllocateContext(); ++ RC4Context *cx; ++ ++ IN_FIPS_RETURN(NULL); ++ ++ cx = RC4_AllocateContext(); + if (cx) { + SECStatus rv = RC4_InitContext(cx, key, len, NULL, 0, 0, 0); + if (rv != SECSuccess) { +@@ -176,6 +184,7 @@ + void + RC4_DestroyContext(RC4Context *cx, PRBool freeit) + { ++ IN_FIPS_RETURN(); + if (freeit) + PORT_ZFree(cx, sizeof(*cx)); + } +@@ -548,6 +557,8 @@ + unsigned int *outputLen, unsigned int maxOutputLen, + const unsigned char *input, unsigned int inputLen) + { ++ IN_FIPS_RETURN(SECFailure); ++ + PORT_Assert(maxOutputLen >= inputLen); + if (maxOutputLen < inputLen) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); +@@ -571,6 +582,8 @@ + unsigned int *outputLen, unsigned int maxOutputLen, + const unsigned char *input, unsigned int inputLen) + { ++ IN_FIPS_RETURN(SECFailure); ++ + PORT_Assert(maxOutputLen >= inputLen); + if (maxOutputLen < inputLen) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); +diff --git a/lib/freebl/deprecated/seed.c b/lib/freebl/deprecated/seed.c +--- a/lib/freebl/deprecated/seed.c ++++ b/lib/freebl/deprecated/seed.c +@@ -17,6 +17,8 @@ + #include "seed.h" + #include "secerr.h" + ++#include "../fips.h" ++ + static const seed_word SS[4][256] = { + { 0x2989a1a8, 0x05858184, 0x16c6d2d4, 0x13c3d3d0, + 0x14445054, 0x1d0d111c, 0x2c8ca0ac, 0x25052124, +@@ -301,6 +303,8 @@ + seed_word K0, K1, K2, K3; + seed_word t0, t1; + ++ IN_FIPS_RETURN(); ++ + char2word(rawkey, K0); + char2word(rawkey + 4, K1); + char2word(rawkey + 8, K2); +@@ -349,6 +353,8 @@ + seed_word L0, L1, R0, R1; + seed_word t0, t1; + ++ IN_FIPS_RETURN(); ++ + char2word(s, L0); + char2word(s + 4, L1); + char2word(s + 8, R0); +@@ -385,6 +391,8 @@ + seed_word L0, L1, R0, R1; + seed_word t0, t1; + ++ IN_FIPS_RETURN(); ++ + char2word(s, L0); + char2word(s + 4, L1); + char2word(s + 8, R0); +@@ -419,6 +427,8 @@ + size_t inLen, + const SEED_KEY_SCHEDULE *ks, int enc) + { ++ IN_FIPS_RETURN(); ++ + if (enc) { + while (inLen > 0) { + SEED_encrypt(in, out, ks); +@@ -445,6 +455,8 @@ + unsigned char tmp[SEED_BLOCK_SIZE]; + const unsigned char *iv = ivec; + ++ IN_FIPS_RETURN(); ++ + if (enc) { + while (len >= SEED_BLOCK_SIZE) { + for (n = 0; n < SEED_BLOCK_SIZE; ++n) { +@@ -528,6 +540,7 @@ + SEEDContext * + SEED_AllocateContext(void) + { ++ IN_FIPS_RETURN(NULL); + return PORT_ZNew(SEEDContext); + } + +@@ -536,6 +549,8 @@ + unsigned int keylen, const unsigned char *iv, + int mode, unsigned int encrypt, unsigned int unused) + { ++ IN_FIPS_RETURN(SECFailure); ++ + if (!cx) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; +@@ -567,10 +582,14 @@ + SEED_CreateContext(const unsigned char *key, const unsigned char *iv, + int mode, PRBool encrypt) + { +- SEEDContext *cx = PORT_ZNew(SEEDContext); +- SECStatus rv = SEED_InitContext(cx, key, SEED_KEY_LENGTH, iv, mode, +- encrypt, 0); ++ SEEDContext *cx; ++ SECStatus rv; + ++ IN_FIPS_RETURN(NULL); ++ ++ cx = PORT_ZNew(SEEDContext); ++ rv = SEED_InitContext(cx, key, SEED_KEY_LENGTH, iv, mode, ++ encrypt, 0); + if (rv != SECSuccess) { + PORT_ZFree(cx, sizeof *cx); + cx = NULL; +@@ -595,6 +614,8 @@ + unsigned int maxOutLen, const unsigned char *in, + unsigned int inLen) + { ++ IN_FIPS_RETURN(SECFailure); ++ + if (!cx) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; +@@ -635,6 +656,8 @@ + unsigned int maxOutLen, const unsigned char *in, + unsigned int inLen) + { ++ IN_FIPS_RETURN(SECFailure); ++ + if (!cx) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; +diff --git a/lib/freebl/fips.h b/lib/freebl/fips.h +--- a/lib/freebl/fips.h ++++ b/lib/freebl/fips.h +@@ -8,8 +8,20 @@ + #ifndef FIPS_H + #define FIPS_H + ++#include "hasht.h" ++#include "secerr.h" ++ ++#define IN_FIPS_RETURN(rv) \ ++ do { \ ++ if (FIPS_mode()) { \ ++ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); \ ++ return rv; \ ++ } \ ++ } while (0) ++ + int FIPS_mode(void); + char* FIPS_rngDev(void); ++PRBool FIPS_hashAlgApproved(HASH_HashType hashAlg); + + #endif + +diff --git a/lib/freebl/md2.c b/lib/freebl/md2.c +--- a/lib/freebl/md2.c ++++ b/lib/freebl/md2.c +@@ -13,6 +13,8 @@ + + #include "blapi.h" + ++#include "fips.h" ++ + #define MD2_DIGEST_LEN 16 + #define MD2_BUFSIZE 16 + #define MD2_X_SIZE 48 /* The X array, [CV | INPUT | TMP VARS] */ +@@ -66,7 +68,11 @@ + MD2_Hash(unsigned char *dest, const char *src) + { + unsigned int len; +- MD2Context *cx = MD2_NewContext(); ++ MD2Context *cx; ++ ++ IN_FIPS_RETURN(SECFailure); ++ ++ cx = MD2_NewContext(); + if (!cx) { + PORT_SetError(PR_OUT_OF_MEMORY_ERROR); + return SECFailure; +@@ -81,7 +87,11 @@ + MD2Context * + MD2_NewContext(void) + { +- MD2Context *cx = (MD2Context *)PORT_ZAlloc(sizeof(MD2Context)); ++ MD2Context *cx; ++ ++ IN_FIPS_RETURN(NULL); ++ ++ cx = (MD2Context *)PORT_ZAlloc(sizeof(MD2Context)); + if (cx == NULL) { + PORT_SetError(PR_OUT_OF_MEMORY_ERROR); + return NULL; +@@ -99,6 +109,8 @@ + void + MD2_Begin(MD2Context *cx) + { ++ IN_FIPS_RETURN(); ++ + memset(cx, 0, sizeof(*cx)); + cx->unusedBuffer = MD2_BUFSIZE; + } +@@ -196,6 +208,8 @@ + { + PRUint32 bytesToConsume; + ++ IN_FIPS_RETURN(); ++ + /* Fill the remaining input buffer. */ + if (cx->unusedBuffer != MD2_BUFSIZE) { + bytesToConsume = PR_MIN(inputLen, cx->unusedBuffer); +@@ -226,6 +240,9 @@ + unsigned int *digestLen, unsigned int maxDigestLen) + { + PRUint8 padStart; ++ ++ IN_FIPS_RETURN(); ++ + if (maxDigestLen < MD2_BUFSIZE) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return; +diff --git a/lib/freebl/md5.c b/lib/freebl/md5.c +--- a/lib/freebl/md5.c ++++ b/lib/freebl/md5.c +@@ -15,6 +15,8 @@ + #include "blapi.h" + #include "blapii.h" + ++#include "fips.h" ++ + #define MD5_HASH_LEN 16 + #define MD5_BUFFER_SIZE 64 + #define MD5_END_BUFFER (MD5_BUFFER_SIZE - 8) +@@ -195,6 +197,7 @@ + SECStatus + MD5_Hash(unsigned char *dest, const char *src) + { ++ IN_FIPS_RETURN(SECFailure); + return MD5_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src)); + } + +@@ -204,6 +207,8 @@ + unsigned int len; + MD5Context cx; + ++ IN_FIPS_RETURN(SECFailure); ++ + MD5_Begin(&cx); + MD5_Update(&cx, src, src_length); + MD5_End(&cx, dest, &len, MD5_HASH_LEN); +@@ -215,7 +220,11 @@ + MD5_NewContext(void) + { + /* no need to ZAlloc, MD5_Begin will init the context */ +- MD5Context *cx = (MD5Context *)PORT_Alloc(sizeof(MD5Context)); ++ MD5Context *cx; ++ ++ IN_FIPS_RETURN(NULL); ++ ++ cx = (MD5Context *)PORT_Alloc(sizeof(MD5Context)); + if (cx == NULL) { + PORT_SetError(PR_OUT_OF_MEMORY_ERROR); + return NULL; +@@ -226,7 +235,8 @@ + void + MD5_DestroyContext(MD5Context *cx, PRBool freeit) + { +- memset(cx, 0, sizeof *cx); ++ if (cx) ++ memset(cx, 0, sizeof *cx); + if (freeit) { + PORT_Free(cx); + } +@@ -235,6 +245,8 @@ + void + MD5_Begin(MD5Context *cx) + { ++ IN_FIPS_RETURN(); ++ + cx->lsbInput = 0; + cx->msbInput = 0; + /* memset(cx->inBuf, 0, sizeof(cx->inBuf)); */ +@@ -425,6 +437,8 @@ + PRUint32 inBufIndex = cx->lsbInput & 63; + const PRUint32 *wBuf; + ++ IN_FIPS_RETURN(); ++ + /* Add the number of input bytes to the 64-bit input counter. */ + addto64(cx->msbInput, cx->lsbInput, inputLen); + if (inBufIndex) { +@@ -498,6 +512,8 @@ + PRUint32 lowInput, highInput; + PRUint32 inBufIndex = cx->lsbInput & 63; + ++ IN_FIPS_RETURN(); ++ + if (maxDigestLen < MD5_HASH_LEN) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return; +@@ -546,6 +562,8 @@ + #endif + PRUint32 cv[4]; + ++ IN_FIPS_RETURN(); ++ + if (maxDigestLen < MD5_HASH_LEN) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return; +diff --git a/lib/freebl/nsslowhash.c b/lib/freebl/nsslowhash.c +--- a/lib/freebl/nsslowhash.c ++++ b/lib/freebl/nsslowhash.c +@@ -12,6 +12,7 @@ + #include "plhash.h" + #include "nsslowhash.h" + #include "blapii.h" ++#include "fips.h" + + struct NSSLOWInitContextStr { + int count; +@@ -92,6 +93,12 @@ + { + NSSLOWHASHContext *context; + ++ /* return with an error if unapproved hash is requested in FIPS mode */ ++ if (!FIPS_hashAlgApproved(hashType)) { ++ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); ++ return NULL; ++ } ++ + if (post_failed) { + PORT_SetError(SEC_ERROR_PKCS11_DEVICE_ERROR); + return NULL; +diff --git a/lib/freebl/rawhash.c b/lib/freebl/rawhash.c +--- a/lib/freebl/rawhash.c ++++ b/lib/freebl/rawhash.c +@@ -10,6 +10,7 @@ + #include "hasht.h" + #include "blapi.h" /* below the line */ + #include "secerr.h" ++#include "fips.h" + + static void * + null_hash_new_context(void) +@@ -146,7 +147,8 @@ + const SECHashObject * + HASH_GetRawHashObject(HASH_HashType hashType) + { +- if (hashType <= HASH_AlgNULL || hashType >= HASH_AlgTOTAL) { ++ if (hashType <= HASH_AlgNULL || hashType >= HASH_AlgTOTAL ++ || (!FIPS_hashAlgApproved(hashType))) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return NULL; + } +diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c +--- a/lib/softoken/pkcs11c.c ++++ b/lib/softoken/pkcs11c.c +@@ -7282,7 +7282,7 @@ + } else { + /* now allocate the hash contexts */ + md5 = MD5_NewContext(); +- if (md5 == NULL) { ++ if (md5 == NULL && !isTLS) { + crv = CKR_HOST_MEMORY; + break; + } diff --git a/nss-fips-cavs-dsa-fixes.patch b/nss-fips-cavs-dsa-fixes.patch new file mode 100644 index 0000000..1a922ba --- /dev/null +++ b/nss-fips-cavs-dsa-fixes.patch @@ -0,0 +1,207 @@ +# HG changeset patch +# User Hans Petter Jansson +# Date 1574237264 -3600 +# Wed Nov 20 09:07:44 2019 +0100 +# Node ID 0e904e6179d1db21965df2c405c80c3fc0258658 +# Parent 969310ea4c573aac64bf08846b8938b8fa783870 +[PATCH] 24 +From ef2620b770082c77dbbbccae2e773157897b005d Mon Sep 17 00:00:00 2001 +--- + nss/cmd/fipstest/fipstest.c | 112 ++++++++++++++++++++++++++++++++---- + 1 file changed, 101 insertions(+), 11 deletions(-) + +diff --git a/cmd/fipstest/fipstest.c b/cmd/fipstest/fipstest.c +--- a/cmd/fipstest/fipstest.c ++++ b/cmd/fipstest/fipstest.c +@@ -5576,7 +5576,7 @@ + void + dsa_pqggen_test(char *reqfn) + { +- char buf[800]; /* holds one line from the input REQUEST file ++ char buf[2048]; /* holds one line from the input REQUEST file + * or to the output RESPONSE file. + * 800 to hold seed = (384 public key (x2 for HEX) + */ +@@ -5592,6 +5592,13 @@ + PQGVerify *vfy = NULL; + unsigned int keySizeIndex = 0; + dsa_pqg_type type = FIPS186_1; ++ SECItem P = { 0, 0, 0 }; ++ SECItem Q = { 0, 0, 0 }; ++ SECItem firstseed = { 0, 0, 0 }; ++ SECItem pseed = { 0, 0, 0 }; ++ SECItem qseed = { 0, 0, 0 }; ++ SECItem index = { 0, 0, 0 }; ++ HASH_HashType hashtype = HASH_AlgNULL; + + dsareq = fopen(reqfn, "r"); + dsaresp = stdout; +@@ -5612,8 +5619,8 @@ + output_g = 1; + exit(1); + } else if (strncmp(&buf[1], "A.2.3", 5) == 0) { +- fprintf(stderr, "NSS only Generates G with P&Q\n"); +- exit(1); ++ type = A_2_3; ++ output_g = 1; + } else if (strncmp(&buf[1], "A.1.2.1", 7) == 0) { + type = A_1_2_1; + output_g = 0; +@@ -5627,14 +5634,17 @@ + + /* [Mod = ... ] */ + if (buf[0] == '[') { ++ int hashbits; + + if (type == FIPS186_1) { + N = 160; + if (sscanf(buf, "[mod = %d]", &L) != 1) { + goto loser; + } +- } else if (sscanf(buf, "[mod = L=%d, N=%d", &L, &N) != 2) { +- goto loser; ++ } else if (sscanf(buf, "[mod = L=%d, N=%d, SHA-%d", &L, &N, &hashbits) != 3) { ++ goto loser; ++ } else { ++ hashtype = sha_get_hashType (hashbits); + } + + fputs(buf, dsaresp); +@@ -5656,7 +5666,7 @@ + continue; + } + /* N = ... */ +- if (buf[0] == 'N') { ++ if (buf[0] == 'N' && type != A_2_3) { + if (strncmp(buf, "Num", 3) == 0) { + if (sscanf(buf, "Num = %d", &count) != 1) { + goto loser; +@@ -5671,7 +5681,10 @@ + rv = PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES, + &pqg, &vfy); + } else { +- rv = PQG_ParamGenV2(L, N, N, &pqg, &vfy); ++ if (firstseed.data) ++ SECITEM_ZfreeItem(&firstseed, PR_FALSE); ++ ++ rv = FREEBL_Test_PQG_ParamGenV2_p(L, N, 0, &pqg, &vfy, &firstseed, hashtype); + } + if (rv != SECSuccess) { + fprintf(dsaresp, +@@ -5682,6 +5695,10 @@ + fprintf(dsaresp, "P = %s\n", buf); + to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len); + fprintf(dsaresp, "Q = %s\n", buf); ++ if (firstseed.data) { ++ to_hex_str(buf, firstseed.data, firstseed.len); ++ fprintf(dsaresp, "firstseed = %s\n", buf); ++ } + if (output_g) { + to_hex_str(buf, pqg->base.data, pqg->base.len); + fprintf(dsaresp, "G = %s\n", buf); +@@ -5697,13 +5714,13 @@ + } + fprintf(dsaresp, "%s\n", buf); + } else { +- unsigned int seedlen = vfy->seed.len / 2; +- unsigned int pgen_counter = vfy->counter >> 16; +- unsigned int qgen_counter = vfy->counter & 0xffff; ++ unsigned int seedlen = (vfy->seed.len - firstseed.len) / 2; ++ unsigned int pgen_counter = vfy->counter & 0xffff; ++ unsigned int qgen_counter = vfy->counter >> 16; + /*fprintf(dsaresp, "index = %02x\n", vfy->h.data[0]); */ +- to_hex_str(buf, vfy->seed.data, seedlen); ++ to_hex_str(buf, vfy->seed.data + firstseed.len, seedlen); + fprintf(dsaresp, "pseed = %s\n", buf); +- to_hex_str(buf, vfy->seed.data + seedlen, seedlen); ++ to_hex_str(buf, vfy->seed.data + firstseed.len + seedlen, seedlen); + fprintf(dsaresp, "qseed = %s\n", buf); + fprintf(dsaresp, "pgen_counter = %d\n", pgen_counter); + fprintf(dsaresp, "qgen_counter = %d\n", qgen_counter); +@@ -5723,12 +5740,85 @@ + vfy = NULL; + } + } +- ++ continue; ++ } ++ ++ if (parse_secitem ("P", buf, &P)) { ++ fputs(buf, dsaresp); ++ continue; ++ } ++ if (parse_secitem ("Q", buf, &Q)) { ++ fputs(buf, dsaresp); ++ continue; ++ } ++ if (parse_secitem ("firstseed", buf, &firstseed)) { ++ fputs(buf, dsaresp); ++ continue; ++ } ++ if (parse_secitem ("pseed", buf, &pseed)) { ++ fputs(buf, dsaresp); ++ continue; ++ } ++ if (parse_secitem ("qseed", buf, &qseed)) { ++ fputs(buf, dsaresp); ++ continue; ++ } ++ if (parse_secitem ("index", buf, &index) && type == A_2_3) { ++ SECStatus rv; ++ PLArenaPool *arena; ++ ++ fputs(buf, dsaresp); ++ ++ arena = PORT_NewArena (NSS_FREEBL_DEFAULT_CHUNKSIZE); ++ pqg = (PQGParams *)PORT_ArenaZAlloc(arena, sizeof(PQGParams)); ++ pqg->arena = arena; ++ ++ arena = PORT_NewArena (NSS_FREEBL_DEFAULT_CHUNKSIZE); ++ vfy = (PQGVerify *)PORT_ArenaZAlloc(arena, sizeof(PQGVerify)); ++ vfy->arena = arena; ++ ++ SECITEM_CopyItem(pqg->arena, &pqg->prime, &P); ++ SECITEM_CopyItem(pqg->arena, &pqg->subPrime, &Q); ++ ++ SECITEM_AllocItem(vfy->arena, &vfy->seed, firstseed.len + pseed.len + qseed.len); ++ memcpy (vfy->seed.data, firstseed.data, firstseed.len); ++ memcpy (vfy->seed.data + firstseed.len, pseed.data, pseed.len); ++ memcpy (vfy->seed.data + firstseed.len + pseed.len, qseed.data, qseed.len); ++ ++ SECITEM_AllocItem(vfy->arena, &vfy->h, 1); ++ vfy->h.data [0] = index.data [0]; ++ ++ rv = FREEBL_Test_PQG_ParamGenV2_p(L, N, 0, &pqg, &vfy, &firstseed, hashtype); ++ if (rv != SECSuccess) { ++ fprintf(dsaresp, ++ "ERROR: Unable to verify PQG parameters"); ++ goto loser; ++ } ++ ++ to_hex_str(buf, pqg->base.data, pqg->base.len); ++ fprintf(dsaresp, "G = %s\n\n", buf); ++ ++ PQG_DestroyParams(pqg); ++ pqg = NULL; ++ PQG_DestroyVerify(vfy); ++ vfy = NULL; + continue; + } + } + loser: + fclose(dsareq); ++ if (P.data) ++ SECITEM_ZfreeItem(&P, PR_FALSE); ++ if (Q.data) ++ SECITEM_ZfreeItem(&Q, PR_FALSE); ++ if (firstseed.data) ++ SECITEM_ZfreeItem(&firstseed, PR_FALSE); ++ if (pseed.data) ++ SECITEM_ZfreeItem(&pseed, PR_FALSE); ++ if (qseed.data) ++ SECITEM_ZfreeItem(&qseed, PR_FALSE); ++ if (index.data) ++ SECITEM_ZfreeItem(&index, PR_FALSE); + if (pqg != NULL) { + PQG_DestroyParams(pqg); + } diff --git a/nss-fips-cavs-general.patch b/nss-fips-cavs-general.patch new file mode 100644 index 0000000..e870783 --- /dev/null +++ b/nss-fips-cavs-general.patch @@ -0,0 +1,311 @@ +# HG changeset patch +# User M. Sirringhaus +# Date 1590413427 -7200 +# Mon May 25 15:30:27 2020 +0200 +# Node ID 969310ea4c573aac64bf08846b8938b8fa783870 +# Parent 60c5e5d73ce1177fa66d8fd6cf49d9b371ca9be4 +imported patch nss-fips-cavs-general.patch + +diff --git a/cmd/fipstest/fipstest.c b/cmd/fipstest/fipstest.c +--- a/cmd/fipstest/fipstest.c ++++ b/cmd/fipstest/fipstest.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + + #include "secitem.h" + #include "blapi.h" +@@ -18,6 +19,9 @@ + #include "lowkeyi.h" + #include "softoken.h" + #include "pkcs11t.h" ++ ++#include "../../lib/freebl/fips.h" ++ + #define __PASTE(x, y) x##y + #undef CK_PKCS11_FUNCTION_INFO + #undef CK_NEED_ARG_LIST +@@ -55,6 +59,10 @@ + #define RSA_MAX_TEST_EXPONENT_BYTES 8 + #define PQG_TEST_SEED_BYTES 20 + ++SECStatus (*FREEBL_Test_PQG_ParamGenV2_p) (unsigned int L, unsigned int N, unsigned int seedBytes, ++ PQGParams **pParams, PQGVerify **pVfy, ++ SECItem *firstseed, HASH_HashType hashtype); ++ + SECStatus + hex_to_byteval(const char *c2, unsigned char *byteval) + { +@@ -168,6 +176,62 @@ + return PR_TRUE; + } + ++#if 0 ++ ++static void ++dump_secitem (FILE *out, SECItem *secitem) ++{ ++ char buf [4096]; ++ ++ to_hex_str(buf, secitem->data, secitem->len); ++ fputs (buf, out); ++} ++ ++static void ++dump_labeled_secitem (FILE *out, const char *name, SECItem *secitem) ++{ ++ fprintf (out, "%s = ", name); ++ dump_secitem (out, secitem); ++ fputs ("\n", out); ++} ++ ++#endif ++ ++static int ++parse_secitem (const char *name, const char *buf, SECItem *secitem) ++{ ++ if (!strncmp (buf, name, strlen (name))) { ++ int i, j, len; ++ ++ i = strlen (name); ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ ++ len = strspn (&buf[i], "0123456789abcdefABCDEF"); ++ if (!len) ++ return 0; ++ ++ if (secitem->data) { ++ SECITEM_ZfreeItem(secitem, PR_FALSE); ++ secitem->data = NULL; ++ } ++ ++ len = (len + 1) / 2; ++ SECITEM_AllocItem(NULL, secitem, len); ++ secitem->len = len; ++ ++ memset(secitem->data, 0, secitem->len); ++ for (j = 0; j < secitem->len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &secitem->data[j]); ++ } ++ ++ return 1; ++ } ++ ++ return 0; ++} ++ + SECStatus + tdea_encrypt_buf( + int mode, +@@ -8930,41 +8994,6 @@ + } + } + +-static int +-parse_secitem (const char *name, const char *buf, SECItem *secitem) +-{ +- if (!strncmp (buf, name, strlen (name))) { +- int i, j, len; +- +- i = strlen (name); +- while (isspace(buf[i]) || buf[i] == '=') { +- i++; +- } +- +- len = strspn (&buf[i], "0123456789abcdefABCDEF"); +- if (!len) +- return 0; +- +- if (secitem->data) { +- SECITEM_ZfreeItem(secitem, PR_FALSE); +- secitem->data = NULL; +- } +- +- len = (len + 1) / 2; +- SECITEM_AllocItem(NULL, secitem, len); +- secitem->len = len; +- +- memset(secitem->data, 0, secitem->len); +- for (j = 0; j < secitem->len; i += 2, j++) { +- hex_to_byteval(&buf[i], &secitem->data[j]); +- } +- +- return 1; +- } +- +- return 0; +-} +- + void + kas_ffc_test(char *reqfn, int do_validity) + { +@@ -9387,12 +9416,34 @@ + free_param_specs (pspecs); + } + ++static void ++init_functions (void) ++{ ++ void *freebl_so; ++ ++ freebl_so = dlopen ("libfreeblpriv3.so", RTLD_LAZY); ++ if (freebl_so == NULL) ++ { ++ fprintf (stderr, "Failed to load libfreeblpriv3.so."); ++ exit (1); ++ } ++ ++ FREEBL_Test_PQG_ParamGenV2_p = dlsym (freebl_so, "FREEBL_Test_PQG_ParamGenV2"); ++ ++ if (FREEBL_Test_PQG_ParamGenV2_p == NULL) ++ { ++ fprintf (stderr, "Failed to bind FREEBL_TEST_PQG_ParamGenV2."); ++ exit (1); ++ } ++} ++ + int + main(int argc, char **argv) + { + if (argc < 2) + exit(-1); + ++ init_functions(); + RNG_RNGInit(); + SECOID_Init(); + +diff --git a/lib/freebl/freebl.def b/lib/freebl/freebl.def +--- a/lib/freebl/freebl.def ++++ b/lib/freebl/freebl.def +@@ -21,6 +21,7 @@ + LIBRARY freebl3 ;- + EXPORTS ;- + FREEBL_GetVector; ++FREEBL_Test_PQG_ParamGenV2; + ;+ local: + ;+ *; + ;+}; +diff --git a/lib/freebl/freebl_hash.def b/lib/freebl/freebl_hash.def +--- a/lib/freebl/freebl_hash.def ++++ b/lib/freebl/freebl_hash.def +@@ -21,6 +21,7 @@ + LIBRARY freebl3 ;- + EXPORTS ;- + FREEBL_GetVector; ++FREEBL_Test_PQG_ParamGenV2; + ;+ local: + ;+ *; + ;+}; +diff --git a/lib/freebl/freebl_hash_vector.def b/lib/freebl/freebl_hash_vector.def +--- a/lib/freebl/freebl_hash_vector.def ++++ b/lib/freebl/freebl_hash_vector.def +@@ -21,6 +21,7 @@ + LIBRARY freebl3 ;- + EXPORTS ;- + FREEBL_GetVector; ++FREEBL_Test_PQG_ParamGenV2; + ;+ local: + ;+ *; + ;+}; +diff --git a/lib/freebl/pqg.c b/lib/freebl/pqg.c +--- a/lib/freebl/pqg.c ++++ b/lib/freebl/pqg.c +@@ -1231,7 +1231,8 @@ + **/ + static SECStatus + pqg_ParamGen(unsigned int L, unsigned int N, pqgGenType type, +- unsigned int seedBytes, PQGParams **pParams, PQGVerify **pVfy) ++ unsigned int seedBytes, PQGParams **pParams, PQGVerify **pVfy, ++ SECItem *firstseed_out, HASH_HashType hashtype) + { + unsigned int n; /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */ + unsigned int seedlen; /* Per FIPS 186-3 app A.1.1.2 (was 'g' 186-1)*/ +@@ -1239,7 +1240,6 @@ + unsigned int offset; /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */ + unsigned int outlen; /* Per FIPS 186-3, appendix A.1.1.2. */ + unsigned int maxCount; +- HASH_HashType hashtype = HASH_AlgNULL; + SECItem *seed; /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */ + PLArenaPool *arena = NULL; + PQGParams *params = NULL; +@@ -1290,7 +1290,8 @@ + /* fill in P Q, */ + SECITEM_TO_MPINT((*pParams)->prime, &P); + SECITEM_TO_MPINT((*pParams)->subPrime, &Q); +- hashtype = getFirstHash(L, N); ++ if (hashtype == HASH_AlgNULL) ++ hashtype = getFirstHash(L, N); + CHECK_SEC_OK(makeGfromIndex(hashtype, &P, &Q, &(*pVfy)->seed, + (*pVfy)->h.data[0], &G)); + MPINT_TO_SECITEM(&G, &(*pParams)->base, (*pParams)->arena); +@@ -1330,7 +1331,8 @@ + /* Select Hash and Compute lengths. */ + /* getFirstHash gives us the smallest acceptable hash for this key + * strength */ +- hashtype = getFirstHash(L, N); ++ if (hashtype == HASH_AlgNULL) ++ hashtype = getFirstHash(L, N); + outlen = HASH_ResultLen(hashtype) * PR_BITS_PER_BYTE; + + /* Step 3: n = Ceil(L/outlen)-1; (same as n = Floor((L-1)/outlen)) */ +@@ -1532,6 +1534,10 @@ + verify->counter = counter; + *pParams = params; + *pVfy = verify; ++ ++ if (firstseed_out) ++ SECITEM_CopyItem (NULL, firstseed_out, &firstseed); ++ + cleanup: + if (pseed.data) { + PORT_Free(pseed.data); +@@ -1576,7 +1582,7 @@ + L = 512 + (j * 64); /* bits in P */ + seedBytes = L / 8; + return pqg_ParamGen(L, DSA1_Q_BITS, FIPS186_1_TYPE, seedBytes, +- pParams, pVfy); ++ pParams, pVfy, NULL, HASH_AlgNULL); + } + + SECStatus +@@ -1591,7 +1597,7 @@ + } + L = 512 + (j * 64); /* bits in P */ + return pqg_ParamGen(L, DSA1_Q_BITS, FIPS186_1_TYPE, seedBytes, +- pParams, pVfy); ++ pParams, pVfy, NULL, HASH_AlgNULL); + } + + SECStatus +@@ -1609,7 +1615,26 @@ + /* error code already set */ + return SECFailure; + } +- return pqg_ParamGen(L, N, FIPS186_3_ST_TYPE, seedBytes, pParams, pVfy); ++ return pqg_ParamGen(L, N, FIPS186_3_ST_TYPE, seedBytes, pParams, pVfy, NULL, HASH_AlgNULL); ++} ++ ++SECStatus ++FREEBL_Test_PQG_ParamGenV2 (unsigned int L, unsigned int N, unsigned int seedBytes, ++ PQGParams **pParams, PQGVerify **pVfy, SECItem *firstseed_out, ++ HASH_HashType hashtype) ++{ ++ if (N == 0) { ++ N = pqg_get_default_N(L); ++ } ++ if (seedBytes == 0) { ++ /* seedBytes == L/8 for probable primes, N/8 for Shawe-Taylor Primes */ ++ seedBytes = N / 8; ++ } ++ if (pqg_validate_dsa2(L, N) != SECSuccess) { ++ /* error code already set */ ++ return SECFailure; ++ } ++ return pqg_ParamGen(L, N, FIPS186_3_ST_TYPE, seedBytes, pParams, pVfy, firstseed_out, hashtype); + } + + /* diff --git a/nss-fips-cavs-kas-ecc.patch b/nss-fips-cavs-kas-ecc.patch new file mode 100644 index 0000000..d0662ee --- /dev/null +++ b/nss-fips-cavs-kas-ecc.patch @@ -0,0 +1,370 @@ +# HG changeset patch +# User Hans Petter Jansson +# Date 1574234615 -3600 +# Wed Nov 20 08:23:35 2019 +0100 +# Node ID f5cf5d16deb68e65b5dd4e799d9e8e3098400d62 +# Parent af7d3ee4e96cf685be0b95dff7aa5a1d3ab64a89 +[PATCH] 21 +From 4c27df62aa425745620f45710465b0264acacbb0 Mon Sep 17 00:00:00 2001 +--- + nss/cmd/fipstest/fipstest.c | 304 ++++++++++++++++++++++++++++++++++++ + nss/cmd/fipstest/kas.sh | 22 +++ + 2 files changed, 326 insertions(+) + +diff --git a/cmd/fipstest/fipstest.c b/cmd/fipstest/fipstest.c +--- a/cmd/fipstest/fipstest.c ++++ b/cmd/fipstest/fipstest.c +@@ -9092,6 +9092,301 @@ + } + } + ++typedef struct ++{ ++ char param_name [2]; ++ ECParams *ecparams; ++ int hash_len; ++ HASH_HashType hash_type; ++} ++ParamSpec; ++ ++#define PARAM_SPECS_MAX 12 ++ ++static int ++find_free_param_spec (const ParamSpec *pspecs) ++{ ++ int i; ++ ++ for (i = 0; i < PARAM_SPECS_MAX; i++) ++ { ++ if (pspecs [i].param_name [0] == 0 ++ && pspecs [i].param_name [1] == 0) ++ return i; ++ } ++ ++ return 0; ++} ++ ++static int ++find_param_spec (const ParamSpec *pspecs, char *name) ++{ ++ int i; ++ ++ for (i = 0; i < PARAM_SPECS_MAX; i++) ++ { ++ if (pspecs [i].param_name [0] == name [0] ++ && pspecs [i].param_name [1] == name [1]) ++ return i; ++ } ++ ++ return 0; ++} ++ ++static void ++free_param_specs (ParamSpec *pspecs) ++{ ++ int i; ++ ++ for (i = 0; i < PARAM_SPECS_MAX; i++) ++ { ++ if (pspecs [i].ecparams) ++ PORT_FreeArena(pspecs [i].ecparams->arena, PR_FALSE); ++ } ++} ++ ++#define CURVE_NAME_MAX 64 ++ ++static ECParams * ++get_and_decode_nistp_params (int n) ++{ ++ char curve_name [CURVE_NAME_MAX]; ++ SECItem *encodedparams; ++ ECParams *ecparams = NULL; ++ ++ snprintf (curve_name, CURVE_NAME_MAX, "nistp%d", n); ++ ++ encodedparams = getECParams (curve_name); ++ if (!encodedparams) ++ return NULL; ++ ++ EC_DecodeParams (encodedparams, &ecparams); ++ SECITEM_FreeItem(encodedparams, PR_TRUE); ++ return ecparams; ++} ++ ++void ++kas_ecc_test(char *reqfn, int do_validity) ++{ ++ char buf[2048]; ++ FILE *req; /* input stream from the REQUEST file */ ++ FILE *resp; /* output stream to the RESPONSE file */ ++ ParamSpec pspecs [PARAM_SPECS_MAX]; ++ SECItem x_ephem_cavs; ++ SECItem y_ephem_cavs; ++ SECItem x_ephem_iut; ++ SECItem y_ephem_iut; ++ SECItem d_ephem_iut; ++ SECItem cavs_hash_zz; ++ SECItem publicValue; ++ int current_pspec_def = -1; ++ ++ req = fopen(reqfn, "r"); ++ resp = stdout; ++ memset(&pspecs, 0, sizeof (pspecs)); ++ memset(&x_ephem_cavs, 0, sizeof(x_ephem_cavs)); ++ memset(&y_ephem_cavs, 0, sizeof(y_ephem_cavs)); ++ memset(&x_ephem_iut, 0, sizeof(x_ephem_iut)); ++ memset(&y_ephem_iut, 0, sizeof(y_ephem_iut)); ++ memset(&d_ephem_iut, 0, sizeof(d_ephem_iut)); ++ memset(&cavs_hash_zz, 0, sizeof(cavs_hash_zz)); ++ memset(&publicValue, 0, sizeof(publicValue)); ++ ++ while (fgets(buf, sizeof buf, req) != NULL) { ++ /* [xx] or ++ * [xx - SHAxxx] or ++ * [SHA(s) supported (Used for hashing Z): SHAxxx] */ ++ if (buf[0] == '[') { ++ char tbuf [2]; ++ int num; ++ ++ if (strlen (buf) >= 4 && buf [3] == ']' ++ && sscanf(buf, "[%c%c]", &tbuf [0], &tbuf [1]) == 2) { ++ int i = current_pspec_def = find_free_param_spec (pspecs); ++ if (i < 0) ++ goto out; ++ ++ pspecs [i].param_name [0] = tbuf [0]; ++ pspecs [i].param_name [1] = tbuf [1]; ++ ++ fputs(buf, resp); ++ continue; ++ } ++ ++ if (strlen (buf) >= 6 && buf [3] == ' ' && buf [4] == '-' ++ && sscanf(buf, "[%c%c - ", &tbuf [0], &tbuf [1]) == 2) { ++ current_pspec_def = find_param_spec (pspecs, tbuf); ++ if (current_pspec_def < 0) ++ goto out; ++ ++ fputs(buf, resp); ++ continue; ++ } ++ ++ if (!strncmp(buf, "[Curve selected:", strlen ("[Curve selected:"))) { ++ char *p = buf + strlen ("[Curve selected:"); ++ p += strcspn (p, "0123456789"); ++ if (!*p) ++ goto out; ++ if (sscanf(p, "%d", &num) != 1) ++ goto out; ++ ++ if (current_pspec_def < 0) ++ goto out; ++ ++ pspecs [current_pspec_def].ecparams = get_and_decode_nistp_params (num); ++ if (!pspecs [current_pspec_def].ecparams) ++ goto out; ++ ++ fputs(buf, resp); ++ continue; ++ } ++ ++ if (sscanf(buf, "[SHA(s) supported (Used for hashing Z): SHA%d", &num) == 1) { ++ if (current_pspec_def < 0) ++ goto out; ++ ++ pspecs [current_pspec_def].hash_len = num; ++ pspecs [current_pspec_def].hash_type = sha_get_hashType(num); ++ fputs(buf, resp); ++ continue; ++ } ++ ++ fputs(buf, resp); ++ continue; ++ } else if (parse_secitem ("QeCAVSx", buf, &x_ephem_cavs)) { ++ fputs(buf, resp); ++ continue; ++ } else if (parse_secitem ("QeCAVSy", buf, &y_ephem_cavs)) { ++ fputs(buf, resp); ++ ++ if (!do_validity) { ++ SECItem ZZ; ++ unsigned char ZZ_hash_buf [1024]; ++ int field_len; ++ int len; ++ ECPrivateKey *privKey; ++ ++ field_len = (pspecs [current_pspec_def].ecparams->fieldID.size + 7) >> 3; ++ ++ if (EC_NewKey(pspecs [current_pspec_def].ecparams, &privKey) != SECSuccess) ++ goto out; ++ ++ len = privKey->publicValue.len; ++ if (len % 2 == 0) { ++ goto out; ++ } ++ len = (len - 1) / 2; ++ if (privKey->publicValue.data[0] != ++ EC_POINT_FORM_UNCOMPRESSED) { ++ goto out; ++ } ++ ++ to_hex_str(buf, &privKey->publicValue.data[1], len); ++ fprintf (resp, "QeIUTx = %s\n", buf); ++ to_hex_str(buf, &privKey->publicValue.data[1 + len], len); ++ fprintf (resp, "QeIUTy = %s\n", buf); ++ ++ SECITEM_AllocItem(NULL, &publicValue, 1 + 2 * field_len); ++ publicValue.len = 1 + 2 * field_len; ++ publicValue.data [0] = EC_POINT_FORM_UNCOMPRESSED; ++ memcpy (&publicValue.data [1], x_ephem_cavs.data + x_ephem_cavs.len - field_len, field_len); ++ memcpy (&publicValue.data [1 + field_len], y_ephem_cavs.data + y_ephem_cavs.len - field_len, field_len); ++ ++ if (ECDH_Derive (&publicValue, pspecs [current_pspec_def].ecparams, &privKey->privateValue, PR_TRUE, &ZZ) != SECSuccess) { ++ goto out; ++ } ++ ++ SECITEM_ZfreeItem(&publicValue, PR_FALSE); ++ publicValue.data = NULL; ++ ++ fips_hashBuf_zeropad(pspecs [current_pspec_def].hash_type, ZZ_hash_buf, ZZ.data, ZZ.len, len); ++ ++ to_hex_str(buf, ZZ_hash_buf, pspecs [current_pspec_def].hash_len / 8); ++ fprintf (resp, "HashZZ = %s\n", buf); ++ ++ PORT_FreeArena(privKey->ecParams.arena, PR_TRUE); ++ } ++ ++ continue; ++ } else if (parse_secitem ("deIUT", buf, &d_ephem_iut)) { ++ fputs(buf, resp); ++ continue; ++ } else if (parse_secitem ("QeIUTx", buf, &x_ephem_iut)) { ++ fputs(buf, resp); ++ continue; ++ } else if (parse_secitem ("QeIUTy", buf, &y_ephem_iut)) { ++ fputs(buf, resp); ++ continue; ++ } else if (parse_secitem ("CAVSHashZZ", buf, &cavs_hash_zz)) { ++ if (do_validity) { ++ SECItem ZZ; ++ unsigned char ZZ_hash_buf [1024]; ++ char Z_buf [1024]; ++ int field_len; ++ ++ field_len = (pspecs [current_pspec_def].ecparams->fieldID.size + 7) >> 3; ++ ++ SECITEM_AllocItem(NULL, &publicValue, 1 + 2 * field_len); ++ publicValue.len = 1 + 2 * field_len; ++ publicValue.data [0] = EC_POINT_FORM_UNCOMPRESSED; ++ memcpy (&publicValue.data [1], x_ephem_cavs.data + x_ephem_cavs.len - field_len, field_len); ++ memcpy (&publicValue.data [1 + field_len], y_ephem_cavs.data + y_ephem_cavs.len - field_len, field_len); ++ ++ if (ECDH_Derive (&publicValue, pspecs [current_pspec_def].ecparams, &d_ephem_iut, PR_TRUE, &ZZ) != SECSuccess) { ++ goto out; ++ } ++ ++ SECITEM_ZfreeItem(&publicValue, PR_FALSE); ++ publicValue.data = NULL; ++ ++ fputs(buf, resp); ++ ++ fips_hashBuf_zeropad(pspecs [current_pspec_def].hash_type, ZZ_hash_buf, ZZ.data, ZZ.len, field_len); ++ to_hex_str(Z_buf, ZZ_hash_buf, pspecs [current_pspec_def].hash_len / 8); ++ fprintf(resp, "IUTHashZZ = %s\n", Z_buf); ++ ++ fprintf(resp, "Result = %s\n", ++ (cavs_hash_zz.len == pspecs [current_pspec_def].hash_len / 8 ++ && memcmp (cavs_hash_zz.data, ZZ_hash_buf, pspecs [current_pspec_def].hash_len / 8) == 0) ? "P" : "F"); ++ } else { ++ fputs(buf, resp); ++ } ++ continue; ++ } else { ++ /* Comments, blank lines, ... */ ++ fputs(buf, resp); ++ } ++ } ++ ++out: ++ fclose(req); ++ ++ if (d_ephem_iut.data) { ++ SECITEM_ZfreeItem(&d_ephem_iut, PR_FALSE); ++ } ++ if (x_ephem_iut.data) { ++ SECITEM_ZfreeItem(&x_ephem_iut, PR_FALSE); ++ } ++ if (y_ephem_iut.data) { ++ SECITEM_ZfreeItem(&y_ephem_iut, PR_FALSE); ++ } ++ if (x_ephem_cavs.data) { ++ SECITEM_ZfreeItem(&x_ephem_cavs, PR_FALSE); ++ } ++ if (y_ephem_cavs.data) { ++ SECITEM_ZfreeItem(&y_ephem_cavs, PR_FALSE); ++ } ++ if (cavs_hash_zz.data) { ++ SECITEM_ZfreeItem(&cavs_hash_zz, PR_FALSE); ++ } ++ if (publicValue.data) { ++ SECITEM_ZfreeItem(&publicValue, PR_FALSE); ++ } ++ ++ free_param_specs (pspecs); ++} ++ + int + main(int argc, char **argv) + { +@@ -9287,6 +9582,15 @@ + } else { + kas_ffc_test(argv[3], PR_FALSE); + } ++ } else if (strcmp(argv[1], "kasecc") == 0) { ++ /***************/ ++ /* KAS ECC */ ++ /***************/ ++ if (strcmp(argv[2], "validity") == 0) { ++ kas_ecc_test(argv[3], PR_TRUE); ++ } else { ++ kas_ecc_test(argv[3], PR_FALSE); ++ } + } + return 0; + } +diff --git a/cmd/fipstest/kas.sh b/cmd/fipstest/kas.sh +--- a/cmd/fipstest/kas.sh ++++ b/cmd/fipstest/kas.sh +@@ -27,6 +27,16 @@ + KASValidityTest_FFCEphem_NOKC_ZZOnly_resp.req + " + ++kas_requests_ecc_function=" ++KASFunctionTest_ECCEphemeralUnified_NOKC_ZZOnly_init.req ++KASFunctionTest_ECCEphemeralUnified_NOKC_ZZOnly_resp.req ++" ++ ++kas_requests_ecc_validity=" ++KASValidityTest_ECCEphemeralUnified_NOKC_ZZOnly_init.req ++KASValidityTest_ECCEphemeralUnified_NOKC_ZZOnly_resp.req ++" ++ + if [ ${COMMAND} = "verify" ]; then + for request in $kas_requests; do + sh ./validate1.sh ${TESTDIR} $request +@@ -45,3 +55,15 @@ + echo $request $response + fipstest kasffc validity ${REQDIR}/$request > ${RSPDIR}/$response + done ++ ++for request in $kas_requests_ecc_function; do ++ response=`echo $request | sed -e "s/req/rsp/"` ++ echo $request $response ++ fipstest kasecc function ${REQDIR}/$request > ${RSPDIR}/$response ++done ++ ++for request in $kas_requests_ecc_validity; do ++ response=`echo $request | sed -e "s/req/rsp/"` ++ echo $request $response ++ fipstest kasecc validity ${REQDIR}/$request > ${RSPDIR}/$response ++done diff --git a/nss-fips-cavs-kas-ffc.patch b/nss-fips-cavs-kas-ffc.patch new file mode 100644 index 0000000..da305be --- /dev/null +++ b/nss-fips-cavs-kas-ffc.patch @@ -0,0 +1,284 @@ +# HG changeset patch +# User Hans Petter Jansson +# Date 1574234297 -3600 +# Wed Nov 20 08:18:17 2019 +0100 +# Node ID af7d3ee4e96cf685be0b95dff7aa5a1d3ab64a89 +# Parent 5d6e015d1af40b5f5b990d0cf4d97932774c2a61 +[PATCH] 20 +From ac98082c3bc0c9f85213078b730980483062f25c Mon Sep 17 00:00:00 2001 +--- + nss/cmd/fipstest/fipstest.c | 194 ++++++++++++++++++++++++++++++++++++ + nss/cmd/fipstest/kas.sh | 47 +++++++++ + 2 files changed, 241 insertions(+) + create mode 100644 nss/cmd/fipstest/kas.sh + +diff --git a/cmd/fipstest/fipstest.c b/cmd/fipstest/fipstest.c +--- a/cmd/fipstest/fipstest.c ++++ b/cmd/fipstest/fipstest.c +@@ -2258,6 +2258,29 @@ + return rv; + } + ++SECStatus ++fips_hashBuf_zeropad(HASH_HashType type, unsigned char *hashBuf, ++ unsigned char *msg, int len, int pad_to_len) ++{ ++ unsigned char buf [8192]; ++ ++ if (pad_to_len > 8192) ++ { ++ fprintf (stderr, "Internal buffer too small.\n"); ++ exit (1); ++ } ++ ++ if (len > pad_to_len) ++ { ++ fprintf (stderr, "Value to hash exceeds maximum length.\n"); ++ exit (1); ++ } ++ ++ memset (buf, 0, pad_to_len - len); ++ memcpy (buf + (pad_to_len - len), msg, len); ++ return fips_hashBuf (type, hashBuf, buf, pad_to_len); ++} ++ + int + fips_hashLen(HASH_HashType type) + { +@@ -8907,6 +8930,168 @@ + } + } + ++static int ++parse_secitem (const char *name, const char *buf, SECItem *secitem) ++{ ++ if (!strncmp (buf, name, strlen (name))) { ++ int i, j, len; ++ ++ i = strlen (name); ++ while (isspace(buf[i]) || buf[i] == '=') { ++ i++; ++ } ++ ++ len = strspn (&buf[i], "0123456789abcdefABCDEF"); ++ if (!len) ++ return 0; ++ ++ if (secitem->data) { ++ SECITEM_ZfreeItem(secitem, PR_FALSE); ++ secitem->data = NULL; ++ } ++ ++ len = (len + 1) / 2; ++ SECITEM_AllocItem(NULL, secitem, len); ++ secitem->len = len; ++ ++ memset(secitem->data, 0, secitem->len); ++ for (j = 0; j < secitem->len; i += 2, j++) { ++ hex_to_byteval(&buf[i], &secitem->data[j]); ++ } ++ ++ return 1; ++ } ++ ++ return 0; ++} ++ ++void ++kas_ffc_test(char *reqfn, int do_validity) ++{ ++ char buf[1024]; ++ FILE *req; /* input stream from the REQUEST file */ ++ FILE *resp; /* output stream to the RESPONSE file */ ++ PQGParams keyParams; ++ HASH_HashType hashType = HASH_AlgNULL; ++ int hashNum = 0; ++ SECItem y_ephem_cavs; ++ SECItem x_ephem_iut; ++ SECItem y_ephem_iut; ++ SECItem cavs_hash_zz; ++ ++ req = fopen(reqfn, "r"); ++ resp = stdout; ++ memset(&keyParams, 0, sizeof(keyParams)); ++ memset(&y_ephem_cavs, 0, sizeof(y_ephem_cavs)); ++ memset(&x_ephem_iut, 0, sizeof(x_ephem_iut)); ++ memset(&y_ephem_iut, 0, sizeof(y_ephem_iut)); ++ memset(&cavs_hash_zz, 0, sizeof(cavs_hash_zz)); ++ ++ while (fgets(buf, sizeof buf, req) != NULL) { ++ /* [xx] or ++ * [xx - SHAxxx] or ++ * [SHA(s) supported (Used for hashing Z): SHAxxx] */ ++ if (buf[0] == '[') { ++ unsigned char tbuf [2]; ++ ++ if (sscanf(buf, "[%c%c - SHA%d]", &tbuf [0], &tbuf [1], ++ &hashNum) != 3) { ++ fputs(buf, resp); ++ continue; ++ } ++ ++ fputs(buf, resp); ++ ++ hashType = sha_get_hashType(hashNum); ++ if (hashType == HASH_AlgNULL) { ++ fprintf(resp, "ERROR: invalid hash (SHA-%d)", hashNum); ++ goto out; ++ } ++ ++ continue; ++ } else if (parse_secitem ("YephemCAVS", buf, &y_ephem_cavs)) { ++ fputs(buf, resp); ++ ++ if (!do_validity) { ++ SECItem ZZ; ++ unsigned char ZZ_hash_buf [1024]; ++ DHParams dh_params; ++ DHPrivateKey *dh_privKey; ++ ++ dh_params.prime = keyParams.prime; ++ dh_params.base = keyParams.base; ++ ++ DH_NewKey (&dh_params, &dh_privKey); ++ DH_Derive(&y_ephem_cavs, &keyParams.prime, &dh_privKey->privateValue, &ZZ, 0); ++ ++ fips_hashBuf_zeropad(hashType, ZZ_hash_buf, ZZ.data, ZZ.len, keyParams.prime.len); ++ ++ to_hex_str(buf, dh_privKey->publicValue.data, dh_privKey->publicValue.len); ++ fprintf(resp, "YephemIUT = %s\n", buf); ++ ++ to_hex_str(buf, ZZ_hash_buf, hashNum / 8); ++ fprintf(resp, "HashZZ = %s\n", buf); ++ ++ PORT_FreeArena(dh_privKey->arena, PR_TRUE); ++ } ++ ++ continue; ++ } else if (parse_secitem ("XephemIUT", buf, &x_ephem_iut)) { ++ fputs(buf, resp); ++ continue; ++ } else if (parse_secitem ("YephemIUT", buf, &y_ephem_iut)) { ++ fputs(buf, resp); ++ continue; ++ } else if (parse_secitem ("CAVSHashZZ", buf, &cavs_hash_zz)) { ++ if (do_validity) { ++ SECItem ZZ; ++ unsigned char ZZ_hash_buf [1024]; ++ char Z_buf [1024]; ++ ++ DH_Derive(&y_ephem_cavs, &keyParams.prime, &x_ephem_iut, &ZZ, 0); ++ ++ fputs(buf, resp); ++ ++ to_hex_str(Z_buf, ZZ.data, ZZ.len); ++ ++ fips_hashBuf_zeropad(hashType, ZZ_hash_buf, ZZ.data, ZZ.len, keyParams.prime.len); ++ to_hex_str(Z_buf, ZZ_hash_buf, hashNum / 8); ++ fprintf(resp, "IUTHashZZ = %s\n", Z_buf); ++ ++ fprintf(resp, "Result = %s\n", ++ (cavs_hash_zz.len == hashNum / 8 && memcmp (cavs_hash_zz.data, ZZ_hash_buf, hashNum / 8) == 0) ? "P" : "F"); ++ } else { ++ fputs(buf, resp); ++ } ++ continue; ++ } else if (parse_secitem ("P", buf, &keyParams.prime)) { ++ fputs(buf, resp); ++ continue; ++ } else if (parse_secitem ("Q", buf, &keyParams.subPrime)) { ++ fputs(buf, resp); ++ continue; ++ } else if (parse_secitem ("G", buf, &keyParams.base)) { ++ fputs(buf, resp); ++ continue; ++ } else { ++ /* Comments, blank lines, ... */ ++ fputs(buf, resp); ++ } ++ } ++ ++out: ++ fclose(req); ++ if (keyParams.prime.data) { /* P */ ++ SECITEM_ZfreeItem(&keyParams.prime, PR_FALSE); ++ } ++ if (keyParams.subPrime.data) { /* Q */ ++ SECITEM_ZfreeItem(&keyParams.subPrime, PR_FALSE); ++ } ++ if (keyParams.base.data) { /* G */ ++ SECITEM_ZfreeItem(&keyParams.base, PR_FALSE); ++ } ++} ++ + int + main(int argc, char **argv) + { +@@ -9093,6 +9278,15 @@ + /* AES Keywrap */ + /***************/ + keywrap(argv[2]); ++ } else if (strcmp(argv[1], "kasffc") == 0) { ++ /***************/ ++ /* KAS FFC */ ++ /***************/ ++ if (strcmp(argv[2], "validity") == 0) { ++ kas_ffc_test(argv[3], PR_TRUE); ++ } else { ++ kas_ffc_test(argv[3], PR_FALSE); ++ } + } + return 0; + } +diff --git a/cmd/fipstest/kas.sh b/cmd/fipstest/kas.sh +new file mode 100644 +--- /dev/null ++++ b/cmd/fipstest/kas.sh +@@ -0,0 +1,47 @@ ++#!/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}/KAS ++COMMAND=${2-run} ++REQDIR=${TESTDIR}/req ++RSPDIR=${TESTDIR}/resp ++ ++kas_requests_ffc_function=" ++KASFunctionTest_FFCEphem_NOKC_ZZOnly_init.req ++KASFunctionTest_FFCEphem_NOKC_ZZOnly_resp.req ++" ++ ++kas_requests_ffc_validity=" ++KASValidityTest_FFCEphem_NOKC_ZZOnly_init.req ++KASValidityTest_FFCEphem_NOKC_ZZOnly_resp.req ++" ++ ++if [ ${COMMAND} = "verify" ]; then ++ for request in $kas_requests; do ++ sh ./validate1.sh ${TESTDIR} $request ++ done ++ exit 0 ++fi ++ ++for request in $kas_requests_ffc_function; do ++ response=`echo $request | sed -e "s/req/rsp/"` ++ echo $request $response ++ fipstest kasffc function ${REQDIR}/$request > ${RSPDIR}/$response ++done ++ ++for request in $kas_requests_ffc_validity; do ++ response=`echo $request | sed -e "s/req/rsp/"` ++ echo $request $response ++ fipstest kasffc validity ${REQDIR}/$request > ${RSPDIR}/$response ++done diff --git a/nss-fips-cavs-keywrap.patch b/nss-fips-cavs-keywrap.patch new file mode 100644 index 0000000..47b709a --- /dev/null +++ b/nss-fips-cavs-keywrap.patch @@ -0,0 +1,235 @@ +# HG changeset patch +# User Hans Petter Jansson +# Date 1574234023 -3600 +# Wed Nov 20 08:13:43 2019 +0100 +# Node ID 5d6e015d1af40b5f5b990d0cf4d97932774c2a61 +# Parent 2f570c6952d8edfc1ad9061cd3830f202eec1960 +[PATCH 1/2] 19 +From f4cbaf95fcf2519029bb3c4407b2f15aa27c94c1 Mon Sep 17 00:00:00 2001 +--- + nss/cmd/fipstest/fipstest.c | 160 ++++++++++++++++++++++++++++++++++++ + nss/cmd/fipstest/keywrap.sh | 40 +++++++++ + 2 files changed, 200 insertions(+) + create mode 100644 nss/cmd/fipstest/keywrap.sh + +diff -r 2f570c6952d8 -r 5d6e015d1af4 cmd/fipstest/fipstest.c +--- a/cmd/fipstest/fipstest.c Sun Mar 15 21:54:30 2020 +0100 ++++ b/cmd/fipstest/fipstest.c Wed Nov 20 08:13:43 2019 +0100 +@@ -8752,6 +8752,161 @@ + return; + } + ++void ++keywrap (char *reqfn) ++{ ++ char buf[1024]; ++ FILE *req; /* input stream from the REQUEST file */ ++ FILE *resp; /* output stream to the RESPONSE file */ ++ int i, j; ++ AESKeyWrapContext *ctx = NULL; ++ unsigned char key_data [1024]; ++ int key_data_len = 0; ++ ++ req = fopen(reqfn, "r"); ++ resp = stdout; ++ ++ while (fgets(buf, sizeof buf, req) != NULL) { ++ /* K = ... */ ++ if (buf[0] == 'K') { ++ /* Skip to value */ ++ for (i = 1; isspace(buf[i]) || buf[i] == '='; i++) ++ ; ++ ++ if (i == 1) { ++ /* Unknown variable starting with 'K' */ ++ fputs(buf, resp); ++ continue; ++ } ++ ++ for (j = 0; isxdigit(buf[i]) && j < sizeof key_data; i += 2, j++) { ++ hex_to_byteval(&buf[i], &key_data[j]); ++ } ++ ++ key_data_len = j; ++ ++ fputs(buf, resp); ++ continue; ++ } ++ /* C = ... */ ++ /* This means we're doing decryption */ ++ /* Make sure we don't pick up COUNT = ... here */ ++ else if (buf[0] == 'C' && (isspace (buf[1]) || buf[1] == '=')) { ++ unsigned char data_in [1024]; ++ unsigned char data_out [1024]; ++ unsigned int data_in_len, data_out_len; ++ ++ if (key_data_len <= 0) { ++ fprintf(resp, "ERROR: No key specified\n"); ++ goto out; ++ } ++ ++ /* Skip to value */ ++ for (i = 1; isspace(buf[i]) || buf[i] == '='; i++) ++ ; ++ ++ if (i == 1) { ++ /* Unknown variable starting with 'C' */ ++ fputs(buf, resp); ++ continue; ++ } ++ ++ fputs(buf, resp); ++ ++ for (j = 0; isxdigit(buf[i]) && j < sizeof data_in; i += 2, j++) { ++ hex_to_byteval(&buf[i], &data_in[j]); ++ } ++ ++ data_in_len = j; ++ ++ if (ctx) { ++ AESKeyWrap_DestroyContext (ctx, PR_TRUE); ++ ctx = NULL; ++ } ++ ++ ctx = AESKeyWrap_CreateContext(key_data, NULL, PR_FALSE, key_data_len); ++ if (!ctx) { ++ fprintf(resp, "ERROR: Unable to create context\n"); ++ goto out; ++ } ++ ++ if (AESKeyWrap_Decrypt(ctx, data_out, &data_out_len, 1024, data_in, data_in_len) ++ != SECSuccess) { ++ fprintf(resp, "FAIL\n"); ++ continue; ++ } ++ ++ fputs("P = ", resp); ++ to_hex_str(buf, data_out, data_out_len); ++ fputs(buf, resp); ++ fputc('\n', resp); ++ } ++ /* P = ... */ ++ /* This means we're doing encryption */ ++ else if (buf[0] == 'P') { ++ unsigned char data_in [1024]; ++ unsigned char data_out [1024]; ++ unsigned int data_in_len, data_out_len; ++ ++ if (key_data_len <= 0) { ++ fprintf(resp, "ERROR: No key specified\n"); ++ goto out; ++ } ++ ++ /* Skip to value */ ++ for (i = 1; isspace(buf[i]) || buf[i] == '='; i++) ++ ; ++ ++ if (i == 1) { ++ /* Unknown variable starting with 'P' */ ++ fputs(buf, resp); ++ continue; ++ } ++ ++ fputs(buf, resp); ++ ++ for (j = 0; isxdigit(buf[i]) && j < sizeof data_in; i += 2, j++) { ++ hex_to_byteval(&buf[i], &data_in[j]); ++ } ++ ++ data_in_len = j; ++ ++ if (ctx) { ++ AESKeyWrap_DestroyContext (ctx, PR_TRUE); ++ ctx = NULL; ++ } ++ ++ ctx = AESKeyWrap_CreateContext(key_data, NULL, PR_TRUE, key_data_len); ++ if (!ctx) { ++ fprintf(resp, "ERROR: Unable to create context\n"); ++ goto out; ++ } ++ ++ if (AESKeyWrap_Encrypt(ctx, data_out, &data_out_len, 1024, data_in, data_in_len) ++ != SECSuccess) { ++ fprintf(resp, "FAIL\n"); ++ continue; ++ } ++ ++ fputs("C = ", resp); ++ to_hex_str(buf, data_out, data_out_len); ++ fputs(buf, resp); ++ fputc('\n', resp); ++ } ++ /* Comments, blank lines, ... */ ++ else { ++ fputs(buf, resp); ++ continue; ++ } ++ } ++ ++out: ++ fclose(req); ++ if (ctx) { ++ AESKeyWrap_DestroyContext (ctx, PR_TRUE); ++ } ++} ++ + int + main(int argc, char **argv) + { +@@ -8933,6 +9088,11 @@ + ikev2(argv[2]); + } else if (strcmp(argv[1], "kbkdf") == 0) { + kbkdf(argv[2]); ++ } else if (strcmp(argv[1], "keywrap") == 0) { ++ /***************/ ++ /* AES Keywrap */ ++ /***************/ ++ keywrap(argv[2]); + } + return 0; + } +diff -r 2f570c6952d8 -r 5d6e015d1af4 cmd/fipstest/keywrap.sh +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/cmd/fipstest/keywrap.sh Wed Nov 20 08:13:43 2019 +0100 +@@ -0,0 +1,40 @@ ++#!/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 keywrap 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}/KeyWrap38F ++COMMAND=${2-run} ++REQDIR=${TESTDIR}/req ++RSPDIR=${TESTDIR}/resp ++ ++keywrap_requests=" ++KW_AD_128.req ++KW_AD_192.req ++KW_AD_256.req ++KW_AE_128.req ++KW_AE_192.req ++KW_AE_256.req ++" ++ ++if [ ${COMMAND} = "verify" ]; then ++ for request in $keywrap_requests; do ++ sh ./validate1.sh ${TESTDIR} $request ++ done ++ exit 0 ++fi ++ ++for request in $keywrap_requests; do ++ response=`echo $request | sed -e "s/req/rsp/"` ++ echo $request $response ++ fipstest keywrap ${REQDIR}/$request > ${RSPDIR}/$response ++done diff --git a/nss-fips-cavs-rsa-fixes.patch b/nss-fips-cavs-rsa-fixes.patch new file mode 100644 index 0000000..77c85b0 --- /dev/null +++ b/nss-fips-cavs-rsa-fixes.patch @@ -0,0 +1,32 @@ +# HG changeset patch +# User Hans Petter Jansson +# Date 1574237297 -3600 +# Wed Nov 20 09:08:17 2019 +0100 +# Node ID 3f4d682c9a1e8b3d939c744ee249e23179db5191 +# Parent 0e904e6179d1db21965df2c405c80c3fc0258658 +[PATCH] 25 +From 9b4636ad75add2ac09ce1844b3071785d563c275 Mon Sep 17 00:00:00 2001 +--- + nss/cmd/fipstest/fipstest.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/cmd/fipstest/fipstest.c b/cmd/fipstest/fipstest.c +--- a/cmd/fipstest/fipstest.c ++++ b/cmd/fipstest/fipstest.c +@@ -6536,7 +6536,7 @@ + /* Output the signature */ + fputs(buf, rsaresp); + to_hex_str(buf, rsa_computed_signature, rsa_bytes_signed); +- fprintf(rsaresp, "S = %s\n", buf); ++ fprintf(rsaresp, "S = %s\n\n", buf); + + /* Perform RSA verification with the RSA public key. */ + rv = RSA_HashCheckSign(shaOid, +@@ -9536,6 +9536,7 @@ + init_functions(); + RNG_RNGInit(); + SECOID_Init(); ++ BL_Init(); + + /*************/ + /* TDEA */ diff --git a/nss-fips-combined-hash-sign-dsa-ecdsa.patch b/nss-fips-combined-hash-sign-dsa-ecdsa.patch new file mode 100644 index 0000000..cf27ca8 --- /dev/null +++ b/nss-fips-combined-hash-sign-dsa-ecdsa.patch @@ -0,0 +1,395 @@ +From 7f3606a84f6c62b002246ee73121279e59f83437 Mon Sep 17 00:00:00 2001 +From: Hans Petter Jansson +Date: Thu, 28 May 2020 22:44:22 +0200 +Subject: [PATCH] CKM_(EC)DSA_SHAxxx mechs: Add some missing pieces. + +This includes pairwise consistency checks and entry points for +power-on self tests. +--- + cmd/lib/pk11table.c | 8 ++ + lib/pk11wrap/pk11mech.c | 8 ++ + lib/softoken/pkcs11c.c | 213 +++++++++++++++++++++++++++------------- + lib/softoken/softoken.h | 10 ++ + 4 files changed, 169 insertions(+), 70 deletions(-) + +diff --git a/cmd/lib/pk11table.c b/cmd/lib/pk11table.c +index f7a45fa..d302436 100644 +--- a/cmd/lib/pk11table.c ++++ b/cmd/lib/pk11table.c +@@ -273,6 +273,10 @@ const Constant _consts[] = { + mkEntry(CKM_DSA_KEY_PAIR_GEN, Mechanism), + mkEntry(CKM_DSA, Mechanism), + mkEntry(CKM_DSA_SHA1, Mechanism), ++ mkEntry(CKM_DSA_SHA224, Mechanism), ++ mkEntry(CKM_DSA_SHA256, Mechanism), ++ mkEntry(CKM_DSA_SHA384, Mechanism), ++ mkEntry(CKM_DSA_SHA512, Mechanism), + mkEntry(CKM_DH_PKCS_KEY_PAIR_GEN, Mechanism), + mkEntry(CKM_DH_PKCS_DERIVE, Mechanism), + mkEntry(CKM_X9_42_DH_DERIVE, Mechanism), +@@ -438,6 +442,10 @@ const Constant _consts[] = { + mkEntry(CKM_EC_KEY_PAIR_GEN, Mechanism), + mkEntry(CKM_ECDSA, Mechanism), + mkEntry(CKM_ECDSA_SHA1, Mechanism), ++ mkEntry(CKM_ECDSA_SHA224, Mechanism), ++ mkEntry(CKM_ECDSA_SHA256, Mechanism), ++ mkEntry(CKM_ECDSA_SHA384, Mechanism), ++ mkEntry(CKM_ECDSA_SHA512, Mechanism), + mkEntry(CKM_ECDH1_DERIVE, Mechanism), + mkEntry(CKM_ECDH1_COFACTOR_DERIVE, Mechanism), + mkEntry(CKM_ECMQV_DERIVE, Mechanism), +diff --git a/lib/pk11wrap/pk11mech.c b/lib/pk11wrap/pk11mech.c +index d94d59a..ac280f0 100644 +--- a/lib/pk11wrap/pk11mech.c ++++ b/lib/pk11wrap/pk11mech.c +@@ -376,6 +376,10 @@ PK11_GetKeyType(CK_MECHANISM_TYPE type, unsigned long len) + return CKK_RSA; + case CKM_DSA: + case CKM_DSA_SHA1: ++ case CKM_DSA_SHA224: ++ case CKM_DSA_SHA256: ++ case CKM_DSA_SHA384: ++ case CKM_DSA_SHA512: + case CKM_DSA_KEY_PAIR_GEN: + return CKK_DSA; + case CKM_DH_PKCS_DERIVE: +@@ -386,6 +390,10 @@ PK11_GetKeyType(CK_MECHANISM_TYPE type, unsigned long len) + return CKK_KEA; + case CKM_ECDSA: + case CKM_ECDSA_SHA1: ++ case CKM_ECDSA_SHA224: ++ case CKM_ECDSA_SHA256: ++ case CKM_ECDSA_SHA384: ++ case CKM_ECDSA_SHA512: + case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */ + case CKM_ECDH1_DERIVE: + return CKK_EC; /* CKK_ECDSA is deprecated */ +diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c +index 08f94bc..ec6b205 100644 +--- a/lib/softoken/pkcs11c.c ++++ b/lib/softoken/pkcs11c.c +@@ -2606,7 +2606,7 @@ nsc_DSA_Verify_Stub(void *ctx, void *sigBuf, unsigned int sigLen, + static SECStatus + nsc_DSA_Sign_Stub(void *ctx, void *sigBuf, + unsigned int *sigLen, unsigned int maxSigLen, +- void *dataBuf, unsigned int dataLen) ++ const void *dataBuf, unsigned int dataLen) + { + SECItem signature, digest; + SECStatus rv; +@@ -2624,6 +2624,22 @@ nsc_DSA_Sign_Stub(void *ctx, void *sigBuf, + return rv; + } + ++SECStatus ++DSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key, ++ unsigned char *sig, unsigned int *sigLen, unsigned int maxLen, ++ const unsigned char *hash, unsigned int hashLen) ++{ ++ SECStatus rv; ++ ++ rv = nsc_DSA_Sign_Stub(key, sig, sigLen, maxLen, hash, hashLen); ++ ++ if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) { ++ sftk_fatalError = PR_TRUE; ++ } ++ ++ return rv; ++} ++ + static SECStatus + nsc_ECDSAVerifyStub(void *ctx, void *sigBuf, unsigned int sigLen, + void *dataBuf, unsigned int dataLen) +@@ -2641,7 +2657,7 @@ nsc_ECDSAVerifyStub(void *ctx, void *sigBuf, unsigned int sigLen, + static SECStatus + nsc_ECDSASignStub(void *ctx, void *sigBuf, + unsigned int *sigLen, unsigned int maxSigLen, +- void *dataBuf, unsigned int dataLen) ++ const void *dataBuf, unsigned int dataLen) + { + SECItem signature, digest; + SECStatus rv; +@@ -2659,6 +2675,22 @@ nsc_ECDSASignStub(void *ctx, void *sigBuf, + return rv; + } + ++SECStatus ++ECDSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key, ++ unsigned char *sig, unsigned int *sigLen, unsigned int maxLen, ++ const unsigned char *hash, unsigned int hashLen) ++{ ++ SECStatus rv; ++ ++ rv = nsc_ECDSASignStub(key, sig, sigLen, maxLen, hash, hashLen); ++ ++ if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) { ++ sftk_fatalError = PR_TRUE; ++ } ++ ++ return rv; ++} ++ + /* NSC_SignInit setups up the signing operations. There are three basic + * types of signing: + * (1) the tradition single part, where "Raw RSA" or "Raw DSA" is applied +@@ -3511,6 +3543,22 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSession, + info->hashOid = SEC_OID_##mmm; \ + goto finish_rsa; + ++#define INIT_DSA_VFY_MECH(mmm) \ ++ case CKM_DSA_##mmm: \ ++ context->multi = PR_TRUE; \ ++ crv = sftk_doSub##mmm(context); \ ++ if (crv != CKR_OK) \ ++ break; \ ++ goto finish_dsa; ++ ++#define INIT_ECDSA_VFY_MECH(mmm) \ ++ case CKM_ECDSA_##mmm: \ ++ context->multi = PR_TRUE; \ ++ crv = sftk_doSub##mmm(context); \ ++ if (crv != CKR_OK) \ ++ break; \ ++ goto finish_ecdsa; ++ + switch (pMechanism->mechanism) { + INIT_RSA_VFY_MECH(MD5) + INIT_RSA_VFY_MECH(MD2) +@@ -3575,13 +3623,15 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSession, + context->destroy = (SFTKDestroy)sftk_Space; + context->verify = (SFTKVerify)sftk_RSACheckSignPSS; + break; +- case CKM_DSA_SHA1: +- context->multi = PR_TRUE; +- crv = sftk_doSubSHA1(context); +- if (crv != CKR_OK) +- break; +- /* fall through */ ++ ++ INIT_DSA_VFY_MECH(SHA1) ++ INIT_DSA_VFY_MECH(SHA224) ++ INIT_DSA_VFY_MECH(SHA256) ++ INIT_DSA_VFY_MECH(SHA384) ++ INIT_DSA_VFY_MECH(SHA512) ++ + case CKM_DSA: ++ finish_dsa: + if (key_type != CKK_DSA) { + crv = CKR_KEY_TYPE_INCONSISTENT; + break; +@@ -3594,13 +3644,15 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSession, + context->verify = (SFTKVerify)nsc_DSA_Verify_Stub; + context->destroy = sftk_Null; + break; +- case CKM_ECDSA_SHA1: +- context->multi = PR_TRUE; +- crv = sftk_doSubSHA1(context); +- if (crv != CKR_OK) +- break; +- /* fall through */ ++ ++ INIT_ECDSA_VFY_MECH(SHA1) ++ INIT_ECDSA_VFY_MECH(SHA224) ++ INIT_ECDSA_VFY_MECH(SHA256) ++ INIT_ECDSA_VFY_MECH(SHA384) ++ INIT_ECDSA_VFY_MECH(SHA512) ++ + case CKM_ECDSA: ++ finish_ecdsa: + if (key_type != CKK_EC) { + crv = CKR_KEY_TYPE_INCONSISTENT; + break; +@@ -4733,6 +4785,73 @@ loser: + #define PAIRWISE_DIGEST_LENGTH SHA224_LENGTH /* 224-bits */ + #define PAIRWISE_MESSAGE_LENGTH 20 /* 160-bits */ + ++static CK_RV ++pairwise_signverify_mech (CK_SESSION_HANDLE hSession, ++ SFTKObject *publicKey, SFTKObject *privateKey, ++ CK_MECHANISM mech, ++ CK_ULONG signature_length, ++ CK_ULONG pairwise_digest_length) ++{ ++ /* Variables used for Signature/Verification functions. */ ++ /* Must be at least 256 bits for DSA2 digest */ ++ unsigned char *known_digest = (unsigned char *)"Mozilla Rules the World through NSS!"; ++ unsigned char *signature; ++ CK_RV crv; ++ ++ /* Allocate space for signature data. */ ++ signature = (unsigned char *)PORT_ZAlloc(signature_length); ++ if (signature == NULL) { ++ return CKR_HOST_MEMORY; ++ } ++ ++ /* Sign the known hash using the private key. */ ++ crv = NSC_SignInit(hSession, &mech, privateKey->handle); ++ if (crv != CKR_OK) { ++ PORT_Free(signature); ++ return crv; ++ } ++ ++ crv = NSC_Sign(hSession, ++ known_digest, ++ 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) && ++ (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, ++ known_digest, ++ pairwise_digest_length, ++ signature, ++ signature_length); ++ ++ /* Free signature data. */ ++ PORT_Free(signature); ++ ++ if ((crv == CKR_SIGNATURE_LEN_RANGE) || ++ (crv == CKR_SIGNATURE_INVALID)) { ++ return CKR_GENERAL_ERROR; ++ } ++ ++ return crv; ++} ++ + /* + * FIPS 140-2 pairwise consistency check utilized to validate key pair. + * +@@ -4780,8 +4899,6 @@ sftk_PairwiseConsistencyCheck(CK_SESSION_HANDLE hSession, + + /* Variables used for Signature/Verification functions. */ + /* Must be at least 256 bits for DSA2 digest */ +- unsigned char *known_digest = (unsigned char *)"Mozilla Rules the World through NSS!"; +- unsigned char *signature; + CK_ULONG signature_length; + + if (keyType == CKK_RSA) { +@@ -4935,76 +5052,32 @@ sftk_PairwiseConsistencyCheck(CK_SESSION_HANDLE hSession, + } + } + ++#define SIGNVERIFY_CHECK_MECH(vfymech) \ ++ mech.mechanism = vfymech; \ ++ crv = pairwise_signverify_mech (hSession, publicKey, privateKey, \ ++ mech, signature_length, pairwise_digest_length); \ ++ if (crv != CKR_OK) \ ++ return crv; ++ + if (canSignVerify) { +- /* Determine length of signature. */ + switch (keyType) { + case CKK_RSA: + signature_length = modulusLen; +- mech.mechanism = CKM_RSA_PKCS; ++ SIGNVERIFY_CHECK_MECH(CKM_SHA224_RSA_PKCS) + break; + case CKK_DSA: + signature_length = DSA_MAX_SIGNATURE_LEN; + pairwise_digest_length = subPrimeLen; +- mech.mechanism = CKM_DSA; ++ SIGNVERIFY_CHECK_MECH(CKM_DSA_SHA224) + break; + case CKK_EC: + signature_length = MAX_ECKEY_LEN * 2; +- mech.mechanism = CKM_ECDSA; ++ SIGNVERIFY_CHECK_MECH(CKM_ECDSA_SHA224) + break; + default: + return CKR_DEVICE_ERROR; + } + +- /* Allocate space for signature data. */ +- signature = (unsigned char *)PORT_ZAlloc(signature_length); +- if (signature == NULL) { +- return CKR_HOST_MEMORY; +- } +- +- /* Sign the known hash using the private key. */ +- crv = NSC_SignInit(hSession, &mech, privateKey->handle); +- if (crv != CKR_OK) { +- PORT_Free(signature); +- return crv; +- } +- +- crv = NSC_Sign(hSession, +- known_digest, +- 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) && +- (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, +- known_digest, +- pairwise_digest_length, +- signature, +- signature_length); +- +- /* Free signature data. */ +- PORT_Free(signature); +- +- if ((crv == CKR_SIGNATURE_LEN_RANGE) || +- (crv == CKR_SIGNATURE_INVALID)) { +- return CKR_GENERAL_ERROR; +- } + if (crv != CKR_OK) { + return crv; + } +diff --git a/lib/softoken/softoken.h b/lib/softoken/softoken.h +index 30586fc..d5aaffa 100644 +--- a/lib/softoken/softoken.h ++++ b/lib/softoken/softoken.h +@@ -35,6 +35,16 @@ RSA_HashCheckSign(SECOidTag hashOid, NSSLOWKEYPublicKey *key, + const unsigned char *sig, unsigned int sigLen, + const unsigned char *hash, unsigned int hashLen); + ++extern SECStatus ++DSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key, ++ unsigned char *sig, unsigned int *sigLen, unsigned int maxLen, ++ const unsigned char *hash, unsigned int hashLen); ++ ++extern SECStatus ++ECDSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key, ++ unsigned char *sig, unsigned int *sigLen, unsigned int maxLen, ++ const unsigned char *hash, unsigned int hashLen); ++ + /* + ** Prepare a buffer for padded CBC encryption, growing to the appropriate + ** boundary, filling with the appropriate padding. +-- +2.26.2 + diff --git a/nss-fips-constructor-self-tests.patch b/nss-fips-constructor-self-tests.patch new file mode 100644 index 0000000..1e7e7cf --- /dev/null +++ b/nss-fips-constructor-self-tests.patch @@ -0,0 +1,1450 @@ +commit d4f90dd0c5e15cfd9db416207d067cc3968b3a0c +Author: Hans Petter Jansson +Date: Sun Mar 15 21:54:30 2020 +0100 + + Patch 23: nss-fips-constructor-self-tests.patch + +diff -r 3a9a84eee4a2 cmd/chktest/chktest.c +--- a/cmd/chktest/chktest.c Wed Nov 20 08:25:39 2019 +0100 ++++ b/cmd/chktest/chktest.c Fri May 29 09:13:35 2020 +0200 +@@ -38,7 +38,7 @@ + } + RNG_SystemInfoForRNG(); + +- good_result = BLAPI_SHVerifyFile(argv[1]); ++ good_result = BLAPI_SHVerifyFile(argv[1], NULL); + printf("%s\n", + (good_result ? "SUCCESS" : "FAILURE")); + return (good_result) ? SECSuccess : SECFailure; +diff -r 3a9a84eee4a2 cmd/shlibsign/shlibsign.c +--- a/cmd/shlibsign/shlibsign.c Wed Nov 20 08:25:39 2019 +0100 ++++ b/cmd/shlibsign/shlibsign.c Fri May 29 09:13:35 2020 +0200 +@@ -946,10 +946,12 @@ + goto cleanup; + } + +- if ((keySize == 0) && mechInfo.ulMaxKeySize >= 2048) { +- keySize = 2048; +- } else { +- keySize = 1024; ++ if (keySize == 0) { ++ if (mechInfo.ulMaxKeySize >= 2048) { ++ keySize = 2048; ++ } else { ++ keySize = 1024; ++ } + } + } + +diff -r 3a9a84eee4a2 lib/freebl/blapi.h +--- a/lib/freebl/blapi.h Wed Nov 20 08:25:39 2019 +0100 ++++ b/lib/freebl/blapi.h Fri May 29 09:13:35 2020 +0200 +@@ -1736,17 +1736,17 @@ + /************************************************************************** + * Verify a given Shared library signature * + **************************************************************************/ +-PRBool BLAPI_SHVerify(const char *name, PRFuncPtr addr); ++PRBool BLAPI_SHVerify(const char *name, PRFuncPtr addr, int *err); + + /************************************************************************** + * Verify a given filename's signature * + **************************************************************************/ +-PRBool BLAPI_SHVerifyFile(const char *shName); ++PRBool BLAPI_SHVerifyFile(const char *shName, int *err); + + /************************************************************************** + * Verify Are Own Shared library signature * + **************************************************************************/ +-PRBool BLAPI_VerifySelf(const char *name); ++PRBool BLAPI_VerifySelf(const char *name, int *err); + + /*********************************************************************/ + extern const SECHashObject *HASH_GetRawHashObject(HASH_HashType hashType); +diff -r 3a9a84eee4a2 lib/freebl/fips-selftest.inc +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/lib/freebl/fips-selftest.inc Fri May 29 09:13:35 2020 +0200 +@@ -0,0 +1,293 @@ ++/* ++ * PKCS #11 FIPS Power-Up Self Test - common stuff. ++ * ++ * 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/. */ ++ ++#ifndef FIPS_INC ++#define FIPS_INC ++ ++/* common functions used for FIPS selftests. Due to the modular design of NSS ++ * putting these into libfreebl would mean either amending the API represented ++ * by FREEBLVectorStr - which might cause problems with newer applications, or ++ * extending the API with another similar function set. Thus, to make things ++ * less complicated in the binaries, we mess up the source a bit. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++#include "blapi.h" ++ ++#define NSS_FORCE_FIPS_ENV "NSS_FIPS" ++#define FIPS_PROC_PATH "/proc/sys/crypto/fips_enabled" ++ ++#define CHECKSUM_SUFFIX ".chk" ++ ++typedef enum fips_check_status { ++ CHECK_UNCHECKED = -1, ++ CHECK_OK = 0, ++ CHECK_FAIL, ++ CHECK_FAIL_CRYPTO, ++ CHECK_MISSING ++} fips_check_status; ++ ++/* initial value of FIPS state is -1 */ ++static int fips_state = -1; ++ ++static int fips_wanted = -1; ++ ++/* debug messages are sent to stderr */ ++static void ++debug(const char *fmt,...) ++{ ++#if 0 ++ va_list args; ++ ++ va_start(args, fmt); ++ vfprintf(stderr, fmt, args); ++ va_end(args); ++ fputc('\n', stderr); ++#endif ++ return; ++} ++ ++/* Fatal messages ending with abort(); this function never returns */ ++static void __attribute__ ((__noreturn__)) ++fatal(const char *fmt,...) ++{ ++ va_list args; ++ ++ va_start(args, fmt); ++ vfprintf(stderr, fmt, args); ++ va_end(args); ++ fputc('\n', stderr); ++ abort(); ++} ++ ++/* check whether FIPS moode is mandated by the kernel */ ++static int ++fips_isWantedProc(void) ++{ ++ int my_fips_wanted = 0; ++ int fips_fd; ++ char fips_sys = 0; ++ ++ struct stat dummy; ++ if (-1 == stat(FIPS_PROC_PATH, &dummy)) { ++ switch (errno) { ++ case ENOENT: ++ case EACCES: /* Mozilla sandboxing returns EACCES instead of ENOENT */ ++ case ENOTDIR: ++ break; ++ default: ++ fatal("Check for system-wide FIPS mode is required and %s cannot" ++ " be accessed for reason other than non-existence - aborting" ++ , FIPS_PROC_PATH); ++ break; ++ } ++ } else { ++ if (-1 == (fips_fd = open(FIPS_PROC_PATH, O_RDONLY))) { ++ fatal("Check for system-wide FIPS mode is required and %s cannot" ++ " be opened for reading - aborting" ++ , FIPS_PROC_PATH); ++ } ++ if (1 > read(fips_fd, &fips_sys, 1)) { ++ fatal("Check for system-wide FIPS mode is required and %s doesn't" ++ " return at least one character - aborting" ++ , FIPS_PROC_PATH); ++ } ++ close(fips_fd); ++ switch (fips_sys) { ++ case '0': ++ case '1': ++ my_fips_wanted = fips_sys - '0'; ++ break; ++ default: ++ fatal("Bogus character %c found in %s - aborting" ++ , fips_sys, FIPS_PROC_PATH); ++ } ++ } ++ return my_fips_wanted; ++} ++ ++/* "legacy" from lib/sysinit/nsssysinit.c */ ++static PRBool ++getFIPSEnv(void) ++{ ++ char *fipsEnv = getenv("NSS_FIPS"); ++ if (!fipsEnv) { ++ return PR_FALSE; ++ } ++ if ((strcasecmp(fipsEnv,"fips") == 0) || ++ (strcasecmp(fipsEnv,"true") == 0) || ++ (strcasecmp(fipsEnv,"on") == 0) || ++ (strcasecmp(fipsEnv,"1") == 0)) { ++ return PR_TRUE; ++ } ++ return PR_FALSE; ++} ++ ++static int ++fips_isWantedEnv(void) ++{ ++ return getFIPSEnv() ? 1 : 0; ++} ++ ++static int ++fips_isWanted(void) ++{ ++ int fips_requests = 0; ++#ifdef LINUX ++ fips_requests += fips_isWantedProc(); ++#endif ++ fips_requests += fips_isWantedEnv(); ++ return fips_requests; ++} ++ ++/* check integrity signatures (if present) */ ++static fips_check_status ++fips_checkSignature(char *libName, PRFuncPtr addr) ++{ ++ PRBool rv; ++ fips_check_status rv_check = CHECK_UNCHECKED; ++ int l = PATH_MAX; ++ int err = 0; ++ int err_NOENT = 0; ++ char full_lib_name[PATH_MAX+1]; ++ full_lib_name[0] = '\0'; ++ ++ if (NULL == libName) { ++ err_NOENT = PR_FILE_NOT_FOUND_ERROR; ++ rv = BLAPI_VerifySelf(SHLIB_PREFIX"freebl"SHLIB_VERSION"."SHLIB_SUFFIX, &err); ++ } else { ++ err_NOENT = PR_FILE_NOT_FOUND_ERROR; ++ strncat(full_lib_name, SHLIB_PREFIX, l); ++ l -= strlen(SHLIB_PREFIX); ++ strncat(full_lib_name, libName, l); ++ l -= strlen(libName); ++ strncat(full_lib_name, SHLIB_VERSION"."SHLIB_SUFFIX, l); ++ l -= strlen(SHLIB_VERSION"."SHLIB_SUFFIX); ++#if 1 ++ rv = BLAPI_SHVerify(full_lib_name, addr, &err); ++#else ++ rv = 1; ++#endif ++ } ++ ++ if (rv) { ++ rv_check = CHECK_OK; ++ } else { ++ if (err_NOENT == err) { ++ rv_check = CHECK_MISSING; ++ } else { ++ rv_check = CHECK_FAIL; ++ } ++ } ++ ++ return rv_check; ++} ++ ++/* decide what to do depending on the results of tests and system/required FIPS ++ * mode */ ++static int ++fips_resolve(fips_check_status check, char *libName) ++{ ++ int state; ++ ++ if (fips_wanted) { ++ switch (check) { ++ case CHECK_OK: ++ debug("fips - %s: mandatory checksum ok" ++ , (libName) ? libName : "freebl"); ++ break; ++ case CHECK_FAIL: ++ fatal("fips - %s: mandatory checksum failed - aborting" ++ , (libName) ? libName : "freebl"); ++ break; ++ case CHECK_FAIL_CRYPTO: ++ fatal("fips - %s: mandatory crypto test failed - aborting" ++ , (libName) ? libName : "freebl"); ++ break; ++ case CHECK_MISSING: ++ fatal("fips - %s: mandatory checksum data missing - aborting" ++ , (libName) ? libName : "freebl"); ++ break; ++ default: ++ fatal("Fatal error: internal error at %s:%u" ++ , __FILE__, __LINE__); ++ break; ++ } ++ state = 1; ++ } else { ++ switch (check) { ++ case CHECK_OK: ++ debug("fips - %s: checksum ok" ++ , (libName) ? libName : "freebl"); ++ break; ++ case CHECK_FAIL: ++#if 0 ++ fatal("fips - %s: checksum failed - aborting" ++ , (libName) ? libName : "freebl"); ++#else ++ debug("fips - %s: checksum failed - not in FIPS mode; continuing" ++ , (libName) ? libName : "freebl"); ++#endif ++ break; ++ case CHECK_FAIL_CRYPTO: ++ fatal("fips - %s: crypto test failed - aborting" ++ , (libName) ? libName : "freebl"); ++ break; ++ case CHECK_MISSING: ++ debug("fips - %s: mandatory checksum data missing, but not required in non FIPS mode; continuing non-FIPS" ++ , (libName) ? libName : "freebl"); ++ break; ++ default: ++ fatal("Fatal error: internal error at %s:%u" ++ , __FILE__, __LINE__); ++ break; ++ } ++ state = 0; ++ } ++ return state; ++} ++ ++/* generic selftest ++ * libName and addr are the name of shared object to check and a function ++ * contained therein; (NULL, NULL) performs selfcheck of freebl. ++ * crypto_check is callback that performs cryptographic algorithms checks; NULL ++ * for libraries that do not implement any cryptographic algorithms per se ++ */ ++static int ++fips_initTest(char *libName, PRFuncPtr addr, fips_check_status cryptoCheck(void)) ++{ ++ fips_check_status check = CHECK_OK; ++ ++ fips_wanted = fips_isWanted(); ++ ++ if (cryptoCheck) { ++ check = cryptoCheck(); ++ debug("fips - %s: crypto check %s" ++ , (libName) ? libName : "freebl" ++ , (CHECK_OK == check) ? "ok" : "failed"); ++ } ++ ++ if (CHECK_OK == check) { ++ check = fips_checkSignature(libName, addr); ++ } ++ ++ return fips_resolve(check, libName); ++} ++ ++#endif +diff -r 3a9a84eee4a2 lib/freebl/fips.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/lib/freebl/fips.c Fri May 29 09:13:35 2020 +0200 +@@ -0,0 +1,7 @@ ++/* ++ * PKCS #11 FIPS Power-Up Self Test. ++ * ++ * 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/. */ ++ +diff -r 3a9a84eee4a2 lib/freebl/fips.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/lib/freebl/fips.h Fri May 29 09:13:35 2020 +0200 +@@ -0,0 +1,15 @@ ++/* ++ * PKCS #11 FIPS Power-Up Self Test. ++ * ++ * 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/. */ ++ ++#ifndef FIPS_H ++#define FIPS_H ++ ++int FIPS_mode(void); ++char* FIPS_rngDev(void); ++ ++#endif ++ +diff -r 3a9a84eee4a2 lib/freebl/fipsfreebl.c +--- a/lib/freebl/fipsfreebl.c Wed Nov 20 08:25:39 2019 +0100 ++++ b/lib/freebl/fipsfreebl.c Fri May 29 09:13:35 2020 +0200 +@@ -20,6 +20,13 @@ + + #include "ec.h" /* Required for EC */ + ++#include "fips-selftest.inc" ++ ++#include "fips.h" ++ ++#define RNG_DEV_FIPS0 "/dev/urandom" ++#define RNG_DEV_FIPS1 "/dev/random" ++ + /* + * different platforms have different ways of calling and initial entry point + * when the dll/.so is loaded. Most platforms support either a posix pragma +@@ -1774,9 +1781,8 @@ + 0x0a, 0x26, 0x21, 0xd0, 0x19, 0xcb, 0x86, 0x73, + 0x10, 0x1f, 0x60, 0xd7 + }; +- + SECStatus rng_status = SECSuccess; +- PRUint8 DSAX[FIPS_DSA_SUBPRIME_LENGTH]; ++ PRUint8 DSAX[DSA1_SUBPRIME_LEN]; + + /*******************************************/ + /* Run the SP 800-90 Health tests */ +@@ -1790,13 +1796,12 @@ + /*******************************************/ + /* Generate DSAX fow given Q. */ + /*******************************************/ +- + rng_status = FIPS186Change_ReduceModQForDSA(GENX, Q, DSAX); + + /* Verify DSAX to perform the RNG integrity check */ + if ((rng_status != SECSuccess) || + (PORT_Memcmp(DSAX, rng_known_DSAX, +- (FIPS_DSA_SUBPRIME_LENGTH)) != 0)) { ++ (DSA1_SUBPRIME_LEN)) != 0)) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } +@@ -1804,17 +1809,19 @@ + return (SECSuccess); + } + ++#if 0 + static SECStatus + freebl_fipsSoftwareIntegrityTest(const char *libname) + { + SECStatus rv = SECSuccess; + + /* make sure that our check file signatures are OK */ +- if (!BLAPI_VerifySelf(libname)) { ++ if (!BLAPI_VerifySelf(libname, NULL)) { + rv = SECFailure; + } + return rv; + } ++#endif + + #define DO_FREEBL 1 + #define DO_REST 2 +@@ -1926,11 +1933,13 @@ + static PRBool self_tests_freebl_success = PR_FALSE; + static PRBool self_tests_success = PR_FALSE; + ++static PRBool freebl_only = PR_FALSE; ++ + /* + * accessors for freebl + */ + PRBool +-BL_POSTRan(PRBool freebl_only) ++BL_POSTRan(PRBool my_freebl_only) + { + SECStatus rv; + /* if the freebl self tests didn't run, there is something wrong with +@@ -1943,7 +1952,7 @@ + return PR_TRUE; + } + /* if we only care about the freebl tests, we are good */ +- if (freebl_only) { ++ if (my_freebl_only) { + return PR_TRUE; + } + /* run the rest of the self tests */ +@@ -1962,31 +1971,15 @@ + return PR_TRUE; + } + ++#if 0 + #include "blname.c" +- +-/* +- * This function is called at dll load time, the code tha makes this +- * happen is platform specific on defined above. +- */ +-static void +-bl_startup_tests(void) +-{ +- const char *libraryName; +- PRBool freebl_only = PR_FALSE; +- SECStatus rv; ++#endif + +- PORT_Assert(self_tests_freebl_ran == PR_FALSE); +- PORT_Assert(self_tests_success == PR_FALSE); +- self_tests_freebl_ran = PR_TRUE; /* we are running the tests */ +- self_tests_success = PR_FALSE; /* force it just in case */ +- self_tests_freebl_success = PR_FALSE; /* force it just in case */ +- +-#ifdef FREEBL_NO_DEPEND +- rv = FREEBL_InitStubs(); +- if (rv != SECSuccess) { +- freebl_only = PR_TRUE; +- } +-#endif ++/* crypto algorithms selftest wrapper */ ++static fips_check_status ++fips_checkCryptoFreebl(void) ++{ ++ SECStatus rv; + + self_tests_freebl_ran = PR_TRUE; /* we are running the tests */ + +@@ -1999,20 +1992,55 @@ + /* always run the post tests */ + rv = freebl_fipsPowerUpSelfTest(freebl_only ? DO_FREEBL : DO_FREEBL | DO_REST); + if (rv != SECSuccess) { +- return; ++ return CHECK_FAIL_CRYPTO; + } + ++#if 0 ++ /* fips_initTest() does this for us by calling fips_checkSignature() */ + libraryName = getLibName(); + rv = freebl_fipsSoftwareIntegrityTest(libraryName); + if (rv != SECSuccess) { +- return; ++ return CHECK_FAIL_CRYPTO; + } ++#endif + + /* posts are happy, allow the fips module to function now */ + self_tests_freebl_success = PR_TRUE; /* we always test the freebl stuff */ + if (!freebl_only) { + self_tests_success = PR_TRUE; + } ++ ++ return CHECK_OK; ++} ++ ++/* ++ * This function is called at dll load time, the code tha makes this ++ * happen is platform specific on defined above. ++ */ ++static void ++bl_startup_tests(void) ++{ ++ SECStatus rv; ++ ++ PORT_Assert(self_tests_freebl_ran == PR_FALSE); ++ PORT_Assert(self_tests_success == PR_FALSE); ++ PORT_Assert(fips_mode_available == PR_FALSE); ++ self_tests_freebl_ran = PR_TRUE; /* we are running the tests */ ++ self_tests_success = PR_FALSE; /* force it just in case */ ++ self_tests_freebl_success = PR_FALSE; /* force it just in case */ ++ ++ freebl_only = PR_FALSE; ++ ++#ifdef FREEBL_NO_DEPEND ++ rv = FREEBL_InitStubs(); ++ if (rv != SECSuccess) { ++ freebl_only = PR_TRUE; ++ } ++#endif ++ ++ /* Detect FIPS mode and verify checksums */ ++ fips_state = fips_initTest(NULL, NULL, fips_checkCryptoFreebl); ++ debug("FIPS mode: %i\n", FIPS_mode()); + } + + /* +@@ -2021,28 +2049,91 @@ + * power on selftest failed. + */ + SECStatus +-BL_FIPSEntryOK(PRBool freebl_only) ++BL_FIPSEntryOK(PRBool my_freebl_only) + { +-#ifdef NSS_NO_INIT_SUPPORT +- /* this should only be set on platforms that can't handle one of the INIT +- * schemes. This code allows those platforms to continue to function, +- * though they don't meet the strict NIST requirements. If NSS_NO_INIT_SUPPORT +- * is not set, and init support has not been properly enabled, freebl +- * will always fail because of the test below +- */ ++ /* For platforms that don't support on-load constructors */ + if (!self_tests_freebl_ran) { + bl_startup_tests(); + } +-#endif ++ + /* if the general self tests succeeded, we're done */ + if (self_tests_success) { + return SECSuccess; + } + /* standalone freebl can initialize */ +- if (freebl_only && self_tests_freebl_success) { ++ if (my_freebl_only && self_tests_freebl_success) { + return SECSuccess; + } + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } ++ ++/* returns the FIPS mode we are running in or the one that we aspire to if the ++ * tests have not completed yet - which might happen during the crypto selftest ++ */ ++int ++FIPS_mode(void) ++{ ++ int fips; ++ ++ if (fips_wanted < 0) ++ fips_wanted = fips_isWanted (); ++ ++ /* until FIPS mode is cleared up, assume we are running in whatever is ++ * wanted by the environment */ ++ fips = (-1 != fips_state) ? fips_state : fips_wanted; ++ switch (fips) { ++ case 0: ++ case 1: ++ return fips; ++ default: ++ fatal("Fatal error: internal error at %s:%u" ++ , __FILE__, __LINE__); ++ } ++} ++ ++/* returns string specifying what system RNG file to use for seeding */ ++char * ++FIPS_rngDev(void) ++{ ++ switch (FIPS_mode()) { ++ case 0: ++ return RNG_DEV_FIPS0; ++ case 1: ++ return RNG_DEV_FIPS1; ++ default: ++ fatal("Fatal error: internal error at %s:%u" ++ , __FILE__, __LINE__); ++ } ++} ++ ++/* either returns the input or aborts if in FIPS and the algorithm is not ++ * approved */ ++PRBool ++FIPS_hashAlgApproved(HASH_HashType hashAlg) ++{ ++ PRBool rv = PR_FALSE; ++ ++ switch (hashAlg) { ++ case HASH_AlgNULL: ++ case HASH_AlgSHA1: ++ case HASH_AlgSHA256: ++ case HASH_AlgSHA384: ++ case HASH_AlgSHA512: ++ case HASH_AlgSHA224: ++ rv = PR_TRUE; ++ break; ++ default: ++ /* ++ fatal("Fatal error: non-approved hash algorithm (id %i)" ++ "requested while running in FIPS mode" ++ , hashAlg); ++ */ ++ if (!FIPS_mode()) ++ rv = PR_TRUE; ++ break; ++ } ++ return rv; ++} ++ + #endif +diff -r 3a9a84eee4a2 lib/freebl/loader.c +--- a/lib/freebl/loader.c Wed Nov 20 08:25:39 2019 +0100 ++++ b/lib/freebl/loader.c Fri May 29 09:13:35 2020 +0200 +@@ -1189,11 +1189,11 @@ + } + + PRBool +-BLAPI_SHVerify(const char *name, PRFuncPtr addr) ++BLAPI_SHVerify(const char *name, PRFuncPtr addr, int *err) + { + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return PR_FALSE; +- return vector->p_BLAPI_SHVerify(name, addr); ++ return vector->p_BLAPI_SHVerify(name, addr, err); + } + + /* +@@ -1203,12 +1203,12 @@ + * in freebl_LoadDSO) to p_BLAPI_VerifySelf. + */ + PRBool +-BLAPI_VerifySelf(const char *name) ++BLAPI_VerifySelf(const char *name, int *err) + { + PORT_Assert(!name); + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return PR_FALSE; +- return vector->p_BLAPI_VerifySelf(libraryName); ++ return vector->p_BLAPI_VerifySelf(libraryName, err); + } + + /* ============== New for 3.006 =============================== */ +@@ -1804,11 +1804,11 @@ + } + + PRBool +-BLAPI_SHVerifyFile(const char *name) ++BLAPI_SHVerifyFile(const char *name, int *err) + { + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return PR_FALSE; +- return vector->p_BLAPI_SHVerifyFile(name); ++ return vector->p_BLAPI_SHVerifyFile(name, err); + } + + /* === new for DSA-2 === */ +diff -r 3a9a84eee4a2 lib/freebl/loader.h +--- a/lib/freebl/loader.h Wed Nov 20 08:25:39 2019 +0100 ++++ b/lib/freebl/loader.h Fri May 29 09:13:35 2020 +0200 +@@ -299,8 +299,8 @@ + + /* Version 3.004 came to here */ + +- PRBool (*p_BLAPI_SHVerify)(const char *name, PRFuncPtr addr); +- PRBool (*p_BLAPI_VerifySelf)(const char *name); ++ PRBool (*p_BLAPI_SHVerify)(const char *name, PRFuncPtr addr, int *err); ++ PRBool (*p_BLAPI_VerifySelf)(const char *name, int *err); + + /* Version 3.005 came to here */ + +@@ -556,7 +556,7 @@ + SECStatus (*p_SHA224_Flatten)(SHA224Context *cx, unsigned char *space); + SHA224Context *(*p_SHA224_Resurrect)(unsigned char *space, void *arg); + void (*p_SHA224_Clone)(SHA224Context *dest, SHA224Context *src); +- PRBool (*p_BLAPI_SHVerifyFile)(const char *name); ++ PRBool (*p_BLAPI_SHVerifyFile)(const char *name, int *err); + + /* Version 3.013 came to here */ + +diff -r 3a9a84eee4a2 lib/freebl/manifest.mn +--- a/lib/freebl/manifest.mn Wed Nov 20 08:25:39 2019 +0100 ++++ b/lib/freebl/manifest.mn Fri May 29 09:13:35 2020 +0200 +@@ -97,6 +97,7 @@ + ecl.h \ + ecl-curve.h \ + eclt.h \ ++ fips.h \ + $(NULL) + + MPI_HDRS = mpi-config.h mpi.h mpi-priv.h mplogic.h mpprime.h logtab.h mp_gf2m.h +@@ -179,6 +180,7 @@ + shsign.h \ + vis_proto.h \ + seed.h \ ++ fips.h \ + $(NULL) + + +diff -r 3a9a84eee4a2 lib/freebl/shvfy.c +--- a/lib/freebl/shvfy.c Wed Nov 20 08:25:39 2019 +0100 ++++ b/lib/freebl/shvfy.c Fri May 29 09:13:35 2020 +0200 +@@ -21,6 +21,8 @@ + + #ifndef NSS_FIPS_DISABLED + ++#undef DEBUG_SHVERIFY ++ + /* + * Most modern version of Linux support a speed optimization scheme where an + * application called prelink modifies programs and shared libraries to quickly +@@ -230,8 +232,6 @@ + } + #endif + +-/* #define DEBUG_SHVERIFY 1 */ +- + static char * + mkCheckFileName(const char *libName) + { +@@ -286,19 +286,19 @@ + return SECSuccess; + } + +-static PRBool blapi_SHVerifyFile(const char *shName, PRBool self); ++static PRBool blapi_SHVerifyFile(const char *shName, PRBool self, int *err); + + static PRBool +-blapi_SHVerify(const char *name, PRFuncPtr addr, PRBool self) ++blapi_SHVerify(const char *name, PRFuncPtr addr, PRBool self, int *err) + { + PRBool result = PR_FALSE; /* if anything goes wrong, +- * the signature does not verify */ ++ * the signature does not verify */ + /* find our shared library name */ + char *shName = PR_GetLibraryFilePathname(name, addr); + if (!shName) { + goto loser; + } +- result = blapi_SHVerifyFile(shName, self); ++ result = blapi_SHVerifyFile(shName, self, err); + + loser: + if (shName != NULL) { +@@ -309,19 +309,19 @@ + } + + PRBool +-BLAPI_SHVerify(const char *name, PRFuncPtr addr) ++BLAPI_SHVerify(const char *name, PRFuncPtr addr, int *err) + { +- return blapi_SHVerify(name, addr, PR_FALSE); ++ return blapi_SHVerify(name, addr, PR_FALSE, err); + } + + PRBool +-BLAPI_SHVerifyFile(const char *shName) ++BLAPI_SHVerifyFile(const char *shName, int *err) + { +- return blapi_SHVerifyFile(shName, PR_FALSE); ++ return blapi_SHVerifyFile(shName, PR_FALSE, err); + } + + static PRBool +-blapi_SHVerifyFile(const char *shName, PRBool self) ++blapi_SHVerifyFile(const char *shName, PRBool self, int *err) + { + char *checkName = NULL; + PRFileDesc *checkFD = NULL; +@@ -339,7 +339,7 @@ + #endif + + PRBool result = PR_FALSE; /* if anything goes wrong, +- * the signature does not verify */ ++ * the signature does not verify */ + unsigned char buf[4096]; + unsigned char hashBuf[HASH_LENGTH_MAX]; + +@@ -366,14 +366,17 @@ + /* open the check File */ + checkFD = PR_Open(checkName, PR_RDONLY, 0); + if (checkFD == NULL) { ++ if (err) { ++ *err = PORT_GetError(); ++ } + #ifdef DEBUG_SHVERIFY +- fprintf(stderr, "Failed to open the check file %s: (%d, %d)\n", +- checkName, (int)PR_GetError(), (int)PR_GetOSError()); ++ fprintf(stderr, "Failed to open the check file %s: (%d)\n", ++ checkName, (int)PORT_GetError()); + #endif /* DEBUG_SHVERIFY */ + goto loser; + } + +- /* read and Verify the headerthe header */ ++ /* read and Verify the header */ + bytesRead = PR_Read(checkFD, buf, 12); + if (bytesRead != 12) { + goto loser; +@@ -414,7 +417,8 @@ + if (rv != SECSuccess) { + goto loser; + } +- /* read the siganture */ ++ ++ /* read the signature */ + rv = readItem(checkFD, &signature); + if (rv != SECSuccess) { + goto loser; +@@ -429,7 +433,7 @@ + goto loser; + } + +-/* open our library file */ ++ /* open our library file */ + #ifdef FREEBL_USE_PRELINK + shFD = bl_OpenUnPrelink(shName, &pid); + #else +@@ -437,13 +441,13 @@ + #endif + if (shFD == NULL) { + #ifdef DEBUG_SHVERIFY +- fprintf(stderr, "Failed to open the library file %s: (%d, %d)\n", +- shName, (int)PR_GetError(), (int)PR_GetOSError()); ++ fprintf(stderr, "Failed to open the library file %s: (%d)\n", ++ shName, (int)PORT_GetError()); + #endif /* DEBUG_SHVERIFY */ + goto loser; + } + +- /* hash our library file with SHA1 */ ++ /* hash our library file */ + hashcx = hashObj->create(); + if (hashcx == NULL) { + goto loser; +@@ -528,7 +532,7 @@ + } + + PRBool +-BLAPI_VerifySelf(const char *name) ++BLAPI_VerifySelf(const char *name, int *err) + { + if (name == NULL) { + /* +@@ -537,7 +541,7 @@ + */ + return PR_TRUE; + } +- return blapi_SHVerify(name, (PRFuncPtr)decodeInt, PR_TRUE); ++ return blapi_SHVerify(name, (PRFuncPtr)decodeInt, PR_TRUE, err); + } + + #else /* NSS_FIPS_DISABLED */ +diff -r 3a9a84eee4a2 lib/softoken/fips.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/lib/softoken/fips.c Fri May 29 09:13:35 2020 +0200 +@@ -0,0 +1,33 @@ ++#include "../freebl/fips-selftest.inc" ++ ++#include "fips.h" ++ ++#include "softoken.h" ++ ++#include ++ ++/* crypto algorithms selftest wrapper */ ++static fips_check_status ++fips_checkCryptoSoftoken(void) ++{ ++ if (CKR_OK == sftk_FIPSEntryOK()) { ++ return CHECK_OK; ++ } else { ++ return CHECK_FAIL_CRYPTO; ++ } ++ ++ return CHECK_OK; ++} ++ ++/* constructor - load-time selfchecks */ ++static void __attribute__ ((constructor)) ++fips_initTestSoftoken(void) ++{ ++ fips_state = fips_initTest("softokn", (PRFuncPtr)fips_initTestSoftoken, fips_checkCryptoSoftoken); ++ ++ /* The legacy DB must be checked unconditionally. The check is performed by ++ * its constructor. */ ++ dlopen (SHLIB_PREFIX "nssdbm" SHLIB_VERSION "." SHLIB_SUFFIX, RTLD_LAZY); ++ ++ return; ++} +diff -r 3a9a84eee4a2 lib/softoken/fips.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/lib/softoken/fips.h Fri May 29 09:13:35 2020 +0200 +@@ -0,0 +1,10 @@ ++#ifndef FIPS_H ++#define FIPS_H ++ ++#include "softoken.h" ++ ++CK_RV FIPS_cryptoSelftestSoftoken(void); ++CK_RV sftk_fipsPowerUpSelfTest(void); ++ ++#endif ++ +diff -r 3a9a84eee4a2 lib/softoken/fipstest.c +--- a/lib/softoken/fipstest.c Wed Nov 20 08:25:39 2019 +0100 ++++ b/lib/softoken/fipstest.c Fri May 29 09:13:35 2020 +0200 +@@ -581,6 +581,327 @@ + return (SECFailure); + } + ++#define FIPS_DSA_TYPE siBuffer ++#define FIPS_DSA_DIGEST_LENGTH 28 /* 224-bits */ ++#define FIPS_DSA_SUBPRIME_LENGTH 28 /* 224-bits */ ++#define FIPS_DSA_SIGNATURE_LENGTH 56 /* 448-bits */ ++#define FIPS_DSA_PRIME_LENGTH 256 /* 2048-bits */ ++#define FIPS_DSA_BASE_LENGTH 256 /* 2048-bits */ ++ ++/* Similar to freebl_fips_DSA_PowerUpSelfTest, but using DSA_HashSign() */ ++static SECStatus ++sftk_fips_DSA_PowerUpSelfTest(void) ++{ ++ /* DSA Known P (2048-bits), Q (224-bits), and G (2048-bits) Values. */ ++ static const PRUint8 dsa_P[] = { ++ 0xfe, 0x9f, 0xba, 0xff, 0x39, 0xa6, 0x00, 0x77, ++ 0x93, 0xfe, 0xa4, 0x58, 0x17, 0xf8, 0x37, 0x54, ++ 0x76, 0x39, 0x18, 0xcb, 0xbe, 0xca, 0x62, 0x8b, ++ 0x85, 0xbc, 0x60, 0x23, 0xf4, 0x7a, 0xb5, 0x75, ++ 0x31, 0xf4, 0x82, 0x83, 0x63, 0xc2, 0xdb, 0x8e, ++ 0x50, 0x67, 0xd6, 0xd9, 0xae, 0xa0, 0xd6, 0x13, ++ 0xc2, 0x35, 0x5b, 0x76, 0xf1, 0x00, 0x9c, 0x37, ++ 0xcb, 0x46, 0x3f, 0x6e, 0xef, 0xca, 0xff, 0xcc, ++ 0x1e, 0x15, 0xa1, 0x96, 0x70, 0x4c, 0xc9, 0x4d, ++ 0x7e, 0xde, 0x00, 0x1e, 0x76, 0x68, 0x35, 0x1c, ++ 0x31, 0x25, 0x37, 0x91, 0x98, 0x64, 0x40, 0x4c, ++ 0xf1, 0xc3, 0x0e, 0xf7, 0xf3, 0x16, 0x17, 0x79, ++ 0x7a, 0xa3, 0x11, 0x9a, 0xba, 0x72, 0x67, 0xe9, ++ 0x70, 0xd0, 0x16, 0x6a, 0x1a, 0x53, 0x4e, 0x1b, ++ 0xca, 0xb2, 0x79, 0xd8, 0x8c, 0x60, 0x53, 0xdb, ++ 0x48, 0x1c, 0x00, 0x2e, 0xd3, 0x29, 0x35, 0x14, ++ 0x6d, 0xd6, 0x23, 0x7c, 0x1c, 0xf3, 0x0d, 0x6a, ++ 0x7e, 0xb7, 0x09, 0x7d, 0xf2, 0x06, 0x29, 0x1c, ++ 0x1a, 0xdf, 0xd9, 0xe6, 0xb9, 0x2e, 0xd6, 0xb8, ++ 0xbf, 0xc5, 0xcd, 0xe7, 0xf4, 0xf9, 0x91, 0x38, ++ 0x2f, 0x61, 0xf9, 0xfe, 0xce, 0x16, 0x85, 0xc8, ++ 0xb7, 0xdd, 0x54, 0xe0, 0xa1, 0x54, 0x4f, 0xb3, ++ 0xdb, 0x72, 0xf3, 0xb9, 0xaa, 0xfe, 0x7b, 0xdd, ++ 0x5e, 0x59, 0x44, 0x6c, 0x4a, 0xfe, 0x67, 0x9b, ++ 0xcf, 0x78, 0x05, 0xd4, 0xc8, 0x98, 0xb3, 0x60, ++ 0x46, 0x44, 0x4e, 0x0b, 0xec, 0x19, 0x6c, 0xda, ++ 0xd6, 0x40, 0x3c, 0xd9, 0x96, 0xc8, 0x4a, 0x3b, ++ 0xc9, 0xb5, 0x52, 0x89, 0x2e, 0x68, 0xb9, 0xa0, ++ 0xd3, 0xbc, 0xa8, 0xd7, 0x6a, 0x7d, 0xe1, 0xf4, ++ 0x8c, 0x68, 0x3e, 0xc1, 0x5a, 0xac, 0x46, 0x6d, ++ 0xad, 0xe3, 0x89, 0x7f, 0x92, 0xa6, 0x29, 0xb2, ++ 0xc3, 0x3b, 0x20, 0x5f, 0x71, 0x00, 0x27, 0x87 ++ }; ++ ++ static const PRUint8 dsa_Q[] = { ++ 0xbc, 0xc9, 0xda, 0xca, 0xf9, 0x6b, 0xfa, 0x7e, ++ 0xbd, 0x9b, 0xfb, 0x48, 0x35, 0x1e, 0xe5, 0x8c, ++ 0x64, 0x46, 0xc7, 0x04, 0xb2, 0x44, 0x70, 0x9b, ++ 0x0a, 0x3f, 0x03, 0x01 ++ }; ++ ++ static const PRUint8 dsa_G[] = { ++ 0x5d, 0x23, 0xd1, 0xc5, 0x2e, 0x7e, 0x22, 0x3b, ++ 0x98, 0x03, 0xc3, 0xc0, 0x9d, 0xbe, 0x8f, 0x68, ++ 0x6b, 0xd0, 0xbf, 0x72, 0x20, 0x89, 0x5c, 0x8f, ++ 0x4c, 0x8e, 0x66, 0xfe, 0x8e, 0xfc, 0x02, 0x21, ++ 0xf3, 0xea, 0xc5, 0x23, 0x96, 0x9b, 0xa4, 0x2e, ++ 0xac, 0x35, 0x9f, 0x70, 0x90, 0x79, 0xd9, 0x42, ++ 0xfa, 0x0e, 0x4c, 0x1f, 0x55, 0xcf, 0x8b, 0xb5, ++ 0x98, 0x71, 0xfa, 0xf1, 0xbc, 0xfd, 0xc7, 0x2b, ++ 0x5a, 0xa6, 0x53, 0x86, 0xf1, 0xa3, 0xd5, 0xbc, ++ 0xad, 0x08, 0x80, 0x23, 0x40, 0xea, 0xc9, 0x2f, ++ 0x58, 0xfb, 0xa9, 0xda, 0x8d, 0xc5, 0xfa, 0x46, ++ 0x0a, 0x0a, 0xe8, 0x03, 0xef, 0x04, 0x53, 0x09, ++ 0xc4, 0x7f, 0x69, 0x59, 0x68, 0xb5, 0x52, 0x91, ++ 0x3d, 0xe1, 0xbc, 0xa0, 0x6b, 0x41, 0xec, 0x07, ++ 0x0b, 0xf5, 0xf5, 0x62, 0xf5, 0xeb, 0xb7, 0x7e, ++ 0xc5, 0x32, 0x3d, 0x1e, 0x03, 0xda, 0x75, 0x24, ++ 0xb6, 0xe5, 0xb9, 0xfd, 0x36, 0x3d, 0xa4, 0xbf, ++ 0xc4, 0xee, 0x3b, 0xb5, 0x14, 0x85, 0x5c, 0x2d, ++ 0x80, 0xb2, 0x55, 0xb6, 0x70, 0x21, 0xf2, 0x94, ++ 0x63, 0xa5, 0xc2, 0x6f, 0xee, 0x34, 0x81, 0xae, ++ 0xc6, 0x0f, 0xf3, 0xef, 0xb4, 0xde, 0xa5, 0x58, ++ 0x6f, 0x57, 0xc1, 0x51, 0x0a, 0xe4, 0x4e, 0xf0, ++ 0xed, 0xee, 0x42, 0xdc, 0xff, 0x4b, 0x14, 0xa3, ++ 0xcc, 0x6e, 0xa8, 0x0c, 0x29, 0x81, 0xdb, 0xce, ++ 0x78, 0x4d, 0x43, 0xe0, 0xe1, 0x60, 0xc8, 0x3e, ++ 0x54, 0x00, 0x29, 0x20, 0x25, 0x40, 0x22, 0xac, ++ 0xfa, 0x75, 0xb1, 0x4e, 0xcc, 0x61, 0x54, 0x27, ++ 0x2c, 0x95, 0xaf, 0x4c, 0x02, 0xa7, 0x55, 0xbd, ++ 0xed, 0xe2, 0x25, 0xfc, 0xba, 0xd2, 0x5b, 0xd7, ++ 0x33, 0xa1, 0xe9, 0xb4, 0x7f, 0x7e, 0xfe, 0xbb, ++ 0xfa, 0x54, 0xce, 0x3c, 0xbc, 0xd1, 0x03, 0x50, ++ 0x9d, 0xa9, 0x38, 0x9a, 0xf8, 0x67, 0xb1, 0xa3 ++ }; ++ /* DSA Known Random Values (known random key block is 224-bits) */ ++ static const PRUint8 dsa_known_random_key_block[] = { ++ "Mozilla Rules World! Always." ++ }; ++ /* DSA Known Digest (224-bits) */ ++ static const PRUint8 dsa_known_digest[] = { "DSA Signature Digest, Longer" }; ++ ++ /* DSA variables. */ ++ DSAPrivateKey *dsa_private_key; ++ SECStatus dsa_status; ++ SECItem dsa_signature_item; ++ SECItem dsa_digest_item; ++ DSAPublicKey dsa_public_key; ++ PRUint8 dsa_computed_signature[FIPS_DSA_SIGNATURE_LENGTH]; ++ static const PQGParams dsa_pqg = { ++ NULL, ++ { FIPS_DSA_TYPE, (unsigned char *)dsa_P, FIPS_DSA_PRIME_LENGTH }, ++ { FIPS_DSA_TYPE, (unsigned char *)dsa_Q, FIPS_DSA_SUBPRIME_LENGTH }, ++ { FIPS_DSA_TYPE, (unsigned char *)dsa_G, FIPS_DSA_BASE_LENGTH } ++ }; ++ NSSLOWKEYPrivateKey lowkey_priv; ++ ++ /******************************************/ ++ /* Generate a DSA public/private key pair */ ++ /******************************************/ ++ ++ /* Generate a DSA public/private key pair. */ ++ dsa_status = DSA_NewKeyFromSeed(&dsa_pqg, dsa_known_random_key_block, ++ &dsa_private_key); ++ ++ if (dsa_status != SECSuccess) { ++ PORT_SetError(SEC_ERROR_NO_MEMORY); ++ return (SECFailure); ++ } ++ ++ /* construct public key from private key. */ ++ dsa_public_key.params = dsa_private_key->params; ++ dsa_public_key.publicValue = dsa_private_key->publicValue; ++ ++ /*********************************/ ++ /* DSA pairwise consistency test */ ++ /*********************************/ ++ ++ dsa_signature_item.data = dsa_computed_signature; ++ dsa_signature_item.len = sizeof dsa_computed_signature; ++ ++ dsa_digest_item.data = (unsigned char *)dsa_known_digest; ++ dsa_digest_item.len = SHA224_LENGTH; ++ ++ /* Perform DSA signature process. */ ++ lowkey_priv.u.dsa = *dsa_private_key; ++ dsa_status = DSA_HashSign (SEC_OID_SHA224, &lowkey_priv, ++ dsa_signature_item.data, &dsa_signature_item.len, ++ sizeof dsa_computed_signature, ++ dsa_digest_item.data, SHA224_LENGTH); ++ ++ /* Check that operation succeeded and that signature is different from hash */ ++ if ((dsa_status != SECSuccess) || ++ (dsa_signature_item.len != FIPS_DSA_SIGNATURE_LENGTH) || ++ (PORT_Memcmp(dsa_computed_signature, dsa_known_digest, ++ PR_MIN (FIPS_DSA_SIGNATURE_LENGTH, FIPS_DSA_DIGEST_LENGTH)) == 0)) { ++ dsa_status = SECFailure; ++ } else { ++ /* Perform DSA verification process. */ ++ dsa_status = DSA_VerifyDigest(&dsa_public_key, ++ &dsa_signature_item, ++ &dsa_digest_item); ++ } ++ ++ PORT_FreeArena(dsa_private_key->params.arena, PR_TRUE); ++ /* Don't free public key, it uses same arena as private key */ ++ ++ /* Verify DSA signature. */ ++ if (dsa_status != SECSuccess) { ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); ++ return SECFailure; ++ } ++ ++ return (SECSuccess); ++} ++ ++#define FIPS_ECDSA_DIGEST_LENGTH 28 /* 224-bits */ ++#define FIPS_ECDSA_SIGNATURE_LENGTH 64 /* 512-bits */ ++ ++/* Similar to freebl_fips_ECDSA_PowerUpSelfTest, but using ECDSA_HashSign() */ ++static SECStatus ++sftk_fips_ECDSA_PowerUpSelfTest(void) ++{ ++ /* 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, ++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC ++ }; ++ static const unsigned char p256_b[] = { ++ 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, 0xEB, 0xBD, 0x55, 0x76, ++ 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, 0x3B, 0xCE, ++ 0x3C, 0x3E, 0x27, 0xD2, 0x60, 0x4B ++ }; ++ static const unsigned char p256_base[] = { ++ 0x04, ++ 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5, 0x63, ++ 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, ++ 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96, ++ 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, ++ 0x0F, 0x9E, 0x16, 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, ++ 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5 ++ }; ++ 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 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 */ ++ { /* a = curvea b = curveb */ ++ /* curve.a */ ++ { siBuffer, (unsigned char *)p256_a, sizeof(p256_a) }, ++ /* curve.b */ ++ { siBuffer, (unsigned char *)p256_b, sizeof(p256_b) }, ++ /* curve.seed */ ++ { siBuffer, NULL, 0 } }, ++ /* base = 04xy*/ ++ { siBuffer, (unsigned char *)p256_base, sizeof(p256_base) }, ++ /* order */ ++ { siBuffer, (unsigned char *)p256_order, sizeof(p256_order) }, ++ 1, /* cofactor */ ++ /* DEREncoding */ ++ { siBuffer, (unsigned char *)p256_encoding, sizeof(p256_encoding) }, ++ ECCurve_X9_62_PRIME_256V1, ++ /* curveOID */ ++ { siBuffer, (unsigned char *)(p256_encoding) + 2, sizeof(p256_encoding) - 2 }, ++ }; ++ /* ECDSA Known Seed info for curves nistp256 and nistk283 */ ++ static const PRUint8 ecdsa_Known_Seed[] = { ++ 0x6a, 0x9b, 0xf6, 0xf7, 0xce, 0xed, 0x79, 0x11, ++ 0xf0, 0xc7, 0xc8, 0x9a, 0xa5, 0xd1, 0x57, 0xb1, ++ 0x7b, 0x5a, 0x3b, 0x76, 0x4e, 0x7b, 0x7c, 0xbc, ++ 0xf2, 0x76, 0x1c, 0x1c, 0x7f, 0xc5, 0x53, 0x2f ++ }; ++ /* ECDSA Known Digest (224-bits) */ ++ static const PRUint8 ecdsa_known_digest[] = { "ECDSA Signature Digest, Longer" }; ++ /* ECDSA variables. */ ++ ECPrivateKey *ecdsa_private_key; ++ SECStatus ecdsa_status; ++ SECItem ecdsa_signature_item; ++ SECItem ecdsa_digest_item; ++ ECPublicKey ecdsa_public_key; ++ PRUint8 ecdsa_computed_signature[2 * MAX_ECKEY_LEN]; ++ NSSLOWKEYPrivateKey lowkey_priv; ++ ++ /*********************************************/ ++ /* Generate an ECDSA public/private key pair */ ++ /*********************************************/ ++ ++ ecdsa_status = EC_NewKeyFromSeed(&ec_known_P256_Params, ++ &ecdsa_private_key, ++ ecdsa_Known_Seed, ++ sizeof (ecdsa_Known_Seed)); ++ ++ if (ecdsa_status != SECSuccess) { ++ PORT_SetError(SEC_ERROR_NO_MEMORY); ++ return (SECFailure); ++ } ++ ++ /* Construct public key from private key. */ ++ ecdsa_public_key.ecParams = ecdsa_private_key->ecParams; ++ ecdsa_public_key.publicValue = ecdsa_private_key->publicValue; ++ ++ /* Validate public key value. */ ++ ecdsa_status = EC_ValidatePublicKey(&ecdsa_public_key.ecParams, ++ &ecdsa_public_key.publicValue); ++ if (ecdsa_status != SECSuccess) { ++ goto loser; ++ } ++ ++ /***********************************/ ++ /* ECDSA pairwise consistency test */ ++ /***********************************/ ++ ++ ecdsa_signature_item.data = ecdsa_computed_signature; ++ ecdsa_signature_item.len = sizeof ecdsa_computed_signature; ++ ++ ecdsa_digest_item.data = (unsigned char *)ecdsa_known_digest; ++ ecdsa_digest_item.len = SHA224_LENGTH; ++ ++ /* Perform ECDSA signature process. */ ++ lowkey_priv.u.ec = *ecdsa_private_key; ++ ecdsa_status = ECDSA_HashSign (SEC_OID_SHA224, &lowkey_priv, ++ ecdsa_signature_item.data, &ecdsa_signature_item.len, ++ sizeof ecdsa_computed_signature, ++ ecdsa_digest_item.data, SHA224_LENGTH); ++ ++ /* Check that operation succeeded and that signature is different from hash */ ++ if ((ecdsa_status != SECSuccess) || ++ (ecdsa_signature_item.len != FIPS_ECDSA_SIGNATURE_LENGTH) || ++ (PORT_Memcmp(ecdsa_computed_signature, ecdsa_known_digest, ++ PR_MIN (FIPS_ECDSA_SIGNATURE_LENGTH, FIPS_ECDSA_DIGEST_LENGTH)) == 0)) { ++ ecdsa_status = SECFailure; ++ } else { ++ /* Perform ECDSA verification process. */ ++ ecdsa_status = ECDSA_VerifyDigest(&ecdsa_public_key, ++ &ecdsa_signature_item, ++ &ecdsa_digest_item); ++ } ++ ++loser: ++ /* Free the memory for the private key arena */ ++ PORT_FreeArena(ecdsa_private_key->ecParams.arena, PR_FALSE); ++ ++ if (ecdsa_status != SECSuccess) { ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); ++ return SECFailure; ++ } ++ ++ return (SECSuccess); ++} ++ + static PRBool sftk_self_tests_ran = PR_FALSE; + static PRBool sftk_self_tests_success = PR_FALSE; + +@@ -592,7 +913,6 @@ + sftk_startup_tests(void) + { + SECStatus rv; +- const char *libraryName = SOFTOKEN_LIB_NAME; + + PORT_Assert(!sftk_self_tests_ran); + PORT_Assert(!sftk_self_tests_success); +@@ -604,6 +924,7 @@ + if (rv != SECSuccess) { + return; + } ++ + /* make sure freebl is initialized, or our RSA check + * may fail. This is normally done at freebl load time, but it's + * possible we may have shut freebl down without unloading it. */ +@@ -621,12 +942,21 @@ + if (rv != SECSuccess) { + return; + } +- if (!BLAPI_SHVerify(libraryName, +- (PRFuncPtr)&sftk_fips_RSA_PowerUpSelfTest)) { +- /* something is wrong with the library, fail without enabling +- * the token */ ++ ++ /* check the DSA combined functions in softoken */ ++ rv = sftk_fips_DSA_PowerUpSelfTest(); ++ if (rv != SECSuccess) { + return; + } ++ ++ /* check the ECDSA combined functions in softoken */ ++ rv = sftk_fips_ECDSA_PowerUpSelfTest(); ++ if (rv != SECSuccess) { ++ return; ++ } ++ ++ /* Checksum is done by fips_initTestSoftoken() in fips.c */ ++ + rv = sftk_fips_IKE_PowerUpSelfTests(); + if (rv != SECSuccess) { + return; +@@ -642,17 +972,11 @@ + CK_RV + sftk_FIPSEntryOK() + { +-#ifdef NSS_NO_INIT_SUPPORT +- /* this should only be set on platforms that can't handle one of the INIT +- * schemes. This code allows those platforms to continue to function, +- * though they don't meet the strict NIST requirements. If NSS_NO_INIT_SUPPORT +- * is not set, and init support has not been properly enabled, softken +- * will always fail because of the test below +- */ ++ /* For platforms that don't support on-load constructors */ + if (!sftk_self_tests_ran) { + sftk_startup_tests(); + } +-#endif ++ + if (!sftk_self_tests_success) { + return CKR_DEVICE_ERROR; + } +diff -r 3a9a84eee4a2 lib/softoken/legacydb/fips.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/lib/softoken/legacydb/fips.c Fri May 29 09:13:35 2020 +0200 +@@ -0,0 +1,25 @@ ++#include "../../freebl/fips-selftest.inc" ++ ++#include "fips.h" ++ ++/*** private per-module symbols ***/ ++ ++/* crypto algorithms selftest wrapper */ ++static fips_check_status ++fips_checkCryptoDbm(void) ++{ ++ /* no checks in dbm */ ++ return CHECK_OK; ++} ++ ++/* constructor - load-time selfchecks */ ++static void __attribute__ ((constructor)) ++fips_initTestDbm(void) ++{ ++ fips_state = fips_initTest("nssdbm", (PRFuncPtr)fips_checkCryptoDbm, NULL); ++ ++ return; ++} ++ ++/*** public per-module symbols ***/ ++ +diff -r 3a9a84eee4a2 lib/softoken/legacydb/fips.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/lib/softoken/legacydb/fips.h Fri May 29 09:13:35 2020 +0200 +@@ -0,0 +1,5 @@ ++#ifndef FIPS_H ++#define FIPS_H ++ ++#endif ++ +diff -r 3a9a84eee4a2 lib/softoken/legacydb/lgfips.c +--- a/lib/softoken/legacydb/lgfips.c Wed Nov 20 08:25:39 2019 +0100 ++++ b/lib/softoken/legacydb/lgfips.c Fri May 29 09:13:35 2020 +0200 +@@ -90,7 +90,7 @@ + + /* no self tests required for the legacy db, only the integrity check */ + /* check the integrity of our shared library */ +- if (!BLAPI_SHVerify(libraryName, (PRFuncPtr)&lg_local_function)) { ++ if (!BLAPI_SHVerify(libraryName, (PRFuncPtr)&lg_local_function, NULL)) { + /* something is wrong with the library, fail without enabling + * the fips token */ + return; +diff -r 3a9a84eee4a2 lib/softoken/legacydb/manifest.mn +--- a/lib/softoken/legacydb/manifest.mn Wed Nov 20 08:25:39 2019 +0100 ++++ b/lib/softoken/legacydb/manifest.mn Fri May 29 09:13:35 2020 +0200 +@@ -12,7 +12,7 @@ + LIBRARY_VERSION = 3 + MAPFILE = $(OBJDIR)/$(LIBRARY_NAME).def + +-DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\" -DLG_LIB_NAME=\"$(notdir $(SHARED_LIBRARY))\" ++DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\" -DLG_LIB_NAME=\"$(notdir $(SHARED_LIBRARY))\" -DSHLIB_VERSION=\"$(LIBRARY_VERSION)\" + + CSRCS = \ + dbmshim.c \ +@@ -28,5 +28,6 @@ + lowkey.c \ + pcertdb.c \ + pk11db.c \ ++ fips.c \ + $(NULL) + +diff -r 3a9a84eee4a2 lib/softoken/manifest.mn +--- a/lib/softoken/manifest.mn Wed Nov 20 08:25:39 2019 +0100 ++++ b/lib/softoken/manifest.mn Fri May 29 09:13:35 2020 +0200 +@@ -29,6 +29,7 @@ + softkver.h \ + sdb.h \ + sftkdbt.h \ ++ fips.h \ + $(NULL) + + CSRCS = \ +@@ -52,6 +53,7 @@ + softkver.c \ + tlsprf.c \ + jpakesftk.c \ ++ fips.c \ + $(NULL) + + ifndef NSS_DISABLE_DBM diff --git a/nss-fips-detect-fips-mode-fixes.patch b/nss-fips-detect-fips-mode-fixes.patch new file mode 100644 index 0000000..9b84ca7 --- /dev/null +++ b/nss-fips-detect-fips-mode-fixes.patch @@ -0,0 +1,93 @@ +# HG changeset patch +# User M. Sirringhaus +# Date 1584305671 -3600 +# Sun Mar 15 21:54:31 2020 +0100 +# Node ID 715834d4a258c535f3abbf116d69d5e77392593b +# Parent 4ddd7d49eeed4ea32850daf41a472ccb50dee45e +commit facacdb9078693d7a4219e84f73ea7b8f977ddc2 +Author: Hans Petter Jansson + Patch 32: nss-fips-detect-fips-mode-fixes.patch + +diff --git a/lib/freebl/nsslowhash.c b/lib/freebl/nsslowhash.c +--- a/lib/freebl/nsslowhash.c ++++ b/lib/freebl/nsslowhash.c +@@ -2,10 +2,15 @@ + * 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/. */ + ++#define _GNU_SOURCE 1 ++#include ++ + #ifdef FREEBL_NO_DEPEND + #include "stubs.h" + #endif ++ + #include "prtypes.h" ++#include "prenv.h" + #include "secerr.h" + #include "blapi.h" + #include "hasht.h" +@@ -24,6 +29,23 @@ + }; + + #ifndef NSS_FIPS_DISABLED ++ ++static PRBool ++getFIPSEnv(void) ++{ ++ char *fipsEnv = secure_getenv("NSS_FIPS"); ++ if (!fipsEnv) { ++ return PR_FALSE; ++ } ++ if ((strcasecmp(fipsEnv, "fips") == 0) || ++ (strcasecmp(fipsEnv, "true") == 0) || ++ (strcasecmp(fipsEnv, "on") == 0) || ++ (strcasecmp(fipsEnv, "1") == 0)) { ++ return PR_TRUE; ++ } ++ return PR_FALSE; ++} ++ + static int + nsslow_GetFIPSEnabled(void) + { +@@ -45,6 +67,7 @@ + #endif /* LINUX */ + return 1; + } ++ + #endif /* NSS_FIPS_DISABLED */ + + static NSSLOWInitContext dummyContext = { 0 }; +@@ -60,7 +83,7 @@ + #ifndef NSS_FIPS_DISABLED + /* make sure the FIPS product is installed if we are trying to + * go into FIPS mode */ +- if (nsslow_GetFIPSEnabled()) { ++ if (nsslow_GetFIPSEnabled() || getFIPSEnv()) { + if (BL_FIPSEntryOK(PR_TRUE) != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + post_failed = PR_TRUE; +diff --git a/lib/sysinit/nsssysinit.c b/lib/sysinit/nsssysinit.c +--- a/lib/sysinit/nsssysinit.c ++++ b/lib/sysinit/nsssysinit.c +@@ -178,16 +178,16 @@ + f = fopen("/proc/sys/crypto/fips_enabled", "r"); + if (!f) { + /* if we don't have a proc flag, fall back to the +- * environment variable */ ++ * environment variable */ + return getFIPSEnv(); + } + + size = fread(&d, 1, 1, f); + fclose(f); + if (size != 1) +- return PR_FALSE; ++ return getFIPSEnv(); + if (d != '1') +- return PR_FALSE; ++ return getFIPSEnv(); + return PR_TRUE; + #else + return PR_FALSE; diff --git a/nss-fips-dsa-kat.patch b/nss-fips-dsa-kat.patch new file mode 100644 index 0000000..e4ead73 --- /dev/null +++ b/nss-fips-dsa-kat.patch @@ -0,0 +1,208 @@ +# HG changeset patch +# User Hans Petter Jansson +# Date 1505605677 -7200 +# Sun Sep 17 01:47:57 2017 +0200 +# Node ID 4ae6bed68a83c01f6d2ce7a37bdb0bdb0556416f +# Parent 5e191a391c38967e49a1d005800713ccd1010b09 +[PATCH 2/6] Make DSA KAT FIPS compliant (1024 -> 2048 bit key). +From b88701933a284ba8640df66b954c04d36ee592c9 Mon Sep 17 00:00:00 2001 +--- + nss/lib/freebl/dsa.c | 2 +- + nss/lib/freebl/fipsfreebl.c | 143 +++++++++++++++++++++++++++----------------- + 2 files changed, 90 insertions(+), 55 deletions(-) + +diff --git a/lib/freebl/dsa.c b/lib/freebl/dsa.c +--- a/lib/freebl/dsa.c ++++ b/lib/freebl/dsa.c +@@ -533,7 +533,7 @@ + return rv; + } + +-/* For FIPS compliance testing. Seed must be exactly 20 bytes. */ ++/* For FIPS compliance testing. Seed must be the same size as subprime. */ + SECStatus + DSA_SignDigestWithSeed(DSAPrivateKey *key, + SECItem *signature, +diff --git a/lib/freebl/fipsfreebl.c b/lib/freebl/fipsfreebl.c +--- a/lib/freebl/fipsfreebl.c ++++ b/lib/freebl/fipsfreebl.c +@@ -124,11 +124,11 @@ + + /* FIPS preprocessor directives for DSA. */ + #define FIPS_DSA_TYPE siBuffer +-#define FIPS_DSA_DIGEST_LENGTH 20 /* 160-bits */ +-#define FIPS_DSA_SUBPRIME_LENGTH 20 /* 160-bits */ +-#define FIPS_DSA_SIGNATURE_LENGTH 40 /* 320-bits */ +-#define FIPS_DSA_PRIME_LENGTH 128 /* 1024-bits */ +-#define FIPS_DSA_BASE_LENGTH 128 /* 1024-bits */ ++#define FIPS_DSA_DIGEST_LENGTH 28 /* 224-bits */ ++#define FIPS_DSA_SUBPRIME_LENGTH 28 /* 224-bits */ ++#define FIPS_DSA_SIGNATURE_LENGTH 56 /* 448-bits */ ++#define FIPS_DSA_PRIME_LENGTH 256 /* 2048-bits */ ++#define FIPS_DSA_BASE_LENGTH 256 /* 2048-bits */ + + /* FIPS preprocessor directives for RNG. */ + #define FIPS_RNG_XKEY_LENGTH 32 /* 256-bits */ +@@ -1445,70 +1445,105 @@ + static SECStatus + freebl_fips_DSA_PowerUpSelfTest(void) + { +- /* DSA Known P (1024-bits), Q (160-bits), and G (1024-bits) Values. */ ++ /* DSA Known P (2048-bits), Q (224-bits), and G (2048-bits) Values. */ + static const PRUint8 dsa_P[] = { +- 0x80, 0xb0, 0xd1, 0x9d, 0x6e, 0xa4, 0xf3, 0x28, +- 0x9f, 0x24, 0xa9, 0x8a, 0x49, 0xd0, 0x0c, 0x63, +- 0xe8, 0x59, 0x04, 0xf9, 0x89, 0x4a, 0x5e, 0xc0, +- 0x6d, 0xd2, 0x67, 0x6b, 0x37, 0x81, 0x83, 0x0c, +- 0xfe, 0x3a, 0x8a, 0xfd, 0xa0, 0x3b, 0x08, 0x91, +- 0x1c, 0xcb, 0xb5, 0x63, 0xb0, 0x1c, 0x70, 0xd0, +- 0xae, 0xe1, 0x60, 0x2e, 0x12, 0xeb, 0x54, 0xc7, +- 0xcf, 0xc6, 0xcc, 0xae, 0x97, 0x52, 0x32, 0x63, +- 0xd3, 0xeb, 0x55, 0xea, 0x2f, 0x4c, 0xd5, 0xd7, +- 0x3f, 0xda, 0xec, 0x49, 0x27, 0x0b, 0x14, 0x56, +- 0xc5, 0x09, 0xbe, 0x4d, 0x09, 0x15, 0x75, 0x2b, +- 0xa3, 0x42, 0x0d, 0x03, 0x71, 0xdf, 0x0f, 0xf4, +- 0x0e, 0xe9, 0x0c, 0x46, 0x93, 0x3d, 0x3f, 0xa6, +- 0x6c, 0xdb, 0xca, 0xe5, 0xac, 0x96, 0xc8, 0x64, +- 0x5c, 0xec, 0x4b, 0x35, 0x65, 0xfc, 0xfb, 0x5a, +- 0x1b, 0x04, 0x1b, 0xa1, 0x0e, 0xfd, 0x88, 0x15 ++ 0xfe, 0x9f, 0xba, 0xff, 0x39, 0xa6, 0x00, 0x77, ++ 0x93, 0xfe, 0xa4, 0x58, 0x17, 0xf8, 0x37, 0x54, ++ 0x76, 0x39, 0x18, 0xcb, 0xbe, 0xca, 0x62, 0x8b, ++ 0x85, 0xbc, 0x60, 0x23, 0xf4, 0x7a, 0xb5, 0x75, ++ 0x31, 0xf4, 0x82, 0x83, 0x63, 0xc2, 0xdb, 0x8e, ++ 0x50, 0x67, 0xd6, 0xd9, 0xae, 0xa0, 0xd6, 0x13, ++ 0xc2, 0x35, 0x5b, 0x76, 0xf1, 0x00, 0x9c, 0x37, ++ 0xcb, 0x46, 0x3f, 0x6e, 0xef, 0xca, 0xff, 0xcc, ++ 0x1e, 0x15, 0xa1, 0x96, 0x70, 0x4c, 0xc9, 0x4d, ++ 0x7e, 0xde, 0x00, 0x1e, 0x76, 0x68, 0x35, 0x1c, ++ 0x31, 0x25, 0x37, 0x91, 0x98, 0x64, 0x40, 0x4c, ++ 0xf1, 0xc3, 0x0e, 0xf7, 0xf3, 0x16, 0x17, 0x79, ++ 0x7a, 0xa3, 0x11, 0x9a, 0xba, 0x72, 0x67, 0xe9, ++ 0x70, 0xd0, 0x16, 0x6a, 0x1a, 0x53, 0x4e, 0x1b, ++ 0xca, 0xb2, 0x79, 0xd8, 0x8c, 0x60, 0x53, 0xdb, ++ 0x48, 0x1c, 0x00, 0x2e, 0xd3, 0x29, 0x35, 0x14, ++ 0x6d, 0xd6, 0x23, 0x7c, 0x1c, 0xf3, 0x0d, 0x6a, ++ 0x7e, 0xb7, 0x09, 0x7d, 0xf2, 0x06, 0x29, 0x1c, ++ 0x1a, 0xdf, 0xd9, 0xe6, 0xb9, 0x2e, 0xd6, 0xb8, ++ 0xbf, 0xc5, 0xcd, 0xe7, 0xf4, 0xf9, 0x91, 0x38, ++ 0x2f, 0x61, 0xf9, 0xfe, 0xce, 0x16, 0x85, 0xc8, ++ 0xb7, 0xdd, 0x54, 0xe0, 0xa1, 0x54, 0x4f, 0xb3, ++ 0xdb, 0x72, 0xf3, 0xb9, 0xaa, 0xfe, 0x7b, 0xdd, ++ 0x5e, 0x59, 0x44, 0x6c, 0x4a, 0xfe, 0x67, 0x9b, ++ 0xcf, 0x78, 0x05, 0xd4, 0xc8, 0x98, 0xb3, 0x60, ++ 0x46, 0x44, 0x4e, 0x0b, 0xec, 0x19, 0x6c, 0xda, ++ 0xd6, 0x40, 0x3c, 0xd9, 0x96, 0xc8, 0x4a, 0x3b, ++ 0xc9, 0xb5, 0x52, 0x89, 0x2e, 0x68, 0xb9, 0xa0, ++ 0xd3, 0xbc, 0xa8, 0xd7, 0x6a, 0x7d, 0xe1, 0xf4, ++ 0x8c, 0x68, 0x3e, 0xc1, 0x5a, 0xac, 0x46, 0x6d, ++ 0xad, 0xe3, 0x89, 0x7f, 0x92, 0xa6, 0x29, 0xb2, ++ 0xc3, 0x3b, 0x20, 0x5f, 0x71, 0x00, 0x27, 0x87 + }; + + static const PRUint8 dsa_Q[] = { +- 0xad, 0x22, 0x59, 0xdf, 0xe5, 0xec, 0x4c, 0x6e, +- 0xf9, 0x43, 0xf0, 0x4b, 0x2d, 0x50, 0x51, 0xc6, +- 0x91, 0x99, 0x8b, 0xcf ++ 0xbc, 0xc9, 0xda, 0xca, 0xf9, 0x6b, 0xfa, 0x7e, ++ 0xbd, 0x9b, 0xfb, 0x48, 0x35, 0x1e, 0xe5, 0x8c, ++ 0x64, 0x46, 0xc7, 0x04, 0xb2, 0x44, 0x70, 0x9b, ++ 0x0a, 0x3f, 0x03, 0x01 + }; + + static const PRUint8 dsa_G[] = { +- 0x78, 0x6e, 0xa9, 0xd8, 0xcd, 0x4a, 0x85, 0xa4, +- 0x45, 0xb6, 0x6e, 0x5d, 0x21, 0x50, 0x61, 0xf6, +- 0x5f, 0xdf, 0x5c, 0x7a, 0xde, 0x0d, 0x19, 0xd3, +- 0xc1, 0x3b, 0x14, 0xcc, 0x8e, 0xed, 0xdb, 0x17, +- 0xb6, 0xca, 0xba, 0x86, 0xa9, 0xea, 0x51, 0x2d, +- 0xc1, 0xa9, 0x16, 0xda, 0xf8, 0x7b, 0x59, 0x8a, +- 0xdf, 0xcb, 0xa4, 0x67, 0x00, 0x44, 0xea, 0x24, +- 0x73, 0xe5, 0xcb, 0x4b, 0xaf, 0x2a, 0x31, 0x25, +- 0x22, 0x28, 0x3f, 0x16, 0x10, 0x82, 0xf7, 0xeb, +- 0x94, 0x0d, 0xdd, 0x09, 0x22, 0x14, 0x08, 0x79, +- 0xba, 0x11, 0x0b, 0xf1, 0xff, 0x2d, 0x67, 0xac, +- 0xeb, 0xb6, 0x55, 0x51, 0x69, 0x97, 0xa7, 0x25, +- 0x6b, 0x9c, 0xa0, 0x9b, 0xd5, 0x08, 0x9b, 0x27, +- 0x42, 0x1c, 0x7a, 0x69, 0x57, 0xe6, 0x2e, 0xed, +- 0xa9, 0x5b, 0x25, 0xe8, 0x1f, 0xd2, 0xed, 0x1f, +- 0xdf, 0xe7, 0x80, 0x17, 0xba, 0x0d, 0x4d, 0x38 ++ 0x5d, 0x23, 0xd1, 0xc5, 0x2e, 0x7e, 0x22, 0x3b, ++ 0x98, 0x03, 0xc3, 0xc0, 0x9d, 0xbe, 0x8f, 0x68, ++ 0x6b, 0xd0, 0xbf, 0x72, 0x20, 0x89, 0x5c, 0x8f, ++ 0x4c, 0x8e, 0x66, 0xfe, 0x8e, 0xfc, 0x02, 0x21, ++ 0xf3, 0xea, 0xc5, 0x23, 0x96, 0x9b, 0xa4, 0x2e, ++ 0xac, 0x35, 0x9f, 0x70, 0x90, 0x79, 0xd9, 0x42, ++ 0xfa, 0x0e, 0x4c, 0x1f, 0x55, 0xcf, 0x8b, 0xb5, ++ 0x98, 0x71, 0xfa, 0xf1, 0xbc, 0xfd, 0xc7, 0x2b, ++ 0x5a, 0xa6, 0x53, 0x86, 0xf1, 0xa3, 0xd5, 0xbc, ++ 0xad, 0x08, 0x80, 0x23, 0x40, 0xea, 0xc9, 0x2f, ++ 0x58, 0xfb, 0xa9, 0xda, 0x8d, 0xc5, 0xfa, 0x46, ++ 0x0a, 0x0a, 0xe8, 0x03, 0xef, 0x04, 0x53, 0x09, ++ 0xc4, 0x7f, 0x69, 0x59, 0x68, 0xb5, 0x52, 0x91, ++ 0x3d, 0xe1, 0xbc, 0xa0, 0x6b, 0x41, 0xec, 0x07, ++ 0x0b, 0xf5, 0xf5, 0x62, 0xf5, 0xeb, 0xb7, 0x7e, ++ 0xc5, 0x32, 0x3d, 0x1e, 0x03, 0xda, 0x75, 0x24, ++ 0xb6, 0xe5, 0xb9, 0xfd, 0x36, 0x3d, 0xa4, 0xbf, ++ 0xc4, 0xee, 0x3b, 0xb5, 0x14, 0x85, 0x5c, 0x2d, ++ 0x80, 0xb2, 0x55, 0xb6, 0x70, 0x21, 0xf2, 0x94, ++ 0x63, 0xa5, 0xc2, 0x6f, 0xee, 0x34, 0x81, 0xae, ++ 0xc6, 0x0f, 0xf3, 0xef, 0xb4, 0xde, 0xa5, 0x58, ++ 0x6f, 0x57, 0xc1, 0x51, 0x0a, 0xe4, 0x4e, 0xf0, ++ 0xed, 0xee, 0x42, 0xdc, 0xff, 0x4b, 0x14, 0xa3, ++ 0xcc, 0x6e, 0xa8, 0x0c, 0x29, 0x81, 0xdb, 0xce, ++ 0x78, 0x4d, 0x43, 0xe0, 0xe1, 0x60, 0xc8, 0x3e, ++ 0x54, 0x00, 0x29, 0x20, 0x25, 0x40, 0x22, 0xac, ++ 0xfa, 0x75, 0xb1, 0x4e, 0xcc, 0x61, 0x54, 0x27, ++ 0x2c, 0x95, 0xaf, 0x4c, 0x02, 0xa7, 0x55, 0xbd, ++ 0xed, 0xe2, 0x25, 0xfc, 0xba, 0xd2, 0x5b, 0xd7, ++ 0x33, 0xa1, 0xe9, 0xb4, 0x7f, 0x7e, 0xfe, 0xbb, ++ 0xfa, 0x54, 0xce, 0x3c, 0xbc, 0xd1, 0x03, 0x50, ++ 0x9d, 0xa9, 0x38, 0x9a, 0xf8, 0x67, 0xb1, 0xa3 + }; + +- /* DSA Known Random Values (known random key block is 160-bits) */ +- /* and (known random signature block is 160-bits). */ ++ /* DSA Known Random Values (known random key block is 224-bits) */ ++ /* and (known random signature block is 224-bits). */ + static const PRUint8 dsa_known_random_key_block[] = { +- "Mozilla Rules World!" ++ "Mozilla Rules World! Always." + }; + static const PRUint8 dsa_known_random_signature_block[] = { +- "Random DSA Signature" ++ "Random DSA Signature, Longer" + }; + +- /* DSA Known Digest (160-bits) */ +- static const PRUint8 dsa_known_digest[] = { "DSA Signature Digest" }; ++ /* DSA Known Digest (224-bits) */ ++ static const PRUint8 dsa_known_digest[] = { "DSA Signature Digest, Longer" }; + +- /* DSA Known Signature (320-bits). */ ++ /* DSA Known Signature (448-bits). */ + static const PRUint8 dsa_known_signature[] = { +- 0x25, 0x7c, 0x3a, 0x79, 0x32, 0x45, 0xb7, 0x32, +- 0x70, 0xca, 0x62, 0x63, 0x2b, 0xf6, 0x29, 0x2c, +- 0x22, 0x2a, 0x03, 0xce, 0x48, 0x15, 0x11, 0x72, +- 0x7b, 0x7e, 0xf5, 0x7a, 0xf3, 0x10, 0x3b, 0xde, +- 0x34, 0xc1, 0x9e, 0xd7, 0x27, 0x9e, 0x77, 0x38 ++ 0x27, 0x04, 0xff, 0xd5, 0x2d, 0x80, 0x32, 0xea, ++ 0xac, 0xb5, 0x8b, 0x47, 0x17, 0xb1, 0x80, 0xed, ++ 0xd6, 0x0f, 0x72, 0x75, 0xe5, 0xba, 0x08, 0xc9, ++ 0x29, 0xc8, 0xc7, 0x75, 0x84, 0x60, 0x5a, 0xe9, ++ 0x55, 0xa4, 0x1c, 0xf0, 0xe3, 0xce, 0x4c, 0x8e, ++ 0x83, 0x3e, 0x7a, 0x77, 0x56, 0x7f, 0x83, 0xad, ++ 0x68, 0x36, 0x13, 0xa9, 0xd6, 0x08, 0x1f, 0x19 + }; + + /* DSA variables. */ +@@ -1550,7 +1585,7 @@ + dsa_signature_item.len = sizeof dsa_computed_signature; + + dsa_digest_item.data = (unsigned char *)dsa_known_digest; +- dsa_digest_item.len = SHA1_LENGTH; ++ dsa_digest_item.len = SHA224_LENGTH; + + /* Perform DSA signature process. */ + dsa_status = DSA_SignDigestWithSeed(dsa_private_key, diff --git a/nss-fips-gcm-ctr.patch b/nss-fips-gcm-ctr.patch new file mode 100644 index 0000000..8139b5b --- /dev/null +++ b/nss-fips-gcm-ctr.patch @@ -0,0 +1,61 @@ +# HG changeset patch +# User Hans Petter Jansson +# Date 1574234739 -3600 +# Wed Nov 20 08:25:39 2019 +0100 +# Node ID 5396ffb26887cc0cd42b9f12cc6c8e3dfdaf194b +# Parent f5cf5d16deb68e65b5dd4e799d9e8e3098400d62 +[PATCH] 22 +From 41dd171b242b0cb550d12760da110db7e2c21daf Mon Sep 17 00:00:00 2001 +--- + nss/lib/freebl/gcm.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff -r f5cf5d16deb6 -r 5396ffb26887 lib/freebl/gcm.c +--- a/lib/freebl/gcm.c Wed Nov 20 08:23:35 2019 +0100 ++++ b/lib/freebl/gcm.c Wed Nov 20 08:25:39 2019 +0100 +@@ -532,8 +532,14 @@ + unsigned char tagKey[MAX_BLOCK_SIZE]; + PRBool ctr_context_init; + gcmIVContext gcm_iv; ++ unsigned long long gcm_iv_bytes; + }; + ++/* NIST SP-800-38D limits the use of GCM with a single IV to 2^39 - 256 ++ * bits which translates to 2^32 - 2 128bit blocks or 2^36 - 32 bytes ++ */ ++#define MAX_GCM_BYTES_PER_IV ((1ULL << 36) - 32) ++ + SECStatus gcm_InitCounter(GCMContext *gcm, const unsigned char *iv, + unsigned int ivLen, unsigned int tagBits, + const unsigned char *aad, unsigned int aadLen); +@@ -669,6 +675,8 @@ + goto loser; + } + ++ gcm->gcm_iv_bytes = MAX_GCM_BYTES_PER_IV; ++ + /* finally mix in the AAD data */ + rv = gcmHash_Reset(ghash, aad, aadLen); + if (rv != SECSuccess) { +@@ -766,6 +774,13 @@ + return SECFailure; + } + ++ /* bail out if this invocation requests processing more than what is ++ * considered to be a safe limit */ ++ if (gcm->gcm_iv_bytes < (unsigned long long)inlen) { ++ PORT_SetError(SEC_ERROR_INPUT_LEN); ++ return SECFailure; ++ } ++ + tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE; + if (UINT_MAX - inlen < tagBytes) { + PORT_SetError(SEC_ERROR_INPUT_LEN); +@@ -794,6 +809,7 @@ + *outlen = 0; + return SECFailure; + }; ++ gcm->gcm_iv_bytes -= inlen; + *outlen += len; + return SECSuccess; + } diff --git a/nss-fips-pairwise-consistency-check.patch b/nss-fips-pairwise-consistency-check.patch new file mode 100644 index 0000000..4fe24a8 --- /dev/null +++ b/nss-fips-pairwise-consistency-check.patch @@ -0,0 +1,34 @@ +# HG changeset patch +# User Hans Petter Jansson +# Date 1574138371 -3600 +# Tue Nov 19 05:39:31 2019 +0100 +# Node ID 557f9009507c9e70941dbe39965028049e1ef5a2 +# Parent 4ae6bed68a83c01f6d2ce7a37bdb0bdb0556416f +[PATCH 07/22] 15 +From 2a162c34b7aad7399f33069cd9930fd92714861c Mon Sep 17 00:00:00 2001 +--- + nss/lib/softoken/pkcs11c.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c +--- a/lib/softoken/pkcs11c.c ++++ b/lib/softoken/pkcs11c.c +@@ -4730,8 +4730,8 @@ + return crv; + } + +-#define PAIRWISE_DIGEST_LENGTH SHA1_LENGTH /* 160-bits */ +-#define PAIRWISE_MESSAGE_LENGTH 20 /* 160-bits */ ++#define PAIRWISE_DIGEST_LENGTH SHA224_LENGTH /* 224-bits */ ++#define PAIRWISE_MESSAGE_LENGTH 20 /* 160-bits */ + + /* + * FIPS 140-2 pairwise consistency check utilized to validate key pair. +@@ -5591,6 +5591,7 @@ + (PRUint32)crv); + sftk_LogAuditMessage(NSS_AUDIT_ERROR, NSS_AUDIT_SELF_TEST, msg); + } ++ sftk_fatalError = PR_TRUE; + } + } + diff --git a/nss-fips-rsa-keygen-strictness.patch b/nss-fips-rsa-keygen-strictness.patch new file mode 100644 index 0000000..220817b --- /dev/null +++ b/nss-fips-rsa-keygen-strictness.patch @@ -0,0 +1,242 @@ +# HG changeset patch +# User M. Sirringhaus +# Date 1584305670 -3600 +# Sun Mar 15 21:54:30 2020 +0100 +# Node ID 2f570c6952d8edfc1ad9061cd3830f202eec1960 +# Parent 557f9009507c9e70941dbe39965028049e1ef5a2 +commit 4b8c0eac6b092717157b4141c82b4d76ccdc91b3 +Author: Hans Petter Jansson + Patch 16: nss-fips-rsa-keygen-strictness.patch + +diff --git a/lib/freebl/mpi/mpprime.c b/lib/freebl/mpi/mpprime.c +--- a/lib/freebl/mpi/mpprime.c ++++ b/lib/freebl/mpi/mpprime.c +@@ -14,6 +14,8 @@ + #include + #include + ++#include "../fips.h" ++ + #define SMALL_TABLE 0 /* determines size of hard-wired prime table */ + + #define RANDOM() rand() +@@ -451,6 +453,25 @@ + } else + num_tests = 50; + ++ /* FIPS 186-4 mandates more M-R tests for probable primes generation - make ++ * sure the minimums are observed (see Appendix C, tables C.1 and C.2). ++ * For DSA this is handled in pqg_ParamGen() through the use of ++ * prime_testcount_p() and prime_testcount_q() respectively. ++ * For RSA this unfortunately seems to be the right place to prevent larger ++ * code changes. On the other hand, it seems to generally speed things up, ++ * since there are measurably less errors while calculating inverse modulo in ++ * rsa_build_from_primes(). ++ */ ++ if (FIPS_mode()) { ++ if (nBits >= 1536) ++ i = 4; ++ else ++ i = 5; ++ if (i > num_tests) ++ num_tests = i; ++ i = 0; ++ } ++ + if (strong) + --nBits; + MP_CHECKOK(mpl_set_bit(start, nBits - 1, 1)); +diff --git a/lib/freebl/rsa.c b/lib/freebl/rsa.c +--- a/lib/freebl/rsa.c ++++ b/lib/freebl/rsa.c +@@ -16,11 +16,13 @@ + #include "prinit.h" + #include "blapi.h" + #include "mpi.h" ++#include "mpi-priv.h" + #include "mpprime.h" + #include "mplogic.h" + #include "secmpi.h" + #include "secitem.h" + #include "blapii.h" ++#include "fips.h" + + /* + ** Number of times to attempt to generate a prime (p or q) from a random +@@ -143,11 +145,24 @@ + err = mp_invmod(d, &phi, e); + } else { + err = mp_invmod(e, &phi, d); +- } ++ /* FIPS 186-4 (B.3.1.3.a) places additional requirements on the ++ * private exponent d: ++ * 2^(n/2) < d < lcm(p-1, q-1) = phi ++ */ ++ if (FIPS_mode() && (MP_OKAY == err)) { ++ CHECK_MPI_OK( mp_2expt(&tmp, keySizeInBits / 2) ); ++ if ((mp_cmp(d, &tmp) <= 0) || (mp_cmp(d, &phi) >= 0)) { ++ /* new set of p, q is needed for another calculation of d */ ++ err = MP_UNDEF; ++ } ++ } ++ } + } else { + err = MP_OKAY; + } +- /* Verify that phi(n) and e have no common divisors */ ++ /* Verify that phi(n) and e have no common divisors ++ * This is also the coprimality constraint from FIPS 186-4 (B.3.1.2.a) ++ */ + if (err != MP_OKAY) { + if (err == MP_UNDEF) { + PORT_SetError(SEC_ERROR_NEED_RANDOM); +@@ -280,10 +295,12 @@ + mp_int q = { 0, 0, 0, NULL }; + mp_int e = { 0, 0, 0, NULL }; + mp_int d = { 0, 0, 0, NULL }; ++ mp_int u = { 0, 0, 0, NULL }; ++ mp_int v = { 0, 0, 0, NULL }; + int kiter; + int max_attempts; + mp_err err = MP_OKAY; +- SECStatus rv = SECSuccess; ++ SECStatus rv = SECFailure; + int prerr = 0; + RSAPrivateKey *key = NULL; + PLArenaPool *arena = NULL; +@@ -301,11 +318,40 @@ + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto cleanup; + } ++ ++ MP_DIGITS(&p) = 0; ++ MP_DIGITS(&q) = 0; ++ MP_DIGITS(&d) = 0; ++ MP_DIGITS(&u) = 0; ++ MP_DIGITS(&v) = 0; ++ CHECK_MPI_OK(mp_init(&p)); ++ CHECK_MPI_OK(mp_init(&q)); ++ CHECK_MPI_OK(mp_init(&d)); ++ CHECK_MPI_OK(mp_init(&u)); ++ CHECK_MPI_OK(mp_init(&v)); ++ + #ifndef NSS_FIPS_DISABLED +- /* Check that the exponent is not smaller than 65537 */ +- if (mp_cmp_d(&e, 0x10001) < 0) { +- PORT_SetError(SEC_ERROR_INVALID_ARGS); +- goto cleanup; ++ if (FIPS_mode()) { ++ /* Check that the exponent is not smaller than 65537 */ ++ if (mp_cmp_d(&e, 0x10001) < 0) { ++ PORT_SetError(SEC_ERROR_INVALID_ARGS); ++ goto cleanup; ++ } ++ ++ /* FIPS 186-4 requires 2^16 < e < 2^256 (B.3.1.1.b) */ ++ CHECK_MPI_OK( mp_2expt(&v, 256) ); ++ if (!(mp_cmp(&e, &v) < 0 )) { ++ err = MP_BADARG; ++ goto cleanup; ++ } ++ ++ /* FIPS 186-4 mandates keys to be either 2048, 3072 or 4096 bits long. ++ * We also allow a key length of 4096, since this is needed in order to ++ * pass the CAVS RSA SigGen test. */ ++ if (keySizeInBits < 2048) { ++ PORT_SetError(SEC_ERROR_INVALID_ARGS); ++ goto cleanup; ++ } + } + #endif + +@@ -323,12 +369,7 @@ + key->arena = arena; + /* length of primes p and q (in bytes) */ + primeLen = keySizeInBits / (2 * PR_BITS_PER_BYTE); +- MP_DIGITS(&p) = 0; +- MP_DIGITS(&q) = 0; +- MP_DIGITS(&d) = 0; +- CHECK_MPI_OK(mp_init(&p)); +- CHECK_MPI_OK(mp_init(&q)); +- CHECK_MPI_OK(mp_init(&d)); ++ + /* 3. Set the version number (PKCS1 v1.5 says it should be zero) */ + SECITEM_AllocItem(arena, &key->version, 1); + key->version.data[0] = 0; +@@ -339,13 +380,64 @@ + PORT_SetError(0); + CHECK_SEC_OK(generate_prime(&p, primeLen)); + CHECK_SEC_OK(generate_prime(&q, primeLen)); +- /* Assure p > q */ ++ /* Assure p >= q */ + /* NOTE: PKCS #1 does not require p > q, and NSS doesn't use any + * implementation optimization that requires p > q. We can remove + * this code in the future. + */ + if (mp_cmp(&p, &q) < 0) + mp_exch(&p, &q); ++ ++ /* FIPS 186-4 puts additional requirements on the primes (B.3.1.2.a-d) ++ * (n = key bit length): ++ * 1) both (p-1) and (q-1) are coprime to e (B.3.1.2.a), i.e.: ++ * gcd(p-1,e) = 1, gcd(q-1,e) = 1 ++ * this is ensured in rsa_build_from_primes(), where ++ * phi = lcm(p-1)(q-1) is tested for coprimality to e ++ * 2) magnitude constraint (B.3.1.2.b and B.3.1.2.c): ++ * both p and q are from open the interval ++ * I = ( sqrt(2) * 2^(n/2 - 1) , 2^(n/2 - 1) ) ++ * 3) minimum distance (B.3.1.2.d): abs(p-q) > 2 ^ (n/2 - 100) ++ */ ++ if (FIPS_mode()) { ++ /* 2 */ ++ /* in order not to constrain the selection too much, ++ * expand the inequality: ++ * x > 2^(1/2) * 2^(n/2 - 1) ++ * = 2^(1/2 + k) * 2^(n/2 - k - 1) ++ * = y(k) * r(k) ++ * for z(k) >= y(k) it clearly holds: ++ * x > z(k) * r(k) ++ * one suitable z(k) such that z(k)/y(k) - 1 = o(1) is ++ * ceil(y(k)) for big-enough k ++ * ceil(y(30))/y(30) - 1 < 10^-10, so lets use that ++ * 2^30.5 = 1518500249.98802484622388101120... ++ * the magic constant is thus z(30) = 1518500250 < 2^31 ++ * ++ * Additionally, since p >= q is required above, the ++ * condtitions can be shortened to: ++ * 1518500250 * 2^(n/2 - 31) = v < q ++ * p < u = 2^(n/2 - 1) ++ */ ++ CHECK_MPI_OK( mp_2expt(&u, keySizeInBits / 2 - 31) ); ++ CHECK_MPI_OK( mp_mul_d(&u, 1518500250, &v) ); ++ CHECK_MPI_OK( mp_2expt(&u, keySizeInBits / 2) ); ++ if ((mp_cmp(&q, &v) <= 0) || (mp_cmp(&p, &u) >= 0)) { ++ prerr = SEC_ERROR_NEED_RANDOM; /* retry with different values */ ++ kiter++; ++ continue; ++ } ++ /* 3 */ ++ CHECK_MPI_OK( mp_sub(&p, &q, &u) ); ++ CHECK_MPI_OK( mp_abs(&u, &u) ); ++ CHECK_MPI_OK( mp_2expt(&v, keySizeInBits / 2 - 100) ); ++ if (mp_cmp(&u, &v) < 0) { ++ prerr = SEC_ERROR_NEED_RANDOM; /* retry with different values */ ++ kiter++; ++ continue; ++ } ++ } ++ + /* Attempt to use these primes to generate a key */ + rv = rsa_build_from_primes(&p, &q, + &e, PR_FALSE, /* needPublicExponent=false */ +@@ -368,7 +460,9 @@ + mp_clear(&q); + mp_clear(&e); + mp_clear(&d); +- if (err) { ++ mp_clear(&u); ++ mp_clear(&v); ++ if (err != MP_OKAY) { + MP_TO_SEC_ERROR(err); + rv = SECFailure; + } diff --git a/nss-fips-tls-allow-md5-prf.patch b/nss-fips-tls-allow-md5-prf.patch new file mode 100644 index 0000000..ccad635 --- /dev/null +++ b/nss-fips-tls-allow-md5-prf.patch @@ -0,0 +1,266 @@ +# HG changeset patch +# User Hans Petter Jansson +# Date 1574240734 -3600 +# Wed Nov 20 10:05:34 2019 +0100 +# Node ID 0efca22bbafd7575b20461f255c46157c9321822 +# Parent 3a2cb65dc157344cdad19e8e16e9c33e36f82d96 +[PATCH] 30 +From ca3b695ac461eccf4ed97e1b3fe0a311c80a792f Mon Sep 17 00:00:00 2001 +--- + nss/lib/freebl/md5.c | 67 ++++++++++++++++++++++++++------------ + nss/lib/freebl/rawhash.c | 37 +++++++++++++++++++++ + nss/lib/freebl/tlsprfalg.c | 5 ++- + nss/lib/softoken/pkcs11c.c | 4 +-- + 4 files changed, 90 insertions(+), 23 deletions(-) + +diff --git a/lib/freebl/md5.c b/lib/freebl/md5.c +--- a/lib/freebl/md5.c ++++ b/lib/freebl/md5.c +@@ -217,13 +217,11 @@ + } + + MD5Context * +-MD5_NewContext(void) ++MD5_NewContext_NonFIPS(void) + { + /* no need to ZAlloc, MD5_Begin will init the context */ + MD5Context *cx; + +- IN_FIPS_RETURN(NULL); +- + cx = (MD5Context *)PORT_Alloc(sizeof(MD5Context)); + if (cx == NULL) { + PORT_SetError(PR_OUT_OF_MEMORY_ERROR); +@@ -232,6 +230,13 @@ + return cx; + } + ++MD5Context * ++MD5_NewContext(void) ++{ ++ IN_FIPS_RETURN(NULL); ++ return MD5_NewContext_NonFIPS(); ++} ++ + void + MD5_DestroyContext(MD5Context *cx, PRBool freeit) + { +@@ -243,10 +248,8 @@ + } + + void +-MD5_Begin(MD5Context *cx) ++MD5_Begin_NonFIPS(MD5Context *cx) + { +- IN_FIPS_RETURN(); +- + cx->lsbInput = 0; + cx->msbInput = 0; + /* memset(cx->inBuf, 0, sizeof(cx->inBuf)); */ +@@ -256,6 +259,13 @@ + cx->cv[3] = CV0_4; + } + ++void ++MD5_Begin(MD5Context *cx) ++{ ++ IN_FIPS_RETURN(); ++ MD5_Begin_NonFIPS(cx); ++} ++ + #define cls(i32, s) (tmp = i32, tmp << s | tmp >> (32 - s)) + + #if defined(SOLARIS) || defined(HPUX) +@@ -431,14 +441,12 @@ + } + + void +-MD5_Update(MD5Context *cx, const unsigned char *input, unsigned int inputLen) ++MD5_Update_NonFIPS(MD5Context *cx, const unsigned char *input, unsigned int inputLen) + { + PRUint32 bytesToConsume; + PRUint32 inBufIndex = cx->lsbInput & 63; + const PRUint32 *wBuf; + +- IN_FIPS_RETURN(); +- + /* Add the number of input bytes to the 64-bit input counter. */ + addto64(cx->msbInput, cx->lsbInput, inputLen); + if (inBufIndex) { +@@ -487,6 +495,13 @@ + memcpy(cx->inBuf, input, inputLen); + } + ++void ++MD5_Update(MD5Context *cx, const unsigned char *input, unsigned int inputLen) ++{ ++ IN_FIPS_RETURN(); ++ MD5_Update_NonFIPS(cx, input, inputLen); ++} ++ + static const unsigned char padbytes[] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +@@ -503,8 +518,8 @@ + }; + + void +-MD5_End(MD5Context *cx, unsigned char *digest, +- unsigned int *digestLen, unsigned int maxDigestLen) ++MD5_End_NonFIPS(MD5Context *cx, unsigned char *digest, ++ unsigned int *digestLen, unsigned int maxDigestLen) + { + #ifndef IS_LITTLE_ENDIAN + PRUint32 tmp; +@@ -512,8 +527,6 @@ + PRUint32 lowInput, highInput; + PRUint32 inBufIndex = cx->lsbInput & 63; + +- IN_FIPS_RETURN(); +- + if (maxDigestLen < MD5_HASH_LEN) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return; +@@ -525,10 +538,10 @@ + lowInput <<= 3; + + if (inBufIndex < MD5_END_BUFFER) { +- MD5_Update(cx, padbytes, MD5_END_BUFFER - inBufIndex); ++ MD5_Update_NonFIPS(cx, padbytes, MD5_END_BUFFER - inBufIndex); + } else { +- MD5_Update(cx, padbytes, +- MD5_END_BUFFER + MD5_BUFFER_SIZE - inBufIndex); ++ MD5_Update_NonFIPS(cx, padbytes, ++ MD5_END_BUFFER + MD5_BUFFER_SIZE - inBufIndex); + } + + /* Store the number of bytes input (before padding) in final 64 bits. */ +@@ -554,16 +567,22 @@ + } + + void +-MD5_EndRaw(MD5Context *cx, unsigned char *digest, +- unsigned int *digestLen, unsigned int maxDigestLen) ++MD5_End(MD5Context *cx, unsigned char *digest, ++ unsigned int *digestLen, unsigned int maxDigestLen) ++{ ++ IN_FIPS_RETURN(); ++ MD5_End_NonFIPS(cx, digest, digestLen, maxDigestLen); ++} ++ ++void ++MD5_EndRaw_NonFIPS(MD5Context *cx, unsigned char *digest, ++ unsigned int *digestLen, unsigned int maxDigestLen) + { + #ifndef IS_LITTLE_ENDIAN + PRUint32 tmp; + #endif + PRUint32 cv[4]; + +- IN_FIPS_RETURN(); +- + if (maxDigestLen < MD5_HASH_LEN) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return; +@@ -581,6 +600,14 @@ + *digestLen = MD5_HASH_LEN; + } + ++void ++MD5_EndRaw(MD5Context *cx, unsigned char *digest, ++ unsigned int *digestLen, unsigned int maxDigestLen) ++{ ++ IN_FIPS_RETURN(); ++ MD5_EndRaw_NonFIPS(cx, digest, digestLen, maxDigestLen); ++} ++ + unsigned int + MD5_FlattenSize(MD5Context *cx) + { +diff --git a/lib/freebl/rawhash.c b/lib/freebl/rawhash.c +--- a/lib/freebl/rawhash.c ++++ b/lib/freebl/rawhash.c +@@ -154,3 +154,40 @@ + } + return &SECRawHashObjects[hashType]; + } ++ ++/* Defined in md5.c */ ++ ++MD5Context *MD5_NewContext_NonFIPS(void); ++void MD5_Begin_NonFIPS(MD5Context *cx); ++void MD5_Update_NonFIPS(MD5Context *cx, const unsigned char *input, unsigned int inputLen); ++void MD5_End_NonFIPS(MD5Context *cx, unsigned char *digest, ++ unsigned int *digestLen, unsigned int maxDigestLen); ++void MD5_EndRaw_NonFIPS(MD5Context *cx, unsigned char *digest, ++ unsigned int *digestLen, unsigned int maxDigestLen); ++ ++static const SECHashObject SECRawHashObjectMD5NonFIPS = { ++ MD5_LENGTH, ++ (void *(*)(void))MD5_NewContext_NonFIPS, ++ (void *(*)(void *))null_hash_clone_context, ++ (void (*)(void *, PRBool))MD5_DestroyContext, ++ (void (*)(void *))MD5_Begin_NonFIPS, ++ (void (*)(void *, const unsigned char *, unsigned int))MD5_Update_NonFIPS, ++ (void (*)(void *, unsigned char *, unsigned int *, unsigned int))MD5_End_NonFIPS, ++ MD5_BLOCK_LENGTH, ++ HASH_AlgMD5, ++ (void (*)(void *, unsigned char *, unsigned int *, unsigned int))MD5_EndRaw_NonFIPS ++}; ++ ++const SECHashObject * ++HASH_GetRawHashObjectNonFIPS(HASH_HashType hashType) ++{ ++ if (hashType <= HASH_AlgNULL || hashType >= HASH_AlgTOTAL) { ++ PORT_SetError(SEC_ERROR_INVALID_ARGS); ++ return NULL; ++ } ++ ++ if (hashType == HASH_AlgMD5) ++ return &SECRawHashObjectMD5NonFIPS; ++ ++ return &SECRawHashObjects[hashType]; ++} +diff --git a/lib/freebl/tlsprfalg.c b/lib/freebl/tlsprfalg.c +--- a/lib/freebl/tlsprfalg.c ++++ b/lib/freebl/tlsprfalg.c +@@ -12,6 +12,9 @@ + #include "hasht.h" + #include "alghmac.h" + ++/* To get valid MD5 object in FIPS mode */ ++const SECHashObject *HASH_GetRawHashObjectNonFIPS(HASH_HashType hashType); ++ + #define PHASH_STATE_MAX_LEN HASH_LENGTH_MAX + + /* TLS P_hash function */ +@@ -27,7 +30,7 @@ + SECStatus status; + HMACContext *cx; + SECStatus rv = SECFailure; +- const SECHashObject *hashObj = HASH_GetRawHashObject(hashType); ++ const SECHashObject *hashObj = HASH_GetRawHashObjectNonFIPS(hashType); + + PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len)); + PORT_Assert((seed != NULL) && (seed->data != NULL)); +diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c +--- a/lib/softoken/pkcs11c.c ++++ b/lib/softoken/pkcs11c.c +@@ -6953,7 +6953,7 @@ + SFTKAttribute *att2 = NULL; + unsigned char *buf; + SHA1Context *sha; +- MD5Context *md5; ++ MD5Context *md5 = NULL; + MD2Context *md2; + CK_ULONG macSize; + CK_ULONG tmpKeySize; +@@ -7484,7 +7484,7 @@ + } + sftk_FreeAttribute(att2); + md5 = MD5_NewContext(); +- if (md5 == NULL) { ++ if (md5 == NULL && !isTLS) { + crv = CKR_HOST_MEMORY; + break; + } diff --git a/nss-fips-use-getrandom.patch b/nss-fips-use-getrandom.patch new file mode 100644 index 0000000..e947e58 --- /dev/null +++ b/nss-fips-use-getrandom.patch @@ -0,0 +1,123 @@ +# HG changeset patch +# User M. Sirringhaus +# Date 1574137588 -3600 +# Tue Nov 19 05:26:28 2019 +0100 +# Node ID 5e191a391c38967e49a1d005800713ccd1010b09 +# Parent 92da25f8ea7d41e938858872e2b6a2fb1aa53bb2 +commit c2a88344b616c75b1873fb163491d7362a4c3e5b +Author: Hans Petter Jansson + 11 + +diff --git a/coreconf/Linux.mk b/coreconf/Linux.mk +--- a/coreconf/Linux.mk ++++ b/coreconf/Linux.mk +@@ -184,6 +184,18 @@ + LDFLAGS += -Wl,-z,relro + endif + ++# ++# On Linux 3.17 or later, use getrandom() to obtain entropy where possible. ++# Set NSS_USE_GETRANDOM to 0 in the environment to override this. ++# ++ifneq ($(OS_TARGET),Android) ++ifeq (3.17,$(firstword $(sort 3.17 $(OS_RELEASE)))) ++ifneq ($(NSS_USE_GETRANDOM),0) ++ DEFINES += -DNSS_USE_GETRANDOM ++endif ++endif ++endif ++ + USE_SYSTEM_ZLIB = 1 + ZLIB_LIBS = -lz + +diff --git a/lib/freebl/unix_rand.c b/lib/freebl/unix_rand.c +--- a/lib/freebl/unix_rand.c ++++ b/lib/freebl/unix_rand.c +@@ -13,6 +13,10 @@ + #include + #include + #include ++#ifdef NSS_USE_GETRANDOM ++# include ++# include ++#endif + #include + #include "secrng.h" + #include "secerr.h" +@@ -21,6 +25,43 @@ + #include "prprf.h" + #include "prenv.h" + ++#ifdef NSS_USE_GETRANDOM ++# ifndef __NR_getrandom ++# if defined __x86_64__ ++# define __NR_getrandom 318 ++# elif defined(__i386__) ++# define __NR_getrandom 355 ++# elif defined(__arm__) ++# define __NR_getrandom 384 ++# elif defined(__aarch64__) ++# define __NR_getrandom 278 ++# elif defined(__ia64__) ++# define __NR_getrandom 1339 ++# elif defined(__m68k__) ++# define __NR_getrandom 352 ++# elif defined(__s390x__) ++# define __NR_getrandom 349 ++# elif defined(__powerpc__) ++# define __NR_getrandom 359 ++# elif defined _MIPS_SIM ++# if _MIPS_SIM == _MIPS_SIM_ABI32 ++# define __NR_getrandom 4353 ++# endif ++# if _MIPS_SIM == _MIPS_SIM_NABI32 ++# define __NR_getrandom 6317 ++# endif ++# if _MIPS_SIM == _MIPS_SIM_ABI64 ++# define __NR_getrandom 5313 ++# endif ++# else ++# warning "__NR_getrandom unknown for your architecture" ++# endif ++# endif ++# ifndef GRND_RANDOM ++# define GRND_RANDOM 0x02 ++# endif ++#endif ++ + size_t RNG_FileUpdate(const char *fileName, size_t limit); + + /* +@@ -862,6 +903,26 @@ + size_t + RNG_SystemRNG(void *dest, size_t maxLen) + { ++#ifdef NSS_USE_GETRANDOM ++ unsigned char *buf = dest; ++ size_t inBytes = 0; ++ int ret; ++ ++ do { ++ ret = syscall(__NR_getrandom, buf + inBytes, maxLen - inBytes, 0); ++ ++ if (0 < ret) ++ inBytes += ret; ++ } while ((0 < ret || EINTR == errno || ERESTART == errno) ++ && inBytes < maxLen); ++ ++ if (inBytes != maxLen) { ++ PORT_SetError(SEC_ERROR_NEED_RANDOM); /* system RNG failed */ ++ inBytes = 0; ++ } ++ ++ return inBytes; ++#else + FILE *file; + int fd; + int bytes; +@@ -895,4 +956,5 @@ + fileBytes = 0; + } + return fileBytes; ++#endif + } diff --git a/nss-fips-use-strong-random-pool.patch b/nss-fips-use-strong-random-pool.patch new file mode 100644 index 0000000..88be129 --- /dev/null +++ b/nss-fips-use-strong-random-pool.patch @@ -0,0 +1,51 @@ +# HG changeset patch +# User Hans Petter Jansson +# Date 1574240799 -3600 +# Wed Nov 20 10:06:39 2019 +0100 +# Node ID 4ddd7d49eeed4ea32850daf41a472ccb50dee45e +# Parent 0efca22bbafd7575b20461f255c46157c9321822 +[PATCH] 31 +From a7cbf64ba8ac07a4a1fdea91f39da56d86af03bf Mon Sep 17 00:00:00 2001 +--- + nss/lib/freebl/unix_rand.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/lib/freebl/unix_rand.c b/lib/freebl/unix_rand.c +--- a/lib/freebl/unix_rand.c ++++ b/lib/freebl/unix_rand.c +@@ -24,6 +24,7 @@ + #include "prthread.h" + #include "prprf.h" + #include "prenv.h" ++#include "fips.h" + + #ifdef NSS_USE_GETRANDOM + # ifndef __NR_getrandom +@@ -779,7 +780,7 @@ + } + + /* grab some data from system's PRNG before any other files. */ +- bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT); ++ bytes = RNG_FileUpdate(FIPS_mode() ? "/dev/random" : "/dev/urandom", SYSTEM_RNG_SEED_COUNT); + if (!bytes) { + PORT_SetError(SEC_ERROR_NEED_RANDOM); + } +@@ -909,7 +910,8 @@ + int ret; + + do { +- ret = syscall(__NR_getrandom, buf + inBytes, maxLen - inBytes, 0); ++ ret = syscall(__NR_getrandom, buf + inBytes, maxLen - inBytes, ++ FIPS_mode () ? GRND_RANDOM : 0); + + if (0 < ret) + inBytes += ret; +@@ -929,7 +931,7 @@ + size_t fileBytes = 0; + unsigned char *buffer = dest; + +- file = fopen("/dev/urandom", "r"); ++ file = fopen(FIPS_mode() ? "/dev/random" : "/dev/urandom", "r"); + if (file == NULL) { + PORT_SetError(SEC_ERROR_NEED_RANDOM); + return 0; diff --git a/nss-fips-zeroization.patch b/nss-fips-zeroization.patch new file mode 100644 index 0000000..05d8a46 --- /dev/null +++ b/nss-fips-zeroization.patch @@ -0,0 +1,209 @@ +# HG changeset patch +# User Hans Petter Jansson +# Date 1574240665 -3600 +# Wed Nov 20 10:04:25 2019 +0100 +# Node ID 3a2cb65dc157344cdad19e8e16e9c33e36f82d96 +# Parent 2d4483f4a1259f965f32ff4c65436e92aef83be7 +[PATCH 07/10] 29 +From 76da775313bd40a1353a9d2f6cc43ebe1a287574 Mon Sep 17 00:00:00 2001 +--- + nss/lib/freebl/aeskeywrap.c | 1 + + nss/lib/freebl/cts.c | 18 +++++++++------ + nss/lib/freebl/dh.c | 4 ++++ + nss/lib/freebl/ec.c | 2 +- + nss/lib/freebl/gcm.c | 45 +++++++++++++++++++++++++++++++++---- + 5 files changed, 58 insertions(+), 12 deletions(-) + +diff --git a/lib/freebl/aeskeywrap.c b/lib/freebl/aeskeywrap.c +--- a/lib/freebl/aeskeywrap.c ++++ b/lib/freebl/aeskeywrap.c +@@ -102,6 +102,7 @@ + { + if (cx) { + AES_DestroyContext(&cx->aescx, PR_FALSE); ++ memset(cx->iv, 0, sizeof (cx->iv)); + /* memset(cx, 0, sizeof *cx); */ + if (freeit) { + PORT_Free(cx->mem); +diff --git a/lib/freebl/cts.c b/lib/freebl/cts.c +--- a/lib/freebl/cts.c ++++ b/lib/freebl/cts.c +@@ -37,6 +37,7 @@ + void + CTS_DestroyContext(CTSContext *cts, PRBool freeit) + { ++ PORT_Memset(cts, 0, sizeof(CTSContext)); + if (freeit) { + PORT_Free(cts); + } +@@ -135,7 +136,7 @@ + PORT_Memset(lastBlock + inlen, 0, blocksize - inlen); + rv = (*cts->cipher)(cts->context, outbuf, &tmp, maxout, lastBlock, + blocksize, blocksize); +- PORT_Memset(lastBlock, 0, blocksize); ++ PORT_Memset(lastBlock, 0, MAX_BLOCK_SIZE); + if (rv == SECSuccess) { + *outlen = written + blocksize; + } else { +@@ -230,13 +231,15 @@ + rv = (*cts->cipher)(cts->context, outbuf, outlen, maxout, inbuf, + fullblocks, blocksize); + if (rv != SECSuccess) { +- return SECFailure; ++ rv = SECFailure; ++ goto cleanup; + } + *outlen = fullblocks; /* AES low level doesn't set outlen */ + inbuf += fullblocks; + inlen -= fullblocks; + if (inlen == 0) { +- return SECSuccess; ++ rv = SECSuccess; ++ goto cleanup; + } + outbuf += fullblocks; + +@@ -280,9 +283,9 @@ + rv = (*cts->cipher)(cts->context, Pn, &tmpLen, blocksize, lastBlock, + blocksize, blocksize); + if (rv != SECSuccess) { +- PORT_Memset(lastBlock, 0, blocksize); + PORT_Memset(saveout, 0, *outlen); +- return SECFailure; ++ rv = SECFailure; ++ goto cleanup; + } + /* make up for the out of order CBC decryption */ + XOR_BLOCK(Pn, Cn_2, blocksize); +@@ -297,7 +300,8 @@ + /* clear last block. At this point last block contains Pn xor Cn_1 xor + * Cn_2, both of with an attacker would know, so we need to clear this + * buffer out */ +- PORT_Memset(lastBlock, 0, blocksize); ++cleanup: ++ PORT_Memset(lastBlock, 0, MAX_BLOCK_SIZE); + /* Cn, Cn_1, and Cn_2 have encrypted data, so no need to clear them */ +- return SECSuccess; ++ return rv; + } +diff --git a/lib/freebl/dh.c b/lib/freebl/dh.c +--- a/lib/freebl/dh.c ++++ b/lib/freebl/dh.c +@@ -192,6 +192,10 @@ + rv = SECFailure; + } + if (rv) { ++ SECITEM_ZfreeItem(&key->prime, PR_FALSE); ++ SECITEM_ZfreeItem(&key->base, PR_FALSE); ++ SECITEM_ZfreeItem(&key->publicValue, PR_FALSE); ++ SECITEM_ZfreeItem(&key->privateValue, PR_FALSE); + *privKey = NULL; + PORT_FreeArena(arena, PR_TRUE); + } +diff --git a/lib/freebl/ec.c b/lib/freebl/ec.c +--- a/lib/freebl/ec.c ++++ b/lib/freebl/ec.c +@@ -958,7 +958,7 @@ + ECParams *ecParams = NULL; + SECItem pointC = { siBuffer, NULL, 0 }; + int slen; /* length in bytes of a half signature (r or s) */ +- int flen; /* length in bytes of the field size */ ++ int flen = 0; /* length in bytes of the field size */ + unsigned olen; /* length in bytes of the base point order */ + unsigned obits; /* length in bits of the base point order */ + +diff --git a/lib/freebl/gcm.c b/lib/freebl/gcm.c +--- a/lib/freebl/gcm.c ++++ b/lib/freebl/gcm.c +@@ -162,6 +162,9 @@ + + *r_high = (uint64_t)(r >> 64); + *r_low = (uint64_t)r; ++ ++ /* Zeroization */ ++ x1 = x2 = x3 = x4 = x5 = y1 = y2 = y3 = y4 = y5 = r = z = 0; + } + + SECStatus +@@ -200,6 +203,12 @@ + } + ghash->x_low = ci_low; + ghash->x_high = ci_high; ++ ++ /* Zeroization */ ++ ci_low = ci_high = z2_low = z2_high = z0_low = z0_high = z1a_low = z1a_high = 0; ++ z_low = z_high = 0; ++ i = 0; ++ + return SECSuccess; + } + #else +@@ -239,6 +248,10 @@ + z = z0 | z1 | z2 | z3; + *r_high = (uint32_t)(z >> 32); + *r_low = (uint32_t)z; ++ ++ /* Zeroization */ ++ x0 = x1 = x2 = x3 = y0 = y1 = y2 = y3 = 0; ++ z0 = z1 = z2 = z3 = z = 0; + } + + SECStatus +@@ -324,6 +337,20 @@ + ghash->x_high = z_high_h; + ghash->x_low = z_high_l; + } ++ ++ /* Zeroization */ ++ ci_low = ci_high = z_high_h = z_high_l = z_low_h = z_low_l = 0; ++ ++ ci_high_h = ci_high_l = ci_low_h = ci_low_l ++ = b_a_h = b_a_l = a_a_h = a_a_l = b_b_h = b_b_l ++ = a_b_h = a_b_l = b_c_h = b_c_l = a_c_h = a_c_l = c_c_h = c_c_l ++ = ci_highXlow_h = ci_highXlow_l = c_a_h = c_a_l = c_b_h = c_b_l ++ = h_high_h = h_high_l = h_low_h = h_low_l = h_highXlow_h = h_highXlow_l ++ = h_highX_xored ++ = 0; ++ ++ i = 0; ++ + return SECSuccess; + } + #endif /* HAVE_INT128_SUPPORT */ +@@ -859,11 +886,13 @@ + /* verify the block */ + rv = gcmHash_Update(gcm->ghash_context, inbuf, inlen); + if (rv != SECSuccess) { +- return SECFailure; ++ rv = SECFailure; ++ goto cleanup; + } + rv = gcm_GetTag(gcm, tag, &len, AES_BLOCK_SIZE); + if (rv != SECSuccess) { +- return SECFailure; ++ rv = SECFailure; ++ goto cleanup; + } + /* Don't decrypt if we can't authenticate the encrypted data! + * This assumes that if tagBits is not a multiple of 8, intag will +@@ -871,10 +900,18 @@ + if (NSS_SecureMemcmp(tag, intag, tagBytes) != 0) { + /* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */ + PORT_SetError(SEC_ERROR_BAD_DATA); +- PORT_Memset(tag, 0, sizeof(tag)); +- return SECFailure; ++ rv = SECFailure; ++ goto cleanup; + } ++cleanup: ++ tagBytes = 0; + PORT_Memset(tag, 0, sizeof(tag)); ++ intag = NULL; ++ len = 0; ++ if (rv != SECSuccess) { ++ return rv; ++ } ++ + /* finish the decryption */ + return CTR_Update(&gcm->ctr_context, outbuf, outlen, maxout, + inbuf, inlen, AES_BLOCK_SIZE); diff --git a/nss-fix-dh-pkcs-derive-inverted-logic.patch b/nss-fix-dh-pkcs-derive-inverted-logic.patch new file mode 100644 index 0000000..41b3390 --- /dev/null +++ b/nss-fix-dh-pkcs-derive-inverted-logic.patch @@ -0,0 +1,20 @@ +# HG changeset patch +# User M. Sirringhaus +# Date 1590586654 -7200 +# Wed May 27 15:37:34 2020 +0200 +# Node ID 582ed54a5cda147cd5996603d6066817edb687fa +# Parent ce99bba6375432c55a73c1367f619dfef7c7e9fc +imported patch nss-fix-dh-pkcs-derive-inverted-logic.patch + +diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c +--- a/lib/softoken/pkcs11c.c ++++ b/lib/softoken/pkcs11c.c +@@ -8316,7 +8316,7 @@ + if (crv == CKR_OK) { + rv = KEA_Verify(&dhPublic, &dhPrime, &dhSubPrime); + PORT_Free(dhSubPrime.data); +- if (rv != SECSuccess) { ++ if (rv == PR_FALSE) { + crv = CKR_ARGUMENTS_BAD; + PORT_Free(dhPrime.data); + PORT_Free(dhValue.data); diff --git a/nss-sqlitename.patch b/nss-sqlitename.patch index ef46df2..fc4d99e 100644 --- a/nss-sqlitename.patch +++ b/nss-sqlitename.patch @@ -1,32 +1,29 @@ # HG changeset patch -# Parent b96f2a8d5f606fd982a8fe3655c4b71e282c3976 +# User M. Sirringhaus +# Date 1590407652 -7200 +# Mon May 25 13:54:12 2020 +0200 +# Node ID b1d7045b31cf4090c0b78003c77a2eb6c8c57436 +# Parent e3d3ed5e142b172289d9d4a1c7fc63dfd4359410 Index: security/nss/lib/sqlite/manifest.mn =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/sqlite/manifest.mn,v retrieving revision 1.5 -diff --git a/lib/sqlite/manifest.mn b/lib/sqlite/manifest.mn ---- a/lib/sqlite/manifest.mn -+++ b/lib/sqlite/manifest.mn -@@ -1,19 +1,20 @@ - # - # 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 = ../.. +diff -r e3d3ed5e142b -r b1d7045b31cf lib/sqlite/manifest.mn +--- a/lib/sqlite/manifest.mn Mon Sep 18 11:24:00 2017 +0200 ++++ b/lib/sqlite/manifest.mn Mon May 25 13:54:12 2020 +0200 +@@ -6,11 +6,11 @@ MODULE = nss -LIBRARY_NAME = sqlite +LIBRARY_NAME = nsssqlite LIBRARY_VERSION = 3 - MAPFILE = $(OBJDIR)/sqlite.def +-MAPFILE = $(OBJDIR)/$(LIBRARY_NAME).def ++MAPFILE = $(OBJDIR)/sqlite.def + RES = $(NULL) +- +MAPFILE_SOURCE = sqlite.def DEFINES += -DSQLITE_THREADSAFE=1 - EXPORTS = \ - $(NULL) - PRIVATE_EXPORTS = \ - sqlite3.h \ - $(NULL) diff --git a/ppc-old-abi-v3.patch b/ppc-old-abi-v3.patch new file mode 100644 index 0000000..b71c12e --- /dev/null +++ b/ppc-old-abi-v3.patch @@ -0,0 +1,37 @@ +From a7a862bab5e4aae4615ddae3cbe230345f92ed0d Mon Sep 17 00:00:00 2001 +From: Lauri Kasanen +Date: Mon, 1 Jun 2020 12:11:45 +0300 +Subject: [PATCH v3] Bug 1642174 /usr/bin/ld: OBJS/Linux_SINGLE_SHLIB/sha512-p8.o: + ABI version 2 is not compatible with ABI version 1 output + +Don't try to build the SHA-2 accelerated asm on old-ABI ppc. + +Currently make only, I don't have enough gyp-fu to do that side. +However, the reporters of 1642174 and 1635625 both used make, not gyp. + +Signed-off-by: Lauri Kasanen +--- + lib/freebl/Makefile | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/lib/freebl/Makefile b/lib/freebl/Makefile +index 5f7384429..e0461c7d3 100644 +--- a/lib/freebl/Makefile ++++ b/lib/freebl/Makefile +@@ -267,9 +267,12 @@ ifeq ($(CPU_ARCH),arm) + endif + ifeq ($(CPU_ARCH),ppc) + EXTRA_SRCS += gcm-ppc.c +- ASFILES += sha512-p8.s + ifdef USE_64 + DEFINES += -DNSS_NO_INIT_SUPPORT ++ PPC_ABI := $(shell $(CC) -dM -E - < /dev/null | awk '$$2 == "_CALL_ELF" {print $$3}') ++ ifeq ($(PPC_ABI),2) ++ ASFILES += sha512-p8.s ++ endif + endif # USE_64 + endif # ppc + endif # Linux +-- +2.19.1 + diff --git a/system-nspr.patch b/system-nspr.patch index 060d937..7874b6d 100644 --- a/system-nspr.patch +++ b/system-nspr.patch @@ -1,25 +1,17 @@ -# HG changeset patch -# Parent bbf8e741ac966df6cf513ea042d1351eb279c122 - diff --git a/Makefile b/Makefile +index eb4ed1a..de9c13d 100644 --- a/Makefile +++ b/Makefile -@@ -42,17 +42,17 @@ include $(CORE_DEPTH)/coreconf/rules.mk +@@ -48,12 +48,10 @@ include $(CORE_DEPTH)/coreconf/rules.mk ####################################################################### + nss_build_all: +- $(MAKE) build_nspr + $(MAKE) all + $(MAKE) latest - - ####################################################################### - # (7) Execute "local" rules. (OPTIONAL). # - ####################################################################### - --nss_build_all: build_nspr all latest -+nss_build_all: all latest - - nss_clean_all: clobber_nspr clobber + nss_clean_all: +- $(MAKE) clobber_nspr + $(MAKE) clobber NSPR_CONFIG_STATUS = $(CORE_DEPTH)/../nspr/$(OBJDIR_NAME)/config.status - NSPR_CONFIGURE = $(CORE_DEPTH)/../nspr/configure - - # - # Translate coreconf build options to NSPR configure options.