static int test_is_zero(unsigned int a) { unsigned int c = constant_time_is_zero(a); if (a == 0 && c != CONSTTIME_TRUE) { fprintf(stderr, "Test failed for constant_time_is_zero(%du): " "expected %du (TRUE), got %du\n", a, CONSTTIME_TRUE, c); return 1; } else if (a != 0 && c != CONSTTIME_FALSE) { fprintf(stderr, "Test failed for constant_time_is_zero(%du): " "expected %du (FALSE), got %du\n", a, CONSTTIME_FALSE, c); return 1; } return 0; }
int RSA_padding_check_PKCS1_type_2(unsigned char *to, int tlen, const unsigned char *from, int flen, int num) { int i; /* |em| is the encoded message, zero-padded to exactly |num| bytes */ unsigned char *em = NULL; unsigned int good, found_zero_byte; int zero_index = 0, msg_index, mlen = -1; if (tlen < 0 || flen < 0) return -1; /* * PKCS#1 v1.5 decryption. See "PKCS #1 v2.2: RSA Cryptography Standard", * section 7.2.2. */ if (flen > num) goto err; if (num < 11) goto err; em = OPENSSL_zalloc(num); if (em == NULL) { RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_2, ERR_R_MALLOC_FAILURE); return -1; } /* * Always do this zero-padding copy (even when num == flen) 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|. * * TODO(emilia): Consider porting BN_bn2bin_padded from BoringSSL. */ memcpy(em + num - flen, from, flen); good = constant_time_is_zero(em[0]); good &= constant_time_eq(em[1], 2); found_zero_byte = 0; for (i = 2; i < num; i++) { unsigned int equals0 = constant_time_is_zero(em[i]); zero_index = constant_time_select_int(~found_zero_byte & equals0, i, zero_index); found_zero_byte |= equals0; } /* * PS must be at least 8 bytes long, and it starts two bytes into |em|. * If we never found a 0-byte, then |zero_index| is 0 and the check * also fails. */ good &= constant_time_ge((unsigned int)(zero_index), 2 + 8); /* * Skip the zero byte. This is incorrect if we never found a zero-byte * but in this case we also do not copy the message out. */ msg_index = zero_index + 1; mlen = num - msg_index; /* * For good measure, do this check in constant time as well; it could * leak something if |tlen| was assuming valid padding. */ good &= constant_time_ge((unsigned int)(tlen), (unsigned int)(mlen)); /* * We can't continue in constant-time because we need to copy the result * and we cannot fake its length. This unavoidably leaks timing * information at the API boundary. * TODO(emilia): this could be addressed at the call site, * see BoringSSL commit 0aa0767340baf925bda4804882aab0cb974b2d26. */ if (!good) { mlen = -1; goto err; } memcpy(to, em + msg_index, mlen); err: OPENSSL_free(em); if (mlen == -1) RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_2, RSA_R_PKCS_DECODING_ERROR); return mlen; }
int RSA_padding_check_PKCS1_type_2(uint8_t *to, unsigned to_len, const uint8_t *from, unsigned from_len) { if (from_len == 0) { OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY); return -1; } /* PKCS#1 v1.5 decryption. See "PKCS #1 v2.2: RSA Cryptography * Standard", section 7.2.2. */ if (from_len < RSA_PKCS1_PADDING_SIZE) { /* |from| is zero-padded to the size of the RSA modulus, a public value, so * this can be rejected in non-constant time. */ OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL); return -1; } unsigned first_byte_is_zero = constant_time_eq(from[0], 0); unsigned second_byte_is_two = constant_time_eq(from[1], 2); unsigned i, zero_index = 0, looking_for_index = ~0u; for (i = 2; i < from_len; i++) { unsigned equals0 = constant_time_is_zero(from[i]); zero_index = constant_time_select(looking_for_index & equals0, (unsigned)i, zero_index); looking_for_index = constant_time_select(equals0, 0, looking_for_index); } /* The input must begin with 00 02. */ unsigned valid_index = first_byte_is_zero; valid_index &= second_byte_is_two; /* We must have found the end of PS. */ valid_index &= ~looking_for_index; /* PS must be at least 8 bytes long, and it starts two bytes into |from|. */ valid_index &= constant_time_ge(zero_index, 2 + 8); /* Skip the zero byte. */ zero_index++; /* NOTE: Although this logic attempts to be constant time, the API contracts * of this function and |RSA_decrypt| with |RSA_PKCS1_PADDING| make it * impossible to completely avoid Bleichenbacher's attack. Consumers should * use |RSA_unpad_key_pkcs1|. */ if (!valid_index) { OPENSSL_PUT_ERROR(RSA, RSA_R_PKCS_DECODING_ERROR); return -1; } const unsigned msg_len = from_len - zero_index; if (msg_len > to_len) { /* This shouldn't happen because this function is always called with * |to_len| as the key size and |from_len| is bounded by the key size. */ OPENSSL_PUT_ERROR(RSA, RSA_R_PKCS_DECODING_ERROR); return -1; } if (msg_len > INT_MAX) { OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW); return -1; } memcpy(to, &from[zero_index], msg_len); return (int)msg_len; }
int RSA_padding_check_PKCS1_type_2(unsigned char *to, int tlen, const unsigned char *from, int flen, int num) { int i; /* |em| is the encoded message, zero-padded to exactly |num| bytes */ unsigned char *em = NULL; unsigned int good, found_zero_byte, mask; int zero_index = 0, msg_index, mlen = -1; if (tlen < 0 || flen < 0) return -1; /* * PKCS#1 v1.5 decryption. See "PKCS #1 v2.2: RSA Cryptography Standard", * section 7.2.2. */ if (flen > num || num < 11) { RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_2, RSA_R_PKCS_DECODING_ERROR); return -1; } em = OPENSSL_malloc(num); if (em == NULL) { RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_2, ERR_R_MALLOC_FAILURE); return -1; } /* * Caller is encouraged to pass zero-padded message created with * 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. */ 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; good = constant_time_is_zero(from[0]); good &= constant_time_eq(from[1], 2); /* scan over padding data */ found_zero_byte = 0; for (i = 2; i < num; i++) { unsigned int equals0 = constant_time_is_zero(from[i]); zero_index = constant_time_select_int(~found_zero_byte & equals0, i, zero_index); found_zero_byte |= equals0; } /* * PS must be at least 8 bytes long, and it starts two bytes into |from|. * If we never found a 0-byte, then |zero_index| is 0 and the check * also fails. */ good &= constant_time_ge(zero_index, 2 + 8); /* * Skip the zero byte. This is incorrect if we never found a zero-byte * but in this case we also do not copy the message out. */ msg_index = zero_index + 1; mlen = num - msg_index; /* * For good measure, do this check in constant time 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 |num| * 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(num, tlen), num, tlen); msg_index = constant_time_select_int(good, msg_index, num - tlen); mlen = num - msg_index; for (from += msg_index, mask = good, i = 0; i < tlen; i++) { unsigned int equals = constant_time_eq(i, mlen); from -= tlen & equals; /* if (i == mlen) rewind */ mask &= mask ^ equals; /* if (i == mlen) mask = 0 */ to[i] = constant_time_select_8(mask, from[i], to[i]); } OPENSSL_cleanse(em, num); OPENSSL_free(em); RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_2, RSA_R_PKCS_DECODING_ERROR); err_clear_last_constant_time(1 & good); return constant_time_select_int(good, mlen, -1); }