Hello community, here is the log from the commit of package mozilla-nss for openSUSE:Leap:15.2 checked in at 2020-05-26 18:32:24 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Leap:15.2/mozilla-nss (Old) and /work/SRC/openSUSE:Leap:15.2/.mozilla-nss.new.2738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "mozilla-nss" Tue May 26 18:32:24 2020 rev:49 rq:808145 version:3.47.1 Changes: -------- --- /work/SRC/openSUSE:Leap:15.2/mozilla-nss/mozilla-nss.changes 2020-01-15 15:31:06.510767232 +0100 +++ /work/SRC/openSUSE:Leap:15.2/.mozilla-nss.new.2738/mozilla-nss.changes 2020-05-26 18:32:29.921591301 +0200 @@ -1,0 +2,91 @@ +Tue May 19 02:15:54 UTC 2020 - Hans Petter Jansson <[email protected]> + +- nss-fips-aes-keywrap-post.patch: Add AES Keywrap POST. +- nss-fips-constructor-self-tests.patch: Accept EACCES in lieu + of ENOENT when trying to access /proc/sys/crypto/fips_enabled + (bsc#1170908). + +------------------------------------------------------------------- +Sun Apr 26 03:42:23 UTC 2020 - Hans Petter Jansson <[email protected]> + +- nss-fips-constructor-self-tests.patch: Add Softoken POSTs for + new DSA and ECDSA hash-and-sign update functinos. + +------------------------------------------------------------------- +Fri Apr 24 01:39:03 UTC 2020 - Hans Petter Jansson <[email protected]> + +- nss-fips-combined-hash-sign-dsa-ecdsa.patch: Add pairwise + consistency check for CKM_SHA224_RSA_PKCS. Remove ditto checks + for CKM_RSA_PKCS, CKM_DSA and CKM_ECDSA, since these are served + by the new CKM_SHA224_RSA_PKCS, CKM_DSA_SHA224, CKM_ECDSA_SHA224 + checks. + +- nss-fips-constructor-self-tests.patch: Replace bad attempt at + unconditional nssdbm checksumming with a dlopen(), so it can be + located consistently and perform its own self-tests. + +------------------------------------------------------------------- +Tue Apr 21 13:27:47 UTC 2020 - Hans Petter Jansson <[email protected]> + +- Add nss-fix-dh-pkcs-derive-inverted-logic.patch. This fixes an + instance of inverted logic due to a boolean being mistaken for + a SECStatus, which caused key derivation to fail when the caller + provided a valid subprime. + +------------------------------------------------------------------- +Fri Apr 17 00:59:27 UTC 2020 - Hans Petter Jansson <[email protected]> + +- Add nss-fips-combined-hash-sign-dsa-ecdsa.patch. This implements + API mechanisms for performing DSA and ECDSA hash-and-sign + in a single call, which will be required in future FIPS cycles. + +------------------------------------------------------------------- +Wed Apr 15 23:54:45 UTC 2020 - Hans Petter Jansson <[email protected]> + +- nss-fips-constructor-self-tests.patch: Always perform nssdbm + checksumming on softoken load, even if nssdbm itself is not + loaded. + +------------------------------------------------------------------- +Mon Apr 6 17:47:25 UTC 2020 - Hans Petter Jansson <[email protected]> + +- nss-fips-detect-fips-mode-fixes.patch: Use secure_getenv() to + avoid PR_GetEnvSecure() being called when NSPR is unavailable, + resulting in an abort (bsc#1168669). + +------------------------------------------------------------------- +Wed Mar 18 14:33:42 UTC 2020 - Hans Petter Jansson <[email protected]> + +- Added patches related to FIPS certification: + * nss-fips-use-getrandom.patch: Use getrandom() to obtain entropy + where possible. + * nss-fips-dsa-kat.patch: Make DSA KAT FIPS compliant. + * nss-fips-pairwise-consistency-check.patch: Use FIPS compliant + hash when validating keypair. + * nss-fips-rsa-keygen-strictness.patch: Enforce FIPS requirements + on RSA key generation. + * nss-fips-cavs-keywrap.patch, + nss-fips-cavs-kas-ffc.patch, + nss-fips-cavs-kas-ecc.patch, + nss-fips-cavs-general.patch, + nss-fips-cavs-dsa-fixes.patch, + nss-fips-cavs-rsa-fixes.patch: Miscellaneous fixes to CAVS + tests. + * nss-fips-gcm-ctr.patch: Enforce FIPS limits on how much data + can be processed without rekeying. + * nss-fips-constructor-self-tests.patch: Run self tests on + library initialization in FIPS mode. + * nss-fips-approved-crypto-non-ec.patch: Disable non-compliant + algorithms in FIPS mode (hashes and the SEED cipher). + * nss-fips-zeroization.patch: Clear various temporary variables + after use. + * nss-fips-tls-allow-md5-prf.patch: Allow MD5 to be used in TLS + PRF. + * nss-fips-use-strong-random-pool.patch: Preferentially gather + entropy from /dev/random over /dev/urandom. + * nss-fips-detect-fips-mode-fixes.patch: Allow enabling FIPS mode + consistently with NSS_FIPS environment variable. + * nss-unit-test-fixes.patch: Fix argument parsing bug in + lowhashtest. + +------------------------------------------------------------------- New: ---- 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 nss-unit-test-fixes.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ mozilla-nss.spec ++++++ --- /var/tmp/diff_new_pack.hPB46Y/_old 2020-05-26 18:32:32.117596098 +0200 +++ /var/tmp/diff_new_pack.hPB46Y/_new 2020-05-26 18:32:32.121596106 +0200 @@ -49,6 +49,28 @@ Patch5: malloc.patch Patch6: bmo-1400603.patch Patch7: nss-sqlitename.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 +Patch33: nss-unit-test-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 + BuildRequires: gcc-c++ BuildRequires: pkgconfig BuildRequires: pkgconfig(nspr) >= %{NSPR_min_version} @@ -179,6 +201,31 @@ %endif %patch6 -p1 %patch7 -p1 +cd .. + +# 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 +%patch33 -p1 +%patch34 -p1 +%patch35 -p1 +%patch36 -p1 + # additional CA certificates #cd security/nss/lib/ckfw/builtins #cat %{SOURCE2} >> certdata.txt @@ -234,7 +281,7 @@ # copy headers cp -rL ../public/nss/*.h %{buildroot}%{_includedir}/nss3 # copy some freebl include files we also want -for file in blapi.h alghmac.h +for file in blapi.h alghmac.h cmac.h do cp -L ../private/nss/$file %{buildroot}/%{_includedir}/nss3 done ++++++ nss-fips-aes-keywrap-post.patch ++++++ commit e78f5a6a2124ce88002796d6aaefc6232f132526 Author: Hans Petter Jansson <[email protected]> Date: Tue May 19 04:14:20 2020 +0200 AES Keywrap POST. diff --git a/nss/lib/freebl/fipsfreebl.c b/nss/lib/freebl/fipsfreebl.c index 407a2db..4dc9f47 100644 --- a/nss/lib/freebl/fipsfreebl.c +++ b/nss/lib/freebl/fipsfreebl.c @@ -110,6 +110,9 @@ BOOL WINAPI DllMain( #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 @@ freebl_fips_AES_PowerUpSelfTest(int aes_key_size) 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 @@ freebl_fips_AES_PowerUpSelfTest(int aes_key_size) 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 @@ freebl_fips_AES_PowerUpSelfTest(int aes_key_size) 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_GCM_PARAMS gcmParams; @@ -554,6 +583,52 @@ freebl_fips_AES_PowerUpSelfTest(int aes_key_size) 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); } ++++++ nss-fips-approved-crypto-non-ec.patch ++++++ diff --git a/nss/lib/freebl/alg2268.c b/nss/lib/freebl/alg2268.c index 54c6f4d..8200bc9 100644 --- a/nss/lib/freebl/alg2268.c +++ b/nss/lib/freebl/alg2268.c @@ -16,6 +16,8 @@ #include <stddef.h> /* for ptrdiff_t */ #endif +#include "fips.h" + /* ** RC2 symmetric block cypher */ @@ -119,6 +121,7 @@ static const PRUint8 S[256] = { RC2Context * RC2_AllocateContext(void) { + IN_FIPS_RETURN(NULL); return PORT_ZNew(RC2Context); } SECStatus @@ -133,6 +136,8 @@ RC2_InitContext(RC2Context *cx, const unsigned char *key, unsigned int len, #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 @@ RC2Context * 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 @@ RC2_Encrypt(RC2Context *cx, unsigned char *output, 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 @@ RC2_Decrypt(RC2Context *cx, unsigned char *output, 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/nss/lib/freebl/arcfour.c b/nss/lib/freebl/arcfour.c index e37b458..5d4a8b2 100644 --- a/nss/lib/freebl/arcfour.c +++ b/nss/lib/freebl/arcfour.c @@ -13,6 +13,7 @@ #include "prtypes.h" #include "blapi.h" +#include "fips.h" /* Architecture-dependent defines */ @@ -108,6 +109,7 @@ static const Stype Kinit[256] = { RC4Context * RC4_AllocateContext(void) { + IN_FIPS_RETURN(NULL); return PORT_ZNew(RC4Context); } @@ -121,6 +123,8 @@ RC4_InitContext(RC4Context *cx, const unsigned char *key, unsigned int len, 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 @@ RC4_InitContext(RC4Context *cx, const unsigned char *key, unsigned int len, 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 @@ RC4_CreateContext(const unsigned char *key, int len) void RC4_DestroyContext(RC4Context *cx, PRBool freeit) { + IN_FIPS_RETURN(); if (freeit) PORT_ZFree(cx, sizeof(*cx)); } @@ -548,6 +557,8 @@ RC4_Encrypt(RC4Context *cx, unsigned char *output, 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 @@ RC4_Decrypt(RC4Context *cx, unsigned char *output, 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/nss/lib/freebl/fips.h b/nss/lib/freebl/fips.h index a4ac7a9..d5f4a0b 100644 --- a/nss/lib/freebl/fips.h +++ b/nss/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/nss/lib/freebl/md2.c b/nss/lib/freebl/md2.c index cb3d3d8..6b1bea5 100644 --- a/nss/lib/freebl/md2.c +++ b/nss/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 @@ SECStatus 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 @@ MD2_Hash(unsigned char *dest, const char *src) 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 @@ MD2_DestroyContext(MD2Context *cx, PRBool freeit) void MD2_Begin(MD2Context *cx) { + IN_FIPS_RETURN(); + memset(cx, 0, sizeof(*cx)); cx->unusedBuffer = MD2_BUFSIZE; } @@ -196,6 +208,8 @@ MD2_Update(MD2Context *cx, const unsigned char *input, unsigned int inputLen) { 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 @@ MD2_End(MD2Context *cx, unsigned char *digest, 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/nss/lib/freebl/md5.c b/nss/lib/freebl/md5.c index bdd36a6..b3a796b 100644 --- a/nss/lib/freebl/md5.c +++ b/nss/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 @@ struct MD5ContextStr { 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 @@ MD5_HashBuf(unsigned char *dest, const unsigned char *src, PRUint32 src_length) 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 @@ MD5Context * 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 @@ MD5_NewContext(void) 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 @@ MD5_DestroyContext(MD5Context *cx, PRBool freeit) 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 @@ MD5_Update(MD5Context *cx, const unsigned char *input, unsigned int inputLen) 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 @@ MD5_End(MD5Context *cx, unsigned char *digest, 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 @@ MD5_EndRaw(MD5Context *cx, unsigned char *digest, #endif PRUint32 cv[4]; + IN_FIPS_RETURN(); + if (maxDigestLen < MD5_HASH_LEN) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return; diff --git a/nss/lib/freebl/nsslowhash.c b/nss/lib/freebl/nsslowhash.c index 22f9781..69a2c1a 100644 --- a/nss/lib/freebl/nsslowhash.c +++ b/nss/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 @@ NSSLOWHASH_NewContext(NSSLOWInitContext *initContext, { 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/nss/lib/freebl/rawhash.c b/nss/lib/freebl/rawhash.c index 551727b..d0e8ee8 100644 --- a/nss/lib/freebl/rawhash.c +++ b/nss/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 SECRawHashObjects[] = { 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/nss/lib/freebl/seed.c b/nss/lib/freebl/seed.c index 377bdeb..95a76b8 100644 --- a/nss/lib/freebl/seed.c +++ b/nss/lib/freebl/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_set_key(const unsigned char rawkey[SEED_KEY_LENGTH], 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_encrypt(const unsigned char s[SEED_BLOCK_SIZE], 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_decrypt(const unsigned char s[SEED_BLOCK_SIZE], seed_word L0, L1, R0, R1; seed_word t0, t1; + IN_FIPS_RETURN(); + char2word(s, L0); char2word(s + 4, L1); char2word(s + 8, R0); @@ -418,6 +426,8 @@ SEED_ecb_encrypt(const unsigned char *in, unsigned char *out, const SEED_KEY_SCHEDULE *ks, int enc) { + IN_FIPS_RETURN(); + if (enc) { SEED_encrypt(in, out, ks); } else { @@ -434,6 +444,8 @@ SEED_cbc_encrypt(const unsigned char *in, unsigned char *out, 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) { @@ -517,6 +529,7 @@ SEED_cbc_encrypt(const unsigned char *in, unsigned char *out, SEEDContext * SEED_AllocateContext(void) { + IN_FIPS_RETURN(NULL); return PORT_ZNew(SEEDContext); } @@ -525,6 +538,8 @@ SEED_InitContext(SEEDContext *cx, const unsigned char *key, 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; @@ -556,10 +571,14 @@ SEEDContext * 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; @@ -584,6 +603,8 @@ SEED_Encrypt(SEEDContext *cx, unsigned char *out, unsigned int *outLen, unsigned int maxOutLen, const unsigned char *in, unsigned int inLen) { + IN_FIPS_RETURN(SECFailure); + if (!cx) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; @@ -624,6 +645,8 @@ SEED_Decrypt(SEEDContext *cx, unsigned char *out, unsigned int *outLen, 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/nss/lib/softoken/pkcs11c.c b/nss/lib/softoken/pkcs11c.c index 4b68f7a..bf47acc 100644 --- a/nss/lib/softoken/pkcs11c.c +++ b/nss/lib/softoken/pkcs11c.c @@ -6997,7 +6997,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession, } else { /* now allocate the hash contexts */ md5 = MD5_NewContext(); - if (md5 == NULL) { + if (md5 == NULL && !isTLS) { crv = CKR_HOST_MEMORY; break; } ++++++ nss-fips-cavs-dsa-fixes.patch ++++++ >From ef2620b770082c77dbbbccae2e773157897b005d Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson <[email protected]> Date: Wed, 20 Nov 2019 09:07:44 +0100 Subject: [PATCH] 24 --- nss/cmd/fipstest/fipstest.c | 112 ++++++++++++++++++++++++++++++++---- 1 file changed, 101 insertions(+), 11 deletions(-) diff --git a/nss/cmd/fipstest/fipstest.c b/nss/cmd/fipstest/fipstest.c index 17aafae..1a1465b 100644 --- a/nss/cmd/fipstest/fipstest.c +++ b/nss/cmd/fipstest/fipstest.c @@ -5576,7 +5576,7 @@ loser: 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 @@ dsa_pqggen_test(char *reqfn) 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 @@ dsa_pqggen_test(char *reqfn) 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 @@ dsa_pqggen_test(char *reqfn) /* [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) { + } 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 @@ dsa_pqggen_test(char *reqfn) 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 @@ dsa_pqggen_test(char *reqfn) 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 @@ dsa_pqggen_test(char *reqfn) 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 @@ dsa_pqggen_test(char *reqfn) } 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 @@ dsa_pqggen_test(char *reqfn) 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); } -- 2.21.0 ++++++ nss-fips-cavs-general.patch ++++++ diff --git a/nss/cmd/fipstest/fipstest.c b/nss/cmd/fipstest/fipstest.c index 9bdd21c..17aafae 100644 --- a/nss/cmd/fipstest/fipstest.c +++ b/nss/cmd/fipstest/fipstest.c @@ -5,6 +5,7 @@ #include <stdio.h> #include <stdlib.h> #include <ctype.h> +#include <dlfcn.h> #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 @@ EC_CopyParams(PLArenaPool *arena, ECParams *dstParams, #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 @@ from_hex_str(unsigned char *buf, unsigned int len, const char *str) 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, @@ -8409,41 +8473,6 @@ out: } } -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) { @@ -8866,12 +8895,34 @@ out: 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/nss/lib/freebl/freebl.def b/nss/lib/freebl/freebl.def index 164c843..a541124 100644 --- a/nss/lib/freebl/freebl.def +++ b/nss/lib/freebl/freebl.def @@ -21,6 +21,7 @@ LIBRARY freebl3 ;- EXPORTS ;- FREEBL_GetVector; +FREEBL_Test_PQG_ParamGenV2; ;+ local: ;+ *; ;+}; diff --git a/nss/lib/freebl/freebl_hash.def b/nss/lib/freebl/freebl_hash.def index 9fd2736..d44fd48 100644 --- a/nss/lib/freebl/freebl_hash.def +++ b/nss/lib/freebl/freebl_hash.def @@ -21,6 +21,7 @@ LIBRARY freebl3 ;- EXPORTS ;- FREEBL_GetVector; +FREEBL_Test_PQG_ParamGenV2; ;+ local: ;+ *; ;+}; diff --git a/nss/lib/freebl/freebl_hash_vector.def b/nss/lib/freebl/freebl_hash_vector.def index 9d7d07d..0e87a7b 100644 --- a/nss/lib/freebl/freebl_hash_vector.def +++ b/nss/lib/freebl/freebl_hash_vector.def @@ -21,6 +21,7 @@ LIBRARY freebl3 ;- EXPORTS ;- FREEBL_GetVector; +FREEBL_Test_PQG_ParamGenV2; ;+ local: ;+ *; ;+}; diff --git a/nss/lib/freebl/pqg.c b/nss/lib/freebl/pqg.c index 626b2fb..9e1c6ce 100644 --- a/nss/lib/freebl/pqg.c +++ b/nss/lib/freebl/pqg.c @@ -1231,7 +1231,8 @@ cleanup: **/ 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 @@ pqg_ParamGen(unsigned int L, unsigned int N, pqgGenType type, 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 @@ pqg_ParamGen(unsigned int L, unsigned int N, pqgGenType type, /* 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 @@ pqg_ParamGen(unsigned int L, unsigned int N, pqgGenType type, /* 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 @@ generate_G: 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 @@ PQG_ParamGen(unsigned int j, PQGParams **pParams, PQGVerify **pVfy) 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 @@ PQG_ParamGenSeedLen(unsigned int j, unsigned int seedBytes, } 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 @@ PQG_ParamGenV2(unsigned int L, unsigned int N, unsigned int seedBytes, /* 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); } /* ++++++ nss-fips-cavs-kas-ecc.patch ++++++ >From 4c27df62aa425745620f45710465b0264acacbb0 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson <[email protected]> Date: Wed, 20 Nov 2019 08:23:35 +0100 Subject: [PATCH] 21 --- nss/cmd/fipstest/fipstest.c | 304 ++++++++++++++++++++++++++++++++++++ nss/cmd/fipstest/kas.sh | 22 +++ 2 files changed, 326 insertions(+) diff --git a/nss/cmd/fipstest/fipstest.c b/nss/cmd/fipstest/fipstest.c index eba22fa..9bdd21c 100644 --- a/nss/cmd/fipstest/fipstest.c +++ b/nss/cmd/fipstest/fipstest.c @@ -8571,6 +8571,301 @@ out: } } +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) { @@ -8764,6 +9059,15 @@ main(int argc, char **argv) } 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/nss/cmd/fipstest/kas.sh b/nss/cmd/fipstest/kas.sh index 148d7c9..dc1627d 100644 --- a/nss/cmd/fipstest/kas.sh +++ b/nss/cmd/fipstest/kas.sh @@ -27,6 +27,16 @@ KASValidityTest_FFCEphem_NOKC_ZZOnly_init.req 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 @@ for request in $kas_requests_ffc_validity; do 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 -- 2.21.0 ++++++ nss-fips-cavs-kas-ffc.patch ++++++ >From ac98082c3bc0c9f85213078b730980483062f25c Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson <[email protected]> Date: Wed, 20 Nov 2019 08:18:17 +0100 Subject: [PATCH] 20 --- 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/nss/cmd/fipstest/fipstest.c b/nss/cmd/fipstest/fipstest.c index 6f495c9..eba22fa 100644 --- a/nss/cmd/fipstest/fipstest.c +++ b/nss/cmd/fipstest/fipstest.c @@ -2258,6 +2258,29 @@ fips_hashBuf(HASH_HashType type, unsigned char *hashBuf, 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) { @@ -8386,6 +8409,168 @@ out: } } +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) { @@ -8570,6 +8755,15 @@ main(int argc, char **argv) /* 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/nss/cmd/fipstest/kas.sh b/nss/cmd/fipstest/kas.sh new file mode 100644 index 0000000..148d7c9 --- /dev/null +++ b/nss/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 -- 2.21.0 ++++++ nss-fips-cavs-keywrap.patch ++++++ >From f4cbaf95fcf2519029bb3c4407b2f15aa27c94c1 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson <[email protected]> Date: Wed, 20 Nov 2019 08:13:43 +0100 Subject: [PATCH 1/2] 19 --- 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 --git a/nss/cmd/fipstest/fipstest.c b/nss/cmd/fipstest/fipstest.c index 1a8008d..6f495c9 100644 --- a/nss/cmd/fipstest/fipstest.c +++ b/nss/cmd/fipstest/fipstest.c @@ -8231,6 +8231,161 @@ loser: fclose(ikereq); } +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) { @@ -8410,6 +8565,11 @@ main(int argc, char **argv) ikev1_psk(argv[2]); } else if (strcmp(argv[1], "ikev2") == 0) { ikev2(argv[2]); + } else if (strcmp(argv[1], "keywrap") == 0) { + /***************/ + /* AES Keywrap */ + /***************/ + keywrap(argv[2]); } return 0; } diff --git a/nss/cmd/fipstest/keywrap.sh b/nss/cmd/fipstest/keywrap.sh new file mode 100644 index 0000000..a04374a --- /dev/null +++ b/nss/cmd/fipstest/keywrap.sh @@ -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 -- 2.21.0 ++++++ nss-fips-cavs-rsa-fixes.patch ++++++ >From 9b4636ad75add2ac09ce1844b3071785d563c275 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson <[email protected]> Date: Wed, 20 Nov 2019 09:08:17 +0100 Subject: [PATCH] 25 --- nss/cmd/fipstest/fipstest.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nss/cmd/fipstest/fipstest.c b/nss/cmd/fipstest/fipstest.c index 1a1465b..c14f532 100644 --- a/nss/cmd/fipstest/fipstest.c +++ b/nss/cmd/fipstest/fipstest.c @@ -6536,7 +6536,7 @@ rsa_siggen_test(char *reqfn) /* 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, @@ -9015,6 +9015,7 @@ main(int argc, char **argv) init_functions(); RNG_RNGInit(); SECOID_Init(); + BL_Init(); /*************/ /* TDEA */ -- 2.21.0 ++++++ nss-fips-combined-hash-sign-dsa-ecdsa.patch ++++++ ++++ 624 lines (skipped) ++++++ nss-fips-constructor-self-tests.patch ++++++ ++++ 1475 lines (skipped) ++++++ nss-fips-detect-fips-mode-fixes.patch ++++++ commit facacdb9078693d7a4219e84f73ea7b8f977ddc2 Author: Hans Petter Jansson <[email protected]> Date: Sun Mar 15 21:54:31 2020 +0100 Patch 32: nss-fips-detect-fips-mode-fixes.patch diff --git a/nss/lib/freebl/nsslowhash.c b/nss/lib/freebl/nsslowhash.c index 69a2c1a..026f4ca 100644 --- a/nss/lib/freebl/nsslowhash.c +++ b/nss/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 <stdlib.h> + #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 @@ struct NSSLOWHASHContextStr { }; #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 @@ nsslow_GetFIPSEnabled(void) #endif /* LINUX */ return 1; } + #endif /* NSS_FIPS_DISABLED */ static NSSLOWInitContext dummyContext = { 0 }; @@ -60,7 +83,7 @@ NSSLOW_Init(void) #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/nss/lib/sysinit/nsssysinit.c b/nss/lib/sysinit/nsssysinit.c index bd0fac2..acfcd19 100644 --- a/nss/lib/sysinit/nsssysinit.c +++ b/nss/lib/sysinit/nsssysinit.c @@ -175,16 +175,16 @@ getFIPSMode(void) 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; } ++++++ nss-fips-dsa-kat.patch ++++++ >From b88701933a284ba8640df66b954c04d36ee592c9 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson <[email protected]> Date: Sun, 17 Sep 2017 01:47:57 +0200 Subject: [PATCH 2/6] Make DSA KAT FIPS compliant (1024 -> 2048 bit key). --- nss/lib/freebl/dsa.c | 2 +- nss/lib/freebl/fipsfreebl.c | 143 +++++++++++++++++++++++++++----------------- 2 files changed, 90 insertions(+), 55 deletions(-) diff --git a/nss/lib/freebl/dsa.c b/nss/lib/freebl/dsa.c index 9324d30..26daadf 100644 --- a/nss/lib/freebl/dsa.c +++ b/nss/lib/freebl/dsa.c @@ -493,7 +493,7 @@ DSA_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest) 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/nss/lib/freebl/fipsfreebl.c b/nss/lib/freebl/fipsfreebl.c index b3ae686..804589d 100644 --- a/nss/lib/freebl/fipsfreebl.c +++ b/nss/lib/freebl/fipsfreebl.c @@ -123,11 +123,11 @@ BOOL WINAPI DllMain( /* 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 */ @@ -1280,70 +1280,105 @@ freebl_fips_ECDSA_PowerUpSelfTest() 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. */ @@ -1385,7 +1420,7 @@ freebl_fips_DSA_PowerUpSelfTest(void) 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, -- 2.12.0 ++++++ nss-fips-gcm-ctr.patch ++++++ >From 41dd171b242b0cb550d12760da110db7e2c21daf Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson <[email protected]> Date: Wed, 20 Nov 2019 08:25:39 +0100 Subject: [PATCH] 22 --- nss/lib/freebl/gcm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/nss/lib/freebl/gcm.c b/nss/lib/freebl/gcm.c index f1e16da..0f42525 100644 --- a/nss/lib/freebl/gcm.c +++ b/nss/lib/freebl/gcm.c @@ -500,9 +500,15 @@ struct GCMContextStr { gcmHashContext *ghash_context; CTRContext ctr_context; unsigned long tagBits; + unsigned long long gcm_iv_bytes; unsigned char tagKey[MAX_BLOCK_SIZE]; }; +/* 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) + GCMContext * GCM_CreateContext(void *context, freeblCipherFunc cipher, const unsigned char *params) @@ -576,6 +582,8 @@ GCM_CreateContext(void *context, freeblCipherFunc cipher, goto loser; } + gcm->gcm_iv_bytes = MAX_GCM_BYTES_PER_IV; + /* finally mix in the AAD data */ rv = gcmHash_Reset(ghash, gcmParams->pAAD, gcmParams->ulAADLen); if (rv != SECSuccess) { @@ -672,6 +680,13 @@ GCM_EncryptUpdate(GCMContext *gcm, unsigned char *outbuf, 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); @@ -700,6 +715,7 @@ GCM_EncryptUpdate(GCMContext *gcm, unsigned char *outbuf, *outlen = 0; return SECFailure; }; + gcm->gcm_iv_bytes -= inlen; *outlen += len; return SECSuccess; } -- 2.21.0 ++++++ nss-fips-pairwise-consistency-check.patch ++++++ >From 2a162c34b7aad7399f33069cd9930fd92714861c Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson <[email protected]> Date: Tue, 19 Nov 2019 05:39:31 +0100 Subject: [PATCH 07/22] 15 --- nss/lib/softoken/pkcs11c.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nss/lib/softoken/pkcs11c.c b/nss/lib/softoken/pkcs11c.c index d9b7e9c..6afb0ee 100644 --- a/nss/lib/softoken/pkcs11c.c +++ b/nss/lib/softoken/pkcs11c.c @@ -4496,8 +4496,8 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSession, 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. @@ -5357,6 +5357,7 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hSession, (PRUint32)crv); sftk_LogAuditMessage(NSS_AUDIT_ERROR, NSS_AUDIT_SELF_TEST, msg); } + sftk_fatalError = PR_TRUE; } } -- 2.21.0 ++++++ nss-fips-rsa-keygen-strictness.patch ++++++ commit 4b8c0eac6b092717157b4141c82b4d76ccdc91b3 Author: Hans Petter Jansson <[email protected]> Date: Sun Mar 15 21:54:30 2020 +0100 Patch 16: nss-fips-rsa-keygen-strictness.patch diff --git a/nss/lib/freebl/mpi/mpprime.c b/nss/lib/freebl/mpi/mpprime.c index 9d6232c..ccb0b53 100644 --- a/nss/lib/freebl/mpi/mpprime.c +++ b/nss/lib/freebl/mpi/mpprime.c @@ -14,6 +14,8 @@ #include <stdlib.h> #include <string.h> +#include "../fips.h" + #define SMALL_TABLE 0 /* determines size of hard-wired prime table */ #define RANDOM() rand() @@ -451,6 +453,25 @@ mpp_make_prime(mp_int *start, mp_size nBits, mp_size strong) } 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/nss/lib/freebl/rsa.c b/nss/lib/freebl/rsa.c index a08636d..b74641a 100644 --- a/nss/lib/freebl/rsa.c +++ b/nss/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 @@ rsa_build_from_primes(const mp_int *p, const mp_int *q, 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 @@ RSA_NewKey(int keySizeInBits, SECItem *publicExponent) 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 @@ RSA_NewKey(int keySizeInBits, SECItem *publicExponent) 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 @@ RSA_NewKey(int keySizeInBits, SECItem *publicExponent) 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 @@ RSA_NewKey(int keySizeInBits, SECItem *publicExponent) 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 @@ cleanup: 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; } ++++++ nss-fips-tls-allow-md5-prf.patch ++++++ >From ca3b695ac461eccf4ed97e1b3fe0a311c80a792f Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson <[email protected]> Date: Wed, 20 Nov 2019 10:05:34 +0100 Subject: [PATCH] 30 --- 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/nss/lib/freebl/md5.c b/nss/lib/freebl/md5.c index b3a796b..b2072cb 100644 --- a/nss/lib/freebl/md5.c +++ b/nss/lib/freebl/md5.c @@ -217,13 +217,11 @@ MD5_HashBuf(unsigned char *dest, const unsigned char *src, PRUint32 src_length) } 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 @@ MD5_NewContext(void) 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 @@ MD5_DestroyContext(MD5Context *cx, PRBool freeit) } 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 @@ MD5_Begin(MD5Context *cx) 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 @@ md5_compress(MD5Context *cx, const PRUint32 *wBuf) } 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 @@ MD5_Update(MD5Context *cx, const unsigned char *input, unsigned int inputLen) 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 @@ static const unsigned char padbytes[] = { }; 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 @@ MD5_End(MD5Context *cx, unsigned char *digest, 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 @@ MD5_End(MD5Context *cx, unsigned char *digest, 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 @@ MD5_End(MD5Context *cx, unsigned char *digest, } 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 @@ MD5_EndRaw(MD5Context *cx, unsigned char *digest, *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/nss/lib/freebl/rawhash.c b/nss/lib/freebl/rawhash.c index d0e8ee8..5fff18c 100644 --- a/nss/lib/freebl/rawhash.c +++ b/nss/lib/freebl/rawhash.c @@ -154,3 +154,40 @@ HASH_GetRawHashObject(HASH_HashType hashType) } 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/nss/lib/freebl/tlsprfalg.c b/nss/lib/freebl/tlsprfalg.c index 1e5e678..d927754 100644 --- a/nss/lib/freebl/tlsprfalg.c +++ b/nss/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 @@ TLS_P_hash(HASH_HashType hashType, const SECItem *secret, const char *label, 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/nss/lib/softoken/pkcs11c.c b/nss/lib/softoken/pkcs11c.c index 88402ce..c4d8f9d 100644 --- a/nss/lib/softoken/pkcs11c.c +++ b/nss/lib/softoken/pkcs11c.c @@ -6510,7 +6510,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession, SFTKAttribute *att2 = NULL; unsigned char *buf; SHA1Context *sha; - MD5Context *md5; + MD5Context *md5 = NULL; MD2Context *md2; CK_ULONG macSize; CK_ULONG tmpKeySize; @@ -7012,7 +7012,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession, } sftk_FreeAttribute(att2); md5 = MD5_NewContext(); - if (md5 == NULL) { + if (md5 == NULL && !isTLS) { crv = CKR_HOST_MEMORY; break; } -- 2.21.0 ++++++ nss-fips-use-getrandom.patch ++++++ commit c2a88344b616c75b1873fb163491d7362a4c3e5b Author: Hans Petter Jansson <[email protected]> Date: Tue Nov 19 05:26:28 2019 +0100 11 diff --git a/nss/coreconf/Linux.mk b/nss/coreconf/Linux.mk index f15ec95..ea53a58 100644 --- a/nss/coreconf/Linux.mk +++ b/nss/coreconf/Linux.mk @@ -183,6 +183,18 @@ DSO_LDOPTS+=-Wl,-z,relro 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/nss/lib/freebl/unix_rand.c b/nss/lib/freebl/unix_rand.c index 24381cb..65a44b3 100644 --- a/nss/lib/freebl/unix_rand.c +++ b/nss/lib/freebl/unix_rand.c @@ -13,6 +13,10 @@ #include <sys/wait.h> #include <sys/stat.h> #include <sys/types.h> +#ifdef NSS_USE_GETRANDOM +# include <sys/syscall.h> +# include <linux/random.h> +#endif #include <dirent.h> #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 @@ ReadFileOK(char *dir, char *file) 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 @@ RNG_SystemRNG(void *dest, size_t maxLen) fileBytes = 0; } return fileBytes; +#endif } ++++++ nss-fips-use-strong-random-pool.patch ++++++ >From a7cbf64ba8ac07a4a1fdea91f39da56d86af03bf Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson <[email protected]> Date: Wed, 20 Nov 2019 10:06:39 +0100 Subject: [PATCH] 31 --- nss/lib/freebl/unix_rand.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/nss/lib/freebl/unix_rand.c b/nss/lib/freebl/unix_rand.c index 65a44b3..ea88012 100644 --- a/nss/lib/freebl/unix_rand.c +++ b/nss/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 @@ RNG_SystemInfoForRNG(void) } /* 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 @@ RNG_SystemRNG(void *dest, size_t maxLen) 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 @@ RNG_SystemRNG(void *dest, size_t maxLen) 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; -- 2.21.0 ++++++ nss-fips-zeroization.patch ++++++ >From 76da775313bd40a1353a9d2f6cc43ebe1a287574 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson <[email protected]> Date: Wed, 20 Nov 2019 10:04:25 +0100 Subject: [PATCH 07/10] 29 --- 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/nss/lib/freebl/aeskeywrap.c b/nss/lib/freebl/aeskeywrap.c index ee909db..b9f0439 100644 --- a/nss/lib/freebl/aeskeywrap.c +++ b/nss/lib/freebl/aeskeywrap.c @@ -100,6 +100,7 @@ AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit) { 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/nss/lib/freebl/cts.c b/nss/lib/freebl/cts.c index 774294b..a12e620 100644 --- a/nss/lib/freebl/cts.c +++ b/nss/lib/freebl/cts.c @@ -37,6 +37,7 @@ CTS_CreateContext(void *context, freeblCipherFunc cipher, void CTS_DestroyContext(CTSContext *cts, PRBool freeit) { + PORT_Memset(cts, 0, sizeof(CTSContext)); if (freeit) { PORT_Free(cts); } @@ -135,7 +136,7 @@ CTS_EncryptUpdate(CTSContext *cts, unsigned char *outbuf, 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 @@ CTS_DecryptUpdate(CTSContext *cts, unsigned char *outbuf, 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 @@ CTS_DecryptUpdate(CTSContext *cts, unsigned char *outbuf, 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 @@ CTS_DecryptUpdate(CTSContext *cts, unsigned char *outbuf, /* 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/nss/lib/freebl/dh.c b/nss/lib/freebl/dh.c index b2d6d74..5ff9551 100644 --- a/nss/lib/freebl/dh.c +++ b/nss/lib/freebl/dh.c @@ -192,6 +192,10 @@ cleanup: 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/nss/lib/freebl/ec.c b/nss/lib/freebl/ec.c index ddbcc23..94fbc72 100644 --- a/nss/lib/freebl/ec.c +++ b/nss/lib/freebl/ec.c @@ -958,7 +958,7 @@ ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, 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/nss/lib/freebl/gcm.c b/nss/lib/freebl/gcm.c index 0f42525..4d960f7 100644 --- a/nss/lib/freebl/gcm.c +++ b/nss/lib/freebl/gcm.c @@ -141,6 +141,9 @@ bmul(uint64_t x, uint64_t y, uint64_t *r_high, uint64_t *r_low) *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 @@ -179,6 +182,12 @@ gcm_HashMult_sftw(gcmHashContext *ghash, const unsigned char *buf, } 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 @@ -218,6 +227,10 @@ bmul32(uint32_t x, uint32_t y, uint32_t *r_high, uint32_t *r_low) 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 @@ -303,6 +316,20 @@ gcm_HashMult_sftw32(gcmHashContext *ghash, const unsigned char *buf, 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 */ @@ -760,11 +787,13 @@ GCM_DecryptUpdate(GCMContext *gcm, unsigned char *outbuf, /* 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 @@ -772,10 +801,18 @@ GCM_DecryptUpdate(GCMContext *gcm, unsigned char *outbuf, 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); -- 2.21.0 ++++++ nss-fix-dh-pkcs-derive-inverted-logic.patch ++++++ diff --git a/nss/lib/softoken/pkcs11c.c b/nss/lib/softoken/pkcs11c.c index dc8819b..2540d87 100644 --- a/nss/lib/softoken/pkcs11c.c +++ b/nss/lib/softoken/pkcs11c.c @@ -8075,7 +8075,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession, 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); ++++++ nss-unit-test-fixes.patch ++++++ commit 108aafd8a614c5e748fac7734d82e68cea1d8d4a Author: Hans Petter Jansson <[email protected]> Date: Sun Mar 8 19:23:24 2020 +0100 tests: Fix lowhashtest diff --git a/nss/cmd/lowhashtest/lowhashtest.c b/nss/cmd/lowhashtest/lowhashtest.c index fcc06a8..95c23f3 100644 --- a/nss/cmd/lowhashtest/lowhashtest.c +++ b/nss/cmd/lowhashtest/lowhashtest.c @@ -415,7 +415,7 @@ main(int argc, char **argv) return 1; } - if (argc || !argv[1] || strlen(argv[1]) == 0) { + if (argc < 2 || !argv[1] || strlen(argv[1]) == 0) { rv += testMD5(initCtx); rv += testSHA1(initCtx); rv += testSHA224(initCtx); @@ -428,7 +428,7 @@ main(int argc, char **argv) rv += testSHA1(initCtx); } else if (strcmp(argv[1], "SHA224") == 0) { rv += testSHA224(initCtx); - } else if (strcmp(argv[1], "SHA226") == 0) { + } else if (strcmp(argv[1], "SHA256") == 0) { rv += testSHA256(initCtx); } else if (strcmp(argv[1], "SHA384") == 0) { rv += testSHA384(initCtx);
