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);