Loading crypto/rsa/rsa_oaep.c +51 −31 Original line number Diff line number Diff line Loading @@ -120,7 +120,7 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, const EVP_MD *mgf1md) { 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; /* * |em| is the encoded message, zero-padded to exactly |num| bytes: em = Loading @@ -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. * This does not leak any side-channel information. */ if (num < flen || num < 2 * mdlen + 2) goto decoding_err; if (num < flen || num < 2 * mdlen + 2) { RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, RSA_R_OAEP_DECODING_ERROR); return -1; } dblen = num - mdlen - 1; db = OPENSSL_malloc(dblen); Loading @@ -157,8 +160,7 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, goto cleanup; } if (flen != num) { em = OPENSSL_zalloc(num); em = OPENSSL_malloc(num); if (em == NULL) { RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, ERR_R_MALLOC_FAILURE); Loading @@ -167,15 +169,17 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, /* * Caller is encouraged to pass zero-padded message created with * BN_bn2binpad, but if it doesn't, we do this zero-padding copy * to avoid leaking that information. The copy still leaks some * side-channel information, but it's impossible to have a fixed * memory access pattern since we can't read out of the bounds of * |from|. * BN_bn2binpad. Trouble is that since we can't read out of |from|'s * bounds, it's impossible to have an invariant memory access pattern * in case |from| was not zero-padded in advance. */ memcpy(em + num - flen, from, flen); from = em; for (from += flen, em += num, i = 0; i < num; i++) { mask = ~constant_time_is_zero(flen); flen -= 1 & mask; from -= 1 & mask; *--em = *from & mask; } from = em; /* * The first byte must be zero, however we must not leak if this is Loading Loading @@ -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 * concern. */ if (!good) goto decoding_err; msg_index = one_index + 1; mlen = dblen - msg_index; if (tlen < mlen) { RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, RSA_R_DATA_TOO_LARGE); mlen = -1; } else { memcpy(to, db + msg_index, mlen); goto cleanup; /* * For good measure, do this check in constant tine as well. */ good &= constant_time_ge(tlen, mlen); /* * 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 * reveal which kind of decoding error happened. */ RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, RSA_R_OAEP_DECODING_ERROR); err_clear_last_constant_time(1 & good); cleanup: OPENSSL_cleanse(seed, sizeof(seed)); OPENSSL_clear_free(db, dblen); OPENSSL_clear_free(em, num); return mlen; return constant_time_select_int(good, mlen, -1); } int PKCS1_MGF1(unsigned char *mask, long len, Loading Loading
crypto/rsa/rsa_oaep.c +51 −31 Original line number Diff line number Diff line Loading @@ -120,7 +120,7 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, const EVP_MD *mgf1md) { 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; /* * |em| is the encoded message, zero-padded to exactly |num| bytes: em = Loading @@ -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. * This does not leak any side-channel information. */ if (num < flen || num < 2 * mdlen + 2) goto decoding_err; if (num < flen || num < 2 * mdlen + 2) { RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, RSA_R_OAEP_DECODING_ERROR); return -1; } dblen = num - mdlen - 1; db = OPENSSL_malloc(dblen); Loading @@ -157,8 +160,7 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, goto cleanup; } if (flen != num) { em = OPENSSL_zalloc(num); em = OPENSSL_malloc(num); if (em == NULL) { RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, ERR_R_MALLOC_FAILURE); Loading @@ -167,15 +169,17 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, /* * Caller is encouraged to pass zero-padded message created with * BN_bn2binpad, but if it doesn't, we do this zero-padding copy * to avoid leaking that information. The copy still leaks some * side-channel information, but it's impossible to have a fixed * memory access pattern since we can't read out of the bounds of * |from|. * BN_bn2binpad. Trouble is that since we can't read out of |from|'s * bounds, it's impossible to have an invariant memory access pattern * in case |from| was not zero-padded in advance. */ memcpy(em + num - flen, from, flen); from = em; for (from += flen, em += num, i = 0; i < num; i++) { mask = ~constant_time_is_zero(flen); flen -= 1 & mask; from -= 1 & mask; *--em = *from & mask; } from = em; /* * The first byte must be zero, however we must not leak if this is Loading Loading @@ -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 * concern. */ if (!good) goto decoding_err; msg_index = one_index + 1; mlen = dblen - msg_index; if (tlen < mlen) { RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, RSA_R_DATA_TOO_LARGE); mlen = -1; } else { memcpy(to, db + msg_index, mlen); goto cleanup; /* * For good measure, do this check in constant tine as well. */ good &= constant_time_ge(tlen, mlen); /* * 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 * reveal which kind of decoding error happened. */ RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, RSA_R_OAEP_DECODING_ERROR); err_clear_last_constant_time(1 & good); cleanup: OPENSSL_cleanse(seed, sizeof(seed)); OPENSSL_clear_free(db, dblen); OPENSSL_clear_free(em, num); return mlen; return constant_time_select_int(good, mlen, -1); } int PKCS1_MGF1(unsigned char *mask, long len, Loading