diff options
Diffstat (limited to 'nss/lib/freebl')
43 files changed, 1136 insertions, 2045 deletions
diff --git a/nss/lib/freebl/Makefile b/nss/lib/freebl/Makefile index 0ce1425..aa02f4b 100644 --- a/nss/lib/freebl/Makefile +++ b/nss/lib/freebl/Makefile @@ -232,8 +232,6 @@ ifeq ($(CPU_ARCH),x86) DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE DEFINES += -DMP_ASSEMBLY_DIV_2DX1D -DMP_USE_UINT_DIGIT DEFINES += -DMP_IS_LITTLE_ENDIAN - # The floating point ECC code doesn't work on Linux x86 (bug 311432). - #ECL_USE_FP = 1 endif ifeq ($(CPU_ARCH),arm) DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE @@ -430,7 +428,6 @@ ifeq ($(CPU_ARCH),sparc) ASFILES = mpv_sparcv8.s montmulfv8.s DEFINES += -DMP_NO_MP_WORD -DMP_USE_UINT_DIGIT -DMP_ASSEMBLY_MULTIPLY DEFINES += -DMP_USING_MONT_MULF -DMP_MONT_USE_MP_MUL - ECL_USE_FP = 1 endif ifdef USE_ABI64_INT # this builds for Sparc v9a pure 64-bit architecture @@ -443,7 +440,6 @@ ifeq ($(CPU_ARCH),sparc) ASFILES = mpv_sparcv9.s montmulfv9.s DEFINES += -DMP_NO_MP_WORD -DMP_USE_UINT_DIGIT -DMP_ASSEMBLY_MULTIPLY DEFINES += -DMP_USING_MONT_MULF -DMP_MONT_USE_MP_MUL - ECL_USE_FP = 1 endif else @@ -491,16 +487,7 @@ else endif endif endif # Solaris for non-sparc family CPUs -endif # target == SunOS - -ifndef NSS_DISABLE_ECC - ifdef ECL_USE_FP - #enable floating point ECC code - DEFINES += -DECL_USE_FP - ECL_SRCS += ecp_fp160.c ecp_fp192.c ecp_fp224.c ecp_fp.c - ECL_HDRS += ecp_fp.h - endif -endif +endif # target == SunO # poly1305-donna-x64-sse2-incremental-source.c requires __int128 support # in GCC 4.6.0. @@ -601,7 +588,7 @@ $(ECL_OBJS): $(ECL_HDRS) -$(OBJDIR)/sysrand$(OBJ_SUFFIX): sysrand.c unix_rand.c win_rand.c os2_rand.c +$(OBJDIR)/sysrand$(OBJ_SUFFIX): sysrand.c unix_rand.c win_rand.c $(OBJDIR)/$(PROG_PREFIX)mpprime$(OBJ_SUFFIX): primes.c diff --git a/nss/lib/freebl/blapi.h b/nss/lib/freebl/blapi.h index 38c3a9f..592624b 100644 --- a/nss/lib/freebl/blapi.h +++ b/nss/lib/freebl/blapi.h @@ -1429,8 +1429,6 @@ extern SECStatus RNG_RandomUpdate(const void *data, size_t bytes); */ extern SECStatus RNG_GenerateGlobalRandomBytes(void *dest, size_t len); -extern SECStatus RNG_ResetForFuzzing(void); - /* Destroy the global RNG context. After a call to RNG_RNGShutdown() ** a call to RNG_RNGInit() is required in order to use the generator again, ** along with seed data (see the comment above RNG_RNGInit()). @@ -1469,6 +1467,12 @@ FIPS186Change_ReduceModQForDSA(const unsigned char *w, const unsigned char *q, unsigned char *xj); +/* To allow NIST KAT tests */ +extern SECStatus +PRNGTEST_Instantiate_Kat(const PRUint8 *entropy, unsigned int entropy_len, + const PRUint8 *nonce, unsigned int nonce_len, + const PRUint8 *personal_string, unsigned int ps_len); + /* * The following functions are for FIPS poweron self test and FIPS algorithm * testing. @@ -1599,7 +1603,6 @@ extern const SECHashObject *HASH_GetRawHashObject(HASH_HashType hashType); extern void BL_SetForkState(PRBool forked); -#ifndef NSS_DISABLE_ECC /* ** pepare an ECParam structure from DEREncoded params */ @@ -1609,7 +1612,11 @@ extern SECStatus EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams); extern SECStatus EC_CopyParams(PLArenaPool *arena, ECParams *dstParams, const ECParams *srcParams); -#endif + +/* + * use the internal table to get the size in bytes of a single EC point + */ +extern int EC_GetPointSize(const ECParams *params); SEC_END_PROTOS diff --git a/nss/lib/freebl/blapii.h b/nss/lib/freebl/blapii.h index 6ad2e28..0087c78 100644 --- a/nss/lib/freebl/blapii.h +++ b/nss/lib/freebl/blapii.h @@ -9,6 +9,7 @@ #define _BLAPII_H_ #include "blapit.h" +#include "mpi.h" /* max block size of supported block ciphers */ #define MAX_BLOCK_SIZE 16 @@ -58,4 +59,12 @@ SEC_END_PROTOS #undef HAVE_NO_SANITIZE_ATTR +SECStatus RSA_Init(); +SECStatus generate_prime(mp_int *prime, int primeLen); + +/* Freebl state. */ +PRBool aesni_support(); +PRBool clmul_support(); +PRBool avx_support(); + #endif /* _BLAPII_H_ */ diff --git a/nss/lib/freebl/blapit.h b/nss/lib/freebl/blapit.h index 7cf8fc6..2a17b5f 100644 --- a/nss/lib/freebl/blapit.h +++ b/nss/lib/freebl/blapit.h @@ -377,7 +377,6 @@ struct ECParamsStr { SECItem DEREncoding; ECCurveName name; SECItem curveOID; - int pointSize; }; typedef struct ECParamsStr ECParams; diff --git a/nss/lib/freebl/blinit.c b/nss/lib/freebl/blinit.c new file mode 100644 index 0000000..d7f2ec5 --- /dev/null +++ b/nss/lib/freebl/blinit.c @@ -0,0 +1,119 @@ +/* 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/. */ + +#ifdef FREEBL_NO_DEPEND +#include "stubs.h" +#endif + +#include "blapii.h" +#include "mpi.h" +#include "secerr.h" +#include "prtypes.h" +#include "prinit.h" +#include "prenv.h" + +#if defined(_MSC_VER) && !defined(_M_IX86) +#include <intrin.h> /* for _xgetbv() */ +#endif + +static PRCallOnceType coFreeblInit; + +/* State variables. */ +static PRBool aesni_support_ = PR_FALSE; +static PRBool clmul_support_ = PR_FALSE; +static PRBool avx_support_ = PR_FALSE; + +#ifdef NSS_X86_OR_X64 +/* + * Adapted from the example code in "How to detect New Instruction support in + * the 4th generation Intel Core processor family" by Max Locktyukhin. + * + * XGETBV: + * Reads an extended control register (XCR) specified by ECX into EDX:EAX. + */ +static PRBool +check_xcr0_ymm() +{ + PRUint32 xcr0; +#if defined(_MSC_VER) +#if defined(_M_IX86) + __asm { + mov ecx, 0 + xgetbv + mov xcr0, eax + } +#else + xcr0 = (PRUint32)_xgetbv(0); /* Requires VS2010 SP1 or later. */ +#endif /* _M_IX86 */ +#else /* _MSC_VER */ + /* Old OSX compilers don't support xgetbv. Use byte form. */ + __asm__(".byte 0x0F, 0x01, 0xd0" + : "=a"(xcr0) + : "c"(0) + : "%edx"); +#endif /* _MSC_VER */ + /* Check if xmm and ymm state are enabled in XCR0. */ + return (xcr0 & 6) == 6; +} + +#define ECX_AESNI (1 << 25) +#define ECX_CLMUL (1 << 1) +#define ECX_XSAVE (1 << 26) +#define ECX_OSXSAVE (1 << 27) +#define ECX_AVX (1 << 28) +#define AVX_BITS (ECX_XSAVE | ECX_OSXSAVE | ECX_AVX) + +void +CheckX86CPUSupport() +{ + unsigned long eax, ebx, ecx, edx; + char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES"); + char *disable_pclmul = PR_GetEnvSecure("NSS_DISABLE_PCLMUL"); + char *disable_avx = PR_GetEnvSecure("NSS_DISABLE_AVX"); + freebl_cpuid(1, &eax, &ebx, &ecx, &edx); + aesni_support_ = (PRBool)((ecx & ECX_AESNI) != 0 && disable_hw_aes == NULL); + clmul_support_ = (PRBool)((ecx & ECX_CLMUL) != 0 && disable_pclmul == NULL); + /* For AVX we check AVX, OSXSAVE, and XSAVE + * as well as XMM and YMM state. */ + avx_support_ = (PRBool)((ecx & AVX_BITS) == AVX_BITS) && check_xcr0_ymm() && + disable_avx == NULL; +} +#endif /* NSS_X86_OR_X64 */ + +PRBool +aesni_support() +{ + return aesni_support_; +} +PRBool +clmul_support() +{ + return clmul_support_; +} +PRBool +avx_support() +{ + return avx_support_; +} + +static PRStatus +FreeblInit(void) +{ +#ifdef NSS_X86_OR_X64 + CheckX86CPUSupport(); +#endif + return PR_SUCCESS; +} + +SECStatus +BL_Init() +{ + if (PR_CallOnce(&coFreeblInit, FreeblInit) != PR_SUCCESS) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + RSA_Init(); + + return SECSuccess; +} diff --git a/nss/lib/freebl/det_rng.c b/nss/lib/freebl/det_rng.c index fcbf9b3..04fce30 100644 --- a/nss/lib/freebl/det_rng.c +++ b/nss/lib/freebl/det_rng.c @@ -9,10 +9,32 @@ #include "seccomon.h" #include "secerr.h" +#define GLOBAL_BYTES_SIZE 100 +static PRUint8 globalBytes[GLOBAL_BYTES_SIZE]; static unsigned long globalNumCalls = 0; +static PZLock *rng_lock = NULL; SECStatus -prng_ResetForFuzzing(PZLock *rng_lock) +RNG_RNGInit(void) +{ + rng_lock = PZ_NewLock(nssILockOther); + if (!rng_lock) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + /* --- LOCKED --- */ + PZ_Lock(rng_lock); + memset(globalBytes, 0, GLOBAL_BYTES_SIZE); + PZ_Unlock(rng_lock); + /* --- UNLOCKED --- */ + + return SECSuccess; +} + +/* Take min(size, GLOBAL_BYTES_SIZE) bytes from data and use as seed and reset + * the rng state. */ +SECStatus +RNG_RandomUpdate(const void *data, size_t bytes) { /* Check for a valid RNG lock. */ PORT_Assert(rng_lock != NULL); @@ -23,7 +45,11 @@ prng_ResetForFuzzing(PZLock *rng_lock) /* --- LOCKED --- */ PZ_Lock(rng_lock); + memset(globalBytes, 0, GLOBAL_BYTES_SIZE); globalNumCalls = 0; + if (data) { + memcpy(globalBytes, (PRUint8 *)data, PR_MIN(bytes, GLOBAL_BYTES_SIZE)); + } PZ_Unlock(rng_lock); /* --- UNLOCKED --- */ @@ -31,9 +57,9 @@ prng_ResetForFuzzing(PZLock *rng_lock) } SECStatus -prng_GenerateDeterministicRandomBytes(PZLock *rng_lock, void *dest, size_t len) +RNG_GenerateGlobalRandomBytes(void *dest, size_t len) { - static const uint8_t key[32]; + static const uint8_t key[32] = { 0 }; uint8_t nonce[12] = { 0 }; /* Check for a valid RNG lock. */ @@ -58,10 +84,60 @@ prng_GenerateDeterministicRandomBytes(PZLock *rng_lock, void *dest, size_t len) } memset(dest, 0, len); + memcpy(dest, globalBytes, PR_MIN(len, GLOBAL_BYTES_SIZE)); ChaCha20XOR(dest, dest, len, key, nonce, 0); ChaCha20Poly1305_DestroyContext(cx, PR_TRUE); PZ_Unlock(rng_lock); /* --- UNLOCKED --- */ + return SECSuccess; } + +void +RNG_RNGShutdown(void) +{ + PZ_DestroyLock(rng_lock); + rng_lock = NULL; +} + +/* Test functions are not implemented! */ +SECStatus +PRNGTEST_Instantiate(const PRUint8 *entropy, unsigned int entropy_len, + const PRUint8 *nonce, unsigned int nonce_len, + const PRUint8 *personal_string, unsigned int ps_len) +{ + return SECFailure; +} + +SECStatus +PRNGTEST_Reseed(const PRUint8 *entropy, unsigned int entropy_len, + const PRUint8 *additional, unsigned int additional_len) +{ + return SECFailure; +} + +SECStatus +PRNGTEST_Generate(PRUint8 *bytes, unsigned int bytes_len, + const PRUint8 *additional, unsigned int additional_len) +{ + return SECFailure; +} + +SECStatus +PRNGTEST_Uninstantiate() +{ + return SECFailure; +} + +SECStatus +PRNGTEST_RunHealthTests() +{ + return SECFailure; +} + +SECStatus +PRNGTEST_Instantiate_Kat() +{ + return SECFailure; +} diff --git a/nss/lib/freebl/dh.c b/nss/lib/freebl/dh.c index 97025c7..587982a 100644 --- a/nss/lib/freebl/dh.c +++ b/nss/lib/freebl/dh.c @@ -14,9 +14,9 @@ #include "secerr.h" #include "blapi.h" +#include "blapii.h" #include "secitem.h" #include "mpi.h" -#include "mpprime.h" #include "secmpi.h" #define KEA_DERIVED_SECRET_LEN 128 @@ -46,9 +46,7 @@ DH_GenParam(int primeLen, DHParams **params) { PLArenaPool *arena; DHParams *dhparams; - unsigned char *pb = NULL; unsigned char *ab = NULL; - unsigned long counter = 0; mp_int p, q, a, h, psub1, test; mp_err err = MP_OKAY; SECStatus rv = SECSuccess; @@ -81,12 +79,7 @@ DH_GenParam(int primeLen, DHParams **params) CHECK_MPI_OK(mp_init(&psub1)); CHECK_MPI_OK(mp_init(&test)); /* generate prime with MPI, uses Miller-Rabin to generate strong prime. */ - pb = PORT_Alloc(primeLen); - CHECK_SEC_OK(RNG_GenerateGlobalRandomBytes(pb, primeLen)); - pb[0] |= 0x80; /* set high-order bit */ - pb[primeLen - 1] |= 0x01; /* set low-order bit */ - CHECK_MPI_OK(mp_read_unsigned_octets(&p, pb, primeLen)); - CHECK_MPI_OK(mpp_make_prime(&p, primeLen * 8, PR_TRUE, &counter)); + CHECK_SEC_OK(generate_prime(&p, primeLen)); /* construct Sophie-Germain prime q = (p-1)/2. */ CHECK_MPI_OK(mp_sub_d(&p, 1, &psub1)); CHECK_MPI_OK(mp_div_2(&psub1, &q)); @@ -121,8 +114,6 @@ cleanup: mp_clear(&h); mp_clear(&psub1); mp_clear(&test); - if (pb) - PORT_ZFree(pb, primeLen); if (ab) PORT_ZFree(ab, primeLen); if (err) { diff --git a/nss/lib/freebl/drbg.c b/nss/lib/freebl/drbg.c index 658faa3..224bbe8 100644 --- a/nss/lib/freebl/drbg.c +++ b/nss/lib/freebl/drbg.c @@ -20,10 +20,6 @@ #include "secrng.h" /* for RNG_SystemRNG() */ #include "secmpi.h" -#ifdef UNSAFE_FUZZER_MODE -#include "det_rng.h" -#endif - /* PRNG_SEEDLEN defined in NIST SP 800-90 section 10.1 * for SHA-1, SHA-224, and SHA-256 it's 440 bits. * for SHA-384 and SHA-512 it's 888 bits */ @@ -99,7 +95,8 @@ struct RNGContextStr { * RNG_RandomUpdate. */ PRUint8 additionalDataCache[PRNG_ADDITONAL_DATA_CACHE_SIZE]; PRUint32 additionalAvail; - PRBool isValid; /* false if RNG reaches an invalid state */ + PRBool isValid; /* false if RNG reaches an invalid state */ + PRBool isKatTest; /* true if running NIST PRNG KAT tests */ }; typedef struct RNGContextStr RNGContext; @@ -150,7 +147,7 @@ prng_Hash_df(PRUint8 *requested_bytes, unsigned int no_of_bytes_to_return, } /* - * Hash_DRBG Instantiate NIST SP 800-80 10.1.1.2 + * Hash_DRBG Instantiate NIST SP 800-90 10.1.1.2 * * NOTE: bytes & len are entropy || nonce || personalization_string. In * normal operation, NSS calculates them all together in a single call. @@ -158,9 +155,11 @@ prng_Hash_df(PRUint8 *requested_bytes, unsigned int no_of_bytes_to_return, static SECStatus prng_instantiate(RNGContext *rng, const PRUint8 *bytes, unsigned int len) { - if (len < PRNG_SEEDLEN) { - /* if the seedlen is to small, it's probably because we failed to get - * enough random data */ + if (!rng->isKatTest && len < PRNG_SEEDLEN) { + /* If the seedlen is too small, it's probably because we failed to get + * enough random data. + * This is stricter than NIST SP800-90A requires. Don't enforce it for + * tests. */ PORT_SetError(SEC_ERROR_NEED_RANDOM); return SECFailure; } @@ -272,7 +271,7 @@ prng_reseed_test(RNGContext *rng, const PRUint8 *entropy, #define PRNG_ADD_BITS_AND_CARRY(dest, dest_len, add, len, carry) \ PRNG_ADD_BITS(dest, dest_len, add, len, carry) \ - PRNG_ADD_CARRY_ONLY(dest, dest_len - len, carry) + PRNG_ADD_CARRY_ONLY(dest, dest_len - len - 1, carry) /* * This function expands the internal state of the prng to fulfill any number @@ -435,12 +434,13 @@ rng_init(void) globalrng = NULL; return PR_FAILURE; } - if (rv != SECSuccess) { return PR_FAILURE; } + /* the RNG is in a valid state */ globalrng->isValid = PR_TRUE; + globalrng->isKatTest = PR_FALSE; /* fetch one random value so that we can populate rng->oldV for our * continous random number test. */ @@ -654,21 +654,7 @@ prng_GenerateGlobalRandomBytes(RNGContext *rng, SECStatus RNG_GenerateGlobalRandomBytes(void *dest, size_t len) { -#ifdef UNSAFE_FUZZER_MODE - return prng_GenerateDeterministicRandomBytes(globalrng->lock, dest, len); -#else return prng_GenerateGlobalRandomBytes(globalrng, dest, len); -#endif -} - -SECStatus -RNG_ResetForFuzzing(void) -{ -#ifdef UNSAFE_FUZZER_MODE - return prng_ResetForFuzzing(globalrng->lock); -#else - return SECFailure; -#endif } void @@ -696,6 +682,17 @@ RNG_RNGShutdown(void) * entropy we may have previously collected. */ RNGContext testContext; +SECStatus +PRNGTEST_Instantiate_Kat(const PRUint8 *entropy, unsigned int entropy_len, + const PRUint8 *nonce, unsigned int nonce_len, + const PRUint8 *personal_string, unsigned int ps_len) +{ + testContext.isKatTest = PR_TRUE; + return PRNGTEST_Instantiate(entropy, entropy_len, + nonce, nonce_len, + personal_string, ps_len); +} + /* * Test vector API. Use NIST SP 800-90 general interface so one of the * other NIST SP 800-90 algorithms may be used in the future. diff --git a/nss/lib/freebl/ec.c b/nss/lib/freebl/ec.c index a9b7c05..669c9b1 100644 --- a/nss/lib/freebl/ec.c +++ b/nss/lib/freebl/ec.c @@ -233,7 +233,6 @@ ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey, key->ecParams.type = ecParams->type; key->ecParams.fieldID.size = ecParams->fieldID.size; key->ecParams.fieldID.type = ecParams->fieldID.type; - key->ecParams.pointSize = ecParams->pointSize; if (ecParams->fieldID.type == ec_field_GFp || ecParams->fieldID.type == ec_field_plain) { CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime, @@ -262,7 +261,7 @@ ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey, CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID, &ecParams->curveOID)); - SECITEM_AllocItem(arena, &key->publicValue, ecParams->pointSize); + SECITEM_AllocItem(arena, &key->publicValue, EC_GetPointSize(ecParams)); len = ecParams->order.len; SECITEM_AllocItem(arena, &key->privateValue, len); @@ -566,11 +565,20 @@ ECDH_Derive(SECItem *publicValue, return SECFailure; } + /* + * Make sure the point is on the requested curve to avoid + * certain small subgroup attacks. + */ + if (EC_ValidatePublicKey(ecParams, publicValue) != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_KEY); + return SECFailure; + } + /* Perform curve specific multiplication using ECMethod */ if (ecParams->fieldID.type == ec_field_plain) { const ECMethod *method; memset(derivedSecret, 0, sizeof(*derivedSecret)); - derivedSecret = SECITEM_AllocItem(NULL, derivedSecret, ecParams->pointSize); + derivedSecret = SECITEM_AllocItem(NULL, derivedSecret, EC_GetPointSize(ecParams)); if (derivedSecret == NULL) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; @@ -581,10 +589,6 @@ ECDH_Derive(SECItem *publicValue, PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); return SECFailure; } - if (method->validate(publicValue) != SECSuccess) { - PORT_SetError(SEC_ERROR_BAD_KEY); - return SECFailure; - } return method->mul(derivedSecret, privateValue, publicValue); } @@ -600,8 +604,8 @@ ECDH_Derive(SECItem *publicValue, MP_DIGITS(&k) = 0; memset(derivedSecret, 0, sizeof *derivedSecret); len = (ecParams->fieldID.size + 7) >> 3; - pointQ.len = ecParams->pointSize; - if ((pointQ.data = PORT_Alloc(ecParams->pointSize)) == NULL) + pointQ.len = EC_GetPointSize(ecParams); + if ((pointQ.data = PORT_Alloc(pointQ.len)) == NULL) goto cleanup; CHECK_MPI_OK(mp_init(&k)); @@ -648,7 +652,7 @@ cleanup: } if (pointQ.data) { - PORT_ZFree(pointQ.data, ecParams->pointSize); + PORT_ZFree(pointQ.data, pointQ.len); } #else PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); @@ -763,8 +767,8 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, ** ** Compute kG */ - kGpoint.len = ecParams->pointSize; - kGpoint.data = PORT_Alloc(ecParams->pointSize); + kGpoint.len = EC_GetPointSize(ecParams); + kGpoint.data = PORT_Alloc(kGpoint.len); if ((kGpoint.data == NULL) || (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint) != SECSuccess)) goto cleanup; @@ -883,7 +887,7 @@ cleanup: } if (kGpoint.data) { - PORT_ZFree(kGpoint.data, ecParams->pointSize); + PORT_ZFree(kGpoint.data, kGpoint.len); } if (err) { @@ -1002,9 +1006,14 @@ ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, } slen = signature->len / 2; - SECITEM_AllocItem(NULL, &pointC, ecParams->pointSize); - if (pointC.data == NULL) + /* + * The incoming point has been verified in sftk_handlePublicKeyObject. + */ + + SECITEM_AllocItem(NULL, &pointC, EC_GetPointSize(ecParams)); + if (pointC.data == NULL) { goto cleanup; + } CHECK_MPI_OK(mp_init(&r_)); CHECK_MPI_OK(mp_init(&s_)); diff --git a/nss/lib/freebl/ecdecode.c b/nss/lib/freebl/ecdecode.c index eda3f0c..54b3e11 100644 --- a/nss/lib/freebl/ecdecode.c +++ b/nss/lib/freebl/ecdecode.c @@ -22,57 +22,6 @@ if (SECSuccess != (rv = func)) \ goto cleanup -/* - * Initializes a SECItem from a hexadecimal string - * - * Warning: This function ignores leading 00's, so any leading 00's - * in the hexadecimal string must be optional. - */ -static SECItem * -hexString2SECItem(PLArenaPool *arena, SECItem *item, const char *str) -{ - int i = 0; - int byteval = 0; - int tmp = PORT_Strlen(str); - - PORT_Assert(arena); - PORT_Assert(item); - - if ((tmp % 2) != 0) - return NULL; - - /* skip leading 00's unless the hex string is "00" */ - while ((tmp > 2) && (str[0] == '0') && (str[1] == '0')) { - str += 2; - tmp -= 2; - } - - item->data = (unsigned char *)PORT_ArenaAlloc(arena, tmp / 2); - if (item->data == NULL) - return NULL; - item->len = tmp / 2; - - while (str[i]) { - if ((str[i] >= '0') && (str[i] <= '9')) - tmp = str[i] - '0'; - else if ((str[i] >= 'a') && (str[i] <= 'f')) - tmp = str[i] - 'a' + 10; - else if ((str[i] >= 'A') && (str[i] <= 'F')) - tmp = str[i] - 'A' + 10; - else - return NULL; - - byteval = byteval * 16 + tmp; - if ((i % 2) != 0) { - item->data[i / 2] = byteval; - byteval = 0; - } - i++; - } - - return item; -} - /* Copy all of the fields from srcParams into dstParams */ SECStatus @@ -85,7 +34,6 @@ EC_CopyParams(PLArenaPool *arena, ECParams *dstParams, dstParams->type = srcParams->type; dstParams->fieldID.size = srcParams->fieldID.size; dstParams->fieldID.type = srcParams->fieldID.type; - dstParams->pointSize = srcParams->pointSize; if (srcParams->fieldID.type == ec_field_GFp || srcParams->fieldID.type == ec_field_plain) { CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->fieldID.u.prime, @@ -121,12 +69,10 @@ cleanup: } static SECStatus -gf_populate_params(ECCurveName name, ECFieldType field_type, ECParams *params) +gf_populate_params_bytes(ECCurveName name, ECFieldType field_type, ECParams *params) { SECStatus rv = SECFailure; - const ECCurveParams *curveParams; - /* 2 ['0'+'4'] + MAX_ECKEY_LEN * 2 [x,y] * 2 [hex string] + 1 ['\0'] */ - char genenc[3 + 2 * 2 * MAX_ECKEY_LEN]; + const ECCurveBytes *curveParams; if ((name < ECCurve_noName) || (name > ECCurve_pastLastCurve)) goto cleanup; @@ -135,27 +81,19 @@ gf_populate_params(ECCurveName name, ECFieldType field_type, ECParams *params) CHECK_OK(curveParams); params->fieldID.size = curveParams->size; params->fieldID.type = field_type; - params->pointSize = curveParams->pointSize; - if (field_type == ec_field_GFp || - field_type == ec_field_plain) { - CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, - curveParams->irr)); - } else { - CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.poly, - curveParams->irr)); + if (field_type != ec_field_GFp && field_type != ec_field_plain) { + return SECFailure; } - CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, - curveParams->curvea)); - CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, - curveParams->curveb)); - genenc[0] = '0'; - genenc[1] = '4'; - genenc[2] = '\0'; - strcat(genenc, curveParams->genx); - strcat(genenc, curveParams->geny); - CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, genenc)); - CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, - curveParams->order)); + params->fieldID.u.prime.len = curveParams->scalarSize; + params->fieldID.u.prime.data = (unsigned char *)curveParams->irr; + params->curve.a.len = curveParams->scalarSize; + params->curve.a.data = (unsigned char *)curveParams->curvea; + params->curve.b.len = curveParams->scalarSize; + params->curve.b.data = (unsigned char *)curveParams->curveb; + params->base.len = curveParams->pointSize; + params->base.data = (unsigned char *)curveParams->base; + params->order.len = curveParams->scalarSize; + params->order.data = (unsigned char *)curveParams->order; params->cofactor = curveParams->cofactor; rv = SECSuccess; @@ -218,29 +156,30 @@ EC_FillParams(PLArenaPool *arena, const SECItem *encodedParams, /* Populate params for prime256v1 aka secp256r1 * (the NIST P-256 curve) */ - CHECK_SEC_OK(gf_populate_params(ECCurve_X9_62_PRIME_256V1, ec_field_GFp, - params)); + CHECK_SEC_OK(gf_populate_params_bytes(ECCurve_X9_62_PRIME_256V1, + ec_field_GFp, params)); break; case SEC_OID_SECG_EC_SECP384R1: /* Populate params for secp384r1 * (the NIST P-384 curve) */ - CHECK_SEC_OK(gf_populate_params(ECCurve_SECG_PRIME_384R1, ec_field_GFp, - params)); + CHECK_SEC_OK(gf_populate_params_bytes(ECCurve_SECG_PRIME_384R1, + ec_field_GFp, params)); break; case SEC_OID_SECG_EC_SECP521R1: /* Populate params for secp521r1 * (the NIST P-521 curve) */ - CHECK_SEC_OK(gf_populate_params(ECCurve_SECG_PRIME_521R1, ec_field_GFp, - params)); + CHECK_SEC_OK(gf_populate_params_bytes(ECCurve_SECG_PRIME_521R1, + ec_field_GFp, params)); break; case SEC_OID_CURVE25519: /* Populate params for Curve25519 */ - CHECK_SEC_OK(gf_populate_params(ECCurve25519, ec_field_plain, params)); + CHECK_SEC_OK(gf_populate_params_bytes(ECCurve25519, ec_field_plain, + params)); break; default: @@ -294,4 +233,24 @@ EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams) } } +int +EC_GetPointSize(const ECParams *params) +{ + ECCurveName name = params->name; + const ECCurveBytes *curveParams; + + if ((name < ECCurve_noName) || (name > ECCurve_pastLastCurve) || + ((curveParams = ecCurve_map[name]) == NULL)) { + /* unknown curve, calculate point size from params. assume standard curves with 2 points + * and a point compression indicator byte */ + int sizeInBytes = (params->fieldID.size + 7) / 8; + return sizeInBytes * 2 + 1; + } + if (name == ECCurve25519) { + /* Only X here */ + return curveParams->scalarSize; + } + return curveParams->pointSize - 1; +} + #endif /* NSS_DISABLE_ECC */ diff --git a/nss/lib/freebl/ecl/README b/nss/lib/freebl/ecl/README index 04a8b3b..2996822 100644 --- a/nss/lib/freebl/ecl/README +++ b/nss/lib/freebl/ecl/README @@ -90,20 +90,6 @@ the linear coefficient in the curve defining equation). ecp_192.c and ecp_224.c provide optimized field arithmetic. -Point Arithmetic over Binary Polynomial Fields ----------------------------------------------- - -ec2_aff.c provides point arithmetic using affine coordinates. - -ec2_proj.c provides point arithmetic using projective coordinates. -(Projective coordinates represent a point (x, y) as (X, Y, Z), where -x=X/Z, y=Y/Z^2). - -ec2_mont.c provides point multiplication using Montgomery projective -coordinates. - -ec2_163.c, ec2_193.c, and ec2_233.c provide optimized field arithmetic. - Field Arithmetic ---------------- @@ -126,18 +112,6 @@ fields defined by nistp192 and nistp224 primes. ecl_gf.c provides wrappers around the basic field operations. -Binary Polynomial Field Arithmetic ----------------------------------- - -../mpi/mp_gf2m.c provides basic binary polynomial field arithmetic, -including addition, multiplication, squaring, mod, and division, as well -as conversion ob polynomial representations between bitstring and int[]. - -ec2_163.c, ec2_193.c, and ec2_233.c provide optimized field mod, mul, -and sqr operations. - -ecl_gf.c provides wrappers around the basic field operations. - Field Encoding -------------- @@ -187,81 +161,3 @@ arithmetic. Instead, they use basic field arithmetic with their optimized reduction (as in ecp_192.c and ecp_224.c). They use the same point multiplication and simultaneous point multiplication algorithms as other curves over prime fields. - -Curves over binary polynomial fields by default use generic field -arithmetic with montgomery point multiplication and basic kP + lQ -computation (multiply, multiply, and add). (Wiring in function -ECGroup_cons_GF2m in ecl.c.) - -Curves over binary polynomial fields that have optimized field -arithmetic (i.e., any 163-, 193, or 233-bit field) use their optimized -field arithmetic. They use the same point multiplication and -simultaneous point multiplication algorithms as other curves over binary -fields. - -Example -------- - -We provide an example for plugging in an optimized implementation for -the Koblitz curve nistk163. - -Suppose the file ec2_k163.c contains the optimized implementation. In -particular it contains a point multiplication function: - - mp_err ec_GF2m_nistk163_pt_mul(const mp_int *n, const mp_int *px, - const mp_int *py, mp_int *rx, mp_int *ry, const ECGroup *group); - -Since only a pt_mul function is provided, the generic pt_add function -will be used. - -There are two options for handling the optimized field arithmetic used -by the ..._pt_mul function. Say the optimized field arithmetic includes -the following functions: - - mp_err ec_GF2m_nistk163_add(const mp_int *a, const mp_int *b, - mp_int *r, const GFMethod *meth); - mp_err ec_GF2m_nistk163_mul(const mp_int *a, const mp_int *b, - mp_int *r, const GFMethod *meth); - mp_err ec_GF2m_nistk163_sqr(const mp_int *a, const mp_int *b, - mp_int *r, const GFMethod *meth); - mp_err ec_GF2m_nistk163_div(const mp_int *a, const mp_int *b, - mp_int *r, const GFMethod *meth); - -First, the optimized field arithmetic could simply be called directly -by the ..._pt_mul function. This would be accomplished by changing -the ecgroup_fromNameAndHex function in ecl.c to include the following -statements: - - if (name == ECCurve_NIST_K163) { - group = ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx, - &geny, &order, params->cofactor); - if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } - MP_CHECKOK( ec_group_set_nistk163(group) ); - } - -and including in ec2_k163.c the following function: - - mp_err ec_group_set_nistk163(ECGroup *group) { - group->point_mul = &ec_GF2m_nistk163_pt_mul; - return MP_OKAY; - } - -As a result, ec_GF2m_pt_add and similar functions would use the -basic binary polynomial field arithmetic ec_GF2m_add, ec_GF2m_mul, -ec_GF2m_sqr, and ec_GF2m_div. - -Alternatively, the optimized field arithmetic could be wired into the -group's GFMethod. This would be accomplished by putting the following -function in ec2_k163.c: - - mp_err ec_group_set_nistk163(ECGroup *group) { - group->meth->field_add = &ec_GF2m_nistk163_add; - group->meth->field_mul = &ec_GF2m_nistk163_mul; - group->meth->field_sqr = &ec_GF2m_nistk163_sqr; - group->meth->field_div = &ec_GF2m_nistk163_div; - group->point_mul = &ec_GF2m_nistk163_pt_mul; - return MP_OKAY; - } - -For an example of functions that use special field encodings, take a -look at ecp_mont.c. diff --git a/nss/lib/freebl/ecl/curve25519_64.c b/nss/lib/freebl/ecl/curve25519_64.c index 89327ad..65f6bd4 100644 --- a/nss/lib/freebl/ecl/curve25519_64.c +++ b/nss/lib/freebl/ecl/curve25519_64.c @@ -206,7 +206,7 @@ fexpand(felem *output, const u8 *in) output[1] = (*((const uint64_t *)(in + 6)) >> 3) & MASK51; output[2] = (*((const uint64_t *)(in + 12)) >> 6) & MASK51; output[3] = (*((const uint64_t *)(in + 19)) >> 1) & MASK51; - output[4] = (*((const uint64_t *)(in + 25)) >> 4) & MASK51; + output[4] = (*((const uint64_t *)(in + 24)) >> 12) & MASK51; } /* Take a fully reduced polynomial form number and contract it into a diff --git a/nss/lib/freebl/ecl/ecl-curve.h b/nss/lib/freebl/ecl/ecl-curve.h index df06139..fc8003f 100644 --- a/nss/lib/freebl/ecl/ecl-curve.h +++ b/nss/lib/freebl/ecl/ecl-curve.h @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ecl-exp.h" +#include "eclt.h" #include <stdlib.h> #ifndef __ecl_curve_h_ @@ -12,52 +13,201 @@ #define KU_DIGITAL_SIGNATURE (0x80) /* bit 0 */ #define KU_KEY_AGREEMENT (0x08) /* bit 4 */ -static const ECCurveParams ecCurve_NIST_P256 = { +static const PRUint8 irr256[32] = + { 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const PRUint8 a256[32] = + { 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC }; +static const PRUint8 b256[32] = + { 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, 0xEB, 0xBD, 0x55, + 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, + 0x3B, 0xCE, 0x3C, 0x3E, 0x27, 0xD2, 0x60, 0x4B }; +static const PRUint8 x256[32] = + { 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5, + 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, + 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96 }; +static const PRUint8 y256[32] = + { 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, + 0x7C, 0x0F, 0x9E, 0x16, 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE, + 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5 }; +static const PRUint8 order256[32] = + { 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, + 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51 }; +static const PRUint8 base256[66] = + { 0x04, 0x00, + 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5, + 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, + 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96, + 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, + 0x7C, 0x0F, 0x9E, 0x16, 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE, + 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5 }; + +static const ECCurveBytes ecCurve_NIST_P256 = { "NIST-P256", ECField_GFp, 256, - "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", - "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", - "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", - "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", - "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", - "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", - 1, 128, 65, KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT + irr256, a256, b256, x256, y256, order256, base256, + 1, 128, 66, 32, + KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT }; -static const ECCurveParams ecCurve_NIST_P384 = { +static const PRUint8 irr384[48] = + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF }; +static const PRUint8 a384[48] = + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFC }; +static const PRUint8 b384[48] = + { 0xB3, 0x31, 0x2F, 0xA7, 0xE2, 0x3E, 0xE7, 0xE4, 0x98, 0x8E, 0x05, 0x6B, + 0xE3, 0xF8, 0x2D, 0x19, 0x18, 0x1D, 0x9C, 0x6E, 0xFE, 0x81, 0x41, 0x12, + 0x03, 0x14, 0x08, 0x8F, 0x50, 0x13, 0x87, 0x5A, 0xC6, 0x56, 0x39, 0x8D, + 0x8A, 0x2E, 0xD1, 0x9D, 0x2A, 0x85, 0xC8, 0xED, 0xD3, 0xEC, 0x2A, 0xEF }; +static const PRUint8 x384[48] = + { 0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05, 0x37, 0x8E, 0xB1, 0xC7, 0x1E, + 0xF3, 0x20, 0xAD, 0x74, 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B, 0x98, + 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A, 0x38, 0x55, 0x02, 0xF2, 0x5D, + 0xBF, 0x55, 0x29, 0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A, 0xB7 }; +static const PRUint8 y384[48] = + { 0x36, 0x17, 0xDE, 0x4A, 0x96, 0x26, 0x2C, 0x6F, 0x5D, 0x9E, 0x98, 0xBF, + 0x92, 0x92, 0xDC, 0x29, 0xF8, 0xF4, 0x1D, 0xBD, 0x28, 0x9A, 0x14, 0x7C, + 0xE9, 0xDA, 0x31, 0x13, 0xB5, 0xF0, 0xB8, 0xC0, 0x0A, 0x60, 0xB1, 0xCE, + 0x1D, 0x7E, 0x81, 0x9D, 0x7A, 0x43, 0x1D, 0x7C, 0x90, 0xEA, 0x0E, 0x5F }; +static const PRUint8 order384[48] = + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF, 0x58, 0x1A, 0x0D, 0xB2, + 0x48, 0xB0, 0xA7, 0x7A, 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73 }; +static const PRUint8 base384[98] = + { 0x04, 0x00, + 0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05, 0x37, 0x8E, 0xB1, 0xC7, 0x1E, + 0xF3, 0x20, 0xAD, 0x74, 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B, 0x98, + 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A, 0x38, 0x55, 0x02, 0xF2, 0x5D, + 0xBF, 0x55, 0x29, 0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A, 0xB7, + 0x36, 0x17, 0xDE, 0x4A, 0x96, 0x26, 0x2C, 0x6F, 0x5D, 0x9E, 0x98, 0xBF, + 0x92, 0x92, 0xDC, 0x29, 0xF8, 0xF4, 0x1D, 0xBD, 0x28, 0x9A, 0x14, 0x7C, + 0xE9, 0xDA, 0x31, 0x13, 0xB5, 0xF0, 0xB8, 0xC0, 0x0A, 0x60, 0xB1, 0xCE, + 0x1D, 0x7E, 0x81, 0x9D, 0x7A, 0x43, 0x1D, 0x7C, 0x90, 0xEA, 0x0E, 0x5F }; + +static const ECCurveBytes ecCurve_NIST_P384 = { "NIST-P384", ECField_GFp, 384, - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", - "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", - "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", - "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", - 1, 192, 97, KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT + irr384, a384, b384, x384, y384, order384, base384, + 1, 192, 98, 48, + KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT }; -static const ECCurveParams ecCurve_NIST_P521 = { +static const PRUint8 irr521[66] = + { 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const PRUint8 a521[66] = + { 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC }; +static const PRUint8 b521[66] = + { 0x00, 0x51, 0x95, 0x3E, 0xB9, 0x61, 0x8E, 0x1C, 0x9A, 0x1F, 0x92, 0x9A, + 0x21, 0xA0, 0xB6, 0x85, 0x40, 0xEE, 0xA2, 0xDA, 0x72, 0x5B, 0x99, 0xB3, + 0x15, 0xF3, 0xB8, 0xB4, 0x89, 0x91, 0x8E, 0xF1, 0x09, 0xE1, 0x56, 0x19, + 0x39, 0x51, 0xEC, 0x7E, 0x93, 0x7B, 0x16, 0x52, 0xC0, 0xBD, 0x3B, 0xB1, + 0xBF, 0x07, 0x35, 0x73, 0xDF, 0x88, 0x3D, 0x2C, 0x34, 0xF1, 0xEF, 0x45, + 0x1F, 0xD4, 0x6B, 0x50, 0x3F, 0x00 }; +static const PRUint8 x521[66] = + { 0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04, 0x04, 0xE9, 0xCD, 0x9E, 0x3E, + 0xCB, 0x66, 0x23, 0x95, 0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05, 0x3F, + 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B, 0x4D, 0x3D, 0xBA, 0xA1, 0x4B, + 0x5E, 0x77, 0xEF, 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2, 0xFF, + 0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85, 0x6A, 0x42, 0x9B, 0xF9, 0x7E, + 0x7E, 0x31, 0xC2, 0xE5, 0xBD, 0x66 }; +static const PRUint8 y521[66] = + { 0x01, 0x18, 0x39, 0x29, 0x6A, 0x78, 0x9A, 0x3B, 0xC0, 0x04, 0x5C, 0x8A, + 0x5F, 0xB4, 0x2C, 0x7D, 0x1B, 0xD9, 0x98, 0xF5, 0x44, 0x49, 0x57, 0x9B, + 0x44, 0x68, 0x17, 0xAF, 0xBD, 0x17, 0x27, 0x3E, 0x66, 0x2C, 0x97, 0xEE, + 0x72, 0x99, 0x5E, 0xF4, 0x26, 0x40, 0xC5, 0x50, 0xB9, 0x01, 0x3F, 0xAD, + 0x07, 0x61, 0x35, 0x3C, 0x70, 0x86, 0xA2, 0x72, 0xC2, 0x40, 0x88, 0xBE, + 0x94, 0x76, 0x9F, 0xD1, 0x66, 0x50 }; +static const PRUint8 order521[66] = + { 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x51, 0x86, + 0x87, 0x83, 0xBF, 0x2F, 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09, + 0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C, 0x47, 0xAE, 0xBB, 0x6F, + 0xB7, 0x1E, 0x91, 0x38, 0x64, 0x09 }; +static const PRUint8 base521[134] = + { + 0x04, 0x00, + 0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04, 0x04, 0xE9, 0xCD, 0x9E, 0x3E, + 0xCB, 0x66, 0x23, 0x95, 0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05, 0x3F, + 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B, 0x4D, 0x3D, 0xBA, 0xA1, 0x4B, + 0x5E, 0x77, 0xEF, 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2, 0xFF, + 0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85, 0x6A, 0x42, 0x9B, 0xF9, 0x7E, + 0x7E, 0x31, 0xC2, 0xE5, 0xBD, 0x66, + 0x01, 0x18, 0x39, 0x29, 0x6A, 0x78, 0x9A, 0x3B, 0xC0, 0x04, 0x5C, 0x8A, + 0x5F, 0xB4, 0x2C, 0x7D, 0x1B, 0xD9, 0x98, 0xF5, 0x44, 0x49, 0x57, 0x9B, + 0x44, 0x68, 0x17, 0xAF, 0xBD, 0x17, 0x27, 0x3E, 0x66, 0x2C, 0x97, 0xEE, + 0x72, 0x99, 0x5E, 0xF4, 0x26, 0x40, 0xC5, 0x50, 0xB9, 0x01, 0x3F, 0xAD, + 0x07, 0x61, 0x35, 0x3C, 0x70, 0x86, 0xA2, 0x72, 0xC2, 0x40, 0x88, 0xBE, + 0x94, 0x76, 0x9F, 0xD1, 0x66, 0x50 + }; + +static const ECCurveBytes ecCurve_NIST_P521 = { "NIST-P521", ECField_GFp, 521, - "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", - "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", - "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", - "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", - "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", - 1, 256, 133, KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT + irr521, a521, b521, x521, y521, order521, base521, + 1, 256, 134, 66, + KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT }; -static const ECCurveParams ecCurve25519 = { +static const PRUint8 irr25519[32] = + { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }; +static const PRUint8 a25519[32] = + { 0x06, 0x6d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const PRUint8 b25519[32] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const PRUint8 x25519[32] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09 }; +static const PRUint8 y25519[32] = + { 0xd9, 0xd3, 0xce, 0x7e, 0xa2, 0xc5, 0xe9, 0x29, 0xb2, 0x61, 0x7c, 0x6d, + 0x7e, 0x4d, 0x3d, 0x92, 0x4c, 0xd1, 0x48, 0x77, 0x2c, 0xdd, 0x1e, 0xe0, + 0xb4, 0x86, 0xa0, 0xb8, 0xa1, 0x19, 0xae, 0x20 }; +static const PRUint8 order25519[32] = + { 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, + 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 }; +static const PRUint8 base25519[66] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0xd9, 0xd3, 0xce, 0x7e, 0xa2, 0xc5, 0xe9, 0x29, 0xb2, 0x61, 0x7c, 0x6d, + 0x7e, 0x4d, 0x3d, 0x92, 0x4c, 0xd1, 0x48, 0x77, 0x2c, 0xdd, 0x1e, 0xe0, + 0xb4, 0x86, 0xa0, 0xb8, 0xa1, 0x19, 0xae, 0x20, 0x00, 0x04 }; + +static const ECCurveBytes ecCurve_25519 = { "Curve25519", ECField_GFp, 255, - "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", - "076D06", - "00", - "0900000000000000000000000000000000000000000000000000000000000000", - "20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9", - "1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed", - 8, 128, 32, KU_KEY_AGREEMENT + irr25519, a25519, b25519, x25519, y25519, order25519, base25519, + 8, 128, 66, 32, + KU_KEY_AGREEMENT }; /* mapping between ECCurveName enum and pointers to ECCurveParams */ -static const ECCurveParams *ecCurve_map[] = { +static const ECCurveBytes *ecCurve_map[] = { NULL, /* ECCurve_noName */ NULL, /* ECCurve_NIST_P192 */ NULL, /* ECCurve_NIST_P224 */ @@ -116,7 +266,7 @@ static const ECCurveParams *ecCurve_map[] = { NULL, /* ECCurve_WTLS_1 */ NULL, /* ECCurve_WTLS_8 */ NULL, /* ECCurve_WTLS_9 */ - &ecCurve25519, /* ECCurve25519 */ + &ecCurve_25519, /* ECCurve25519 */ NULL /* ECCurve_pastLastCurve */ }; diff --git a/nss/lib/freebl/ecl/ecl-priv.h b/nss/lib/freebl/ecl/ecl-priv.h index f43f193..2168559 100644 --- a/nss/lib/freebl/ecl/ecl-priv.h +++ b/nss/lib/freebl/ecl/ecl-priv.h @@ -246,12 +246,5 @@ mp_err ec_group_set_gf2m233(ECGroup *group, ECCurveName name); /* Optimized point multiplication */ mp_err ec_group_set_gfp256_32(ECGroup *group, ECCurveName name); -/* Optimized floating-point arithmetic */ -#ifdef ECL_USE_FP -mp_err ec_group_set_secp160r1_fp(ECGroup *group); -mp_err ec_group_set_nistp192_fp(ECGroup *group); -mp_err ec_group_set_nistp224_fp(ECGroup *group); -#endif - SECStatus ec_Curve25519_mul(PRUint8 *q, const PRUint8 *s, const PRUint8 *p); #endif /* __ecl_priv_h_ */ diff --git a/nss/lib/freebl/ecl/ecl.c b/nss/lib/freebl/ecl/ecl.c index 3540af7..ca87b49 100644 --- a/nss/lib/freebl/ecl/ecl.c +++ b/nss/lib/freebl/ecl/ecl.c @@ -2,11 +2,16 @@ * 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/. */ +#ifdef FREEBL_NO_DEPEND +#include "../stubs.h" +#endif + #include "mpi.h" #include "mplogic.h" #include "ecl.h" #include "ecl-priv.h" #include "ecp.h" +#include "ecl-curve.h" #include <stdlib.h> #include <string.h> @@ -128,37 +133,16 @@ CLEANUP: return group; } -/* Construct ECGroup from hex parameters and name, if any. Called by - * ECGroup_fromHex and ECGroup_fromName. */ +/* Construct an ECGroup. */ ECGroup * -ecgroup_fromNameAndHex(const ECCurveName name, - const ECCurveParams *params) +construct_ecgroup(const ECCurveName name, mp_int irr, mp_int curvea, + mp_int curveb, mp_int genx, mp_int geny, mp_int order, + int cofactor, ECField field, const char *text) { - mp_int irr, curvea, curveb, genx, geny, order; int bits; ECGroup *group = NULL; mp_err res = MP_OKAY; - /* initialize values */ - MP_DIGITS(&irr) = 0; - MP_DIGITS(&curvea) = 0; - MP_DIGITS(&curveb) = 0; - MP_DIGITS(&genx) = 0; - MP_DIGITS(&geny) = 0; - MP_DIGITS(&order) = 0; - MP_CHECKOK(mp_init(&irr)); - MP_CHECKOK(mp_init(&curvea)); - MP_CHECKOK(mp_init(&curveb)); - MP_CHECKOK(mp_init(&genx)); - MP_CHECKOK(mp_init(&geny)); - MP_CHECKOK(mp_init(&order)); - MP_CHECKOK(mp_read_radix(&irr, params->irr, 16)); - MP_CHECKOK(mp_read_radix(&curvea, params->curvea, 16)); - MP_CHECKOK(mp_read_radix(&curveb, params->curveb, 16)); - MP_CHECKOK(mp_read_radix(&genx, params->genx, 16)); - MP_CHECKOK(mp_read_radix(&geny, params->geny, 16)); - MP_CHECKOK(mp_read_radix(&order, params->order, 16)); - /* determine number of bits */ bits = mpl_significant_bits(&irr) - 1; if (bits < MP_OKAY) { @@ -167,12 +151,12 @@ ecgroup_fromNameAndHex(const ECCurveName name, } /* determine which optimizations (if any) to use */ - if (params->field == ECField_GFp) { + if (field == ECField_GFp) { switch (name) { case ECCurve_SECG_PRIME_256R1: group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, - &order, params->cofactor); + &order, cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; @@ -183,7 +167,7 @@ ecgroup_fromNameAndHex(const ECCurveName name, case ECCurve_SECG_PRIME_521R1: group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, - &order, params->cofactor); + &order, cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; @@ -194,7 +178,7 @@ ecgroup_fromNameAndHex(const ECCurveName name, /* use generic arithmetic */ group = ECGroup_consGFp_mont(&irr, &curvea, &curveb, &genx, &geny, - &order, params->cofactor); + &order, cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; @@ -206,62 +190,95 @@ ecgroup_fromNameAndHex(const ECCurveName name, } /* set name, if any */ - if ((group != NULL) && (params->text != NULL)) { - group->text = strdup(params->text); + if ((group != NULL) && (text != NULL)) { + group->text = strdup(text); if (group->text == NULL) { res = MP_MEM; } } CLEANUP: + if (group && res != MP_OKAY) { + ECGroup_free(group); + return NULL; + } + return group; +} + +/* Construct ECGroup from parameters and name, if any. */ +ECGroup * +ecgroup_fromName(const ECCurveName name, + const ECCurveBytes *params) +{ + mp_int irr, curvea, curveb, genx, geny, order; + ECGroup *group = NULL; + mp_err res = MP_OKAY; + + /* initialize values */ + MP_DIGITS(&irr) = 0; + MP_DIGITS(&curvea) = 0; + MP_DIGITS(&curveb) = 0; + MP_DIGITS(&genx) = 0; + MP_DIGITS(&geny) = 0; + MP_DIGITS(&order) = 0; + MP_CHECKOK(mp_init(&irr)); + MP_CHECKOK(mp_init(&curvea)); + MP_CHECKOK(mp_init(&curveb)); + MP_CHECKOK(mp_init(&genx)); + MP_CHECKOK(mp_init(&geny)); + MP_CHECKOK(mp_init(&order)); + MP_CHECKOK(mp_read_unsigned_octets(&irr, params->irr, params->scalarSize)); + MP_CHECKOK(mp_read_unsigned_octets(&curvea, params->curvea, params->scalarSize)); + MP_CHECKOK(mp_read_unsigned_octets(&curveb, params->curveb, params->scalarSize)); + MP_CHECKOK(mp_read_unsigned_octets(&genx, params->genx, params->scalarSize)); + MP_CHECKOK(mp_read_unsigned_octets(&geny, params->geny, params->scalarSize)); + MP_CHECKOK(mp_read_unsigned_octets(&order, params->order, params->scalarSize)); + + group = construct_ecgroup(name, irr, curvea, curveb, genx, geny, order, + params->cofactor, params->field, params->text); + +CLEANUP: mp_clear(&irr); mp_clear(&curvea); mp_clear(&curveb); mp_clear(&genx); mp_clear(&geny); mp_clear(&order); - if (res != MP_OKAY) { + if (group && res != MP_OKAY) { ECGroup_free(group); return NULL; } return group; } -/* Construct ECGroup from hexadecimal representations of parameters. */ -ECGroup * -ECGroup_fromHex(const ECCurveParams *params) +/* Construct ECCurveBytes from an ECCurveName */ +const ECCurveBytes * +ec_GetNamedCurveParams(const ECCurveName name) { - return ecgroup_fromNameAndHex(ECCurve_noName, params); + if ((name <= ECCurve_noName) || (ECCurve_pastLastCurve <= name) || + (ecCurve_map[name] == NULL)) { + return NULL; + } else { + return ecCurve_map[name]; + } } /* Construct ECGroup from named parameters. */ ECGroup * ECGroup_fromName(const ECCurveName name) { - ECGroup *group = NULL; - ECCurveParams *params = NULL; - mp_err res = MP_OKAY; + const ECCurveBytes *params = NULL; - params = EC_GetNamedCurveParams(name); + /* This doesn't work with Curve25519 but it's not necessary to. */ + PORT_Assert(name != ECCurve25519); + + params = ec_GetNamedCurveParams(name); if (params == NULL) { - res = MP_UNDEF; - goto CLEANUP; + return NULL; } /* construct actual group */ - group = ecgroup_fromNameAndHex(name, params); - if (group == NULL) { - res = MP_UNDEF; - goto CLEANUP; - } - -CLEANUP: - EC_FreeCurveParams(params); - if (res != MP_OKAY) { - ECGroup_free(group); - return NULL; - } - return group; + return ecgroup_fromName(name, params); } /* Validates an EC public key as described in Section 5.2.2 of X9.62. */ diff --git a/nss/lib/freebl/ecl/ecl.h b/nss/lib/freebl/ecl/ecl.h index ddcbb1f..f6d5bc4 100644 --- a/nss/lib/freebl/ecl/ecl.h +++ b/nss/lib/freebl/ecl/ecl.h @@ -11,28 +11,17 @@ #include "blapi.h" #include "ecl-exp.h" #include "mpi.h" +#include "eclt.h" struct ECGroupStr; typedef struct ECGroupStr ECGroup; -/* Construct ECGroup from hexadecimal representations of parameters. */ -ECGroup *ECGroup_fromHex(const ECCurveParams *params); - /* Construct ECGroup from named parameters. */ ECGroup *ECGroup_fromName(const ECCurveName name); /* Free an allocated ECGroup. */ void ECGroup_free(ECGroup *group); -/* Construct ECCurveParams from an ECCurveName */ -ECCurveParams *EC_GetNamedCurveParams(const ECCurveName name); - -/* Duplicates an ECCurveParams */ -ECCurveParams *ECCurveParams_dup(const ECCurveParams *params); - -/* Free an allocated ECCurveParams */ -void EC_FreeCurveParams(ECCurveParams *params); - /* Elliptic curve scalar-point multiplication. Computes Q(x, y) = k * P(x, * y). If x, y = NULL, then P is assumed to be the generator (base point) * of the group of points on the elliptic curve. Input and output values diff --git a/nss/lib/freebl/ecl/ecl_curve.c b/nss/lib/freebl/ecl/ecl_curve.c deleted file mode 100644 index cf090cf..0000000 --- a/nss/lib/freebl/ecl/ecl_curve.c +++ /dev/null @@ -1,93 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "ecl.h" -#include "ecl-curve.h" -#include "ecl-priv.h" -#include <stdlib.h> -#include <string.h> - -#define CHECK(func) \ - if ((func) == NULL) { \ - res = 0; \ - goto CLEANUP; \ - } - -/* Duplicates an ECCurveParams */ -ECCurveParams * -ECCurveParams_dup(const ECCurveParams *params) -{ - int res = 1; - ECCurveParams *ret = NULL; - - CHECK(ret = (ECCurveParams *)calloc(1, sizeof(ECCurveParams))); - if (params->text != NULL) { - CHECK(ret->text = strdup(params->text)); - } - ret->field = params->field; - ret->size = params->size; - if (params->irr != NULL) { - CHECK(ret->irr = strdup(params->irr)); - } - if (params->curvea != NULL) { - CHECK(ret->curvea = strdup(params->curvea)); - } - if (params->curveb != NULL) { - CHECK(ret->curveb = strdup(params->curveb)); - } - if (params->genx != NULL) { - CHECK(ret->genx = strdup(params->genx)); - } - if (params->geny != NULL) { - CHECK(ret->geny = strdup(params->geny)); - } - if (params->order != NULL) { - CHECK(ret->order = strdup(params->order)); - } - ret->cofactor = params->cofactor; - -CLEANUP: - if (res != 1) { - EC_FreeCurveParams(ret); - return NULL; - } - return ret; -} - -#undef CHECK - -/* Construct ECCurveParams from an ECCurveName */ -ECCurveParams * -EC_GetNamedCurveParams(const ECCurveName name) -{ - if ((name <= ECCurve_noName) || (ECCurve_pastLastCurve <= name) || - (ecCurve_map[name] == NULL)) { - return NULL; - } else { - return ECCurveParams_dup(ecCurve_map[name]); - } -} - -/* Free the memory allocated (if any) to an ECCurveParams object. */ -void -EC_FreeCurveParams(ECCurveParams *params) -{ - if (params == NULL) - return; - if (params->text != NULL) - free(params->text); - if (params->irr != NULL) - free(params->irr); - if (params->curvea != NULL) - free(params->curvea); - if (params->curveb != NULL) - free(params->curveb); - if (params->genx != NULL) - free(params->genx); - if (params->geny != NULL) - free(params->geny); - if (params->order != NULL) - free(params->order); - free(params); -} diff --git a/nss/lib/freebl/ecl/eclt.h b/nss/lib/freebl/ecl/eclt.h new file mode 100644 index 0000000..e763706 --- /dev/null +++ b/nss/lib/freebl/ecl/eclt.h @@ -0,0 +1,30 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* This header holds ECC types and must not be exported publicly. */ + +#ifndef __eclt_h_ +#define __eclt_h_ + +/* byte encoding of curve parameters */ +struct ECCurveBytesStr { + char *text; + ECField field; + size_t size; + const PRUint8 *irr; + const PRUint8 *curvea; + const PRUint8 *curveb; + const PRUint8 *genx; + const PRUint8 *geny; + const PRUint8 *order; + const PRUint8 *base; + int cofactor; + int security; + size_t pointSize; + size_t scalarSize; + unsigned int usage; +}; +typedef struct ECCurveBytesStr ECCurveBytes; + +#endif /* __ecl_h_ */ diff --git a/nss/lib/freebl/ecl/ecp_25519.c b/nss/lib/freebl/ecl/ecp_25519.c index a8d4152..1e7875f 100644 --- a/nss/lib/freebl/ecl/ecp_25519.c +++ b/nss/lib/freebl/ecl/ecp_25519.c @@ -79,8 +79,7 @@ ec_Curve25519_pt_validate(const SECItem *px) 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, }; - /* The point must not be longer than 32 (it can be smaller). */ - if (px->len <= 32) { + if (px->len == 32) { p = px->data; } else { return SECFailure; diff --git a/nss/lib/freebl/ecl/ecp_jm.c b/nss/lib/freebl/ecl/ecp_jm.c index a1106ce..bd13fa0 100644 --- a/nss/lib/freebl/ecl/ecp_jm.c +++ b/nss/lib/freebl/ecl/ecp_jm.c @@ -127,6 +127,17 @@ ec_GFp_pt_add_jm_aff(const mp_int *px, const mp_int *py, const mp_int *pz, MP_CHECKOK(group->meth->field_mul(A, qx, A, group->meth)); MP_CHECKOK(group->meth->field_mul(B, qy, B, group->meth)); + /* Check P == Q */ + if (mp_cmp(A, px) == 0) { + if (mp_cmp(B, py) == 0) { + /* If Px == Qx && Py == Qy, double P. */ + return ec_GFp_pt_dbl_jm(px, py, pz, paz4, rx, ry, rz, raz4, + scratch, group); + } + /* If Px == Qx && Py != Qy, return point at infinity. */ + return ec_GFp_pt_set_inf_jac(rx, ry, rz); + } + /* C = A - px, D = B - py */ MP_CHECKOK(group->meth->field_sub(A, px, C, group->meth)); MP_CHECKOK(group->meth->field_sub(B, py, D, group->meth)); diff --git a/nss/lib/freebl/ecl/tests/ec_naft.c b/nss/lib/freebl/ecl/tests/ec_naft.c deleted file mode 100644 index 61ef15c..0000000 --- a/nss/lib/freebl/ecl/tests/ec_naft.c +++ /dev/null @@ -1,121 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mpi.h" -#include "mplogic.h" -#include "ecl.h" -#include "ecp.h" -#include "ecl-priv.h" - -#include <sys/types.h> -#include <stdio.h> -#include <time.h> -#include <sys/time.h> -#include <sys/resource.h> - -/* Returns 2^e as an integer. This is meant to be used for small powers of - * two. */ -int ec_twoTo(int e); - -/* Number of bits of scalar to test */ -#define BITSIZE 160 - -/* Time k repetitions of operation op. */ -#define M_TimeOperation(op, k) \ - { \ - double dStart, dNow, dUserTime; \ - struct rusage ru; \ - int i; \ - getrusage(RUSAGE_SELF, &ru); \ - dStart = (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec * 0.000001; \ - for (i = 0; i < k; i++) { \ - { \ - op; \ - } \ - }; \ - getrusage(RUSAGE_SELF, &ru); \ - dNow = (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec * 0.000001; \ - dUserTime = dNow - dStart; \ - if (dUserTime) \ - printf(" %-45s\n k: %6i, t: %6.2f sec\n", #op, k, dUserTime); \ - } - -/* Tests wNAF computation. Non-adjacent-form is discussed in the paper: D. - * Hankerson, J. Hernandez and A. Menezes, "Software implementation of - * elliptic curve cryptography over binary fields", Proc. CHES 2000. */ - -mp_err -main(void) -{ - signed char naf[BITSIZE + 1]; - ECGroup *group = NULL; - mp_int k; - mp_int *scalar; - int i, count; - int res; - int w = 5; - char s[1000]; - - /* Get a 160 bit scalar to compute wNAF from */ - group = ECGroup_fromName(ECCurve_SECG_PRIME_160R1); - scalar = &group->genx; - - /* Compute wNAF representation of scalar */ - ec_compute_wNAF(naf, BITSIZE, scalar, w); - - /* Verify correctness of representation */ - mp_init(&k); /* init k to 0 */ - - for (i = BITSIZE; i >= 0; i--) { - mp_add(&k, &k, &k); - /* digits in mp_???_d are unsigned */ - if (naf[i] >= 0) { - mp_add_d(&k, naf[i], &k); - } else { - mp_sub_d(&k, -naf[i], &k); - } - } - - if (mp_cmp(&k, scalar) != 0) { - printf("Error: incorrect NAF value.\n"); - MP_CHECKOK(mp_toradix(&k, s, 16)); - printf("NAF value %s\n", s); - MP_CHECKOK(mp_toradix(scalar, s, 16)); - printf("original value %s\n", s); - goto CLEANUP; - } - - /* Verify digits of representation are valid */ - for (i = 0; i <= BITSIZE; i++) { - if (naf[i] % 2 == 0 && naf[i] != 0) { - printf("Error: Even non-zero digit found.\n"); - goto CLEANUP; - } - if (naf[i] < -(ec_twoTo(w - 1)) || naf[i] >= ec_twoTo(w - 1)) { - printf("Error: Magnitude of naf digit too large.\n"); - goto CLEANUP; - } - } - - /* Verify sparsity of representation */ - count = w - 1; - for (i = 0; i <= BITSIZE; i++) { - if (naf[i] != 0) { - if (count < w - 1) { - printf("Error: Sparsity failed.\n"); - goto CLEANUP; - } - count = 0; - } else - count++; - } - - /* Check timing */ - M_TimeOperation(ec_compute_wNAF(naf, BITSIZE, scalar, w), 10000); - - printf("Test passed.\n"); -CLEANUP: - ECGroup_free(group); - return MP_OKAY; -} diff --git a/nss/lib/freebl/ecl/tests/ecp_test.c b/nss/lib/freebl/ecl/tests/ecp_test.c deleted file mode 100644 index dcec4d7..0000000 --- a/nss/lib/freebl/ecl/tests/ecp_test.c +++ /dev/null @@ -1,409 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mpi.h" -#include "mplogic.h" -#include "mpprime.h" -#include "ecl.h" -#include "ecl-curve.h" -#include "ecp.h" -#include <stdio.h> -#include <strings.h> -#include <assert.h> - -#include <time.h> -#include <sys/time.h> -#include <sys/resource.h> - -/* Time k repetitions of operation op. */ -#define M_TimeOperation(op, k) \ - { \ - double dStart, dNow, dUserTime; \ - struct rusage ru; \ - int i; \ - getrusage(RUSAGE_SELF, &ru); \ - dStart = (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec * 0.000001; \ - for (i = 0; i < k; i++) { \ - { \ - op; \ - } \ - }; \ - getrusage(RUSAGE_SELF, &ru); \ - dNow = (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec * 0.000001; \ - dUserTime = dNow - dStart; \ - if (dUserTime) \ - printf(" %-45s k: %6i, t: %6.2f sec\n", #op, k, dUserTime); \ - } - -/* Test curve using generic field arithmetic. */ -#define ECTEST_GENERIC_GFP(name_c, name) \ - printf("Testing %s using generic implementation...\n", name_c); \ - params = EC_GetNamedCurveParams(name); \ - if (params == NULL) { \ - printf(" Error: could not construct params.\n"); \ - res = MP_NO; \ - goto CLEANUP; \ - } \ - ECGroup_free(group); \ - group = ECGroup_fromHex(params); \ - if (group == NULL) { \ - printf(" Error: could not construct group.\n"); \ - res = MP_NO; \ - goto CLEANUP; \ - } \ - MP_CHECKOK(ectest_curve_GFp(group, ectestPrint, ectestTime, 1)); \ - printf("... okay.\n"); - -/* Test curve using specific field arithmetic. */ -#define ECTEST_NAMED_GFP(name_c, name) \ - printf("Testing %s using specific implementation...\n", name_c); \ - ECGroup_free(group); \ - group = ECGroup_fromName(name); \ - if (group == NULL) { \ - printf(" Warning: could not construct group.\n"); \ - printf("... failed; continuing with remaining tests.\n"); \ - } else { \ - MP_CHECKOK(ectest_curve_GFp(group, ectestPrint, ectestTime, 0)); \ - printf("... okay.\n"); \ - } - -/* Performs basic tests of elliptic curve cryptography over prime fields. - * If tests fail, then it prints an error message, aborts, and returns an - * error code. Otherwise, returns 0. */ -int -ectest_curve_GFp(ECGroup *group, int ectestPrint, int ectestTime, - int generic) -{ - - mp_int one, order_1, gx, gy, rx, ry, n; - int size; - mp_err res; - char s[1000]; - - /* initialize values */ - MP_CHECKOK(mp_init(&one)); - MP_CHECKOK(mp_init(&order_1)); - MP_CHECKOK(mp_init(&gx)); - MP_CHECKOK(mp_init(&gy)); - MP_CHECKOK(mp_init(&rx)); - MP_CHECKOK(mp_init(&ry)); - MP_CHECKOK(mp_init(&n)); - - MP_CHECKOK(mp_set_int(&one, 1)); - MP_CHECKOK(mp_sub(&group->order, &one, &order_1)); - - /* encode base point */ - if (group->meth->field_dec) { - MP_CHECKOK(group->meth->field_dec(&group->genx, &gx, group->meth)); - MP_CHECKOK(group->meth->field_dec(&group->geny, &gy, group->meth)); - } else { - MP_CHECKOK(mp_copy(&group->genx, &gx)); - MP_CHECKOK(mp_copy(&group->geny, &gy)); - } - if (ectestPrint) { - /* output base point */ - printf(" base point P:\n"); - MP_CHECKOK(mp_toradix(&gx, s, 16)); - printf(" %s\n", s); - MP_CHECKOK(mp_toradix(&gy, s, 16)); - printf(" %s\n", s); - if (group->meth->field_enc) { - printf(" base point P (encoded):\n"); - MP_CHECKOK(mp_toradix(&group->genx, s, 16)); - printf(" %s\n", s); - MP_CHECKOK(mp_toradix(&group->geny, s, 16)); - printf(" %s\n", s); - } - } - -#ifdef ECL_ENABLE_GFP_PT_MUL_AFF - /* multiply base point by order - 1 and check for negative of base - * point */ - MP_CHECKOK(ec_GFp_pt_mul_aff(&order_1, &group->genx, &group->geny, &rx, &ry, group)); - if (ectestPrint) { - printf(" (order-1)*P (affine):\n"); - MP_CHECKOK(mp_toradix(&rx, s, 16)); - printf(" %s\n", s); - MP_CHECKOK(mp_toradix(&ry, s, 16)); - printf(" %s\n", s); - } - MP_CHECKOK(group->meth->field_neg(&ry, &ry, group->meth)); - if ((mp_cmp(&rx, &group->genx) != 0) || (mp_cmp(&ry, &group->geny) != 0)) { - printf(" Error: invalid result (expected (- base point)).\n"); - res = MP_NO; - goto CLEANUP; - } -#endif - -#ifdef ECL_ENABLE_GFP_PT_MUL_AFF - /* multiply base point by order - 1 and check for negative of base - * point */ - MP_CHECKOK(ec_GFp_pt_mul_jac(&order_1, &group->genx, &group->geny, &rx, &ry, group)); - if (ectestPrint) { - printf(" (order-1)*P (jacobian):\n"); - MP_CHECKOK(mp_toradix(&rx, s, 16)); - printf(" %s\n", s); - MP_CHECKOK(mp_toradix(&ry, s, 16)); - printf(" %s\n", s); - } - MP_CHECKOK(group->meth->field_neg(&ry, &ry, group->meth)); - if ((mp_cmp(&rx, &group->genx) != 0) || (mp_cmp(&ry, &group->geny) != 0)) { - printf(" Error: invalid result (expected (- base point)).\n"); - res = MP_NO; - goto CLEANUP; - } -#endif - - /* multiply base point by order - 1 and check for negative of base - * point */ - MP_CHECKOK(ECPoint_mul(group, &order_1, NULL, NULL, &rx, &ry)); - if (ectestPrint) { - printf(" (order-1)*P (ECPoint_mul):\n"); - MP_CHECKOK(mp_toradix(&rx, s, 16)); - printf(" %s\n", s); - MP_CHECKOK(mp_toradix(&ry, s, 16)); - printf(" %s\n", s); - } - MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry)); - if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) { - printf(" Error: invalid result (expected (- base point)).\n"); - res = MP_NO; - goto CLEANUP; - } - - /* multiply base point by order - 1 and check for negative of base - * point */ - MP_CHECKOK(ECPoint_mul(group, &order_1, &gx, &gy, &rx, &ry)); - if (ectestPrint) { - printf(" (order-1)*P (ECPoint_mul):\n"); - MP_CHECKOK(mp_toradix(&rx, s, 16)); - printf(" %s\n", s); - MP_CHECKOK(mp_toradix(&ry, s, 16)); - printf(" %s\n", s); - } - MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry)); - if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) { - printf(" Error: invalid result (expected (- base point)).\n"); - res = MP_NO; - goto CLEANUP; - } - -#ifdef ECL_ENABLE_GFP_PT_MUL_AFF - /* multiply base point by order and check for point at infinity */ - MP_CHECKOK(ec_GFp_pt_mul_aff(&group->order, &group->genx, &group->geny, &rx, &ry, - group)); - if (ectestPrint) { - printf(" (order)*P (affine):\n"); - MP_CHECKOK(mp_toradix(&rx, s, 16)); - printf(" %s\n", s); - MP_CHECKOK(mp_toradix(&ry, s, 16)); - printf(" %s\n", s); - } - if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) { - printf(" Error: invalid result (expected point at infinity).\n"); - res = MP_NO; - goto CLEANUP; - } -#endif - -#ifdef ECL_ENABLE_GFP_PT_MUL_JAC - /* multiply base point by order and check for point at infinity */ - MP_CHECKOK(ec_GFp_pt_mul_jac(&group->order, &group->genx, &group->geny, &rx, &ry, - group)); - if (ectestPrint) { - printf(" (order)*P (jacobian):\n"); - MP_CHECKOK(mp_toradix(&rx, s, 16)); - printf(" %s\n", s); - MP_CHECKOK(mp_toradix(&ry, s, 16)); - printf(" %s\n", s); - } - if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) { - printf(" Error: invalid result (expected point at infinity).\n"); - res = MP_NO; - goto CLEANUP; - } -#endif - - /* multiply base point by order and check for point at infinity */ - MP_CHECKOK(ECPoint_mul(group, &group->order, NULL, NULL, &rx, &ry)); - if (ectestPrint) { - printf(" (order)*P (ECPoint_mul):\n"); - MP_CHECKOK(mp_toradix(&rx, s, 16)); - printf(" %s\n", s); - MP_CHECKOK(mp_toradix(&ry, s, 16)); - printf(" %s\n", s); - } - if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) { - printf(" Error: invalid result (expected point at infinity).\n"); - res = MP_NO; - goto CLEANUP; - } - - /* multiply base point by order and check for point at infinity */ - MP_CHECKOK(ECPoint_mul(group, &group->order, &gx, &gy, &rx, &ry)); - if (ectestPrint) { - printf(" (order)*P (ECPoint_mul):\n"); - MP_CHECKOK(mp_toradix(&rx, s, 16)); - printf(" %s\n", s); - MP_CHECKOK(mp_toradix(&ry, s, 16)); - printf(" %s\n", s); - } - if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) { - printf(" Error: invalid result (expected point at infinity).\n"); - res = MP_NO; - goto CLEANUP; - } - - /* check that (order-1)P + (order-1)P + P == (order-1)P */ - MP_CHECKOK(ECPoints_mul(group, &order_1, &order_1, &gx, &gy, &rx, &ry)); - MP_CHECKOK(ECPoints_mul(group, &one, &one, &rx, &ry, &rx, &ry)); - if (ectestPrint) { - printf(" (order-1)*P + (order-1)*P + P == (order-1)*P (ECPoints_mul):\n"); - MP_CHECKOK(mp_toradix(&rx, s, 16)); - printf(" %s\n", s); - MP_CHECKOK(mp_toradix(&ry, s, 16)); - printf(" %s\n", s); - } - MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry)); - if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) { - printf(" Error: invalid result (expected (- base point)).\n"); - res = MP_NO; - goto CLEANUP; - } - - /* test validate_point function */ - if (ECPoint_validate(group, &gx, &gy) != MP_YES) { - printf(" Error: validate point on base point failed.\n"); - res = MP_NO; - goto CLEANUP; - } - MP_CHECKOK(mp_add_d(&gy, 1, &ry)); - if (ECPoint_validate(group, &gx, &ry) != MP_NO) { - printf(" Error: validate point on invalid point passed.\n"); - res = MP_NO; - goto CLEANUP; - } - - if (ectestTime) { - /* compute random scalar */ - size = mpl_significant_bits(&group->meth->irr); - if (size < MP_OKAY) { - goto CLEANUP; - } - MP_CHECKOK(mpp_random_size(&n, (size + ECL_BITS - 1) / ECL_BITS)); - MP_CHECKOK(group->meth->field_mod(&n, &n, group->meth)); - /* timed test */ - if (generic) { -#ifdef ECL_ENABLE_GFP_PT_MUL_AFF - M_TimeOperation(MP_CHECKOK(ec_GFp_pt_mul_aff(&n, &group->genx, &group->geny, &rx, &ry, - group)), - 100); -#endif - M_TimeOperation(MP_CHECKOK(ECPoint_mul(group, &n, NULL, NULL, &rx, &ry)), - 100); - M_TimeOperation(MP_CHECKOK(ECPoints_mul(group, &n, &n, &gx, &gy, &rx, &ry)), 100); - } else { - M_TimeOperation(MP_CHECKOK(ECPoint_mul(group, &n, NULL, NULL, &rx, &ry)), - 100); - M_TimeOperation(MP_CHECKOK(ECPoint_mul(group, &n, &gx, &gy, &rx, &ry)), - 100); - M_TimeOperation(MP_CHECKOK(ECPoints_mul(group, &n, &n, &gx, &gy, &rx, &ry)), 100); - } - } - -CLEANUP: - mp_clear(&one); - mp_clear(&order_1); - mp_clear(&gx); - mp_clear(&gy); - mp_clear(&rx); - mp_clear(&ry); - mp_clear(&n); - if (res != MP_OKAY) { - printf(" Error: exiting with error value %i\n", res); - } - return res; -} - -/* Prints help information. */ -void -printUsage() -{ - printf("Usage: ecp_test [--print] [--time]\n"); - printf(" --print Print out results of each point arithmetic test.\n"); - printf(" --time Benchmark point operations and print results.\n"); -} - -/* Performs tests of elliptic curve cryptography over prime fields If - * tests fail, then it prints an error message, aborts, and returns an - * error code. Otherwise, returns 0. */ -int -main(int argv, char **argc) -{ - - int ectestTime = 0; - int ectestPrint = 0; - int i; - ECGroup *group = NULL; - ECCurveParams *params = NULL; - mp_err res; - - /* read command-line arguments */ - for (i = 1; i < argv; i++) { - if ((strcasecmp(argc[i], "time") == 0) || (strcasecmp(argc[i], "-time") == 0) || (strcasecmp(argc[i], "--time") == 0)) { - ectestTime = 1; - } else if ((strcasecmp(argc[i], "print") == 0) || (strcasecmp(argc[i], "-print") == 0) || (strcasecmp(argc[i], "--print") == 0)) { - ectestPrint = 1; - } else { - printUsage(); - return 0; - } - } - - /* generic arithmetic tests */ - ECTEST_GENERIC_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1); - - /* specific arithmetic tests */ - ECTEST_NAMED_GFP("NIST-P192", ECCurve_NIST_P192); - ECTEST_NAMED_GFP("NIST-P224", ECCurve_NIST_P224); - ECTEST_NAMED_GFP("NIST-P256", ECCurve_NIST_P256); - ECTEST_NAMED_GFP("NIST-P384", ECCurve_NIST_P384); - ECTEST_NAMED_GFP("NIST-P521", ECCurve_NIST_P521); - ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v1", ECCurve_X9_62_PRIME_192V1); - ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v2", ECCurve_X9_62_PRIME_192V2); - ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v3", ECCurve_X9_62_PRIME_192V3); - ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v1", ECCurve_X9_62_PRIME_239V1); - ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v2", ECCurve_X9_62_PRIME_239V2); - ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v3", ECCurve_X9_62_PRIME_239V3); - ECTEST_NAMED_GFP("ANSI X9.62 PRIME256v1", ECCurve_X9_62_PRIME_256V1); - ECTEST_NAMED_GFP("SECP-112R1", ECCurve_SECG_PRIME_112R1); - ECTEST_NAMED_GFP("SECP-112R2", ECCurve_SECG_PRIME_112R2); - ECTEST_NAMED_GFP("SECP-128R1", ECCurve_SECG_PRIME_128R1); - ECTEST_NAMED_GFP("SECP-128R2", ECCurve_SECG_PRIME_128R2); - ECTEST_NAMED_GFP("SECP-160K1", ECCurve_SECG_PRIME_160K1); - ECTEST_NAMED_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1); - ECTEST_NAMED_GFP("SECP-160R2", ECCurve_SECG_PRIME_160R2); - ECTEST_NAMED_GFP("SECP-192K1", ECCurve_SECG_PRIME_192K1); - ECTEST_NAMED_GFP("SECP-192R1", ECCurve_SECG_PRIME_192R1); - ECTEST_NAMED_GFP("SECP-224K1", ECCurve_SECG_PRIME_224K1); - ECTEST_NAMED_GFP("SECP-224R1", ECCurve_SECG_PRIME_224R1); - ECTEST_NAMED_GFP("SECP-256K1", ECCurve_SECG_PRIME_256K1); - ECTEST_NAMED_GFP("SECP-256R1", ECCurve_SECG_PRIME_256R1); - ECTEST_NAMED_GFP("SECP-384R1", ECCurve_SECG_PRIME_384R1); - ECTEST_NAMED_GFP("SECP-521R1", ECCurve_SECG_PRIME_521R1); - ECTEST_NAMED_GFP("WTLS-6 (112)", ECCurve_WTLS_6); - ECTEST_NAMED_GFP("WTLS-7 (160)", ECCurve_WTLS_7); - ECTEST_NAMED_GFP("WTLS-8 (112)", ECCurve_WTLS_8); - ECTEST_NAMED_GFP("WTLS-9 (160)", ECCurve_WTLS_9); - ECTEST_NAMED_GFP("WTLS-12 (224)", ECCurve_WTLS_12); - ECTEST_NAMED_GFP("Curve25519", ECCurve25519); - -CLEANUP: - EC_FreeCurveParams(params); - ECGroup_free(group); - if (res != MP_OKAY) { - printf("Error: exiting with error value %i\n", res); - } - return res; -} diff --git a/nss/lib/freebl/ecl/uint128.c b/nss/lib/freebl/ecl/uint128.c index 22cbd02..5465875 100644 --- a/nss/lib/freebl/ecl/uint128.c +++ b/nss/lib/freebl/ecl/uint128.c @@ -31,6 +31,9 @@ init128x(uint64_t x) return ret; } +#define CONSTANT_TIME_CARRY(a, b) \ + ((a ^ ((a ^ b) | ((a - b) ^ b))) >> (sizeof(a) * 8 - 1)) + /* arithmetic */ uint128_t @@ -38,7 +41,7 @@ add128(uint128_t a, uint128_t b) { uint128_t ret; ret.lo = a.lo + b.lo; - ret.hi = a.hi + b.hi + (ret.lo < b.lo); + ret.hi = a.hi + b.hi + CONSTANT_TIME_CARRY(ret.lo, b.lo); return ret; } diff --git a/nss/lib/freebl/exports.gyp b/nss/lib/freebl/exports.gyp index ef81685..aded6bf 100644 --- a/nss/lib/freebl/exports.gyp +++ b/nss/lib/freebl/exports.gyp @@ -33,6 +33,7 @@ 'ec.h', 'ecl/ecl-curve.h', 'ecl/ecl.h', + 'ecl/eclt.h', 'hmacct.h', 'secmpi.h', 'secrng.h' diff --git a/nss/lib/freebl/freebl.gyp b/nss/lib/freebl/freebl.gyp index f5ae232..f754742 100644 --- a/nss/lib/freebl/freebl.gyp +++ b/nss/lib/freebl/freebl.gyp @@ -32,121 +32,55 @@ '<(DEPTH)/exports.gyp:nss_exports' ] }, + # For test builds, build a static freebl library so we can statically + # link it into the test build binary. This way we don't have to + # dlopen() the shared lib but can directly call freebl functions. { - 'target_name': '<(freebl_name)', - 'type': 'shared_library', - 'sources': [ - 'aeskeywrap.c', - 'alg2268.c', - 'alghmac.c', - 'arcfive.c', - 'arcfour.c', - 'camellia.c', - 'chacha20poly1305.c', - 'ctr.c', - 'cts.c', - 'des.c', - 'desblapi.c', - 'dh.c', - 'drbg.c', - 'dsa.c', - 'ec.c', - 'ecdecode.c', - 'ecl/ec_naf.c', - 'ecl/ecl.c', - 'ecl/ecl_curve.c', - 'ecl/ecl_gf.c', - 'ecl/ecl_mult.c', - 'ecl/ecp_25519.c', - 'ecl/ecp_256.c', - 'ecl/ecp_256_32.c', - 'ecl/ecp_384.c', - 'ecl/ecp_521.c', - 'ecl/ecp_aff.c', - 'ecl/ecp_jac.c', - 'ecl/ecp_jm.c', - 'ecl/ecp_mont.c', - 'fipsfreebl.c', - 'freeblver.c', - 'gcm.c', - 'hmacct.c', - 'jpake.c', - 'ldvector.c', - 'md2.c', - 'md5.c', - 'mpi/mp_gf2m.c', - 'mpi/mpcpucache.c', - 'mpi/mpi.c', - 'mpi/mplogic.c', - 'mpi/mpmontg.c', - 'mpi/mpprime.c', - 'pqg.c', - 'rawhash.c', - 'rijndael.c', - 'rsa.c', - 'rsapkcs.c', - 'seed.c', - 'sha512.c', - 'sha_fast.c', - 'shvfy.c', - 'sysrand.c', - 'tlsprfalg.c' + 'target_name': 'freebl_static', + 'type': 'static_library', + 'includes': [ + 'freebl_base.gypi', + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', ], 'conditions': [ [ 'OS=="linux"', { - 'sources': [ - 'nsslowhash.c', - 'stubs.c', + 'defines!': [ + 'FREEBL_NO_DEPEND', + 'FREEBL_LOWHASH', + 'USE_HW_AES', + 'INTEL_GCM', ], 'conditions': [ - [ 'test_build==1', { - 'dependencies': [ - '<(DEPTH)/lib/util/util.gyp:nssutil3', - ], - }], [ 'target_arch=="x64"', { - 'sources': [ - 'arcfour-amd64-gas.s', + # The AES assembler code doesn't work in static test builds. + # The linker complains about non-relocatable code, and I + # currently don't know how to fix this properly. + 'sources!': [ 'intel-aes.s', 'intel-gcm.s', - 'mpi/mpi_amd64.c', - 'mpi/mpi_amd64_gas.s', - 'mpi/mp_comba.c', - ], - 'dependencies': [ - 'intel-gcm-wrap_c_lib', - ], - 'conditions': [ - [ 'cc_is_clang==1', { - 'cflags': [ - '-no-integrated-as', - ], - 'cflags_mozilla': [ - '-no-integrated-as', - ], - 'asflags_mozilla': [ - '-no-integrated-as', - ], - }], - ], - }], - [ 'target_arch=="ia32"', { - 'sources': [ - 'mpi/mpi_x86.s', - ], - }], - [ 'target_arch=="arm"', { - 'sources': [ - 'mpi/mpi_arm.c', ], }], ], - }, { - # not Linux + }], + ], + }, + { + 'target_name': '<(freebl_name)', + 'type': 'shared_library', + 'includes': [ + 'freebl_base.gypi', + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', + ], + 'conditions': [ + [ 'OS!="linux" and OS!="android"', { 'conditions': [ [ 'moz_fold_libs==0', { 'dependencies': [ - '../util/util.gyp:nssutil3', + '<(DEPTH)/lib/util/util.gyp:nssutil3', ], }, { 'libraries': [ @@ -154,97 +88,23 @@ ], }], ], - }], - [ 'OS=="win"', { - 'sources': [ - #TODO: building with mingw should not need this. - 'ecl/uint128.c', - #TODO: clang-cl needs -msse3 here - 'intel-gcm-wrap.c', - ], - 'libraries': [ - 'advapi32.lib', - ], - 'conditions': [ - [ 'target_arch=="x64"', { - 'sources': [ - 'arcfour-amd64-masm.asm', - 'mpi/mpi_amd64.c', - 'mpi/mpi_amd64_masm.asm', - 'mpi/mp_comba_amd64_masm.asm', - 'intel-aes-x64-masm.asm', - 'intel-gcm-x64-masm.asm', - ], - }, { - # not x64 - 'sources': [ - 'mpi/mpi_x86_asm.c', - 'intel-aes-x86-masm.asm', - 'intel-gcm-x86-masm.asm', - ], - }], - ], - }], - ['target_arch=="ia32" or target_arch=="x64"', { - 'sources': [ - # All intel architectures get the 64 bit version - 'ecl/curve25519_64.c', - ], - }, { - 'sources': [ - # All non intel architectures get the generic 32 bit implementation (slow!) - 'ecl/curve25519_32.c', + }, 'target_arch=="x64"', { + 'dependencies': [ + 'intel-gcm-wrap_c_lib', ], }], - #TODO uint128.c - [ 'disable_chachapoly==0', { - 'conditions': [ - [ 'OS!="win" and target_arch=="x64"', { - 'sources': [ - 'chacha20_vec.c', - 'poly1305-donna-x64-sse2-incremental-source.c', - ], - }, { - # not x64 - 'sources': [ - 'chacha20.c', - 'poly1305.c', - ], - }], + [ 'OS=="win" and cc_is_clang==1', { + 'dependencies': [ + 'intel-gcm-wrap_c_lib', ], }], - [ 'fuzz==1', { + [ 'OS=="linux"', { 'sources': [ - 'det_rng.c', - ], - 'defines': [ - 'UNSAFE_FUZZER_MODE', - ], - }], - [ 'test_build==1', { - 'defines': [ - 'CT_VERIF', - ], - }], - [ 'OS=="mac"', { - 'conditions': [ - [ 'target_arch=="ia32"', { - 'sources': [ - 'mpi/mpi_sse2.s', - ], - 'defines': [ - 'MP_USE_UINT_DIGIT', - 'MP_ASSEMBLY_MULTIPLY', - 'MP_ASSEMBLY_SQUARE', - 'MP_ASSEMBLY_DIV_2DX1D', - ], - }], + 'nsslowhash.c', + 'stubs.c', ], }], ], - 'dependencies': [ - '<(DEPTH)/exports.gyp:nss_exports', - ], 'variables': { 'conditions': [ [ 'OS=="linux"', { @@ -254,9 +114,6 @@ }], ] }, - 'ldflags': [ - '-Wl,-Bsymbolic' - ] }, ], 'conditions': [ @@ -301,8 +158,6 @@ 'VCCLCompilerTool': { #TODO: -Ox optimize flags 'PreprocessorDefinitions': [ - 'NSS_X86_OR_X64', - 'NSS_X86', 'MP_ASSEMBLY_MULTIPLY', 'MP_ASSEMBLY_SQUARE', 'MP_ASSEMBLY_DIV_2DX1D', @@ -319,9 +174,7 @@ 'VCCLCompilerTool': { #TODO: -Ox optimize flags 'PreprocessorDefinitions': [ - 'NSS_USE_64', - 'NSS_X86_OR_X64', - 'NSS_X64', + # Should be copied to mingw defines below 'MP_IS_LITTLE_ENDIAN', 'NSS_BEVAND_ARCFOUR', 'MPI_AMD64', @@ -333,13 +186,21 @@ }, }, }], + [ 'cc_use_gnu_ld==1 and OS=="win" and target_arch=="x64"', { + 'defines': [ + 'MP_IS_LITTLE_ENDIAN', + 'NSS_BEVAND_ARCFOUR', + 'MPI_AMD64', + 'MP_ASSEMBLY_MULTIPLY', + 'NSS_USE_COMBA', + 'USE_HW_AES', + 'INTEL_GCM', + ], + }], [ 'OS!="win"', { 'conditions': [ - [ 'target_arch=="x64"', { + [ 'target_arch=="x64" or target_arch=="arm64" or target_arch=="aarch64"', { 'defines': [ - 'NSS_USE_64', - 'NSS_X86_OR_X64', - 'NSS_X64', # The Makefile does version-tests on GCC, but we're not doing that here. 'HAVE_INT128_SUPPORT', ], @@ -348,24 +209,16 @@ 'ecl/uint128.c', ], }], - [ 'target_arch=="ia32"', { - 'defines': [ - 'NSS_X86_OR_X64', - 'NSS_X86', - ], - }], ], }], [ 'OS=="linux"', { 'defines': [ 'FREEBL_LOWHASH', + 'FREEBL_NO_DEPEND', ], + }], + [ 'OS=="linux" or OS=="android"', { 'conditions': [ - [ 'test_build==0', { - 'defines': [ - 'FREEBL_NO_DEPEND', - ], - }], [ 'target_arch=="x64"', { 'defines': [ 'MP_IS_LITTLE_ENDIAN', @@ -375,7 +228,7 @@ 'NSS_USE_COMBA', ], }], - [ 'target_arch=="x64" and use_msan==0', { + [ 'target_arch=="x64"', { 'defines': [ 'USE_HW_AES', 'INTEL_GCM', @@ -396,6 +249,7 @@ 'MP_ASSEMBLY_SQUARE', 'MP_USE_UINT_DIGIT', 'SHA_NO_LONG_LONG', + 'ARMHF', ], }], ], diff --git a/nss/lib/freebl/freebl_base.gypi b/nss/lib/freebl/freebl_base.gypi new file mode 100644 index 0000000..027aa27 --- /dev/null +++ b/nss/lib/freebl/freebl_base.gypi @@ -0,0 +1,201 @@ +# 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/. +{ + 'sources': [ + 'aeskeywrap.c', + 'alg2268.c', + 'alghmac.c', + 'arcfive.c', + 'arcfour.c', + 'camellia.c', + 'chacha20poly1305.c', + 'ctr.c', + 'cts.c', + 'des.c', + 'desblapi.c', + 'dh.c', + 'drbg.c', + 'dsa.c', + 'ec.c', + 'ecdecode.c', + 'ecl/ec_naf.c', + 'ecl/ecl.c', + 'ecl/ecl_gf.c', + 'ecl/ecl_mult.c', + 'ecl/ecp_25519.c', + 'ecl/ecp_256.c', + 'ecl/ecp_256_32.c', + 'ecl/ecp_384.c', + 'ecl/ecp_521.c', + 'ecl/ecp_aff.c', + 'ecl/ecp_jac.c', + 'ecl/ecp_jm.c', + 'ecl/ecp_mont.c', + 'fipsfreebl.c', + 'blinit.c', + 'freeblver.c', + 'gcm.c', + 'hmacct.c', + 'jpake.c', + 'ldvector.c', + 'md2.c', + 'md5.c', + 'mpi/mp_gf2m.c', + 'mpi/mpcpucache.c', + 'mpi/mpi.c', + 'mpi/mplogic.c', + 'mpi/mpmontg.c', + 'mpi/mpprime.c', + 'pqg.c', + 'rawhash.c', + 'rijndael.c', + 'rsa.c', + 'rsapkcs.c', + 'seed.c', + 'sha512.c', + 'sha_fast.c', + 'shvfy.c', + 'sysrand.c', + 'tlsprfalg.c' + ], + 'conditions': [ + [ 'OS=="linux" or OS=="android"', { + 'conditions': [ + [ 'target_arch=="x64"', { + 'sources': [ + 'arcfour-amd64-gas.s', + 'intel-aes.s', + 'intel-gcm.s', + 'mpi/mpi_amd64.c', + 'mpi/mpi_amd64_gas.s', + 'mpi/mp_comba.c', + ], + 'conditions': [ + [ 'cc_is_clang==1', { + 'cflags': [ + '-no-integrated-as', + ], + 'cflags_mozilla': [ + '-no-integrated-as', + ], + 'asflags_mozilla': [ + '-no-integrated-as', + ], + }], + ], + }], + [ 'target_arch=="ia32"', { + 'sources': [ + 'mpi/mpi_x86.s', + ], + }], + [ 'target_arch=="arm"', { + 'sources': [ + 'mpi/mpi_arm.c', + ], + }], + ], + }], + [ 'OS=="win"', { + 'sources': [ + #TODO: building with mingw should not need this. + 'ecl/uint128.c', + ], + 'libraries': [ + 'advapi32.lib', + ], + 'conditions': [ + [ 'cc_use_gnu_ld!=1 and target_arch=="x64"', { + 'sources': [ + 'arcfour-amd64-masm.asm', + 'mpi/mpi_amd64.c', + 'mpi/mpi_amd64_masm.asm', + 'mpi/mp_comba_amd64_masm.asm', + 'intel-aes-x64-masm.asm', + 'intel-gcm-x64-masm.asm', + ], + }], + [ 'cc_use_gnu_ld!=1 and target_arch!="x64"', { + # not x64 + 'sources': [ + 'mpi/mpi_x86_asm.c', + 'intel-aes-x86-masm.asm', + 'intel-gcm-x86-masm.asm', + ], + }], + [ 'cc_is_clang!=1', { + # MSVC + 'sources': [ + 'intel-gcm-wrap.c', + ], + }], + ], + }], + ['target_arch=="ia32" or target_arch=="x64"', { + 'sources': [ + # All intel architectures get the 64 bit version + 'ecl/curve25519_64.c', + ], + }, { + 'sources': [ + # All non intel architectures get the generic 32 bit implementation (slow!) + 'ecl/curve25519_32.c', + ], + }], + #TODO uint128.c + [ 'disable_chachapoly==0', { + 'conditions': [ + [ 'OS!="win" and target_arch=="x64"', { + 'sources': [ + 'chacha20_vec.c', + 'poly1305-donna-x64-sse2-incremental-source.c', + ], + }, { + # not x64 + 'sources': [ + 'chacha20.c', + 'poly1305.c', + ], + }], + ], + }], + [ 'fuzz==1', { + 'sources!': [ 'drbg.c' ], + 'sources': [ 'det_rng.c' ], + }], + [ 'fuzz_tls==1', { + 'defines': [ + 'UNSAFE_FUZZER_MODE', + ], + }], + [ 'ct_verif==1', { + 'defines': [ + 'CT_VERIF', + ], + }], + [ 'only_dev_random==1', { + 'defines': [ + 'SEED_ONLY_DEV_URANDOM', + ] + }], + [ 'OS=="mac"', { + 'conditions': [ + [ 'target_arch=="ia32"', { + 'sources': [ + 'mpi/mpi_sse2.s', + ], + 'defines': [ + 'MP_USE_UINT_DIGIT', + 'MP_ASSEMBLY_MULTIPLY', + 'MP_ASSEMBLY_SQUARE', + 'MP_ASSEMBLY_DIV_2DX1D', + ], + }], + ], + }], + ], + 'ldflags': [ + '-Wl,-Bsymbolic' + ], +} diff --git a/nss/lib/freebl/ldvector.c b/nss/lib/freebl/ldvector.c index fb986a6..2447a0c 100644 --- a/nss/lib/freebl/ldvector.c +++ b/nss/lib/freebl/ldvector.c @@ -294,9 +294,13 @@ static const struct FREEBLVectorStr vector = ChaCha20Poly1305_CreateContext, ChaCha20Poly1305_DestroyContext, ChaCha20Poly1305_Seal, - ChaCha20Poly1305_Open + ChaCha20Poly1305_Open, /* End of Version 3.018 */ + + EC_GetPointSize + + /* End of Version 3.019 */ }; const FREEBLVector* diff --git a/nss/lib/freebl/loader.c b/nss/lib/freebl/loader.c index 84876c1..792171b 100644 --- a/nss/lib/freebl/loader.c +++ b/nss/lib/freebl/loader.c @@ -2116,3 +2116,11 @@ ChaCha20Poly1305_Open(const ChaCha20Poly1305Context *ctx, ctx, output, outputLen, maxOutputLen, input, inputLen, nonce, nonceLen, ad, adLen); } + +int +EC_GetPointSize(const ECParams *params) +{ + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return SECFailure; + return (vector->p_EC_GetPointSize)(params); +} diff --git a/nss/lib/freebl/loader.h b/nss/lib/freebl/loader.h index ced03b5..ed392cc 100644 --- a/nss/lib/freebl/loader.h +++ b/nss/lib/freebl/loader.h @@ -10,7 +10,7 @@ #include "blapi.h" -#define FREEBL_VERSION 0x0312 +#define FREEBL_VERSION 0x0313 struct FREEBLVectorStr { @@ -732,6 +732,10 @@ struct FREEBLVectorStr { /* Version 3.018 came to here */ + int (*p_EC_GetPointSize)(const ECParams *); + + /* Version 3.019 came to here */ + /* Add new function pointers at the end of this struct and bump * FREEBL_VERSION at the beginning of this file. */ }; diff --git a/nss/lib/freebl/manifest.mn b/nss/lib/freebl/manifest.mn index 1ef9839..bf81442 100644 --- a/nss/lib/freebl/manifest.mn +++ b/nss/lib/freebl/manifest.mn @@ -94,6 +94,7 @@ PRIVATE_EXPORTS = \ ec.h \ ecl.h \ ecl-curve.h \ + eclt.h \ $(NULL) MPI_HDRS = mpi-config.h mpi.h mpi-priv.h mplogic.h mpprime.h logtab.h mp_gf2m.h @@ -102,7 +103,7 @@ MPI_SRCS = mpprime.c mpmontg.c mplogic.c mpi.c mp_gf2m.c ECL_HDRS = ecl-exp.h ecl.h ecp.h ecl-priv.h ifndef NSS_DISABLE_ECC -ECL_SRCS = ecl.c ecl_curve.c ecl_mult.c ecl_gf.c \ +ECL_SRCS = ecl.c ecl_mult.c ecl_gf.c \ ecp_aff.c ecp_jac.c ecp_mont.c \ ec_naf.c ecp_jm.c ecp_256.c ecp_384.c ecp_521.c \ ecp_256_32.c ecp_25519.c @@ -131,6 +132,7 @@ CSRCS = \ chacha20poly1305.c \ cts.c \ ctr.c \ + blinit.c \ fipsfreebl.c \ gcm.c \ hmacct.c \ diff --git a/nss/lib/freebl/mpi/README b/nss/lib/freebl/mpi/README index 475549b..f1c66df 100644 --- a/nss/lib/freebl/mpi/README +++ b/nss/lib/freebl/mpi/README @@ -503,9 +503,6 @@ MP_MODARITH - Define true to include the modular arithmetic in your application, you can set this to zero to leave out all the modular routines. -MP_NUMTH - Define true to include number theoretic functions - such as mp_gcd(), mp_lcm(), and mp_invmod(). - MP_LOGTAB - If true, the file "logtab.h" is included, which is basically a static table of base 2 logarithms. These are used to compute how big the buffers for diff --git a/nss/lib/freebl/mpi/mpi-config.h b/nss/lib/freebl/mpi/mpi-config.h index f365592..c6f72b2 100644 --- a/nss/lib/freebl/mpi/mpi-config.h +++ b/nss/lib/freebl/mpi/mpi-config.h @@ -24,10 +24,6 @@ #define MP_MODARITH 1 /* include modular arithmetic ? */ #endif -#ifndef MP_NUMTH -#define MP_NUMTH 1 /* include number theoretic functions? */ -#endif - #ifndef MP_LOGTAB #define MP_LOGTAB 1 /* use table of logs instead of log()? */ #endif diff --git a/nss/lib/freebl/mpi/mpi.c b/nss/lib/freebl/mpi/mpi.c index f6f7543..f7784c8 100644 --- a/nss/lib/freebl/mpi/mpi.c +++ b/nss/lib/freebl/mpi/mpi.c @@ -1695,7 +1695,6 @@ mp_iseven(const mp_int *a) /*------------------------------------------------------------------------*/ /* {{{ Number theoretic functions */ -#if MP_NUMTH /* {{{ mp_gcd(a, b, c) */ /* @@ -2376,7 +2375,6 @@ mp_invmod(const mp_int *a, const mp_int *m, mp_int *c) } /* end mp_invmod() */ /* }}} */ -#endif /* if MP_NUMTH */ /* }}} */ @@ -2861,6 +2859,9 @@ void s_mp_exch(mp_int *a, mp_int *b) { mp_int tmp; + if (!a || !b) { + return; + } tmp = *a; *a = *b; @@ -4088,7 +4089,7 @@ s_mpv_sqr_add_prop(const mp_digit *pa, mp_size a_len, mp_digit *ps) } #endif -#if (defined(MP_NO_MP_WORD) || defined(MP_NO_DIV_WORD)) && !defined(MP_ASSEMBLY_DIV_2DX1D) +#if !defined(MP_ASSEMBLY_DIV_2DX1D) /* ** Divide 64-bit (Nhi,Nlo) by 32-bit divisor, which must be normalized ** so its high bit is 1. This code is from NSPR. @@ -4166,11 +4167,7 @@ mp_err s_mp_div(mp_int *rem, /* i: dividend, o: remainder */ mp_int *quot) /* i: 0; o: quotient */ { mp_int part, t; -#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD) - mp_word q_msd; -#else mp_digit q_msd; -#endif mp_err res; mp_digit d; mp_digit div_msd; @@ -4215,7 +4212,7 @@ mp_err s_mp_div(mp_int *rem, /* i: dividend, o: remainder */ MP_USED(&part) = MP_USED(div); /* We have now truncated the part of the remainder to the same length as - * the divisor. If part is smaller than div, extend part by one digit. */ + * the divisor. If part is smaller than div, extend part by one digit. */ if (s_mp_cmp(&part, div) < 0) { --unusedRem; #if MP_ARGCHK == 2 @@ -4232,18 +4229,12 @@ mp_err s_mp_div(mp_int *rem, /* i: dividend, o: remainder */ div_msd = MP_DIGIT(div, MP_USED(div) - 1); if (!partExtended) { /* In this case, q_msd /= div_msd is always 1. First, since div_msd is - * normalized to have the high bit set, 2*div_msd > MP_DIGIT_MAX. Since - * we didn't extend part, q_msd >= div_msd. Therefore we know that - * div_msd <= q_msd <= MP_DIGIT_MAX < 2*div_msd. Dividing by div_msd we - * get 1 <= q_msd/div_msd < 2. So q_msd /= div_msd must be 1. */ + * normalized to have the high bit set, 2*div_msd > MP_DIGIT_MAX. Since + * we didn't extend part, q_msd >= div_msd. Therefore we know that + * div_msd <= q_msd <= MP_DIGIT_MAX < 2*div_msd. Dividing by div_msd we + * get 1 <= q_msd/div_msd < 2. So q_msd /= div_msd must be 1. */ q_msd = 1; } else { -#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD) - q_msd = (q_msd << MP_DIGIT_BIT) | MP_DIGIT(&part, MP_USED(&part) - 2); - q_msd /= div_msd; - if (q_msd == RADIX) - --q_msd; -#else if (q_msd == div_msd) { q_msd = MP_DIGIT_MAX; } else { @@ -4251,7 +4242,6 @@ mp_err s_mp_div(mp_int *rem, /* i: dividend, o: remainder */ MP_CHECKOK(s_mpv_div_2dx1d(q_msd, MP_DIGIT(&part, MP_USED(&part) - 2), div_msd, &q_msd, &r)); } -#endif } #if MP_ARGCHK == 2 assert(q_msd > 0); /* This case should never occur any more. */ @@ -4261,15 +4251,15 @@ mp_err s_mp_div(mp_int *rem, /* i: dividend, o: remainder */ /* See what that multiplies out to */ mp_copy(div, &t); - MP_CHECKOK(s_mp_mul_d(&t, (mp_digit)q_msd)); + MP_CHECKOK(s_mp_mul_d(&t, q_msd)); /* - If it's too big, back it off. We should not have to do this - more than once, or, in rare cases, twice. Knuth describes a - method by which this could be reduced to a maximum of once, but - I didn't implement that here. - * When using s_mpv_div_2dx1d, we may have to do this 3 times. - */ + If it's too big, back it off. We should not have to do this + more than once, or, in rare cases, twice. Knuth describes a + method by which this could be reduced to a maximum of once, but + I didn't implement that here. + When using s_mpv_div_2dx1d, we may have to do this 3 times. + */ for (i = 4; s_mp_cmp(&t, &part) > 0 && i > 0; --i) { --q_msd; MP_CHECKOK(s_mp_sub(&t, div)); /* t -= div */ @@ -4284,11 +4274,11 @@ mp_err s_mp_div(mp_int *rem, /* i: dividend, o: remainder */ s_mp_clamp(rem); /* - Include the digit in the quotient. We allocated enough memory - for any quotient we could ever possibly get, so we should not - have to check for failures here - */ - MP_DIGIT(quot, unusedRem) = (mp_digit)q_msd; + Include the digit in the quotient. We allocated enough memory + for any quotient we could ever possibly get, so we should not + have to check for failures here + */ + MP_DIGIT(quot, unusedRem) = q_msd; } /* Denormalize remainder */ diff --git a/nss/lib/freebl/mpi/mpi.h b/nss/lib/freebl/mpi/mpi.h index 64ffe75..97af0f0 100644 --- a/nss/lib/freebl/mpi/mpi.h +++ b/nss/lib/freebl/mpi/mpi.h @@ -225,13 +225,11 @@ int mp_isodd(const mp_int *a); int mp_iseven(const mp_int *a); /* Number theoretic */ -#if MP_NUMTH mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c); mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c); mp_err mp_xgcd(const mp_int *a, const mp_int *b, mp_int *g, mp_int *x, mp_int *y); mp_err mp_invmod(const mp_int *a, const mp_int *m, mp_int *c); mp_err mp_invmod_xgcd(const mp_int *a, const mp_int *m, mp_int *c); -#endif /* end MP_NUMTH */ /* Input and output */ #if MP_IOFUNC diff --git a/nss/lib/freebl/mpi/mpprime.c b/nss/lib/freebl/mpi/mpprime.c index 5828719..9d6232c 100644 --- a/nss/lib/freebl/mpi/mpprime.c +++ b/nss/lib/freebl/mpi/mpprime.c @@ -402,8 +402,7 @@ mpp_sieve(mp_int *trial, const mp_digit *primes, mp_size nPrimes, #define SIEVE_SIZE 32 * 1024 mp_err -mpp_make_prime(mp_int *start, mp_size nBits, mp_size strong, - unsigned long *nTries) +mpp_make_prime(mp_int *start, mp_size nBits, mp_size strong) { mp_digit np; mp_err res; @@ -548,8 +547,6 @@ mpp_make_prime(mp_int *start, mp_size nBits, mp_size strong, CLEANUP: mp_clear(&trial); mp_clear(&q); - if (nTries) - *nTries += i; if (sieve != NULL) { memset(sieve, 0, SIEVE_SIZE); free(sieve); diff --git a/nss/lib/freebl/mpi/mpprime.h b/nss/lib/freebl/mpi/mpprime.h index c47c618..acd888d 100644 --- a/nss/lib/freebl/mpi/mpprime.h +++ b/nss/lib/freebl/mpi/mpprime.h @@ -13,6 +13,8 @@ #include "mpi.h" +SEC_BEGIN_PROTOS + extern const int prime_tab_size; /* number of primes available */ extern const mp_digit prime_tab[]; @@ -32,7 +34,8 @@ mp_err mpp_fermat_list(mp_int *a, const mp_digit *primes, mp_size nPrimes); mp_err mpp_pprime(mp_int *a, int nt); mp_err mpp_sieve(mp_int *trial, const mp_digit *primes, mp_size nPrimes, unsigned char *sieve, mp_size nSieve); -mp_err mpp_make_prime(mp_int *start, mp_size nBits, mp_size strong, - unsigned long *nTries); +mp_err mpp_make_prime(mp_int *start, mp_size nBits, mp_size strong); + +SEC_END_PROTOS #endif /* end _H_MP_PRIME_ */ diff --git a/nss/lib/freebl/os2_rand.c b/nss/lib/freebl/os2_rand.c deleted file mode 100644 index 407b080..0000000 --- a/nss/lib/freebl/os2_rand.c +++ /dev/null @@ -1,334 +0,0 @@ -/* 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/. */ - -#define INCL_DOS -#define INCL_DOSERRORS -#include <os2.h> -#include "secrng.h" -#include "prerror.h" -#include <stdlib.h> -#include <time.h> -#include <stdio.h> -#include <sys/stat.h> - -static BOOL -clockTickTime(unsigned long *phigh, unsigned long *plow) -{ - APIRET rc = NO_ERROR; - QWORD qword = { 0, 0 }; - - rc = DosTmrQueryTime(&qword); - if (rc != NO_ERROR) - return FALSE; - - *phigh = qword.ulHi; - *plow = qword.ulLo; - - return TRUE; -} - -size_t -RNG_GetNoise(void *buf, size_t maxbuf) -{ - unsigned long high = 0; - unsigned long low = 0; - clock_t val = 0; - int n = 0; - int nBytes = 0; - time_t sTime; - - if (maxbuf <= 0) - return 0; - - clockTickTime(&high, &low); - - /* get the maximally changing bits first */ - nBytes = sizeof(low) > maxbuf ? maxbuf : sizeof(low); - memcpy(buf, &low, nBytes); - n += nBytes; - maxbuf -= nBytes; - - if (maxbuf <= 0) - return n; - - nBytes = sizeof(high) > maxbuf ? maxbuf : sizeof(high); - memcpy(((char *)buf) + n, &high, nBytes); - n += nBytes; - maxbuf -= nBytes; - - if (maxbuf <= 0) - return n; - - /* get the number of milliseconds that have elapsed since application started */ - val = clock(); - - nBytes = sizeof(val) > maxbuf ? maxbuf : sizeof(val); - memcpy(((char *)buf) + n, &val, nBytes); - n += nBytes; - maxbuf -= nBytes; - - if (maxbuf <= 0) - return n; - - /* get the time in seconds since midnight Jan 1, 1970 */ - time(&sTime); - nBytes = sizeof(sTime) > maxbuf ? maxbuf : sizeof(sTime); - memcpy(((char *)buf) + n, &sTime, nBytes); - n += nBytes; - - return n; -} - -static BOOL -EnumSystemFiles(void (*func)(const char *)) -{ - APIRET rc; - ULONG sysInfo = 0; - char bootLetter[2]; - char sysDir[_MAX_PATH] = ""; - char filename[_MAX_PATH]; - HDIR hdir = HDIR_CREATE; - ULONG numFiles = 1; - FILEFINDBUF3 fileBuf = { 0 }; - ULONG buflen = sizeof(FILEFINDBUF3); - - if (DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, (PVOID)&sysInfo, - sizeof(ULONG)) == NO_ERROR) { - bootLetter[0] = sysInfo + 'A' - 1; - bootLetter[1] = '\0'; - strcpy(sysDir, bootLetter); - strcpy(sysDir + 1, ":\\OS2\\"); - - strcpy(filename, sysDir); - strcat(filename, "*.*"); - } - - rc = DosFindFirst(filename, &hdir, FILE_NORMAL, &fileBuf, buflen, - &numFiles, FIL_STANDARD); - if (rc == NO_ERROR) { - do { - // pass the full pathname to the callback - sprintf(filename, "%s%s", sysDir, fileBuf.achName); - (*func)(filename); - - numFiles = 1; - rc = DosFindNext(hdir, &fileBuf, buflen, &numFiles); - if (rc != NO_ERROR && rc != ERROR_NO_MORE_FILES) - printf("DosFindNext errod code = %d\n", rc); - } while (rc == NO_ERROR); - - rc = DosFindClose(hdir); - if (rc != NO_ERROR) - printf("DosFindClose error code = %d", rc); - } else - printf("DosFindFirst error code = %d", rc); - - return TRUE; -} - -static int dwNumFiles, dwReadEvery, dwFileToRead = 0; - -static void -CountFiles(const char *file) -{ - dwNumFiles++; -} - -static void -ReadFiles(const char *file) -{ - if ((dwNumFiles % dwReadEvery) == 0) - RNG_FileForRNG(file); - - dwNumFiles++; -} - -static void -ReadSingleFile(const char *filename) -{ - unsigned char buffer[1024]; - FILE *file; - - file = fopen((char *)filename, "rb"); - if (file != NULL) { - while (fread(buffer, 1, sizeof(buffer), file) > 0) - ; - fclose(file); - } -} - -static void -ReadOneFile(const char *file) -{ - if (dwNumFiles == dwFileToRead) { - ReadSingleFile(file); - } - - dwNumFiles++; -} - -static void -ReadSystemFiles(void) -{ - // first count the number of files - dwNumFiles = 0; - if (!EnumSystemFiles(CountFiles)) - return; - - RNG_RandomUpdate(&dwNumFiles, sizeof(dwNumFiles)); - - // now read 10 files - if (dwNumFiles == 0) - return; - - dwReadEvery = dwNumFiles / 10; - if (dwReadEvery == 0) - dwReadEvery = 1; // less than 10 files - - dwNumFiles = 0; - EnumSystemFiles(ReadFiles); -} - -void -RNG_SystemInfoForRNG(void) -{ - unsigned long *plong = 0; - PTIB ptib; - PPIB ppib; - APIRET rc = NO_ERROR; - DATETIME dt; - COUNTRYCODE cc = { 0 }; - COUNTRYINFO ci = { 0 }; - unsigned long actual = 0; - char path[_MAX_PATH] = ""; - char fullpath[_MAX_PATH] = ""; - unsigned long pathlength = sizeof(path); - FSALLOCATE fsallocate; - FILESTATUS3 fstatus; - unsigned long defaultdrive = 0; - unsigned long logicaldrives = 0; - unsigned long sysInfo[QSV_MAX] = { 0 }; - char buffer[20]; - int nBytes = 0; - - nBytes = RNG_GetNoise(buffer, sizeof(buffer)); - RNG_RandomUpdate(buffer, nBytes); - - /* allocate memory and use address and memory */ - plong = (unsigned long *)malloc(sizeof(*plong)); - RNG_RandomUpdate(&plong, sizeof(plong)); - RNG_RandomUpdate(plong, sizeof(*plong)); - free(plong); - - /* process info */ - rc = DosGetInfoBlocks(&ptib, &ppib); - if (rc == NO_ERROR) { - RNG_RandomUpdate(ptib, sizeof(*ptib)); - RNG_RandomUpdate(ppib, sizeof(*ppib)); - } - - /* time */ - rc = DosGetDateTime(&dt); - if (rc == NO_ERROR) { - RNG_RandomUpdate(&dt, sizeof(dt)); - } - - /* country */ - rc = DosQueryCtryInfo(sizeof(ci), &cc, &ci, &actual); - if (rc == NO_ERROR) { - RNG_RandomUpdate(&cc, sizeof(cc)); - RNG_RandomUpdate(&ci, sizeof(ci)); - RNG_RandomUpdate(&actual, sizeof(actual)); - } - - /* current directory */ - rc = DosQueryCurrentDir(0, path, &pathlength); - strcat(fullpath, "\\"); - strcat(fullpath, path); - if (rc == NO_ERROR) { - RNG_RandomUpdate(fullpath, strlen(fullpath)); - // path info - rc = DosQueryPathInfo(fullpath, FIL_STANDARD, &fstatus, sizeof(fstatus)); - if (rc == NO_ERROR) { - RNG_RandomUpdate(&fstatus, sizeof(fstatus)); - } - } - - /* file system info */ - rc = DosQueryFSInfo(0, FSIL_ALLOC, &fsallocate, sizeof(fsallocate)); - if (rc == NO_ERROR) { - RNG_RandomUpdate(&fsallocate, sizeof(fsallocate)); - } - - /* drive info */ - rc = DosQueryCurrentDisk(&defaultdrive, &logicaldrives); - if (rc == NO_ERROR) { - RNG_RandomUpdate(&defaultdrive, sizeof(defaultdrive)); - RNG_RandomUpdate(&logicaldrives, sizeof(logicaldrives)); - } - - /* system info */ - rc = DosQuerySysInfo(1L, QSV_MAX, (PVOID)&sysInfo, sizeof(ULONG) * QSV_MAX); - if (rc == NO_ERROR) { - RNG_RandomUpdate(&sysInfo, sizeof(sysInfo)); - } - - // now let's do some files - ReadSystemFiles(); - - /* more noise */ - nBytes = RNG_GetNoise(buffer, sizeof(buffer)); - RNG_RandomUpdate(buffer, nBytes); -} - -void -RNG_FileForRNG(const char *filename) -{ - struct stat stat_buf; - unsigned char buffer[1024]; - FILE *file = 0; - int nBytes = 0; - static int totalFileBytes = 0; - - if (stat((char *)filename, &stat_buf) < 0) - return; - - RNG_RandomUpdate((unsigned char *)&stat_buf, sizeof(stat_buf)); - - file = fopen((char *)filename, "r"); - if (file != NULL) { - for (;;) { - size_t bytes = fread(buffer, 1, sizeof(buffer), file); - - if (bytes == 0) - break; - - RNG_RandomUpdate(buffer, bytes); - totalFileBytes += bytes; - if (totalFileBytes > 250000) - break; - } - fclose(file); - } - - nBytes = RNG_GetNoise(buffer, 20); - RNG_RandomUpdate(buffer, nBytes); -} - -static void -rng_systemJitter(void) -{ - dwNumFiles = 0; - EnumSystemFiles(ReadOneFile); - dwFileToRead++; - if (dwFileToRead >= dwNumFiles) { - dwFileToRead = 0; - } -} - -size_t -RNG_SystemRNG(void *dest, size_t maxLen) -{ - return rng_systemFromNoise(dest, maxLen); -} diff --git a/nss/lib/freebl/rijndael.c b/nss/lib/freebl/rijndael.c index 4bb1826..0c3ab58 100644 --- a/nss/lib/freebl/rijndael.c +++ b/nss/lib/freebl/rijndael.c @@ -26,17 +26,11 @@ #include "mpi.h" #ifdef USE_HW_AES -static int has_intel_aes = 0; static PRBool use_hw_aes = PR_FALSE; #ifdef INTEL_GCM #include "intel-gcm.h" -static int has_intel_avx = 0; -static int has_intel_clmul = 0; static PRBool use_hw_gcm = PR_FALSE; -#if defined(_MSC_VER) && !defined(_M_IX86) -#include <intrin.h> /* for _xgetbv() */ -#endif #endif #endif /* USE_HW_AES */ @@ -999,39 +993,6 @@ AES_AllocateContext(void) return PORT_ZNew(AESContext); } -#ifdef INTEL_GCM -/* - * Adapted from the example code in "How to detect New Instruction support in - * the 4th generation Intel Core processor family" by Max Locktyukhin. - * - * XGETBV: - * Reads an extended control register (XCR) specified by ECX into EDX:EAX. - */ -static PRBool -check_xcr0_ymm() -{ - PRUint32 xcr0; -#if defined(_MSC_VER) -#if defined(_M_IX86) - __asm { - mov ecx, 0 - xgetbv - mov xcr0, eax - } -#else - xcr0 = (PRUint32)_xgetbv(0); /* Requires VS2010 SP1 or later. */ -#endif -#else - __asm__("xgetbv" - : "=a"(xcr0) - : "c"(0) - : "%edx"); -#endif - /* Check if xmm and ymm state are enabled in XCR0. */ - return (xcr0 & 6) == 6; -} -#endif - /* ** Initialize a new AES context suitable for AES encryption/decryption in ** the ECB or CBC mode. @@ -1070,33 +1031,9 @@ aes_InitContext(AESContext *cx, const unsigned char *key, unsigned int keysize, return SECFailure; } #ifdef USE_HW_AES - if (has_intel_aes == 0) { - unsigned long eax, ebx, ecx, edx; - char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES"); - - if (disable_hw_aes == NULL) { - freebl_cpuid(1, &eax, &ebx, &ecx, &edx); - has_intel_aes = (ecx & (1 << 25)) != 0 ? 1 : -1; -#ifdef INTEL_GCM - has_intel_clmul = (ecx & (1 << 1)) != 0 ? 1 : -1; - if ((ecx & (1 << 27)) != 0 && (ecx & (1 << 28)) != 0 && - check_xcr0_ymm()) { - has_intel_avx = 1; - } else { - has_intel_avx = -1; - } -#endif - } else { - has_intel_aes = -1; -#ifdef INTEL_GCM - has_intel_avx = -1; - has_intel_clmul = -1; -#endif - } - } - use_hw_aes = (PRBool)(has_intel_aes > 0 && (keysize % 8) == 0 && blocksize == 16); + use_hw_aes = aesni_support() && (keysize % 8) == 0 && blocksize == 16; #ifdef INTEL_GCM - use_hw_gcm = (PRBool)(use_hw_aes && has_intel_avx > 0 && has_intel_clmul > 0); + use_hw_gcm = use_hw_aes && avx_support() && clmul_support(); #endif #endif /* USE_HW_AES */ /* Nb = (block size in bits) / 32 */ diff --git a/nss/lib/freebl/rsa.c b/nss/lib/freebl/rsa.c index ff8c40e..17d1d87 100644 --- a/nss/lib/freebl/rsa.c +++ b/nss/lib/freebl/rsa.c @@ -190,12 +190,12 @@ cleanup: } return rv; } -static SECStatus + +SECStatus generate_prime(mp_int *prime, int primeLen) { mp_err err = MP_OKAY; SECStatus rv = SECSuccess; - unsigned long counter = 0; int piter; unsigned char *pb = NULL; pb = PORT_Alloc(primeLen); @@ -208,7 +208,7 @@ generate_prime(mp_int *prime, int primeLen) pb[0] |= 0xC0; /* set two high-order bits */ pb[primeLen - 1] |= 0x01; /* set low-order bit */ CHECK_MPI_OK(mp_read_unsigned_octets(prime, pb, primeLen)); - err = mpp_make_prime(prime, primeLen * 8, PR_FALSE, &counter); + err = mpp_make_prime(prime, primeLen * 8, PR_FALSE); if (err != MP_NO) goto cleanup; /* keep going while err == MP_NO */ @@ -1236,7 +1236,10 @@ get_blinding_params(RSAPrivateKey *key, mp_int *n, unsigned int modLen, * Now, search its list of ready blinding params for a usable one. */ while (0 != (bp = rsabp->bp)) { - if (--(bp->counter) > 0) { +#ifndef UNSAFE_FUZZER_MODE + if (--(bp->counter) > 0) +#endif + { /* Found a match and there are still remaining uses left */ /* Return the parameters */ CHECK_MPI_OK(mp_copy(&bp->f, f)); @@ -1548,7 +1551,7 @@ cleanup: return rv; } -static SECStatus +SECStatus RSA_Init(void) { if (PR_CallOnce(&coBPInit, init_blinding_params_list) != PR_SUCCESS) { @@ -1558,12 +1561,6 @@ RSA_Init(void) return SECSuccess; } -SECStatus -BL_Init(void) -{ - return RSA_Init(); -} - /* cleanup at shutdown */ void RSA_Cleanup(void) diff --git a/nss/lib/freebl/rsapkcs.c b/nss/lib/freebl/rsapkcs.c index 577fe1f..c8a15da 100644 --- a/nss/lib/freebl/rsapkcs.c +++ b/nss/lib/freebl/rsapkcs.c @@ -85,6 +85,25 @@ rsa_modulusLen(SECItem *modulus) return modLen; } +static unsigned int +rsa_modulusBits(SECItem *modulus) +{ + unsigned char byteZero = modulus->data[0]; + unsigned int numBits = (modulus->len - 1) * 8; + + if (byteZero == 0) { + numBits -= 8; + byteZero = modulus->data[1]; + } + + while (byteZero > 0) { + numBits++; + byteZero >>= 1; + } + + return numBits; +} + /* * Format one block of data for public/private key encryption using * the rules defined in PKCS #1. @@ -962,12 +981,11 @@ failure: * We use mHash instead of M as input. * emBits from the RFC is just modBits - 1, see section 8.1.1. * We only support MGF1 as the MGF. - * - * NOTE: this code assumes modBits is a multiple of 8. */ static SECStatus emsa_pss_encode(unsigned char *em, unsigned int emLen, + unsigned int emBits, const unsigned char *mHash, HASH_HashType hashAlg, HASH_HashType maskHashAlg, @@ -1032,7 +1050,7 @@ emsa_pss_encode(unsigned char *em, PORT_Free(dbMask); /* Step 11 */ - em[0] &= 0x7f; + em[0] &= 0xff >> (8 * emLen - emBits); /* Step 12 */ em[emLen - 1] = 0xbc; @@ -1046,13 +1064,12 @@ emsa_pss_encode(unsigned char *em, * We use mHash instead of M as input. * emBits from the RFC is just modBits - 1, see section 8.1.2. * We only support MGF1 as the MGF. - * - * NOTE: this code assumes modBits is a multiple of 8. */ static SECStatus emsa_pss_verify(const unsigned char *mHash, const unsigned char *em, unsigned int emLen, + unsigned int emBits, HASH_HashType hashAlg, HASH_HashType maskHashAlg, unsigned int saltLen) @@ -1063,15 +1080,22 @@ emsa_pss_verify(const unsigned char *mHash, unsigned char *H_; /* H' from the RFC */ unsigned int i; unsigned int dbMaskLen; + unsigned int zeroBits; SECStatus rv; hash = HASH_GetRawHashObject(hashAlg); dbMaskLen = emLen - hash->length - 1; - /* Step 3 + 4 + 6 */ + /* Step 3 + 4 */ if ((emLen < (hash->length + saltLen + 2)) || - (em[emLen - 1] != 0xbc) || - ((em[0] & 0x80) != 0)) { + (em[emLen - 1] != 0xbc)) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + return SECFailure; + } + + /* Step 6 */ + zeroBits = 8 * emLen - emBits; + if (em[0] >> (8 - zeroBits)) { PORT_SetError(SEC_ERROR_BAD_SIGNATURE); return SECFailure; } @@ -1091,7 +1115,7 @@ emsa_pss_verify(const unsigned char *mHash, } /* Step 9 */ - db[0] &= 0x7f; + db[0] &= 0xff >> zeroBits; /* Step 10 */ for (i = 0; i < (dbMaskLen - saltLen - 1); i++) { @@ -1156,7 +1180,9 @@ RSA_SignPSS(RSAPrivateKey *key, { SECStatus rv = SECSuccess; unsigned int modulusLen = rsa_modulusLen(&key->modulus); - unsigned char *pssEncoded = NULL; + unsigned int modulusBits = rsa_modulusBits(&key->modulus); + unsigned int emLen = modulusLen; + unsigned char *pssEncoded, *em; if (maxOutputLen < modulusLen) { PORT_SetError(SEC_ERROR_OUTPUT_LEN); @@ -1168,16 +1194,24 @@ RSA_SignPSS(RSAPrivateKey *key, return SECFailure; } - pssEncoded = (unsigned char *)PORT_Alloc(modulusLen); + pssEncoded = em = (unsigned char *)PORT_Alloc(modulusLen); if (pssEncoded == NULL) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } - rv = emsa_pss_encode(pssEncoded, modulusLen, input, hashAlg, + + /* len(em) == ceil((modulusBits - 1) / 8). */ + if (modulusBits % 8 == 1) { + em[0] = 0; + emLen--; + em++; + } + rv = emsa_pss_encode(em, emLen, modulusBits - 1, input, hashAlg, maskHashAlg, salt, saltLength); if (rv != SECSuccess) goto done; + // This sets error codes upon failure. rv = RSA_PrivateKeyOpDoubleChecked(key, output, pssEncoded); *outputLen = modulusLen; @@ -1198,7 +1232,9 @@ RSA_CheckSignPSS(RSAPublicKey *key, { SECStatus rv; unsigned int modulusLen = rsa_modulusLen(&key->modulus); - unsigned char *buffer; + unsigned int modulusBits = rsa_modulusBits(&key->modulus); + unsigned int emLen = modulusLen; + unsigned char *buffer, *em; if (sigLen != modulusLen) { PORT_SetError(SEC_ERROR_BAD_SIGNATURE); @@ -1210,7 +1246,7 @@ RSA_CheckSignPSS(RSAPublicKey *key, return SECFailure; } - buffer = (unsigned char *)PORT_Alloc(modulusLen); + buffer = em = (unsigned char *)PORT_Alloc(modulusLen); if (!buffer) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; @@ -1223,14 +1259,18 @@ RSA_CheckSignPSS(RSAPublicKey *key, return SECFailure; } - rv = emsa_pss_verify(hash, buffer, modulusLen, hashAlg, + /* len(em) == ceil((modulusBits - 1) / 8). */ + if (modulusBits % 8 == 1) { + emLen--; + em++; + } + rv = emsa_pss_verify(hash, em, emLen, modulusBits - 1, hashAlg, maskHashAlg, saltLength); - PORT_Free(buffer); + PORT_Free(buffer); return rv; } -/* XXX Doesn't set error code */ SECStatus RSA_Sign(RSAPrivateKey *key, unsigned char *output, @@ -1239,34 +1279,34 @@ RSA_Sign(RSAPrivateKey *key, const unsigned char *input, unsigned int inputLen) { - SECStatus rv = SECSuccess; + SECStatus rv = SECFailure; unsigned int modulusLen = rsa_modulusLen(&key->modulus); - SECItem formatted; - SECItem unformatted; + SECItem formatted = { siBuffer, NULL, 0 }; + SECItem unformatted = { siBuffer, (unsigned char *)input, inputLen }; - if (maxOutputLen < modulusLen) - return SECFailure; + if (maxOutputLen < modulusLen) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + goto done; + } - unformatted.len = inputLen; - unformatted.data = (unsigned char *)input; - formatted.data = NULL; rv = rsa_FormatBlock(&formatted, modulusLen, RSA_BlockPrivate, &unformatted); - if (rv != SECSuccess) + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); goto done; + } + // This sets error codes upon failure. rv = RSA_PrivateKeyOpDoubleChecked(key, output, formatted.data); *outputLen = modulusLen; - goto done; - done: - if (formatted.data != NULL) + if (formatted.data != NULL) { PORT_ZFree(formatted.data, modulusLen); + } return rv; } -/* XXX Doesn't set error code */ SECStatus RSA_CheckSign(RSAPublicKey *key, const unsigned char *sig, @@ -1274,60 +1314,71 @@ RSA_CheckSign(RSAPublicKey *key, const unsigned char *data, unsigned int dataLen) { - SECStatus rv; + SECStatus rv = SECFailure; unsigned int modulusLen = rsa_modulusLen(&key->modulus); unsigned int i; - unsigned char *buffer; + unsigned char *buffer = NULL; + + if (sigLen != modulusLen) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + goto done; + } - if (sigLen != modulusLen) - goto failure; /* * 0x00 || BT || Pad || 0x00 || ActualData * * The "3" below is the first octet + the second octet + the 0x00 * octet that always comes just before the ActualData. */ - if (dataLen > modulusLen - (3 + RSA_BLOCK_MIN_PAD_LEN)) - goto failure; + if (dataLen > modulusLen - (3 + RSA_BLOCK_MIN_PAD_LEN)) { + PORT_SetError(SEC_ERROR_BAD_DATA); + goto done; + } buffer = (unsigned char *)PORT_Alloc(modulusLen + 1); - if (!buffer) - goto failure; + if (!buffer) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + goto done; + } - rv = RSA_PublicKeyOp(key, buffer, sig); - if (rv != SECSuccess) - goto loser; + if (RSA_PublicKeyOp(key, buffer, sig) != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + goto done; + } /* * check the padding that was used */ if (buffer[0] != RSA_BLOCK_FIRST_OCTET || buffer[1] != (unsigned char)RSA_BlockPrivate) { - goto loser; + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + goto done; } for (i = 2; i < modulusLen - dataLen - 1; i++) { - if (buffer[i] != RSA_BLOCK_PRIVATE_PAD_OCTET) - goto loser; + if (buffer[i] != RSA_BLOCK_PRIVATE_PAD_OCTET) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + goto done; + } + } + if (buffer[i] != RSA_BLOCK_AFTER_PAD_OCTET) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + goto done; } - if (buffer[i] != RSA_BLOCK_AFTER_PAD_OCTET) - goto loser; /* * make sure we get the same results */ - if (PORT_Memcmp(buffer + modulusLen - dataLen, data, dataLen) != 0) - goto loser; - - PORT_Free(buffer); - return SECSuccess; + if (PORT_Memcmp(buffer + modulusLen - dataLen, data, dataLen) == 0) { + rv = SECSuccess; + } -loser: - PORT_Free(buffer); -failure: - return SECFailure; +done: + if (buffer) { + PORT_Free(buffer); + } + return rv; } -/* XXX Doesn't set error code */ SECStatus RSA_CheckSignRecover(RSAPublicKey *key, unsigned char *output, @@ -1336,21 +1387,27 @@ RSA_CheckSignRecover(RSAPublicKey *key, const unsigned char *sig, unsigned int sigLen) { - SECStatus rv; + SECStatus rv = SECFailure; unsigned int modulusLen = rsa_modulusLen(&key->modulus); unsigned int i; - unsigned char *buffer; + unsigned char *buffer = NULL; - if (sigLen != modulusLen) - goto failure; + if (sigLen != modulusLen) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + goto done; + } buffer = (unsigned char *)PORT_Alloc(modulusLen + 1); - if (!buffer) - goto failure; + if (!buffer) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + goto done; + } + + if (RSA_PublicKeyOp(key, buffer, sig) != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + goto done; + } - rv = RSA_PublicKeyOp(key, buffer, sig); - if (rv != SECSuccess) - goto loser; *outputLen = 0; /* @@ -1358,28 +1415,34 @@ RSA_CheckSignRecover(RSAPublicKey *key, */ if (buffer[0] != RSA_BLOCK_FIRST_OCTET || buffer[1] != (unsigned char)RSA_BlockPrivate) { - goto loser; + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + goto done; } for (i = 2; i < modulusLen; i++) { if (buffer[i] == RSA_BLOCK_AFTER_PAD_OCTET) { *outputLen = modulusLen - i - 1; break; } - if (buffer[i] != RSA_BLOCK_PRIVATE_PAD_OCTET) - goto loser; + if (buffer[i] != RSA_BLOCK_PRIVATE_PAD_OCTET) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + goto done; + } + } + if (*outputLen == 0) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + goto done; + } + if (*outputLen > maxOutputLen) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + goto done; } - if (*outputLen == 0) - goto loser; - if (*outputLen > maxOutputLen) - goto loser; PORT_Memcpy(output, buffer + modulusLen - *outputLen, *outputLen); + rv = SECSuccess; - PORT_Free(buffer); - return SECSuccess; - -loser: - PORT_Free(buffer); -failure: - return SECFailure; +done: + if (buffer) { + PORT_Free(buffer); + } + return rv; } diff --git a/nss/lib/freebl/sysrand.c b/nss/lib/freebl/sysrand.c index 0128fa0..763f6af 100644 --- a/nss/lib/freebl/sysrand.c +++ b/nss/lib/freebl/sysrand.c @@ -8,42 +8,11 @@ #include "seccomon.h" -#ifndef XP_WIN -static size_t rng_systemFromNoise(unsigned char *dest, size_t maxLen); -#endif - -#if defined(XP_UNIX) || defined(XP_BEOS) +#if (defined(XP_UNIX) || defined(XP_BEOS)) && defined(SEED_ONLY_DEV_URANDOM) +#include "unix_urandom.c" +#elif defined(XP_UNIX) || defined(XP_BEOS) #include "unix_rand.c" #endif #ifdef XP_WIN #include "win_rand.c" #endif -#ifdef XP_OS2 -#include "os2_rand.c" -#endif - -#ifndef XP_WIN -/* - * Normal RNG_SystemRNG() isn't available, use the system noise to collect - * the required amount of entropy. - */ -static size_t -rng_systemFromNoise(unsigned char *dest, size_t maxLen) -{ - size_t retBytes = maxLen; - - while (maxLen) { - size_t nbytes = RNG_GetNoise(dest, maxLen); - - PORT_Assert(nbytes != 0); - - dest += nbytes; - maxLen -= nbytes; - - /* some hw op to try to introduce more entropy into the next - * RNG_GetNoise call */ - rng_systemJitter(); - } - return retBytes; -} -#endif diff --git a/nss/lib/freebl/unix_rand.c b/nss/lib/freebl/unix_rand.c index ea3b6af..20c76ec 100644 --- a/nss/lib/freebl/unix_rand.c +++ b/nss/lib/freebl/unix_rand.c @@ -160,7 +160,7 @@ RNG_kstat(PRUint32 *fed) #endif -#if defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(FREEBSD) || defined(NETBSD) || defined(DARWIN) || defined(OPENBSD) || defined(NTO) || defined(__riscos__) +#if defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(FREEBSD) || defined(NETBSD) || defined(DARWIN) || defined(OPENBSD) || defined(NTO) || defined(__riscos__) || defined(__GNU__) || defined(__FreeBSD_kernel__) || defined(__NetBSD_kernel__) #include <sys/times.h> #define getdtablesize() sysconf(_SC_OPEN_MAX) @@ -682,134 +682,6 @@ RNG_GetNoise(void *buf, size_t maxbytes) return n; } -#define SAFE_POPEN_MAXARGS 10 /* must be at least 2 */ - -/* - * safe_popen is static to this module and we know what arguments it is - * called with. Note that this version only supports a single open child - * process at any time. - */ -static pid_t safe_popen_pid; -static struct sigaction oldact; - -static FILE * -safe_popen(char *cmd) -{ - int p[2], fd, argc; - pid_t pid; - char *argv[SAFE_POPEN_MAXARGS + 1]; - FILE *fp; - static char blank[] = " \t"; - static struct sigaction newact; - - if (pipe(p) < 0) - return 0; - - fp = fdopen(p[0], "r"); - if (fp == 0) { - close(p[0]); - close(p[1]); - return 0; - } - - /* Setup signals so that SIGCHLD is ignored as we want to do waitpid */ - newact.sa_handler = SIG_DFL; - newact.sa_flags = 0; - sigfillset(&newact.sa_mask); - sigaction(SIGCHLD, &newact, &oldact); - - pid = fork(); - switch (pid) { - int ndesc; - - case -1: - fclose(fp); /* this closes p[0], the fd associated with fp */ - close(p[1]); - sigaction(SIGCHLD, &oldact, NULL); - return 0; - - case 0: - /* dup write-side of pipe to stderr and stdout */ - if (p[1] != 1) - dup2(p[1], 1); - if (p[1] != 2) - dup2(p[1], 2); - - /* - * close the other file descriptors, except stdin which we - * try reassociating with /dev/null, first (bug 174993) - */ - if (!freopen("/dev/null", "r", stdin)) - close(0); - ndesc = getdtablesize(); - for (fd = PR_MIN(65536, ndesc); --fd > 2; close(fd)) - ; - - /* clean up environment in the child process */ - putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc"); - putenv("SHELL=/bin/sh"); - putenv("IFS= \t"); - - /* - * The caller may have passed us a string that is in text - * space. It may be illegal to modify the string - */ - cmd = strdup(cmd); - /* format argv */ - argv[0] = strtok(cmd, blank); - argc = 1; - while ((argv[argc] = strtok(0, blank)) != 0) { - if (++argc == SAFE_POPEN_MAXARGS) { - argv[argc] = 0; - break; - } - } - - /* and away we go */ - execvp(argv[0], argv); - exit(127); - break; - - default: - close(p[1]); - break; - } - - /* non-zero means there's a cmd running */ - safe_popen_pid = pid; - return fp; -} - -static int -safe_pclose(FILE *fp) -{ - pid_t pid; - int status = -1, rv; - - if ((pid = safe_popen_pid) == 0) - return -1; - safe_popen_pid = 0; - - fclose(fp); - - /* yield the processor so the child gets some time to exit normally */ - PR_Sleep(PR_INTERVAL_NO_WAIT); - - /* if the child hasn't exited, kill it -- we're done with its output */ - while ((rv = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR) - ; - if (rv == 0) { - kill(pid, SIGKILL); - while ((rv = waitpid(pid, &status, 0)) == -1 && errno == EINTR) - ; - } - - /* Reset SIGCHLD signal hander before returning */ - sigaction(SIGCHLD, &oldact, NULL); - - return status; -} - #ifdef DARWIN #include <TargetConditionals.h> #if !TARGET_OS_IPHONE @@ -817,15 +689,9 @@ safe_pclose(FILE *fp) #endif #endif -/* Fork netstat to collect its output by default. Do not unset this unless - * another source of entropy is available - */ -#define DO_NETSTAT 1 - void RNG_SystemInfoForRNG(void) { - FILE *fp; char buf[BUFSIZ]; size_t bytes; const char *const *cp; @@ -860,12 +726,6 @@ RNG_SystemInfoForRNG(void) }; #endif -#if defined(BSDI) - static char netstat_ni_cmd[] = "netstat -nis"; -#else - static char netstat_ni_cmd[] = "netstat -ni"; -#endif - GiveSystemInfo(); bytes = RNG_GetNoise(buf, sizeof(buf)); @@ -890,10 +750,12 @@ RNG_SystemInfoForRNG(void) if (gethostname(buf, sizeof(buf)) == 0) { RNG_RandomUpdate(buf, strlen(buf)); } - GiveSystemInfo(); /* grab some data from system's PRNG before any other files. */ bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT); + if (!bytes) { + PORT_SetError(SEC_ERROR_NEED_RANDOM); + } /* If the user points us to a random file, pass it through the rng */ randfile = PR_GetEnvSecure("NSRANDFILE"); @@ -911,33 +773,12 @@ RNG_SystemInfoForRNG(void) for (cp = files; *cp; cp++) RNG_FileForRNG(*cp); -/* - * Bug 100447: On BSD/OS 4.2 and 4.3, we have problem calling safe_popen - * in a pthreads environment. Therefore, we call safe_popen last and on - * BSD/OS we do not call safe_popen when we succeeded in getting data - * from /dev/urandom. - * - * Bug 174993: On platforms providing /dev/urandom, don't fork netstat - * either, if data has been gathered successfully. - */ - #if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(DARWIN) || defined(LINUX) || defined(HPUX) if (bytes) return; #endif #ifdef SOLARIS - -/* - * On Solaris, NSS may be initialized automatically from libldap in - * applications that are unaware of the use of NSS. safe_popen forks, and - * sometimes creates issues with some applications' pthread_atfork handlers. - * We always have /dev/urandom on Solaris 9 and above as an entropy source, - * and for Solaris 8 we have the libkstat interface, so we don't need to - * fork netstat. - */ - -#undef DO_NETSTAT if (!bytes) { /* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */ PRUint32 kstat_bytes = 0; @@ -948,15 +789,6 @@ RNG_SystemInfoForRNG(void) PORT_Assert(bytes); } #endif - -#ifdef DO_NETSTAT - fp = safe_popen(netstat_ni_cmd); - if (fp != NULL) { - while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0) - RNG_RandomUpdate(buf, bytes); - safe_pclose(fp); - } -#endif } #define TOTAL_FILE_LIMIT 1000000 /* one million */ @@ -1022,20 +854,6 @@ RNG_FileForRNG(const char *fileName) RNG_FileUpdate(fileName, TOTAL_FILE_LIMIT); } -void -ReadSingleFile(const char *fileName) -{ - FILE *file; - unsigned char buffer[BUFSIZ]; - - file = fopen(fileName, "rb"); - if (file != NULL) { - while (fread(buffer, 1, sizeof(buffer), file) > 0) - ; - fclose(file); - } -} - #define _POSIX_PTHREAD_SEMANTICS #include <dirent.h> @@ -1055,89 +873,6 @@ ReadFileOK(char *dir, char *file) return S_ISREG(stat_buf.st_mode) ? PR_TRUE : PR_FALSE; } -/* - * read one file out of either /etc or the user's home directory. - * fileToRead tells which file to read. - * - * return 1 if it's time to reset the fileToRead (no more files to read). - */ -static int -ReadOneFile(int fileToRead) -{ - char *dir = "/etc"; - DIR *fd = opendir(dir); - int resetCount = 0; - struct dirent *entry; -#if defined(__sun) - char firstName[256]; -#else - char firstName[NAME_MAX + 1]; -#endif - const char *name = NULL; - int i; - - if (fd == NULL) { - dir = PR_GetEnvSecure("HOME"); - if (dir) { - fd = opendir(dir); - } - } - if (fd == NULL) { - return 1; - } - - firstName[0] = '\0'; - for (i = 0; i <= fileToRead; i++) { - do { - /* readdir() isn't guaranteed to be thread safe on every platform; - * this code assumes the same directory isn't read concurrently. - * This usage is confirmed safe on Linux, see bug 1254334. */ - entry = readdir(fd); - } while (entry != NULL && !ReadFileOK(dir, &entry->d_name[0])); - if (entry == NULL) { - resetCount = 1; /* read to the end, start again at the beginning */ - if (firstName[0]) { - /* ran out of entries in the directory, use the first one */ - name = firstName; - } - break; - } - name = entry->d_name; - if (i == 0) { - /* copy the name of the first in case we run out of entries */ - PORT_Assert(PORT_Strlen(name) < sizeof(firstName)); - PORT_Strncpy(firstName, name, sizeof(firstName) - 1); - firstName[sizeof(firstName) - 1] = '\0'; - } - } - - if (name) { - char filename[PATH_MAX]; - int count = snprintf(filename, sizeof(filename), "%s/%s", dir, name); - if (count >= 1) { - ReadSingleFile(filename); - } - } - - closedir(fd); - return resetCount; -} - -/* - * do something to try to introduce more noise into the 'GetNoise' call - */ -static void -rng_systemJitter(void) -{ - static int fileToRead = 1; - - if (ReadOneFile(fileToRead)) { - fileToRead = 1; - } else { - fileToRead++; - } -} - size_t RNG_SystemRNG(void *dest, size_t maxLen) { @@ -1149,7 +884,8 @@ RNG_SystemRNG(void *dest, size_t maxLen) file = fopen("/dev/urandom", "r"); if (file == NULL) { - return rng_systemFromNoise(dest, maxLen); + PORT_SetError(SEC_ERROR_NEED_RANDOM); + return 0; } /* Read from the underlying file descriptor directly to bypass stdio * buffering and avoid reading more bytes than we need from /dev/urandom. diff --git a/nss/lib/freebl/unix_urandom.c b/nss/lib/freebl/unix_urandom.c new file mode 100644 index 0000000..25e6ad9 --- /dev/null +++ b/nss/lib/freebl/unix_urandom.c @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <fcntl.h> +#include <unistd.h> +#include "secerr.h" +#include "secrng.h" +#include "prprf.h" + +void +RNG_SystemInfoForRNG(void) +{ + PRUint8 bytes[SYSTEM_RNG_SEED_COUNT]; + size_t numBytes = RNG_SystemRNG(bytes, SYSTEM_RNG_SEED_COUNT); + if (!numBytes) { + /* error is set */ + return; + } + RNG_RandomUpdate(bytes, numBytes); +} + +size_t +RNG_SystemRNG(void *dest, size_t maxLen) +{ + int fd; + int bytes; + size_t fileBytes = 0; + unsigned char *buffer = dest; + + fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + PORT_SetError(SEC_ERROR_NEED_RANDOM); + return 0; + } + while (fileBytes < maxLen) { + bytes = read(fd, buffer, maxLen - fileBytes); + if (bytes <= 0) { + break; + } + fileBytes += bytes; + buffer += bytes; + } + (void)close(fd); + if (fileBytes != maxLen) { + PORT_SetError(SEC_ERROR_NEED_RANDOM); + return 0; + } + return fileBytes; +} |