static int bn_cmp_words_consttime(const BN_ULONG *a, size_t a_len, const BN_ULONG *b, size_t b_len) { OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t), crypto_word_t_too_small); int ret = 0; // Process the common words in little-endian order. size_t min = a_len < b_len ? a_len : b_len; for (size_t i = 0; i < min; i++) { crypto_word_t eq = constant_time_eq_w(a[i], b[i]); crypto_word_t lt = constant_time_lt_w(a[i], b[i]); ret = constant_time_select_int(eq, ret, constant_time_select_int(lt, -1, 1)); } // If |a| or |b| has non-zero words beyond |min|, they take precedence. if (a_len < b_len) { crypto_word_t mask = 0; for (size_t i = a_len; i < b_len; i++) { mask |= b[i]; } ret = constant_time_select_int(constant_time_is_zero_w(mask), ret, -1); } else if (b_len < a_len) { crypto_word_t mask = 0; for (size_t i = b_len; i < a_len; i++) { mask |= a[i]; } ret = constant_time_select_int(constant_time_is_zero_w(mask), ret, 1); } return ret; }
static int pkey_rsa_decrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) { int ret; RSA_PKEY_CTX *rctx = ctx->data; if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) { if (!setup_tbuf(rctx, ctx)) return -1; ret = RSA_private_decrypt(inlen, in, rctx->tbuf, ctx->pkey->pkey.rsa, RSA_NO_PADDING); if (ret <= 0) return ret; ret = RSA_padding_check_PKCS1_OAEP_mgf1(out, ret, rctx->tbuf, ret, ret, rctx->oaep_label, rctx->oaep_labellen, rctx->md, rctx->mgf1md); } else { ret = RSA_private_decrypt(inlen, in, out, ctx->pkey->pkey.rsa, rctx->pad_mode); } *outlen = constant_time_select_s(constant_time_msb_s(ret), *outlen, ret); ret = constant_time_select_int(constant_time_msb(ret), ret, 1); return ret; }
static int test_select_int(int a, int b) { int selected = constant_time_select_int(CONSTTIME_TRUE, a, b); if (selected != a) { fprintf(stderr, "Test failed for constant_time_select(%du, %d," "%d): expected %d(first value), got %d\n", CONSTTIME_TRUE, a, b, a, selected); return 1; } selected = constant_time_select_int(CONSTTIME_FALSE, a, b); if (selected != b) { fprintf(stderr, "Test failed for constant_time_select(%du, %d," "%d): expected %d(second value), got %d\n", CONSTTIME_FALSE, a, b, b, selected); return 1; } return 0; }
int EVP_tls_cbc_remove_padding(unsigned *out_len, const uint8_t *in, unsigned in_len, unsigned block_size, unsigned mac_size) { unsigned padding_length, good, to_check, i; const unsigned overhead = 1 /* padding length byte */ + mac_size; /* These lengths are all public so we can test them in non-constant time. */ if (overhead > in_len) { return 0; } padding_length = in[in_len - 1]; good = constant_time_ge(in_len, overhead + padding_length); /* The padding consists of a length byte at the end of the record and * then that many bytes of padding, all with the same value as the * length byte. Thus, with the length byte included, there are i+1 * bytes of padding. * * We can't check just |padding_length+1| bytes because that leaks * decrypted information. Therefore we always have to check the maximum * amount of padding possible. (Again, the length of the record is * public information so we can use it.) */ to_check = 256; /* maximum amount of padding, inc length byte. */ if (to_check > in_len) { to_check = in_len; } for (i = 0; i < to_check; i++) { uint8_t mask = constant_time_ge_8(padding_length, i); uint8_t b = in[in_len - 1 - i]; /* The final |padding_length+1| bytes should all have the value * |padding_length|. Therefore the XOR should be zero. */ good &= ~(mask & (padding_length ^ b)); } /* If any of the final |padding_length+1| bytes had the wrong value, * one or more of the lower eight bits of |good| will be cleared. */ good = constant_time_eq(0xff, good & 0xff); /* Always treat |padding_length| as zero on error. If, assuming block size of * 16, a padding of [<15 arbitrary bytes> 15] treated |padding_length| as 16 * and returned -1, distinguishing good MAC and bad padding from bad MAC and * bad padding would give POODLE's padding oracle. */ padding_length = good & (padding_length + 1); *out_len = in_len - padding_length; return constant_time_select_int(good, 1, -1); }
void err_clear_last_constant_time(int clear) { ERR_STATE *es; int top; es = ERR_get_state(); if (es == NULL) return; top = es->top; /* * Flag error as cleared but remove it elsewhere to avoid two errors * accessing the same error stack location, revealing timing information. */ clear = constant_time_select_int(constant_time_eq_int(clear, 0), 0, ERR_FLAG_CLEAR); es->err_flags[top] |= clear; }
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(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); }