提交 f5ebe54c 编写于 作者: A Andy Polyakov 提交者: Matt Caswell

rsa/rsa_oaep.c: remove memcpy calls from RSA_padding_check_PKCS1_OAEP.

And make RSAErr call unconditional.
Reviewed-by: NRichard Levitte <levitte@openssl.org>
Reviewed-by: NMatt Caswell <matt@openssl.org>
(cherry picked from commit 75f5e944be97f28867e7c489823c889d89d0bd06)
上级 db1b63f4
...@@ -120,7 +120,7 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, ...@@ -120,7 +120,7 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
const EVP_MD *mgf1md) const EVP_MD *mgf1md)
{ {
int i, dblen = 0, mlen = -1, one_index = 0, msg_index; int i, dblen = 0, mlen = -1, one_index = 0, msg_index;
unsigned int good, found_one_byte; unsigned int good = 0, found_one_byte, mask;
const unsigned char *maskedseed, *maskeddb; const unsigned char *maskedseed, *maskeddb;
/* /*
* |em| is the encoded message, zero-padded to exactly |num| bytes: em = * |em| is the encoded message, zero-padded to exactly |num| bytes: em =
...@@ -147,8 +147,11 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, ...@@ -147,8 +147,11 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
* the ciphertext, see PKCS #1 v2.2, section 7.1.2. * the ciphertext, see PKCS #1 v2.2, section 7.1.2.
* This does not leak any side-channel information. * This does not leak any side-channel information.
*/ */
if (num < flen || num < 2 * mdlen + 2) if (num < flen || num < 2 * mdlen + 2) {
goto decoding_err; RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1,
RSA_R_OAEP_DECODING_ERROR);
return -1;
}
dblen = num - mdlen - 1; dblen = num - mdlen - 1;
db = OPENSSL_malloc(dblen); db = OPENSSL_malloc(dblen);
...@@ -157,25 +160,26 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, ...@@ -157,25 +160,26 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
goto cleanup; goto cleanup;
} }
if (flen != num) { em = OPENSSL_malloc(num);
em = OPENSSL_zalloc(num); if (em == NULL) {
if (em == NULL) { RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1,
RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, ERR_R_MALLOC_FAILURE);
ERR_R_MALLOC_FAILURE); goto cleanup;
goto cleanup; }
}
/* /*
* Caller is encouraged to pass zero-padded message created with * Caller is encouraged to pass zero-padded message created with
* BN_bn2binpad, but if it doesn't, we do this zero-padding copy * BN_bn2binpad. Trouble is that since we can't read out of |from|'s
* to avoid leaking that information. The copy still leaks some * bounds, it's impossible to have an invariant memory access pattern
* side-channel information, but it's impossible to have a fixed * in case |from| was not zero-padded in advance.
* memory access pattern since we can't read out of the bounds of */
* |from|. for (from += flen, em += num, i = 0; i < num; i++) {
*/ mask = ~constant_time_is_zero(flen);
memcpy(em + num - flen, from, flen); flen -= 1 & mask;
from = em; from -= 1 & mask;
*--em = *from & mask;
} }
from = em;
/* /*
* The first byte must be zero, however we must not leak if this is * The first byte must be zero, however we must not leak if this is
...@@ -222,32 +226,48 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, ...@@ -222,32 +226,48 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
* so plaintext-awareness ensures timing side-channels are no longer a * so plaintext-awareness ensures timing side-channels are no longer a
* concern. * concern.
*/ */
if (!good)
goto decoding_err;
msg_index = one_index + 1; msg_index = one_index + 1;
mlen = dblen - msg_index; mlen = dblen - msg_index;
if (tlen < mlen) { /*
RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, RSA_R_DATA_TOO_LARGE); * For good measure, do this check in constant tine as well.
mlen = -1; */
} else { good &= constant_time_ge(tlen, mlen);
memcpy(to, db + msg_index, mlen);
goto cleanup; /*
* Even though we can't fake result's length, we can pretend copying
* |tlen| bytes where |mlen| bytes would be real. Last |tlen| of |dblen|
* bytes are viewed as circular buffer with start at |tlen|-|mlen'|,
* where |mlen'| is "saturated" |mlen| value. Deducing information
* about failure or |mlen| would take attacker's ability to observe
* memory access pattern with byte granularity *as it occurs*. It
* should be noted that failure is indistinguishable from normal
* operation if |tlen| is fixed by protocol.
*/
tlen = constant_time_select_int(constant_time_lt(dblen, tlen), dblen, tlen);
msg_index = constant_time_select_int(good, msg_index, dblen - tlen);
mlen = dblen - msg_index;
for (from = db + msg_index, mask = good, i = 0; i < tlen; i++) {
unsigned int equals = constant_time_eq(i, mlen);
from -= dblen & equals; /* if (i == dblen) rewind */
mask &= mask ^ equals; /* if (i == dblen) mask = 0 */
to[i] = constant_time_select_8(mask, from[i], to[i]);
} }
decoding_err:
/* /*
* To avoid chosen ciphertext attacks, the error message should not * To avoid chosen ciphertext attacks, the error message should not
* reveal which kind of decoding error happened. * reveal which kind of decoding error happened.
*/ */
RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1,
RSA_R_OAEP_DECODING_ERROR); RSA_R_OAEP_DECODING_ERROR);
err_clear_last_constant_time(1 & good);
cleanup: cleanup:
OPENSSL_cleanse(seed, sizeof(seed)); OPENSSL_cleanse(seed, sizeof(seed));
OPENSSL_clear_free(db, dblen); OPENSSL_clear_free(db, dblen);
OPENSSL_clear_free(em, num); OPENSSL_clear_free(em, num);
return mlen;
return constant_time_select_int(good, mlen, -1);
} }
int PKCS1_MGF1(unsigned char *mask, long len, int PKCS1_MGF1(unsigned char *mask, long len,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册