Remove non-CBC codepaths from e_tls.cc RC4 and auth-only ciphers are long, long gone. Make this code not try to do two things at once. While I'm here, replace `% block_size` with `& (block_size - 1)`. The compiler doesn't know these are powers of 2, but we do. Change-Id: Id0307a03827410a90c02de46b0ab9fe294b83e1e Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/85148 Reviewed-by: Rudolf Polzer <rpolzer@google.com> Auto-Submit: David Benjamin <davidben@google.com> Commit-Queue: Rudolf Polzer <rpolzer@google.com>
diff --git a/crypto/cipher/e_tls.cc b/crypto/cipher/e_tls.cc index f6c8241..b0f3ab3 100644 --- a/crypto/cipher/e_tls.cc +++ b/crypto/cipher/e_tls.cc
@@ -102,18 +102,14 @@ const size_t extra_in_len) { assert(extra_in_len == 0); const AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)&ctx->state; + assert(EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE); const size_t hmac_len = HMAC_size(tls_ctx->hmac_ctx); - if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) != EVP_CIPH_CBC_MODE) { - // The NULL cipher. - return hmac_len; - } - const size_t block_size = EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx); // An overflow of |in_len + hmac_len| doesn't affect the result mod // |block_size|, provided that |block_size| is a smaller power of two. - assert(block_size != 0 && (block_size & (block_size - 1)) == 0); - const size_t pad_len = block_size - (in_len + hmac_len) % block_size; + assert(block_size == 8 /*3DES*/ || block_size == 16 /*AES*/); + const size_t pad_len = block_size - ((in_len + hmac_len) & (block_size - 1)); return hmac_len + pad_len; } @@ -167,8 +163,8 @@ } // Configure the explicit IV. - if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE && - !tls_ctx->implicit_iv && + assert(EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE); + if (!tls_ctx->implicit_iv && !EVP_EncryptInit_ex(&tls_ctx->cipher_ctx, nullptr, nullptr, nullptr, nonce)) { return 0; @@ -182,13 +178,13 @@ } unsigned block_size = EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx); + assert(block_size == 8 /*3DES*/ || block_size == 16 /*AES*/); // Feed the MAC into the cipher in two steps. First complete the final partial // block from encrypting the input and split the result between |out| and // |out_tag|. Then feed the rest. - const size_t early_mac_len = - (block_size - (in_len % block_size)) % block_size; + const size_t early_mac_len = (block_size - in_len) & (block_size - 1); if (early_mac_len != 0) { assert(len + block_size - early_mac_len == in_len); uint8_t buf[EVP_MAX_BLOCK_LENGTH]; @@ -210,21 +206,15 @@ } tag_len += len; - if (block_size > 1) { - assert(block_size <= 256); - assert(EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE); - - // Compute padding and feed that into the cipher. - uint8_t padding[256]; - unsigned padding_len = block_size - ((in_len + mac_len) % block_size); - OPENSSL_memset(padding, padding_len - 1, padding_len); - if (!EVP_EncryptUpdate_ex(&tls_ctx->cipher_ctx, out_tag + tag_len, &len, - max_out_tag_len - tag_len, padding, - padding_len)) { - return 0; - } - tag_len += len; + // Compute padding and feed that into the cipher. + uint8_t padding[256]; + unsigned padding_len = block_size - ((in_len + mac_len) & (block_size - 1)); + OPENSSL_memset(padding, padding_len - 1, padding_len); + if (!EVP_EncryptUpdate_ex(&tls_ctx->cipher_ctx, out_tag + tag_len, &len, + max_out_tag_len - tag_len, padding, padding_len)) { + return 0; } + tag_len += len; if (!EVP_EncryptFinal_ex2(&tls_ctx->cipher_ctx, out_tag + tag_len, &len, max_out_tag_len - tag_len)) { @@ -272,8 +262,8 @@ } // Configure the explicit IV. - if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE && - !tls_ctx->implicit_iv && + assert(EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE); + if (!tls_ctx->implicit_iv && !EVP_DecryptInit_ex(&tls_ctx->cipher_ctx, nullptr, nullptr, nullptr, nonce)) { return 0; @@ -300,21 +290,13 @@ // |padding_ok| and |data_plus_mac_len| for CBC ciphers. size_t data_plus_mac_len; crypto_word_t padding_ok; - if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE) { - if (!EVP_tls_cbc_remove_padding( - &padding_ok, &data_plus_mac_len, out, total, - EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx), - HMAC_size(tls_ctx->hmac_ctx))) { - // Publicly invalid. This can be rejected in non-constant time. - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); - return 0; - } - } else { - padding_ok = CONSTTIME_TRUE_W; - data_plus_mac_len = total; - // |data_plus_mac_len| = |total| = |in_len| at this point. |in_len| has - // already been checked against the MAC size at the top of the function. - assert(data_plus_mac_len >= HMAC_size(tls_ctx->hmac_ctx)); + if (!EVP_tls_cbc_remove_padding( + &padding_ok, &data_plus_mac_len, out, total, + EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx), + HMAC_size(tls_ctx->hmac_ctx))) { + // Publicly invalid. This can be rejected in non-constant time. + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; } size_t data_len = data_plus_mac_len - HMAC_size(tls_ctx->hmac_ctx); @@ -333,37 +315,17 @@ // Compute the MAC and extract the one in the record. uint8_t mac[EVP_MAX_MD_SIZE]; size_t mac_len; - uint8_t record_mac_tmp[EVP_MAX_MD_SIZE]; - uint8_t *record_mac; - if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE && - EVP_tls_cbc_record_digest_supported(tls_ctx->hmac_ctx->md)) { - if (!EVP_tls_cbc_digest_record(tls_ctx->hmac_ctx->md, mac, &mac_len, - ad_fixed, out, data_len, total, - tls_ctx->mac_key, tls_ctx->mac_key_len)) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); - return 0; - } - assert(mac_len == HMAC_size(tls_ctx->hmac_ctx)); - - record_mac = record_mac_tmp; - EVP_tls_cbc_copy_mac(record_mac, mac_len, out, data_plus_mac_len, total); - } else { - // We should support the constant-time path for all CBC-mode ciphers - // implemented. - assert(EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) != EVP_CIPH_CBC_MODE); - - unsigned mac_len_u; - if (!HMAC_Init_ex(tls_ctx->hmac_ctx, nullptr, 0, nullptr, nullptr) || - !HMAC_Update(tls_ctx->hmac_ctx, ad_fixed, ad_len) || - !HMAC_Update(tls_ctx->hmac_ctx, out, data_len) || - !HMAC_Final(tls_ctx->hmac_ctx, mac, &mac_len_u)) { - return 0; - } - mac_len = mac_len_u; - - assert(mac_len == HMAC_size(tls_ctx->hmac_ctx)); - record_mac = &out[data_len]; + assert(EVP_tls_cbc_record_digest_supported(tls_ctx->hmac_ctx->md)); + if (!EVP_tls_cbc_digest_record(tls_ctx->hmac_ctx->md, mac, &mac_len, ad_fixed, + out, data_len, total, tls_ctx->mac_key, + tls_ctx->mac_key_len)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; } + assert(mac_len == HMAC_size(tls_ctx->hmac_ctx)); + + uint8_t record_mac[EVP_MAX_MD_SIZE]; + EVP_tls_cbc_copy_mac(record_mac, mac_len, out, data_plus_mac_len, total); // Perform the MAC check and the padding check in constant-time. It should be // safe to simply perform the padding check first, but it would not be under a