Commit 81d1998e authored by Geoff Thorpe's avatar Geoff Thorpe
Browse files

Currently, RSA code, when using no padding scheme, simply checks that input

does not contain more bytes than the RSA modulus 'n' - it does not check
that the input is strictly *less* than 'n'. Whether this should be the
case or not is open to debate - however, due to security problems with
returning miscalculated CRT results, the 'rsa_mod_exp' implementation in
rsa_eay.c now performs a public-key exponentiation to verify the CRT result
and in the event of an error will instead recalculate and return a non-CRT
(more expensive) mod_exp calculation. As the mod_exp of 'I' is equivalent
to the mod_exp of 'I mod n', and the verify result is automatically between
0 and n-1 inclusive, the verify only matches the input if 'I' was less than
'n', otherwise even a correct CRT calculation is only congruent to 'I' (ie.
they differ by a multiple of 'n'). Rather than rejecting correct
calculations and doing redundant and slower ones instead, this changes the
equality check in the verification code to a congruence check.
parent 6b46ca13
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -545,11 +545,20 @@ static int RSA_eay_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa)
	if (rsa->e && rsa->n)
		{
		if (!meth->bn_mod_exp(&vrfy,r0,rsa->e,rsa->n,ctx,NULL)) goto err;
		if (BN_cmp(I, &vrfy) != 0)
			{
		/* If 'I' was greater than (or equal to) rsa->n, the operation
		 * will be equivalent to using 'I mod n'. However, the result of
		 * the verify will *always* be less than 'n' so we don't check
		 * for absolute equality, just congruency. */
		if (!BN_sub(&vrfy, &vrfy, I)) goto err;
		if (!BN_mod(&vrfy, &vrfy, rsa->n, ctx)) goto err;
		if (vrfy.neg)
			if (!BN_add(&vrfy, &vrfy, rsa->n)) goto err;
		if (!BN_is_zero(&vrfy))
			/* 'I' and 'vrfy' aren't congruent mod n. Don't leak
			 * miscalculated CRT output, just do a raw (slower)
			 * mod_exp and return that instead. */
			if (!meth->bn_mod_exp(r0,I,rsa->d,rsa->n,ctx,NULL)) goto err;
		}
		}
	ret=1;
err:
	BN_clear_free(&m1);