Refactor HPKE API to include explicit length parameters.
Bug: 275
Change-Id: I724e9315b860e230e8fed92de34d89a875ef043c
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/46184
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/err/evp.errordata b/crypto/err/evp.errordata
index d0f09d4..a581b1b 100644
--- a/crypto/err/evp.errordata
+++ b/crypto/err/evp.errordata
@@ -9,6 +9,7 @@
EVP,107,EXPECTING_AN_RSA_KEY
EVP,108,EXPECTING_A_DSA_KEY
EVP,109,ILLEGAL_OR_UNSUPPORTED_PADDING_MODE
+EVP,137,INVALID_BUFFER_SIZE
EVP,110,INVALID_DIGEST_LENGTH
EVP,111,INVALID_DIGEST_TYPE
EVP,112,INVALID_KEYBITS
diff --git a/crypto/hpke/hpke.c b/crypto/hpke/hpke.c
index d3e9c7c..29f60fc 100644
--- a/crypto/hpke/hpke.c
+++ b/crypto/hpke/hpke.c
@@ -17,6 +17,7 @@
#include <openssl/aead.h>
#include <openssl/bytestring.h>
+#include <openssl/curve25519.h>
#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/evp_errors.h>
@@ -316,27 +317,44 @@
EVP_AEAD_CTX_cleanup(&ctx->aead_ctx);
}
-int EVP_HPKE_CTX_setup_base_s_x25519(
- EVP_HPKE_CTX *hpke, uint8_t out_enc[X25519_PUBLIC_VALUE_LEN],
- uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
- const uint8_t *info, size_t info_len) {
+int EVP_HPKE_CTX_setup_base_s_x25519(EVP_HPKE_CTX *hpke, uint8_t *out_enc,
+ size_t out_enc_len, uint16_t kdf_id,
+ uint16_t aead_id,
+ const uint8_t *peer_public_value,
+ size_t peer_public_value_len,
+ const uint8_t *info, size_t info_len) {
+ if (out_enc_len != X25519_PUBLIC_VALUE_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
+ return 0;
+ }
+
// The GenerateKeyPair() step technically belongs in the KEM's Encap()
// function, but we've moved it up a layer to make it easier for tests to
// inject an ephemeral keypair.
uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN];
X25519_keypair(out_enc, ephemeral_private);
return EVP_HPKE_CTX_setup_base_s_x25519_for_test(
- hpke, kdf_id, aead_id, peer_public_value, info, info_len,
- ephemeral_private, out_enc);
+ hpke, kdf_id, aead_id, peer_public_value, peer_public_value_len, info,
+ info_len, ephemeral_private, sizeof(ephemeral_private), out_enc,
+ out_enc_len);
}
int EVP_HPKE_CTX_setup_base_s_x25519_for_test(
EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
- const uint8_t *info, size_t info_len,
- const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],
- const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN]) {
+ const uint8_t *peer_public_value, size_t peer_public_value_len,
+ const uint8_t *info, size_t info_len, const uint8_t *ephemeral_private,
+ size_t ephemeral_private_len, const uint8_t *ephemeral_public,
+ size_t ephemeral_public_len) {
+ if (peer_public_value_len != X25519_PUBLIC_VALUE_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
+ return 0;
+ }
+ if (ephemeral_private_len != X25519_PRIVATE_KEY_LEN ||
+ ephemeral_public_len != X25519_PUBLIC_VALUE_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+ return 0;
+ }
+
hpke->is_sender = 1;
hpke->kdf_id = kdf_id;
hpke->aead_id = aead_id;
@@ -355,12 +373,23 @@
return 1;
}
-int EVP_HPKE_CTX_setup_base_r_x25519(
- EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t enc[X25519_PUBLIC_VALUE_LEN],
- const uint8_t public_key[X25519_PUBLIC_VALUE_LEN],
- const uint8_t private_key[X25519_PRIVATE_KEY_LEN], const uint8_t *info,
- size_t info_len) {
+int EVP_HPKE_CTX_setup_base_r_x25519(EVP_HPKE_CTX *hpke, uint16_t kdf_id,
+ uint16_t aead_id, const uint8_t *enc,
+ size_t enc_len, const uint8_t *public_key,
+ size_t public_key_len,
+ const uint8_t *private_key,
+ size_t private_key_len,
+ const uint8_t *info, size_t info_len) {
+ if (enc_len != X25519_PUBLIC_VALUE_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
+ return 0;
+ }
+ if (public_key_len != X25519_PUBLIC_VALUE_LEN ||
+ private_key_len != X25519_PRIVATE_KEY_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+ return 0;
+ }
+
hpke->is_sender = 0;
hpke->kdf_id = kdf_id;
hpke->aead_id = aead_id;
@@ -378,29 +407,47 @@
return 1;
}
-int EVP_HPKE_CTX_setup_psk_s_x25519(
- EVP_HPKE_CTX *hpke, uint8_t out_enc[X25519_PUBLIC_VALUE_LEN],
- uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
- const uint8_t *info, size_t info_len, const uint8_t *psk, size_t psk_len,
- const uint8_t *psk_id, size_t psk_id_len) {
+int EVP_HPKE_CTX_setup_psk_s_x25519(EVP_HPKE_CTX *hpke, uint8_t *out_enc,
+ size_t out_enc_len, uint16_t kdf_id,
+ uint16_t aead_id,
+ const uint8_t *peer_public_value,
+ size_t peer_public_value_len,
+ const uint8_t *info, size_t info_len,
+ const uint8_t *psk, size_t psk_len,
+ const uint8_t *psk_id, size_t psk_id_len) {
+ if (out_enc_len != X25519_PUBLIC_VALUE_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
+ return 0;
+ }
+
// The GenerateKeyPair() step technically belongs in the KEM's Encap()
// function, but we've moved it up a layer to make it easier for tests to
// inject an ephemeral keypair.
uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN];
X25519_keypair(out_enc, ephemeral_private);
return EVP_HPKE_CTX_setup_psk_s_x25519_for_test(
- hpke, kdf_id, aead_id, peer_public_value, info, info_len, psk, psk_len,
- psk_id, psk_id_len, ephemeral_private, out_enc);
+ hpke, kdf_id, aead_id, peer_public_value, peer_public_value_len, info,
+ info_len, psk, psk_len, psk_id, psk_id_len, ephemeral_private,
+ sizeof(ephemeral_private), out_enc, out_enc_len);
}
int EVP_HPKE_CTX_setup_psk_s_x25519_for_test(
EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
+ const uint8_t *peer_public_value, size_t peer_public_value_len,
const uint8_t *info, size_t info_len, const uint8_t *psk, size_t psk_len,
- const uint8_t *psk_id, size_t psk_id_len,
- const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],
- const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN]) {
+ const uint8_t *psk_id, size_t psk_id_len, const uint8_t *ephemeral_private,
+ size_t ephemeral_private_len, const uint8_t *ephemeral_public,
+ size_t ephemeral_public_len) {
+ if (peer_public_value_len != X25519_PUBLIC_VALUE_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
+ return 0;
+ }
+ if (ephemeral_private_len != X25519_PRIVATE_KEY_LEN ||
+ ephemeral_public_len != X25519_PUBLIC_VALUE_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+ return 0;
+ }
+
hpke->is_sender = 1;
hpke->kdf_id = kdf_id;
hpke->aead_id = aead_id;
@@ -420,12 +467,21 @@
}
int EVP_HPKE_CTX_setup_psk_r_x25519(
- EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t enc[X25519_PUBLIC_VALUE_LEN],
- const uint8_t public_key[X25519_PUBLIC_VALUE_LEN],
- const uint8_t private_key[X25519_PRIVATE_KEY_LEN], const uint8_t *info,
+ EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id, const uint8_t *enc,
+ size_t enc_len, const uint8_t *public_key, size_t public_key_len,
+ const uint8_t *private_key, size_t private_key_len, const uint8_t *info,
size_t info_len, const uint8_t *psk, size_t psk_len, const uint8_t *psk_id,
size_t psk_id_len) {
+ if (enc_len != X25519_PUBLIC_VALUE_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
+ return 0;
+ }
+ if (public_key_len != X25519_PUBLIC_VALUE_LEN ||
+ private_key_len != X25519_PRIVATE_KEY_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+ return 0;
+ }
+
hpke->is_sender = 0;
hpke->kdf_id = kdf_id;
hpke->aead_id = aead_id;
diff --git a/crypto/hpke/hpke_test.cc b/crypto/hpke/hpke_test.cc
index c007b3d..d3f841c 100644
--- a/crypto/hpke/hpke_test.cc
+++ b/crypto/hpke/hpke_test.cc
@@ -62,13 +62,15 @@
// Set up the sender.
ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519_for_test(
sender_ctx.get(), kdf_id_, aead_id_, public_key_r_.data(),
- info_.data(), info_.size(), secret_key_e_.data(),
- public_key_e_.data()));
+ public_key_r_.size(), info_.data(), info_.size(),
+ secret_key_e_.data(), secret_key_e_.size(), public_key_e_.data(),
+ public_key_e_.size()));
// Set up the receiver.
ASSERT_TRUE(EVP_HPKE_CTX_setup_base_r_x25519(
receiver_ctx.get(), kdf_id_, aead_id_, public_key_e_.data(),
- public_key_r_.data(), secret_key_r_.data(), info_.data(),
+ public_key_e_.size(), public_key_r_.data(), public_key_r_.size(),
+ secret_key_r_.data(), secret_key_r_.size(), info_.data(),
info_.size()));
break;
@@ -80,14 +82,15 @@
// Set up the sender.
ASSERT_TRUE(EVP_HPKE_CTX_setup_psk_s_x25519_for_test(
sender_ctx.get(), kdf_id_, aead_id_, public_key_r_.data(),
- info_.data(), info_.size(), psk_.data(), psk_.size(),
- psk_id_.data(), psk_id_.size(), secret_key_e_.data(),
- public_key_e_.data()));
+ public_key_r_.size(), info_.data(), info_.size(), psk_.data(),
+ psk_.size(), psk_id_.data(), psk_id_.size(), secret_key_e_.data(),
+ secret_key_e_.size(), public_key_e_.data(), public_key_e_.size()));
// Set up the receiver.
ASSERT_TRUE(EVP_HPKE_CTX_setup_psk_r_x25519(
receiver_ctx.get(), kdf_id_, aead_id_, public_key_e_.data(),
- public_key_r_.data(), secret_key_r_.data(), info_.data(),
+ public_key_e_.size(), public_key_r_.data(), public_key_r_.size(),
+ secret_key_r_.data(), secret_key_r_.size(), info_.data(),
info_.size(), psk_.data(), psk_.size(), psk_id_.data(),
psk_id_.size()));
break;
@@ -282,14 +285,15 @@
ScopedEVP_HPKE_CTX sender_ctx;
uint8_t enc[X25519_PUBLIC_VALUE_LEN];
ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519(
- sender_ctx.get(), enc, kdf_id, aead_id, public_key_r, info.data(),
- info.size()));
+ sender_ctx.get(), enc, sizeof(enc), kdf_id, aead_id, 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_id, aead_id, enc, public_key_r,
- secret_key_r, info.data(), info.size()));
+ receiver_ctx.get(), kdf_id, aead_id, enc, sizeof(enc),
+ public_key_r, sizeof(public_key_r), secret_key_r,
+ sizeof(secret_key_r), info.data(), info.size()));
const char kCleartextPayload[] = "foobar";
@@ -347,14 +351,15 @@
ScopedEVP_HPKE_CTX sender_ctx;
uint8_t enc[X25519_PUBLIC_VALUE_LEN];
ASSERT_FALSE(EVP_HPKE_CTX_setup_base_s_x25519(
- sender_ctx.get(), enc, kdf_id, aead_id, kSmallOrderPoint, nullptr,
- 0));
+ sender_ctx.get(), enc, sizeof(enc), kdf_id, aead_id, kSmallOrderPoint,
+ sizeof(kSmallOrderPoint), nullptr, 0));
// Set up the receiver, passing in kSmallOrderPoint as |enc|.
ScopedEVP_HPKE_CTX receiver_ctx;
ASSERT_FALSE(EVP_HPKE_CTX_setup_base_r_x25519(
- receiver_ctx.get(), kdf_id, aead_id, kSmallOrderPoint, public_key_r,
- secret_key_r, nullptr, 0));
+ receiver_ctx.get(), kdf_id, aead_id, kSmallOrderPoint,
+ sizeof(kSmallOrderPoint), public_key_r, sizeof(public_key_r),
+ secret_key_r, sizeof(secret_key_r), nullptr, 0));
}
}
}
@@ -373,7 +378,8 @@
ScopedEVP_HPKE_CTX receiver_ctx;
ASSERT_TRUE(EVP_HPKE_CTX_setup_base_r_x25519(
receiver_ctx.get(), EVP_HPKE_HKDF_SHA256, EVP_HPKE_AEAD_AES_GCM_128,
- kMockEnc, public_key_r, secret_key_r, nullptr, 0));
+ kMockEnc, sizeof(kMockEnc), public_key_r, sizeof(public_key_r),
+ secret_key_r, sizeof(secret_key_r), nullptr, 0));
// Call Seal() on the receiver.
size_t ciphertext_len;
@@ -398,8 +404,9 @@
ScopedEVP_HPKE_CTX sender_ctx;
uint8_t enc[X25519_PUBLIC_VALUE_LEN];
ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519(
- sender_ctx.get(), enc, EVP_HPKE_HKDF_SHA256, EVP_HPKE_AEAD_AES_GCM_128,
- public_key_r, nullptr, 0));
+ sender_ctx.get(), enc, sizeof(enc), EVP_HPKE_HKDF_SHA256,
+ EVP_HPKE_AEAD_AES_GCM_128, public_key_r, sizeof(public_key_r), nullptr,
+ 0));
// Call Open() on the sender.
uint8_t cleartext[128];
@@ -432,24 +439,10 @@
ScopedEVP_HPKE_CTX sender_ctx;
uint8_t enc[X25519_PUBLIC_VALUE_LEN];
- ASSERT_EQ(EVP_HPKE_CTX_setup_psk_s_x25519(
- sender_ctx.get(), enc, EVP_HPKE_HKDF_SHA256,
- EVP_HPKE_AEAD_AES_GCM_128, public_key_r, nullptr, 0,
- psk.data(), psk.size(), psk_id.data(), psk_id.size()),
- kExpectSuccess);
-
- if (!kExpectSuccess) {
- uint32_t err = ERR_get_error();
- EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
- EXPECT_EQ(EVP_R_EMPTY_PSK, ERR_GET_REASON(err));
- }
- ERR_clear_error();
-
- ScopedEVP_HPKE_CTX receiver_ctx;
ASSERT_EQ(
- EVP_HPKE_CTX_setup_psk_r_x25519(
- receiver_ctx.get(), EVP_HPKE_HKDF_SHA256,
- EVP_HPKE_AEAD_AES_GCM_128, kMockEnc, public_key_r, secret_key_r,
+ EVP_HPKE_CTX_setup_psk_s_x25519(
+ sender_ctx.get(), enc, sizeof(enc), EVP_HPKE_HKDF_SHA256,
+ EVP_HPKE_AEAD_AES_GCM_128, public_key_r, sizeof(public_key_r),
nullptr, 0, psk.data(), psk.size(), psk_id.data(), psk_id.size()),
kExpectSuccess);
@@ -459,10 +452,185 @@
EXPECT_EQ(EVP_R_EMPTY_PSK, ERR_GET_REASON(err));
}
ERR_clear_error();
+
+ ScopedEVP_HPKE_CTX receiver_ctx;
+ ASSERT_EQ(EVP_HPKE_CTX_setup_psk_r_x25519(
+ receiver_ctx.get(), EVP_HPKE_HKDF_SHA256,
+ EVP_HPKE_AEAD_AES_GCM_128, kMockEnc, sizeof(kMockEnc),
+ public_key_r, sizeof(public_key_r), secret_key_r,
+ sizeof(secret_key_r), nullptr, 0, psk.data(), psk.size(),
+ psk_id.data(), psk_id.size()),
+ kExpectSuccess);
+
+ if (!kExpectSuccess) {
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
+ EXPECT_EQ(EVP_R_EMPTY_PSK, ERR_GET_REASON(err));
+ }
+ ERR_clear_error();
}
}
}
+TEST(HPKETest, SetupSenderWrongLengthEnc) {
+ 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];
+ {
+ ASSERT_FALSE(EVP_HPKE_CTX_setup_base_s_x25519(
+ sender_ctx.get(), bogus_enc, sizeof(bogus_enc), EVP_HPKE_HKDF_SHA256,
+ EVP_HPKE_AEAD_AES_GCM_128, public_key_r, sizeof(public_key_r), nullptr,
+ 0));
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
+ EXPECT_EQ(EVP_R_INVALID_BUFFER_SIZE, ERR_GET_REASON(err));
+ ERR_clear_error();
+ }
+ {
+ const uint8_t psk[] = {1, 2, 3, 4};
+ const uint8_t psk_id[] = {1, 2, 3, 4};
+ ASSERT_FALSE(EVP_HPKE_CTX_setup_psk_s_x25519(
+ sender_ctx.get(), bogus_enc, sizeof(bogus_enc), EVP_HPKE_HKDF_SHA256,
+ EVP_HPKE_AEAD_AES_GCM_128, public_key_r, sizeof(public_key_r), nullptr,
+ 0, psk, sizeof(psk), psk_id, sizeof(psk_id)));
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
+ EXPECT_EQ(EVP_R_INVALID_BUFFER_SIZE, ERR_GET_REASON(err));
+ ERR_clear_error();
+ }
+}
+
+TEST(HPKETest, SetupReceiverWrongLengthEnc) {
+ uint8_t private_key[X25519_PRIVATE_KEY_LEN];
+ uint8_t public_key[X25519_PUBLIC_VALUE_LEN];
+ X25519_keypair(public_key, private_key);
+
+ const uint8_t bogus_enc[X25519_PUBLIC_VALUE_LEN + 5] = {0xff};
+
+ ScopedEVP_HPKE_CTX receiver_ctx;
+ {
+ ASSERT_FALSE(EVP_HPKE_CTX_setup_base_r_x25519(
+ receiver_ctx.get(), EVP_HPKE_HKDF_SHA256, EVP_HPKE_AEAD_AES_GCM_128,
+ bogus_enc, sizeof(bogus_enc), public_key, sizeof(public_key),
+ private_key, sizeof(private_key), nullptr, 0));
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
+ EXPECT_EQ(EVP_R_INVALID_PEER_KEY, ERR_GET_REASON(err));
+ ERR_clear_error();
+ }
+ {
+ const uint8_t psk[] = {1, 2, 3, 4};
+ const uint8_t psk_id[] = {1, 2, 3, 4};
+ ASSERT_FALSE(EVP_HPKE_CTX_setup_psk_r_x25519(
+ receiver_ctx.get(), EVP_HPKE_HKDF_SHA256, EVP_HPKE_AEAD_AES_GCM_128,
+ bogus_enc, sizeof(bogus_enc), public_key, sizeof(public_key),
+ private_key, sizeof(private_key), nullptr, 0, psk, sizeof(psk), psk_id,
+ sizeof(psk_id)));
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
+ EXPECT_EQ(EVP_R_INVALID_PEER_KEY, ERR_GET_REASON(err));
+ ERR_clear_error();
+ }
+}
+
+TEST(HPKETest, SetupSenderWrongLengthPeerPublicValue) {
+ 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];
+ {
+ ASSERT_FALSE(EVP_HPKE_CTX_setup_base_s_x25519(
+ sender_ctx.get(), enc, sizeof(enc), EVP_HPKE_HKDF_SHA256,
+ EVP_HPKE_AEAD_AES_GCM_128, bogus_public_key_r,
+ sizeof(bogus_public_key_r), nullptr, 0));
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
+ EXPECT_EQ(EVP_R_INVALID_PEER_KEY, ERR_GET_REASON(err));
+ ERR_clear_error();
+ }
+ {
+ const uint8_t psk[] = {1, 2, 3, 4};
+ const uint8_t psk_id[] = {1, 2, 3, 4};
+
+ ASSERT_FALSE(EVP_HPKE_CTX_setup_psk_s_x25519(
+ sender_ctx.get(), enc, sizeof(enc), EVP_HPKE_HKDF_SHA256,
+ EVP_HPKE_AEAD_AES_GCM_128, bogus_public_key_r,
+ sizeof(bogus_public_key_r), nullptr, 0, psk, sizeof(psk), psk_id,
+ sizeof(psk_id)));
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
+ EXPECT_EQ(EVP_R_INVALID_PEER_KEY, ERR_GET_REASON(err));
+ ERR_clear_error();
+ }
+}
+
+TEST(HPKETest, SetupReceiverWrongLengthKeys) {
+ uint8_t private_key[X25519_PRIVATE_KEY_LEN];
+ uint8_t public_key[X25519_PUBLIC_VALUE_LEN];
+ X25519_keypair(public_key, private_key);
+
+ uint8_t unused[X25519_PRIVATE_KEY_LEN];
+ uint8_t enc[X25519_PUBLIC_VALUE_LEN];
+ X25519_keypair(enc, unused);
+
+ const uint8_t bogus_public_key[X25519_PUBLIC_VALUE_LEN + 5] = {0xff};
+ const uint8_t bogus_private_key[X25519_PUBLIC_VALUE_LEN + 5] = {0xff};
+
+ ScopedEVP_HPKE_CTX receiver_ctx;
+ {
+ // Test base mode with |bogus_public_key|.
+ ASSERT_FALSE(EVP_HPKE_CTX_setup_base_r_x25519(
+ receiver_ctx.get(), EVP_HPKE_HKDF_SHA256, EVP_HPKE_AEAD_AES_GCM_128,
+ enc, sizeof(enc), bogus_public_key, sizeof(bogus_public_key),
+ private_key, sizeof(private_key), nullptr, 0));
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
+ EXPECT_EQ(EVP_R_DECODE_ERROR, ERR_GET_REASON(err));
+ ERR_clear_error();
+ }
+ {
+ // Test base mode with |bogus_private_key|.
+ ASSERT_FALSE(EVP_HPKE_CTX_setup_base_r_x25519(
+ receiver_ctx.get(), EVP_HPKE_HKDF_SHA256, EVP_HPKE_AEAD_AES_GCM_128,
+ enc, sizeof(enc), public_key, sizeof(public_key), bogus_private_key,
+ sizeof(bogus_private_key), nullptr, 0));
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
+ EXPECT_EQ(EVP_R_DECODE_ERROR, ERR_GET_REASON(err));
+ ERR_clear_error();
+ }
+ {
+ // Test PSK mode with |bogus_public_key|.
+ const uint8_t psk[] = {1, 2, 3, 4};
+ const uint8_t psk_id[] = {1, 2, 3, 4};
+ ASSERT_FALSE(EVP_HPKE_CTX_setup_psk_r_x25519(
+ receiver_ctx.get(), EVP_HPKE_HKDF_SHA256, EVP_HPKE_AEAD_AES_GCM_128,
+ enc, sizeof(enc), bogus_public_key, sizeof(bogus_public_key),
+ private_key, sizeof(private_key), nullptr, 0, psk, sizeof(psk), psk_id,
+ sizeof(psk_id)));
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
+ EXPECT_EQ(EVP_R_DECODE_ERROR, ERR_GET_REASON(err));
+ ERR_clear_error();
+ }
+ {
+ // Test PSK mode with |bogus_private_key|.
+ const uint8_t psk[] = {1, 2, 3, 4};
+ const uint8_t psk_id[] = {1, 2, 3, 4};
+ ASSERT_FALSE(EVP_HPKE_CTX_setup_psk_r_x25519(
+ receiver_ctx.get(), EVP_HPKE_HKDF_SHA256, EVP_HPKE_AEAD_AES_GCM_128,
+ enc, sizeof(enc), public_key, sizeof(public_key), bogus_private_key,
+ sizeof(bogus_private_key), nullptr, 0, psk, sizeof(psk), psk_id,
+ sizeof(psk_id)));
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
+ EXPECT_EQ(EVP_R_DECODE_ERROR, ERR_GET_REASON(err));
+ ERR_clear_error();
+ }
+}
+
TEST(HPKETest, InternalParseIntSafe) {
uint8_t u8 = 0xff;
ASSERT_FALSE(ParseIntSafe(&u8, "-1"));
diff --git a/crypto/hpke/internal.h b/crypto/hpke/internal.h
index 3d2f4ba..51a3313 100644
--- a/crypto/hpke/internal.h
+++ b/crypto/hpke/internal.h
@@ -86,32 +86,35 @@
// 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 to |out_enc|.
+// 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|.
OPENSSL_EXPORT int EVP_HPKE_CTX_setup_base_s_x25519(
- EVP_HPKE_CTX *hpke, uint8_t out_enc[X25519_PUBLIC_VALUE_LEN],
- uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
- const uint8_t *info, size_t info_len);
+ EVP_HPKE_CTX *hpke, uint8_t *out_enc, size_t out_enc_len, uint16_t kdf_id,
+ uint16_t aead_id, const uint8_t *peer_public_value,
+ size_t peer_public_value_len, const uint8_t *info, size_t info_len);
// EVP_HPKE_CTX_setup_base_s_x25519_for_test behaves like
// |EVP_HPKE_CTX_setup_base_s_x25519|, but takes a pre-generated ephemeral
-// sender key.
+// sender key. The caller ensures that |ephemeral_public| and
+// |ephemeral_private| are a valid keypair.
OPENSSL_EXPORT int EVP_HPKE_CTX_setup_base_s_x25519_for_test(
EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
- const uint8_t *info, size_t info_len,
- const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],
- const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN]);
+ const uint8_t *peer_public_value, size_t peer_public_value_len,
+ const uint8_t *info, size_t info_len, const uint8_t *ephemeral_private,
+ size_t ephemeral_private_len, const uint8_t *ephemeral_public,
+ size_t ephemeral_public_len);
// EVP_HPKE_CTX_setup_base_r_x25519 sets up |hpke| as a recipient context that
-// can decrypt messages. |private_key| is the recipient's private key, and |enc|
-// is the encapsulated shared secret from the sender. Note that this function
-// will fail if |enc| is invalid.
+// can decrypt messages. It returns one on success, and zero otherwise.
+//
+// The recipient's keypair is composed of |public_key| and |private_key|, and
+// |enc| is the encapsulated shared secret from the sender. If |enc| is invalid,
+// this function will fail.
OPENSSL_EXPORT int EVP_HPKE_CTX_setup_base_r_x25519(
- EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t enc[X25519_PUBLIC_VALUE_LEN],
- const uint8_t public_key[X25519_PUBLIC_VALUE_LEN],
- const uint8_t private_key[X25519_PRIVATE_KEY_LEN], const uint8_t *info,
+ EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id, const uint8_t *enc,
+ size_t enc_len, const uint8_t *public_key, size_t public_key_len,
+ const uint8_t *private_key, size_t private_key_len, const uint8_t *info,
size_t info_len);
// EVP_HPKE_CTX_setup_psk_s_x25519 sets up |hpke| as a sender context that can
@@ -124,39 +127,44 @@
// must be nonempty (|psk_len| and |psk_id_len| must be non-zero), or this
// function will fail.
//
-// This function writes the encapsulated shared secret to |out_enc|.
+// 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|.
OPENSSL_EXPORT int EVP_HPKE_CTX_setup_psk_s_x25519(
- EVP_HPKE_CTX *hpke, uint8_t out_enc[X25519_PUBLIC_VALUE_LEN],
- uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
- const uint8_t *info, size_t info_len, const uint8_t *psk, size_t psk_len,
- const uint8_t *psk_id, size_t psk_id_len);
+ EVP_HPKE_CTX *hpke, uint8_t *out_enc, size_t out_enc_len, uint16_t kdf_id,
+ uint16_t aead_id, const uint8_t *peer_public_value,
+ size_t peer_public_value_len, const uint8_t *info, size_t info_len,
+ const uint8_t *psk, size_t psk_len, const uint8_t *psk_id,
+ size_t psk_id_len);
// EVP_HPKE_CTX_setup_psk_s_x25519_for_test behaves like
// |EVP_HPKE_CTX_setup_psk_s_x25519|, but takes a pre-generated ephemeral sender
-// key.
+// key. The caller ensures that |ephemeral_public| and |ephemeral_private| are a
+// valid keypair.
OPENSSL_EXPORT int EVP_HPKE_CTX_setup_psk_s_x25519_for_test(
EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
+ const uint8_t *peer_public_value, size_t peer_public_value_len,
const uint8_t *info, size_t info_len, const uint8_t *psk, size_t psk_len,
- const uint8_t *psk_id, size_t psk_id_len,
- const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],
- const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN]);
+ const uint8_t *psk_id, size_t psk_id_len, const uint8_t *ephemeral_private,
+ size_t ephemeral_private_len, const uint8_t *ephemeral_public,
+ size_t ephemeral_public_len);
// EVP_HPKE_CTX_setup_psk_r_x25519 sets up |hpke| as a recipient context that
// can decrypt messages. Future open (decrypt) operations will fail if the
-// sender does not possess the PSK indicated by |psk| and |psk_id|.
-// |private_key| is the recipient's private key, and |enc| is the encapsulated
-// shared secret from the sender. If |enc| is invalid, this function will fail.
+// sender does not possess the PSK indicated by |psk| and |psk_id|. It returns
+// one on success, and zero otherwise.
+//
+// The recipient's keypair is composed of |public_key| and |private_key|, and
+// |enc| is the encapsulated shared secret from the sender. If |enc| is invalid,
+// this function will fail.
//
// The PSK and its ID must be provided in |psk| and |psk_id|, respectively. Both
// must be nonempty (|psk_len| and |psk_id_len| must be non-zero), or this
// function will fail.
OPENSSL_EXPORT int EVP_HPKE_CTX_setup_psk_r_x25519(
- EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t enc[X25519_PUBLIC_VALUE_LEN],
- const uint8_t public_key[X25519_PUBLIC_VALUE_LEN],
- const uint8_t private_key[X25519_PRIVATE_KEY_LEN], const uint8_t *info,
+ EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id, const uint8_t *enc,
+ size_t enc_len, const uint8_t *public_key, size_t public_key_len,
+ const uint8_t *private_key, size_t private_key_len, const uint8_t *info,
size_t info_len, const uint8_t *psk, size_t psk_len, const uint8_t *psk_id,
size_t psk_id_len);
diff --git a/include/openssl/evp_errors.h b/include/openssl/evp_errors.h
index 2482584..8583f52 100644
--- a/include/openssl/evp_errors.h
+++ b/include/openssl/evp_errors.h
@@ -94,5 +94,6 @@
#define EVP_R_INVALID_PEER_KEY 134
#define EVP_R_NOT_XOF_OR_INVALID_LENGTH 135
#define EVP_R_EMPTY_PSK 136
+#define EVP_R_INVALID_BUFFER_SIZE 137
#endif // OPENSSL_HEADER_EVP_ERRORS_H