diff options
Diffstat (limited to 'security/nss/lib/freebl')
-rw-r--r-- | security/nss/lib/freebl/blapi.h | 15 | ||||
-rw-r--r-- | security/nss/lib/freebl/blapi_bsf.c | 22 | ||||
-rw-r--r-- | security/nss/lib/freebl/ldvector.c | 4 | ||||
-rw-r--r-- | security/nss/lib/freebl/loader.c | 20 | ||||
-rw-r--r-- | security/nss/lib/freebl/loader.h | 11 | ||||
-rw-r--r-- | security/nss/lib/freebl/mpi/montmulf.c | 2 | ||||
-rw-r--r-- | security/nss/lib/freebl/mpi/montmulfv8.s | 14 | ||||
-rw-r--r-- | security/nss/lib/freebl/mpi/montmulfv9.s | 6 | ||||
-rw-r--r-- | security/nss/lib/freebl/prng_fips1861.c | 5 | ||||
-rw-r--r-- | security/nss/lib/freebl/rsa.c | 204 |
10 files changed, 270 insertions, 33 deletions
diff --git a/security/nss/lib/freebl/blapi.h b/security/nss/lib/freebl/blapi.h index 2bd4c3274..4449dc66f 100644 --- a/security/nss/lib/freebl/blapi.h +++ b/security/nss/lib/freebl/blapi.h @@ -77,6 +77,19 @@ extern SECStatus RSA_PrivateKeyOp(RSAPrivateKey * key, unsigned char * output, const unsigned char * input); +/* +** Perform a raw private-key operation, and check the parameters used in +** the operation for validity by performing a test operation first. +** Length of input and output buffers are equal to key's modulus len. +*/ +extern SECStatus RSA_PrivateKeyOpDoubleChecked(RSAPrivateKey * key, + unsigned char * output, + const unsigned char * input); + +/* +** Perform a check of private key parameters for consistency. +*/ +extern SECStatus RSA_PrivateKeyCheck(RSAPrivateKey *key); /******************************************************************** @@ -712,7 +725,7 @@ extern SECStatus RNG_RNGInit(void); ** Update the global random number generator with more seeding ** material */ -extern SECStatus RNG_RandomUpdate(void *data, size_t bytes); +extern SECStatus RNG_RandomUpdate(const void *data, size_t bytes); /* ** Generate some random bytes, using the global random number generator diff --git a/security/nss/lib/freebl/blapi_bsf.c b/security/nss/lib/freebl/blapi_bsf.c index 28e6fc705..37caf4b20 100644 --- a/security/nss/lib/freebl/blapi_bsf.c +++ b/security/nss/lib/freebl/blapi_bsf.c @@ -1508,6 +1508,26 @@ loser: return SECFailure; } +/* + * this should check the operation!!!! + */ +SECStatus +RSA_PrivateKeyOpDoubleChecked(RSAPrivateKey *key, + unsigned char *output, + const unsigned char *input) +{ + return RSA_PrivateKeyOp(key, output, input); +} + +/* + * this should check the key!!! + */ +SECStatus +RSA_PrivateKeyCheck(RSAPrivateKey *key) +{ + return SECSuccess; +} + /***************************************************************************** ** BLAPI implementation of DSA ******************************************************************************/ @@ -2044,7 +2064,7 @@ RNG_RNGInit(void) } SECStatus -RNG_RandomUpdate(void *data, size_t bytes) +RNG_RandomUpdate(const void *data, size_t bytes) { int status; if (data == NULL || bytes <= 0) { diff --git a/security/nss/lib/freebl/ldvector.c b/security/nss/lib/freebl/ldvector.c index 249985f61..0345b8dd5 100644 --- a/security/nss/lib/freebl/ldvector.c +++ b/security/nss/lib/freebl/ldvector.c @@ -112,7 +112,9 @@ static const struct FREEBLVectorStr vector = { RNG_RNGShutdown, PQG_ParamGen, PQG_ParamGenSeedLen, - PQG_VerifyParams + PQG_VerifyParams, + RSA_PrivateKeyOpDoubleChecked, + RSA_PrivateKeyCheck, }; diff --git a/security/nss/lib/freebl/loader.c b/security/nss/lib/freebl/loader.c index 333d4748f..564b14ee7 100644 --- a/security/nss/lib/freebl/loader.c +++ b/security/nss/lib/freebl/loader.c @@ -322,6 +322,24 @@ RSA_PrivateKeyOp(RSAPrivateKey * key, return (vector->p_RSA_PrivateKeyOp)(key, output, input); } +SECStatus +RSA_PrivateKeyOpDoubleChecked(RSAPrivateKey *key, + unsigned char *output, + const unsigned char *input) +{ + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return SECFailure; + return (vector->p_RSA_PrivateKeyOpDoubleChecked)(key, output, input); +} + +SECStatus +RSA_PrivateKeyCheck(RSAPrivateKey *key) +{ + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return SECFailure; + return (vector->p_RSA_PrivateKeyCheck)(key); +} + SECStatus DSA_NewKey(const PQGParams * params, DSAPrivateKey ** privKey) { @@ -866,7 +884,7 @@ RNG_RNGInit(void) } SECStatus -RNG_RandomUpdate(void *data, size_t bytes) +RNG_RandomUpdate(const void *data, size_t bytes) { if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) return SECFailure; diff --git a/security/nss/lib/freebl/loader.h b/security/nss/lib/freebl/loader.h index 0d62b5708..b4ce4c0ec 100644 --- a/security/nss/lib/freebl/loader.h +++ b/security/nss/lib/freebl/loader.h @@ -40,7 +40,7 @@ #include "blapi.h" -#define FREEBL_VERSION 0x0301 +#define FREEBL_VERSION 0x0302 struct FREEBLVectorStr { @@ -235,7 +235,7 @@ struct FREEBLVectorStr { SECStatus (* p_RNG_RNGInit)(void); - SECStatus (* p_RNG_RandomUpdate)(void *data, size_t bytes); + SECStatus (* p_RNG_RandomUpdate)(const void *data, size_t bytes); SECStatus (* p_RNG_GenerateGlobalRandomBytes)(void *dest, size_t len); @@ -249,6 +249,13 @@ struct FREEBLVectorStr { SECStatus (* p_PQG_VerifyParams)(const PQGParams *params, const PQGVerify *vfy, SECStatus *result); + + SECStatus (* p_RSA_PrivateKeyOpDoubleChecked)(RSAPrivateKey *key, + unsigned char *output, + const unsigned char *input); + + SECStatus (* p_RSA_PrivateKeyCheck)(RSAPrivateKey *key); + }; typedef struct FREEBLVectorStr FREEBLVector; diff --git a/security/nss/lib/freebl/mpi/montmulf.c b/security/nss/lib/freebl/mpi/montmulf.c index 0cdacce88..2cf0825f8 100644 --- a/security/nss/lib/freebl/mpi/montmulf.c +++ b/security/nss/lib/freebl/mpi/montmulf.c @@ -196,7 +196,7 @@ int i; if(i32[len]>0) i=-1; else { - for(i=len-1; i>=0; i++) + for(i=len-1; i>=0; i--) { if(i32[i]!=nint[i]) break; } diff --git a/security/nss/lib/freebl/mpi/montmulfv8.s b/security/nss/lib/freebl/mpi/montmulfv8.s index 39568d98b..f6b90dfd8 100644 --- a/security/nss/lib/freebl/mpi/montmulfv8.s +++ b/security/nss/lib/freebl/mpi/montmulfv8.s @@ -836,7 +836,7 @@ TwoToMinus32: ! 191 ! else ! 192 ! { -! 193 ! for(i=len-1; i>=0; i++) +! 193 ! for(i=len-1; i>=0; i--) /* 0x0024 193 */ sub %o2,1,%g4 /* 0x0028 */ sll %g4,2,%g1 @@ -852,9 +852,9 @@ TwoToMinus32: /* 0x0040 193 */ add %o0,%g1,%g3 .L900000510: /* 0x0044 195 */ ld [%g3],%o2 -/* 0x0048 */ add %g4,1,%g1 -/* 0x004c */ add %g2,4,%g2 -/* 0x0050 */ add %g3,4,%g3 +/* 0x0048 */ sub %g4,1,%g1 +/* 0x004c */ sub %g2,4,%g2 +/* 0x0050 */ sub %g3,4,%g3 /* 0x0054 */ cmp %o2,%o5 /* 0x0058 */ bne,pn %icc,.L77000182 /* 0x005c */ nop @@ -1758,9 +1758,9 @@ TwoToMinus32: /* 0x0a14 */ ld [%o1],%g2 .L900000648: /* 0x0a18 */ ld [%o4],%g3 -/* 0x0a1c */ add %o5,1,%o0 -/* 0x0a20 */ add %o1,4,%o1 -/* 0x0a24 */ add %o4,4,%o4 +/* 0x0a1c */ sub %o5,1,%o0 +/* 0x0a20 */ sub %o1,4,%o1 +/* 0x0a24 */ sub %o4,4,%o4 /* 0x0a28 */ cmp %g3,%g2 /* 0x0a2c */ bne,pn %icc,.L77000244 /* 0x0a30 */ nop diff --git a/security/nss/lib/freebl/mpi/montmulfv9.s b/security/nss/lib/freebl/mpi/montmulfv9.s index a1ff27044..3a0a17f7e 100644 --- a/security/nss/lib/freebl/mpi/montmulfv9.s +++ b/security/nss/lib/freebl/mpi/montmulfv9.s @@ -1164,7 +1164,7 @@ TwoToMinus32: ! 191 ! else ! 192 ! { -! 193 ! for(i=len-1; i>=0; i++) +! 193 ! for(i=len-1; i>=0; i--) /* 0x0030 193 */ sub %o1,1,%o2 /* 0x0034 */ cmp %o2,0 @@ -1176,7 +1176,7 @@ TwoToMinus32: ! 195 ! if(i32[i]!=nint[i]) break; /* 0x0040 195 */ sllx %g2,2,%g2 -/* 0x0044 */ add %o2,1,%o0 +/* 0x0044 */ sub %o2,1,%o0 /* 0x0048 */ ld [%i1+%g2],%g3 /* 0x004c */ ld [%i2+%g2],%g2 /* 0x0050 */ cmp %g2,%g3 @@ -2240,7 +2240,7 @@ TwoToMinus32: /* 0x0bcc */ sra %o1,0,%g2 .L900000645: /* 0x0bd0 */ sllx %g2,2,%g2 -/* 0x0bd4 */ add %o1,1,%o0 +/* 0x0bd4 */ sub %o1,1,%o0 /* 0x0bd8 */ ld [%l3+%g2],%g3 /* 0x0bdc */ ld [%l2+%g2],%g2 /* 0x0be0 */ cmp %g2,%g3 diff --git a/security/nss/lib/freebl/prng_fips1861.c b/security/nss/lib/freebl/prng_fips1861.c index c11fdff22..2359913fd 100644 --- a/security/nss/lib/freebl/prng_fips1861.c +++ b/security/nss/lib/freebl/prng_fips1861.c @@ -271,7 +271,8 @@ RNG_RNGInit(void) ** material */ SECStatus -prng_RandomUpdate(RNGContext *rng, void *data, size_t bytes, unsigned char *q) +prng_RandomUpdate(RNGContext *rng, + const void *data, size_t bytes, unsigned char *q) { SECStatus rv = SECSuccess; unsigned char inputhash[BSIZE]; @@ -343,7 +344,7 @@ prng_RandomUpdate(RNGContext *rng, void *data, size_t bytes, unsigned char *q) ** material. Not DSA, so no q. */ SECStatus -RNG_RandomUpdate(void *data, size_t bytes) +RNG_RandomUpdate(const void *data, size_t bytes) { return prng_RandomUpdate(globalrng, data, bytes, NULL); } diff --git a/security/nss/lib/freebl/rsa.c b/security/nss/lib/freebl/rsa.c index e91ed3c22..43d22383c 100644 --- a/security/nss/lib/freebl/rsa.c +++ b/security/nss/lib/freebl/rsa.c @@ -359,8 +359,8 @@ cleanup: ** RSA Private key operation (no CRT). */ static SECStatus -rsa_PrivateKeyOp(RSAPrivateKey *key, mp_int *m, mp_int *c, mp_int *n, - unsigned int modLen) +rsa_PrivateKeyOpNoCRT(RSAPrivateKey *key, mp_int *m, mp_int *c, mp_int *n, + unsigned int modLen) { mp_int d; mp_err err = MP_OKAY; @@ -383,11 +383,10 @@ cleanup: ** RSA Private key operation using CRT. */ static SECStatus -rsa_PrivateKeyOpCRT(RSAPrivateKey *key, mp_int *m, mp_int *c, - unsigned int modLen) +rsa_PrivateKeyOpCRTNoCheck(RSAPrivateKey *key, mp_int *m, mp_int *c) { mp_int p, q, d_p, d_q, qInv; - mp_int m1, m2, b2, h, ctmp; + mp_int m1, m2, h, ctmp; mp_err err = MP_OKAY; SECStatus rv = SECSuccess; MP_DIGITS(&p) = 0; @@ -397,7 +396,6 @@ rsa_PrivateKeyOpCRT(RSAPrivateKey *key, mp_int *m, mp_int *c, MP_DIGITS(&qInv) = 0; MP_DIGITS(&m1) = 0; MP_DIGITS(&m2) = 0; - MP_DIGITS(&b2) = 0; MP_DIGITS(&h) = 0; MP_DIGITS(&ctmp) = 0; CHECK_MPI_OK( mp_init(&p) ); @@ -407,14 +405,13 @@ rsa_PrivateKeyOpCRT(RSAPrivateKey *key, mp_int *m, mp_int *c, CHECK_MPI_OK( mp_init(&qInv) ); CHECK_MPI_OK( mp_init(&m1) ); CHECK_MPI_OK( mp_init(&m2) ); - CHECK_MPI_OK( mp_init(&b2) ); CHECK_MPI_OK( mp_init(&h) ); CHECK_MPI_OK( mp_init(&ctmp) ); /* copy private key parameters into mp integers */ SECITEM_TO_MPINT(key->prime1, &p); /* p */ SECITEM_TO_MPINT(key->prime2, &q); /* q */ SECITEM_TO_MPINT(key->exponent1, &d_p); /* d_p = d mod (p-1) */ - SECITEM_TO_MPINT(key->exponent2, &d_q); /* d_p = d mod (q-1) */ + SECITEM_TO_MPINT(key->exponent2, &d_q); /* d_q = d mod (q-1) */ SECITEM_TO_MPINT(key->coefficient, &qInv); /* qInv = q**-1 mod p */ /* 1. m1 = c**d_p mod p */ CHECK_MPI_OK( mp_mod(c, &p, &ctmp) ); @@ -436,7 +433,6 @@ cleanup: mp_clear(&qInv); mp_clear(&m1); mp_clear(&m2); - mp_clear(&b2); mp_clear(&h); mp_clear(&ctmp); if (err) { @@ -446,6 +442,46 @@ cleanup: return rv; } +/* +** An attack against RSA CRT was described by Boneh, DeMillo, and Lipton in: +** "On the Importance of Eliminating Errors in Cryptographic Computations", +** http://theory.stanford.edu/~dabo/papers/faults.ps.gz +** +** As a defense against the attack, carry out the private key operation, +** followed up with a public key operation to invert the result. +** Verify that result against the input. +*/ +static SECStatus +rsa_PrivateKeyOpCRTCheckedPubKey(RSAPrivateKey *key, mp_int *m, mp_int *c) +{ + mp_int n, e, s; + mp_err err = MP_OKAY; + SECStatus rv = SECSuccess; + MP_DIGITS(&n) = 0; + MP_DIGITS(&e) = 0; + MP_DIGITS(&s) = 0; + CHECK_MPI_OK( mp_init(&n) ); + CHECK_MPI_OK( mp_init(&e) ); + CHECK_MPI_OK( mp_init(&s) ); + CHECK_SEC_OK( rsa_PrivateKeyOpCRTNoCheck(key, m, c) ); + SECITEM_TO_MPINT(key->modulus, &n); + SECITEM_TO_MPINT(key->publicExponent, &e); + /* Perform a public key operation c = m ** e mod n */ + CHECK_MPI_OK( mp_exptmod(m, &e, &n, &s) ); + if (mp_cmp(&s, c) != 0) { + rv = SECFailure; + } +cleanup: + mp_clear(&n); + mp_clear(&e); + mp_clear(&s); + if (err) { + MP_TO_SEC_ERROR(err); + rv = SECFailure; + } + return rv; +} + static PRCallOnceType coBPInit = { 0, 0, 0 }; static PRStatus init_blinding_params_list(void) @@ -619,10 +655,11 @@ cleanup: ** Perform a raw private-key operation ** Length of input and output buffers are equal to key's modulus len. */ -SECStatus -RSA_PrivateKeyOp(RSAPrivateKey *key, +static SECStatus +rsa_PrivateKeyOp(RSAPrivateKey *key, unsigned char *output, - const unsigned char *input) + const unsigned char *input, + PRBool check) { unsigned int modLen; unsigned int offset; @@ -667,9 +704,11 @@ RSA_PrivateKeyOp(RSAPrivateKey *key, key->exponent1.len == 0 || key->exponent2.len == 0 || key->coefficient.len == 0) { - CHECK_SEC_OK( rsa_PrivateKeyOp(key, &m, &c, &n, modLen) ); + CHECK_SEC_OK( rsa_PrivateKeyOpNoCRT(key, &m, &c, &n, modLen) ); + } else if (check) { + CHECK_SEC_OK( rsa_PrivateKeyOpCRTCheckedPubKey(key, &m, &c) ); } else { - CHECK_SEC_OK( rsa_PrivateKeyOpCRT(key, &m, &c, modLen) ); + CHECK_SEC_OK( rsa_PrivateKeyOpCRTNoCheck(key, &m, &c) ); } /* If blinding, compute post-image of plaintext by multiplying by ** blinding factor @@ -692,3 +731,140 @@ cleanup: } return rv; } + +SECStatus +RSA_PrivateKeyOp(RSAPrivateKey *key, + unsigned char *output, + const unsigned char *input) +{ + return rsa_PrivateKeyOp(key, output, input, PR_FALSE); +} + +SECStatus +RSA_PrivateKeyOpDoubleChecked(RSAPrivateKey *key, + unsigned char *output, + const unsigned char *input) +{ + return rsa_PrivateKeyOp(key, output, input, PR_TRUE); +} + +SECStatus +RSA_PrivateKeyCheck(RSAPrivateKey *key) +{ + mp_int p, q, n, psub1, qsub1, e, d, d_p, d_q, qInv, res; + mp_err err = MP_OKAY; + SECStatus rv = SECSuccess; + MP_DIGITS(&n) = 0; + MP_DIGITS(&psub1)= 0; + MP_DIGITS(&qsub1)= 0; + MP_DIGITS(&e) = 0; + MP_DIGITS(&d) = 0; + MP_DIGITS(&d_p) = 0; + MP_DIGITS(&d_q) = 0; + MP_DIGITS(&qInv) = 0; + MP_DIGITS(&res) = 0; + CHECK_MPI_OK( mp_init(&n) ); + CHECK_MPI_OK( mp_init(&p) ); + CHECK_MPI_OK( mp_init(&q) ); + CHECK_MPI_OK( mp_init(&psub1)); + CHECK_MPI_OK( mp_init(&qsub1)); + CHECK_MPI_OK( mp_init(&e) ); + CHECK_MPI_OK( mp_init(&d) ); + CHECK_MPI_OK( mp_init(&d_p) ); + CHECK_MPI_OK( mp_init(&d_q) ); + CHECK_MPI_OK( mp_init(&qInv) ); + CHECK_MPI_OK( mp_init(&res) ); + SECITEM_TO_MPINT(key->modulus, &n); + SECITEM_TO_MPINT(key->prime1, &p); + SECITEM_TO_MPINT(key->prime2, &q); + SECITEM_TO_MPINT(key->publicExponent, &e); + SECITEM_TO_MPINT(key->privateExponent, &d); + SECITEM_TO_MPINT(key->exponent1, &d_p); + SECITEM_TO_MPINT(key->exponent2, &d_q); + SECITEM_TO_MPINT(key->coefficient, &qInv); + /* p > q */ + if (mp_cmp(&p, &q) <= 0) { + /* mind the p's and q's */ + SECItem tmp; + mp_exch(&p, &q); + tmp.data = key->prime1.data; + tmp.len = key->prime1.len; + key->prime1.data = key->prime2.data; + key->prime1.len = key->prime2.len; + key->prime2.data = tmp.data; + key->prime2.len = tmp.len; + } +#define VERIFY_MPI_EQUAL(m1, m2) \ + if (mp_cmp(m1, m2) != 0) { \ + rv = SECFailure; \ + goto cleanup; \ + } +#define VERIFY_MPI_EQUAL_1(m) \ + if (mp_cmp_d(m, 1) != 0) { \ + rv = SECFailure; \ + goto cleanup; \ + } + /* + * The following errors cannot be recovered from. + */ + /* n == p * q */ + CHECK_MPI_OK( mp_mul(&p, &q, &res) ); + VERIFY_MPI_EQUAL(&res, &n); + /* gcd(e, p-1) == 1 */ + CHECK_MPI_OK( mp_sub_d(&p, 1, &psub1) ); + CHECK_MPI_OK( mp_gcd(&e, &psub1, &res) ); + VERIFY_MPI_EQUAL_1(&res); + /* gcd(e, q-1) == 1 */ + CHECK_MPI_OK( mp_sub_d(&q, 1, &qsub1) ); + CHECK_MPI_OK( mp_gcd(&e, &qsub1, &res) ); + VERIFY_MPI_EQUAL_1(&res); + /* d*e == 1 mod p-1 */ + CHECK_MPI_OK( mp_mulmod(&d, &e, &psub1, &res) ); + VERIFY_MPI_EQUAL_1(&res); + /* d*e == 1 mod q-1 */ + CHECK_MPI_OK( mp_mulmod(&d, &e, &qsub1, &res) ); + VERIFY_MPI_EQUAL_1(&res); + /* + * The following errors can be recovered from. + */ + /* d_p == d mod p-1 */ + CHECK_MPI_OK( mp_mod(&d, &psub1, &res) ); + if (mp_cmp(&d_p, &res) != 0) { + /* swap in the correct value */ + SECITEM_ZfreeItem(&key->exponent1, PR_FALSE); + MPINT_TO_SECITEM(&res, &key->exponent1, key->arena); + } + /* d_q == d mod q-1 */ + CHECK_MPI_OK( mp_mod(&d, &qsub1, &res) ); + if (mp_cmp(&d_q, &res) != 0) { + /* swap in the correct value */ + SECITEM_ZfreeItem(&key->exponent2, PR_FALSE); + MPINT_TO_SECITEM(&res, &key->exponent2, key->arena); + } + /* q * q**-1 == 1 mod p */ + CHECK_MPI_OK( mp_mulmod(&q, &qInv, &p, &res) ); + if (mp_cmp_d(&res, 1) != 0) { + /* compute the correct value */ + CHECK_MPI_OK( mp_invmod(&q, &p, &qInv) ); + SECITEM_ZfreeItem(&key->coefficient, PR_FALSE); + MPINT_TO_SECITEM(&res, &key->coefficient, key->arena); + } +cleanup: + mp_clear(&n); + mp_clear(&p); + mp_clear(&q); + mp_clear(&psub1); + mp_clear(&qsub1); + mp_clear(&e); + mp_clear(&d); + mp_clear(&d_p); + mp_clear(&d_q); + mp_clear(&qInv); + mp_clear(&res); + if (err) { + MP_TO_SEC_ERROR(err); + rv = SECFailure; + } + return rv; +} + |