EVP_AEAD: implement sealv/openv for the TLS ciphers. Performance note: this seems to cost 13 to 261 CPU cycles per call with LTO, and 8 to 158 CPU cycles without; no measurable per-byte overhead though. Bug: 383343306 Change-Id: I7eeacf3044aca9bd40993d8f70a8898f90156671 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/84667 Commit-Queue: David Benjamin <davidben@google.com> Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/cipher/aead_test.cc b/crypto/cipher/aead_test.cc index e50a2c5..f4c16e3 100644 --- a/crypto/cipher/aead_test.cc +++ b/crypto/cipher/aead_test.cc
@@ -614,6 +614,7 @@ } SCOPED_TRACE(FormatSplits(splits)); + ctx.Reset(); ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction( ctx.get(), aead_config.func(), key.data(), key.size(), tag_len, evp_aead_seal));
diff --git a/crypto/cipher/e_tls.cc b/crypto/cipher/e_tls.cc index 7be0644..da35da6 100644 --- a/crypto/cipher/e_tls.cc +++ b/crypto/cipher/e_tls.cc
@@ -23,9 +23,11 @@ #include <openssl/md5.h> #include <openssl/mem.h> #include <openssl/sha.h> +#include <openssl/span.h> #include "../fipsmodule/cipher/internal.h" #include "../internal.h" +#include "../mem_internal.h" #include "internal.h" @@ -113,14 +115,12 @@ return hmac_len + pad_len; } -static int aead_tls_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out, - uint8_t *out_tag, size_t *out_tag_len, - const size_t max_out_tag_len, - const uint8_t *nonce, const size_t nonce_len, - const uint8_t *in, const size_t in_len, - const uint8_t *extra_in, - const size_t extra_in_len, const uint8_t *ad, - const size_t ad_len) { +static int aead_tls_sealv(const EVP_AEAD_CTX *ctx, + bssl::Span<const CRYPTO_IOVEC> iovecs, + uint8_t *out_tag, size_t *out_tag_len, + const size_t max_out_tag_len, const uint8_t *nonce, + const size_t nonce_len, + bssl::Span<const CRYPTO_IVEC> aadvecs) { AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)&ctx->state; if (!tls_ctx->cipher_ctx.encrypt) { @@ -129,7 +129,8 @@ return 0; } - if (max_out_tag_len < aead_tls_tag_len(ctx, in_len, extra_in_len)) { + size_t in_len = bssl::iovec::TotalLength(iovecs); + if (max_out_tag_len < aead_tls_tag_len(ctx, in_len, 0)) { OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); return 0; } @@ -139,6 +140,7 @@ return 0; } + size_t ad_len = bssl::iovec::TotalLength(aadvecs); if (ad_len != 13 - 2 /* length bytes */) { OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE); return 0; @@ -153,12 +155,24 @@ // Compute the MAC. This must be first in case the operation is being done // in-place. uint8_t mac[EVP_MAX_MD_SIZE]; + if (!HMAC_Init_ex(tls_ctx->hmac_ctx, nullptr, 0, nullptr, nullptr)) { + return 0; + } + for (const CRYPTO_IVEC &aadvec : aadvecs) { + if (!HMAC_Update(tls_ctx->hmac_ctx, aadvec.in, aadvec.len)) { + return 0; + } + } + if (!HMAC_Update(tls_ctx->hmac_ctx, ad_extra, sizeof(ad_extra))) { + return 0; + } + for (const CRYPTO_IOVEC &iovec : iovecs) { + if (!HMAC_Update(tls_ctx->hmac_ctx, iovec.in, iovec.len)) { + return 0; + } + } unsigned mac_len; - if (!HMAC_Init_ex(tls_ctx->hmac_ctx, nullptr, 0, nullptr, nullptr) || - !HMAC_Update(tls_ctx->hmac_ctx, ad, ad_len) || - !HMAC_Update(tls_ctx->hmac_ctx, ad_extra, sizeof(ad_extra)) || - !HMAC_Update(tls_ctx->hmac_ctx, in, in_len) || - !HMAC_Final(tls_ctx->hmac_ctx, mac, &mac_len)) { + if (!HMAC_Final(tls_ctx->hmac_ctx, mac, &mac_len)) { return 0; } @@ -170,34 +184,59 @@ return 0; } - // Encrypt the input. - size_t len; - if (!EVP_EncryptUpdate_ex(&tls_ctx->cipher_ctx, out, &len, in_len, in, - in_len)) { - return 0; - } - - unsigned block_size = EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx); + size_t 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. + // Encrypt the input. + size_t len = 0; + size_t tag_len = 0; + if (!bssl::iovec::ForEachBlockRange_Dynamic</*WriteOut=*/true>( + block_size, iovecs, + [&](const uint8_t *in, uint8_t *out, size_t chunk_len) { + // Complete block(s). + size_t out_len; + if (!EVP_EncryptUpdate_ex(&tls_ctx->cipher_ctx, out, &out_len, + chunk_len, in, chunk_len)) { + return false; + } + assert(out_len == chunk_len); + len += out_len; + return true; + }, + [&](const uint8_t *in, uint8_t *out, size_t chunk_len) { + // Final chunk, possibly with a partial block. + size_t out_len; + if (!EVP_EncryptUpdate_ex(&tls_ctx->cipher_ctx, out, &out_len, + chunk_len, in, chunk_len)) { + return false; + } + len += out_len; + size_t remaining = chunk_len - out_len; + assert(remaining < block_size); + if (remaining == 0) { + return true; + } - 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]; - size_t buf_len; - if (!EVP_EncryptUpdate_ex(&tls_ctx->cipher_ctx, buf, &buf_len, sizeof(buf), - mac, early_mac_len)) { - return 0; - } - assert(buf_len == block_size); - OPENSSL_memcpy(out + len, buf, block_size - early_mac_len); - OPENSSL_memcpy(out_tag, buf + block_size - early_mac_len, early_mac_len); + // 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 - remaining; + assert(early_mac_len < block_size); + assert(len + block_size - early_mac_len == in_len); + uint8_t buf[EVP_MAX_BLOCK_LENGTH]; + size_t buf_len; + if (!EVP_EncryptUpdate_ex(&tls_ctx->cipher_ctx, buf, &buf_len, + sizeof(buf), mac, early_mac_len)) { + return false; + } + assert(buf_len == block_size); + OPENSSL_memcpy(out + out_len, buf, remaining); + OPENSSL_memcpy(out_tag, buf + remaining, early_mac_len); + tag_len = early_mac_len; + return true; + })) { + return 0; } - size_t tag_len = early_mac_len; if (!EVP_EncryptUpdate_ex(&tls_ctx->cipher_ctx, out_tag + tag_len, &len, max_out_tag_len - tag_len, mac + tag_len, @@ -221,16 +260,17 @@ return 0; } assert(len == 0); // Padding is explicit. - assert(tag_len == aead_tls_tag_len(ctx, in_len, extra_in_len)); + assert(tag_len == aead_tls_tag_len(ctx, in_len, 0)); *out_tag_len = tag_len; return 1; } -static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, - size_t max_out_len, const uint8_t *nonce, - size_t nonce_len, const uint8_t *in, size_t in_len, - const uint8_t *ad, size_t ad_len) { +static int aead_tls_openv(const EVP_AEAD_CTX *ctx, + bssl::Span<const CRYPTO_IOVEC> iovecs, + size_t *out_total_bytes, const uint8_t *nonce, + size_t nonce_len, + bssl::Span<const CRYPTO_IVEC> aadvecs) { AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)&ctx->state; if (tls_ctx->cipher_ctx.encrypt) { @@ -239,23 +279,18 @@ return 0; } + size_t in_len = bssl::iovec::TotalLength(iovecs); if (in_len < HMAC_size(tls_ctx->hmac_ctx)) { OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); return 0; } - if (max_out_len < in_len) { - // This requires that the caller provide space for the MAC, even though it - // will always be removed on return. - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); - return 0; - } - if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) { OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE); return 0; } + size_t ad_len = bssl::iovec::TotalLength(aadvecs); if (ad_len != 13 - 2 /* length bytes */) { OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE); return 0; @@ -271,61 +306,91 @@ // Decrypt to get the plaintext + MAC + padding. size_t total = 0; - size_t len; - if (!EVP_DecryptUpdate_ex(&tls_ctx->cipher_ctx, out, &len, max_out_len, in, - in_len)) { - return 0; + size_t block_size = EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx); + auto decrypt_update = [&](const uint8_t *in, uint8_t *out, size_t len) { + size_t out_len; + if (!EVP_DecryptUpdate_ex(&tls_ctx->cipher_ctx, out, &out_len, len, in, + len)) { + return false; + } + CONSTTIME_SECRET(out, out_len); + if (out_len != len) { + // A byte sequence that was not a multiple of the block size was provided + // as ciphertext. This is generally invalid and thus should be rejected. + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return false; + } + total += len; + return true; + }; + if (!bssl::iovec::ForEachBlockRange_Dynamic</*WriteOut=*/true>( + block_size, iovecs, decrypt_update, decrypt_update)) { + return false; } - total += len; - if (!EVP_DecryptFinal_ex2(&tls_ctx->cipher_ctx, out + total, &len, - max_out_len - total)) { - return 0; - } - total += len; assert(total == in_len); - CONSTTIME_SECRET(out, total); + for (const CRYPTO_IOVEC &iovec : iovecs) { + CONSTTIME_SECRET(iovec.out, iovec.len); + } + + const size_t mac_len = HMAC_size(tls_ctx->hmac_ctx); + + // Split the decrypted record into |iovecs_without_trailer| and |trailer|, + // based on the public lower bound of where the plaintext ends. The plaintext + // is followed by |mac_len| and then at most 256 bytes of padding. + bssl::InplaceVector<CRYPTO_IOVEC, CRYPTO_IOVEC_MAX> iovecs_without_trailer; + iovecs_without_trailer.CopyFrom(iovecs); + uint8_t trailer_buf[EVP_MAX_MD_SIZE + 256]; + const size_t trailer_len = std::min(in_len, mac_len + 256); + std::optional<bssl::Span<const uint8_t>> trailer = + bssl::iovec::GetAndRemoveOutSuffix( + bssl::Span(trailer_buf).first(trailer_len), + bssl::Span(iovecs_without_trailer)); + BSSL_CHECK(trailer.has_value()); // Remove CBC padding. Code from here on is timing-sensitive with respect to // |padding_ok| and |data_plus_mac_len| for CBC ciphers. - size_t data_plus_mac_len; crypto_word_t padding_ok; - 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))) { + size_t reduced_trailer; + if (!EVP_tls_cbc_remove_padding(&padding_ok, &reduced_trailer, + trailer->data(), trailer->size(), block_size, + mac_len)) { // 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); + assert(reduced_trailer >= mac_len); + size_t data_plus_mac_len = total + reduced_trailer - trailer->size(); + size_t data_len = data_plus_mac_len - mac_len; + size_t data_in_trailer_len = reduced_trailer - mac_len; - // At this point, if the padding is valid, the first |data_plus_mac_len| bytes - // after |out| are the plaintext and MAC. Otherwise, |data_plus_mac_len| is - // still large enough to extract a MAC, but it will be irrelevant. + // At this point, if the padding is valid, |trailer->first(reduced_trailer)| + // is the last bytes of plaintext and the MAC. Otherwise, it is still large + // enough to extract a MAC, but it will be irrelevant. Note that + // |reduced_trailer| is secret. - // To allow for CBC mode which changes cipher length, |ad| doesn't include the - // length for legacy ciphers. - uint8_t ad_fixed[13]; - OPENSSL_memcpy(ad_fixed, ad, 11); - ad_fixed[11] = (uint8_t)(data_len >> 8); - ad_fixed[12] = (uint8_t)(data_len & 0xff); - ad_len += 2; + // To allow for CBC mode which changes cipher length, |ad_len| doesn't + // include the length for legacy ciphers. + uint8_t ad_extra[2]; + ad_extra[0] = (uint8_t)(data_len >> 8); + ad_extra[1] = (uint8_t)(data_len & 0xff); // Compute the MAC and extract the one in the record. uint8_t mac[EVP_MAX_MD_SIZE]; - size_t mac_len; + size_t got_mac_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)) { + if (!EVP_tls_cbc_digest_record(tls_ctx->hmac_ctx->md, mac, &got_mac_len, + ad_extra, aadvecs, iovecs_without_trailer, + *trailer, data_in_trailer_len, + 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)); + assert(got_mac_len == mac_len); uint8_t record_mac[EVP_MAX_MD_SIZE]; - EVP_tls_cbc_copy_mac(record_mac, mac_len, out, data_plus_mac_len, total); + EVP_tls_cbc_copy_mac(record_mac, mac_len, trailer->data(), reduced_trailer, + trailer->size()); // 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 @@ -341,11 +406,13 @@ } CONSTTIME_DECLASSIFY(&data_len, sizeof(data_len)); - CONSTTIME_DECLASSIFY(out, data_len); + for (const CRYPTO_IOVEC &iovec : iovecs) { + CONSTTIME_SECRET(iovec.out, iovec.len); + } // End of timing-sensitive code. - *out_len = data_len; + *out_total_bytes = data_len; return 1; } @@ -424,11 +491,11 @@ nullptr, // init aead_aes_128_cbc_sha1_tls_init, aead_tls_cleanup, - aead_tls_open, - aead_tls_seal_scatter, + nullptr, // open + nullptr, // seal_scatter, nullptr, // open_gather - nullptr, // openv - nullptr, // sealv + aead_tls_openv, + aead_tls_sealv, nullptr, // openv_detached nullptr, // get_iv aead_tls_tag_len, @@ -444,11 +511,11 @@ nullptr, // init aead_aes_128_cbc_sha1_tls_implicit_iv_init, aead_tls_cleanup, - aead_tls_open, - aead_tls_seal_scatter, - nullptr, // open_gather - nullptr, // openv - nullptr, // sealv + nullptr, // open + nullptr, // seal_scatter, + nullptr, // open_gather + aead_tls_openv, + aead_tls_sealv, nullptr, // openv_detached aead_tls_get_iv, // get_iv aead_tls_tag_len, @@ -464,11 +531,11 @@ nullptr, // init aead_aes_128_cbc_sha256_tls_init, aead_tls_cleanup, - aead_tls_open, - aead_tls_seal_scatter, + nullptr, // open + nullptr, // seal_scatter, nullptr, // open_gather - nullptr, // openv - nullptr, // sealv + aead_tls_openv, + aead_tls_sealv, nullptr, // openv_detached nullptr, // get_iv aead_tls_tag_len, @@ -484,11 +551,11 @@ nullptr, // init aead_aes_256_cbc_sha1_tls_init, aead_tls_cleanup, - aead_tls_open, - aead_tls_seal_scatter, + nullptr, // open + nullptr, // seal_scatter, nullptr, // open_gather - nullptr, // openv - nullptr, // sealv + aead_tls_openv, + aead_tls_sealv, nullptr, // openv_detached nullptr, // get_iv aead_tls_tag_len, @@ -504,11 +571,11 @@ nullptr, // init aead_aes_256_cbc_sha1_tls_implicit_iv_init, aead_tls_cleanup, - aead_tls_open, - aead_tls_seal_scatter, - nullptr, // open_gather - nullptr, // openv - nullptr, // sealv + nullptr, // open + nullptr, // seal_scatter, + nullptr, // open_gather + aead_tls_openv, + aead_tls_sealv, nullptr, // openv_detached aead_tls_get_iv, // get_iv aead_tls_tag_len, @@ -524,11 +591,11 @@ nullptr, // init aead_des_ede3_cbc_sha1_tls_init, aead_tls_cleanup, - aead_tls_open, - aead_tls_seal_scatter, + nullptr, // open + nullptr, // seal_scatter, nullptr, // open_gather - nullptr, // openv - nullptr, // sealv + aead_tls_openv, + aead_tls_sealv, nullptr, // openv_detached nullptr, // get_iv aead_tls_tag_len, @@ -544,11 +611,11 @@ nullptr, // init aead_des_ede3_cbc_sha1_tls_implicit_iv_init, aead_tls_cleanup, - aead_tls_open, - aead_tls_seal_scatter, - nullptr, // open_gather - nullptr, // openv - nullptr, // sealv + nullptr, // open + nullptr, // seal_scatter, + nullptr, // open_gather + aead_tls_openv, + aead_tls_sealv, nullptr, // openv_detached aead_tls_get_iv, // get_iv aead_tls_tag_len,
diff --git a/crypto/cipher/internal.h b/crypto/cipher/internal.h index 1a517bb..ed09f4b 100644 --- a/crypto/cipher/internal.h +++ b/crypto/cipher/internal.h
@@ -20,6 +20,7 @@ #include <openssl/base.h> #include <openssl/sha.h> +#include <openssl/span.h> #include "../internal.h" @@ -83,23 +84,25 @@ // EVP_tls_cbc_record_digest_supported must return true for this hash. // md_out: the digest output. At most EVP_MAX_MD_SIZE bytes will be written. // md_out_size: the number of output bytes is written here. -// header: the 13-byte, TLS record header. -// data: the record data itself -// data_size: the secret, reported length of the data once the padding and MAC -// have been removed. -// data_plus_mac_plus_padding_size: the public length of the whole -// record, including padding. +// len_header: the two length bytes of the TLS record header. +// aadvecs: the 11-byte TLS record header as it was provided by the caller. +// iovecs_without_trailer: the section of the plaintext that does not include +// the trailer whose length is secret (typically the entire plaintext with +// an upper bound of padding and MAC size removed) +// trailer: the remaining portion of plaintext, MAC and padding +// data_in_trailer_size: the secret, reported length of the data portion in +// |trailer| once the padding and MAC have been removed. // // On entry: by virtue of having been through one of the remove_padding // functions, above, we know that data_plus_mac_size is large enough to contain // a padding byte and MAC. (If the padding was invalid, it might contain the // padding too. ) -int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out, - size_t *md_out_size, const uint8_t header[13], - const uint8_t *data, size_t data_size, - size_t data_plus_mac_plus_padding_size, - const uint8_t *mac_secret, - unsigned mac_secret_length); +int EVP_tls_cbc_digest_record( + const EVP_MD *md, uint8_t *md_out, size_t *md_out_size, + const uint8_t len_header[2], bssl::Span<const CRYPTO_IVEC> aadvecs, + bssl::Span<const CRYPTO_IOVEC> iovecs_without_trailer, + bssl::Span<const uint8_t> trailer, size_t data_in_trailer_size, + const uint8_t *mac_secret, unsigned mac_secret_length); #define POLY1305_TAG_LEN 16
diff --git a/crypto/cipher/tls_cbc.cc b/crypto/cipher/tls_cbc.cc index 31d3218..9dc220f 100644 --- a/crypto/cipher/tls_cbc.cc +++ b/crypto/cipher/tls_cbc.cc
@@ -18,10 +18,11 @@ #include <openssl/digest.h> #include <openssl/nid.h> #include <openssl/sha.h> +#include <openssl/span.h> +#include "../fipsmodule/cipher/internal.h" #include "../internal.h" #include "internal.h" -#include "../fipsmodule/cipher/internal.h" int EVP_tls_cbc_remove_padding(crypto_word_t *out_padding_ok, size_t *out_len, @@ -335,12 +336,12 @@ } } -static int tls_cbc_digest_record_sha1(uint8_t *md_out, size_t *md_out_size, - const uint8_t header[13], - const uint8_t *data, size_t data_size, - size_t data_plus_mac_plus_padding_size, - const uint8_t *mac_secret, - unsigned mac_secret_length) { +static int tls_cbc_digest_record_sha1( + uint8_t *md_out, size_t *md_out_size, const uint8_t len_header[2], + bssl::Span<const CRYPTO_IVEC> aadvecs, + bssl::Span<const CRYPTO_IOVEC> iovecs_without_trailer, + bssl::Span<const uint8_t> trailer, size_t data_in_trailer_size, + const uint8_t *mac_secret, unsigned mac_secret_length) { if (mac_secret_length > SHA_CBLOCK) { // HMAC pads small keys with zeros and hashes large keys down. This function // should never reach the large key case. @@ -359,24 +360,22 @@ SHA_CTX ctx; SHA1_Init(&ctx); SHA1_Update(&ctx, hmac_pad, SHA_CBLOCK); - SHA1_Update(&ctx, header, 13); - - // There are at most 256 bytes of padding, so we can compute the public - // minimum length for |data_size|. - size_t min_data_size = 0; - if (data_plus_mac_plus_padding_size > SHA_DIGEST_LENGTH + 256) { - min_data_size = data_plus_mac_plus_padding_size - SHA_DIGEST_LENGTH - 256; + for (const CRYPTO_IVEC &aadvec : aadvecs) { + SHA1_Update(&ctx, aadvec.in, aadvec.len); } + SHA1_Update(&ctx, len_header, 2); // Hash the public minimum length directly. This reduces the number of blocks // that must be computed in constant-time. - SHA1_Update(&ctx, data, min_data_size); + for (const CRYPTO_IOVEC &iovec : iovecs_without_trailer) { + SHA1_Update(&ctx, iovec.out, iovec.len); + } - // Hash the remaining data without leaking |data_size|. + // Hash the remaining data without leaking |data_in_trailer_size|. uint8_t mac_out[SHA_DIGEST_LENGTH]; - if (!EVP_sha1_final_with_secret_suffix( - &ctx, mac_out, data + min_data_size, data_size - min_data_size, - data_plus_mac_plus_padding_size - min_data_size)) { + if (!EVP_sha1_final_with_secret_suffix(&ctx, mac_out, trailer.data(), + data_in_trailer_size, + trailer.size())) { return 0; } @@ -393,12 +392,12 @@ return 1; } -static int tls_cbc_digest_record_sha256(uint8_t *md_out, size_t *md_out_size, - const uint8_t header[13], - const uint8_t *data, size_t data_size, - size_t data_plus_mac_plus_padding_size, - const uint8_t *mac_secret, - unsigned mac_secret_length) { +static int tls_cbc_digest_record_sha256( + uint8_t *md_out, size_t *md_out_size, const uint8_t len_header[2], + bssl::Span<const CRYPTO_IVEC> aadvecs, + bssl::Span<const CRYPTO_IOVEC> iovecs_without_trailer, + bssl::Span<const uint8_t> trailer, size_t data_in_trailer_size, + const uint8_t *mac_secret, unsigned mac_secret_length) { if (mac_secret_length > SHA256_CBLOCK) { // HMAC pads small keys with zeros and hashes large keys down. This function // should never reach the large key case. @@ -417,25 +416,22 @@ SHA256_CTX ctx; SHA256_Init(&ctx); SHA256_Update(&ctx, hmac_pad, SHA256_CBLOCK); - SHA256_Update(&ctx, header, 13); - - // There are at most 256 bytes of padding, so we can compute the public - // minimum length for |data_size|. - size_t min_data_size = 0; - if (data_plus_mac_plus_padding_size > SHA256_DIGEST_LENGTH + 256) { - min_data_size = - data_plus_mac_plus_padding_size - SHA256_DIGEST_LENGTH - 256; + for (const CRYPTO_IVEC &aadvec : aadvecs) { + SHA256_Update(&ctx, aadvec.in, aadvec.len); } + SHA256_Update(&ctx, len_header, 2); // Hash the public minimum length directly. This reduces the number of blocks // that must be computed in constant-time. - SHA256_Update(&ctx, data, min_data_size); + for (const CRYPTO_IOVEC &iovec : iovecs_without_trailer) { + SHA256_Update(&ctx, iovec.out, iovec.len); + } - // Hash the remaining data without leaking |data_size|. + // Hash the remaining data without leaking |data_in_trailer_size|. uint8_t mac_out[SHA256_DIGEST_LENGTH]; - if (!EVP_sha256_final_with_secret_suffix( - &ctx, mac_out, data + min_data_size, data_size - min_data_size, - data_plus_mac_plus_padding_size - min_data_size)) { + if (!EVP_sha256_final_with_secret_suffix(&ctx, mac_out, trailer.data(), + data_in_trailer_size, + trailer.size())) { return 0; } @@ -452,22 +448,22 @@ return 1; } -int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out, - size_t *md_out_size, const uint8_t header[13], - const uint8_t *data, size_t data_size, - size_t data_plus_mac_plus_padding_size, - const uint8_t *mac_secret, - unsigned mac_secret_length) { +int EVP_tls_cbc_digest_record( + const EVP_MD *md, uint8_t *md_out, size_t *md_out_size, + const uint8_t len_header[2], bssl::Span<const CRYPTO_IVEC> aadvecs, + bssl::Span<const CRYPTO_IOVEC> iovecs_without_trailer, + bssl::Span<const uint8_t> trailer, size_t data_in_trailer_size, + const uint8_t *mac_secret, unsigned mac_secret_length) { switch (EVP_MD_type(md)) { case NID_sha1: - return tls_cbc_digest_record_sha1( - md_out, md_out_size, header, data, data_size, - data_plus_mac_plus_padding_size, mac_secret, mac_secret_length); + return tls_cbc_digest_record_sha1( // + md_out, md_out_size, len_header, aadvecs, iovecs_without_trailer, + trailer, data_in_trailer_size, mac_secret, mac_secret_length); case NID_sha256: - return tls_cbc_digest_record_sha256( - md_out, md_out_size, header, data, data_size, - data_plus_mac_plus_padding_size, mac_secret, mac_secret_length); + return tls_cbc_digest_record_sha256( // + md_out, md_out_size, len_header, aadvecs, iovecs_without_trailer, + trailer, data_in_trailer_size, mac_secret, mac_secret_length); default: // EVP_tls_cbc_record_digest_supported should have been called first to
diff --git a/crypto/internal.h b/crypto/internal.h index 1a22a94..10a041e 100644 --- a/crypto/internal.h +++ b/crypto/internal.h
@@ -472,8 +472,17 @@ #else -#define CONSTTIME_SECRET(ptr, len) -#define CONSTTIME_DECLASSIFY(ptr, len) +// Just disable unused warnings for those. +#define CONSTTIME_SECRET(ptr, len) \ + do { \ + (void)(ptr); \ + (void)(len); \ + } while (false) +#define CONSTTIME_DECLASSIFY(ptr, len) \ + do { \ + (void)(ptr); \ + (void)(len); \ + } while (false) #endif // BORINGSSL_CONSTANT_TIME_VALIDATION