Switch HPKE to a three-parameter output buffer. This is a little tedious but aligns with some of our other variable-length parameters. This is in preparation for making the HPKE APIs KEM-agnostic, so we don't need to make so many variations on the HPKE functions for each KEM. (Especially if we ever need to implement SetupPSK*, SetupAuth*, or SetupAuthPSK*.) Bug: 410 Change-Id: I0625580b15358ab1f02b7835122256e8f058a779 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/47328 Commit-Queue: David Benjamin <davidben@google.com> Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/hpke/hpke.c b/crypto/hpke/hpke.c index 3e98159..09bd020 100644 --- a/crypto/hpke/hpke.c +++ b/crypto/hpke/hpke.c
@@ -292,7 +292,7 @@ } int EVP_HPKE_CTX_setup_base_s_x25519(EVP_HPKE_CTX *hpke, uint8_t *out_enc, - size_t out_enc_len, + size_t *out_enc_len, size_t max_enc, const EVP_HPKE_KDF *kdf, const EVP_HPKE_AEAD *aead, const uint8_t *peer_public_value, @@ -301,17 +301,17 @@ uint8_t seed[X25519_PRIVATE_KEY_LEN]; RAND_bytes(seed, sizeof(seed)); return EVP_HPKE_CTX_setup_base_s_x25519_with_seed_for_testing( - hpke, out_enc, out_enc_len, kdf, aead, peer_public_value, + hpke, out_enc, out_enc_len, max_enc, kdf, aead, peer_public_value, peer_public_value_len, info, info_len, seed, sizeof(seed)); } int EVP_HPKE_CTX_setup_base_s_x25519_with_seed_for_testing( - EVP_HPKE_CTX *hpke, uint8_t *out_enc, size_t out_enc_len, + EVP_HPKE_CTX *hpke, uint8_t *out_enc, size_t *out_enc_len, size_t max_enc, const EVP_HPKE_KDF *kdf, const EVP_HPKE_AEAD *aead, const uint8_t *peer_public_value, size_t peer_public_value_len, const uint8_t *info, size_t info_len, const uint8_t *seed, size_t seed_len) { - if (out_enc_len != X25519_PUBLIC_VALUE_LEN) { + if (max_enc < X25519_PUBLIC_VALUE_LEN) { OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE); return 0; } @@ -334,6 +334,7 @@ info_len)) { return 0; } + *out_enc_len = X25519_PUBLIC_VALUE_LEN; return 1; }
diff --git a/crypto/hpke/hpke_test.cc b/crypto/hpke/hpke_test.cc index 82ba229..c7bc2c4 100644 --- a/crypto/hpke/hpke_test.cc +++ b/crypto/hpke/hpke_test.cc
@@ -63,16 +63,17 @@ // Set up the sender. ScopedEVP_HPKE_CTX sender_ctx; uint8_t enc[X25519_PUBLIC_VALUE_LEN]; + size_t enc_len; ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519_with_seed_for_testing( - sender_ctx.get(), enc, sizeof(enc), kdf, aead, public_key_r_.data(), - public_key_r_.size(), info_.data(), info_.size(), secret_key_e_.data(), - secret_key_e_.size())); - EXPECT_EQ(Bytes(enc), Bytes(public_key_e_)); + sender_ctx.get(), enc, &enc_len, sizeof(enc), kdf, aead, + public_key_r_.data(), public_key_r_.size(), info_.data(), info_.size(), + secret_key_e_.data(), secret_key_e_.size())); + EXPECT_EQ(Bytes(enc, enc_len), Bytes(public_key_e_)); // Set up the receiver. ScopedEVP_HPKE_CTX receiver_ctx; ASSERT_TRUE(EVP_HPKE_CTX_setup_base_r_x25519( - receiver_ctx.get(), kdf, aead, enc, sizeof(enc), public_key_r_.data(), + receiver_ctx.get(), kdf, aead, enc, enc_len, public_key_r_.data(), public_key_r_.size(), secret_key_r_.data(), secret_key_r_.size(), info_.data(), info_.size())); @@ -265,14 +266,15 @@ // Set up the sender. ScopedEVP_HPKE_CTX sender_ctx; uint8_t enc[X25519_PUBLIC_VALUE_LEN]; + size_t enc_len; ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519( - sender_ctx.get(), enc, sizeof(enc), kdf(), aead(), public_key_r, - sizeof(public_key_r), info.data(), info.size())); + sender_ctx.get(), enc, &enc_len, sizeof(enc), kdf(), aead(), + public_key_r, sizeof(public_key_r), info.data(), info.size())); // Set up the receiver. ScopedEVP_HPKE_CTX receiver_ctx; ASSERT_TRUE(EVP_HPKE_CTX_setup_base_r_x25519( - receiver_ctx.get(), kdf(), aead(), enc, sizeof(enc), public_key_r, + receiver_ctx.get(), kdf(), aead(), enc, enc_len, public_key_r, sizeof(public_key_r), secret_key_r, sizeof(secret_key_r), info.data(), info.size())); @@ -328,9 +330,10 @@ // Set up the sender, passing in kSmallOrderPoint as |peer_public_value|. ScopedEVP_HPKE_CTX sender_ctx; uint8_t enc[X25519_PUBLIC_VALUE_LEN]; + size_t enc_len; ASSERT_FALSE(EVP_HPKE_CTX_setup_base_s_x25519( - sender_ctx.get(), enc, sizeof(enc), kdf(), aead(), kSmallOrderPoint, - sizeof(kSmallOrderPoint), nullptr, 0)); + sender_ctx.get(), enc, &enc_len, sizeof(enc), kdf(), aead(), + kSmallOrderPoint, sizeof(kSmallOrderPoint), nullptr, 0)); // Set up the receiver, passing in kSmallOrderPoint as |enc|. ScopedEVP_HPKE_CTX receiver_ctx; @@ -381,8 +384,9 @@ // Set up the sender. ScopedEVP_HPKE_CTX sender_ctx; uint8_t enc[X25519_PUBLIC_VALUE_LEN]; + size_t enc_len; ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519( - sender_ctx.get(), enc, sizeof(enc), EVP_hpke_hkdf_sha256(), + sender_ctx.get(), enc, &enc_len, sizeof(enc), EVP_hpke_hkdf_sha256(), EVP_hpke_aes_128_gcm(), public_key_r, sizeof(public_key_r), nullptr, 0)); // Call Open() on the sender. @@ -393,15 +397,16 @@ kMockCiphertextLen, nullptr, 0)); } -TEST(HPKETest, SetupSenderWrongLengthEnc) { +TEST(HPKETest, SetupSenderBufferTooSmall) { uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN]; uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN]; X25519_keypair(public_key_r, secret_key_r); ScopedEVP_HPKE_CTX sender_ctx; - uint8_t bogus_enc[X25519_PUBLIC_VALUE_LEN + 5]; + uint8_t enc[X25519_PUBLIC_VALUE_LEN - 1]; + size_t enc_len; ASSERT_FALSE(EVP_HPKE_CTX_setup_base_s_x25519( - sender_ctx.get(), bogus_enc, sizeof(bogus_enc), EVP_hpke_hkdf_sha256(), + sender_ctx.get(), enc, &enc_len, sizeof(enc), EVP_hpke_hkdf_sha256(), EVP_hpke_aes_128_gcm(), public_key_r, sizeof(public_key_r), nullptr, 0)); uint32_t err = ERR_get_error(); EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err)); @@ -409,6 +414,22 @@ ERR_clear_error(); } +TEST(HPKETest, SetupSenderBufferTooLarge) { + uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN]; + uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN]; + X25519_keypair(public_key_r, secret_key_r); + + // Too large of an output buffer is fine because the function reports the + // actual length. + ScopedEVP_HPKE_CTX sender_ctx; + uint8_t enc[X25519_PUBLIC_VALUE_LEN + 1]; + size_t enc_len; + EXPECT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519( + sender_ctx.get(), enc, &enc_len, sizeof(enc), EVP_hpke_hkdf_sha256(), + EVP_hpke_aes_128_gcm(), public_key_r, sizeof(public_key_r), nullptr, 0)); + EXPECT_EQ(size_t{X25519_PUBLIC_VALUE_LEN}, enc_len); +} + TEST(HPKETest, SetupReceiverWrongLengthEnc) { uint8_t private_key[X25519_PRIVATE_KEY_LEN]; uint8_t public_key[X25519_PUBLIC_VALUE_LEN]; @@ -431,8 +452,9 @@ const uint8_t bogus_public_key_r[X25519_PRIVATE_KEY_LEN + 5] = {0xff}; ScopedEVP_HPKE_CTX sender_ctx; uint8_t enc[X25519_PUBLIC_VALUE_LEN]; + size_t enc_len; ASSERT_FALSE(EVP_HPKE_CTX_setup_base_s_x25519( - sender_ctx.get(), enc, sizeof(enc), EVP_hpke_hkdf_sha256(), + sender_ctx.get(), enc, &enc_len, sizeof(enc), EVP_hpke_hkdf_sha256(), EVP_hpke_aes_128_gcm(), bogus_public_key_r, sizeof(bogus_public_key_r), nullptr, 0)); uint32_t err = ERR_get_error();
diff --git a/crypto/hpke/internal.h b/crypto/hpke/internal.h index 6dee25a..db98d72 100644 --- a/crypto/hpke/internal.h +++ b/crypto/hpke/internal.h
@@ -89,11 +89,12 @@ // recipient's public key). It returns one on success, and zero otherwise. Note // that this function will fail if |peer_public_value| is invalid. // -// This function writes the encapsulated shared secret, a Diffie-Hellman public -// key, to |out_enc|. It will fail if the buffer's size in |out_enc_len| is not -// exactly |X25519_PUBLIC_VALUE_LEN|. +// This function writes the encapsulated shared secret to |out_enc| and sets +// |*out_enc_len| to the number of bytes written. It writes at most |max_enc| +// bytes and fails if the buffer is too small. |max_enc| must be at least +// |X25519_PUBLIC_VALUE_LEN| to ensure the buffer is large enough. OPENSSL_EXPORT int EVP_HPKE_CTX_setup_base_s_x25519( - EVP_HPKE_CTX *hpke, uint8_t *out_enc, size_t out_enc_len, + EVP_HPKE_CTX *hpke, uint8_t *out_enc, size_t *out_enc_len, size_t max_enc, const EVP_HPKE_KDF *kdf, const EVP_HPKE_AEAD *aead, const uint8_t *peer_public_value, size_t peer_public_value_len, const uint8_t *info, size_t info_len); @@ -102,7 +103,7 @@ // |EVP_HPKE_CTX_setup_base_s_x25519|, but takes a seed value to behave // deterministically. This seed is the sender's ephemeral X25519 key. OPENSSL_EXPORT int EVP_HPKE_CTX_setup_base_s_x25519_with_seed_for_testing( - EVP_HPKE_CTX *hpke, uint8_t *out_enc, size_t out_enc_len, + EVP_HPKE_CTX *hpke, uint8_t *out_enc, size_t *out_enc_len, size_t max_enc, const EVP_HPKE_KDF *kdf, const EVP_HPKE_AEAD *aead, const uint8_t *peer_public_value, size_t peer_public_value_len, const uint8_t *info, size_t info_len, const uint8_t *seed, size_t seed_len);