From d9ee55a89f9eee0c8febccc1091b4770401407ef Mon Sep 17 00:00:00 2001 From: Dan McArdle Date: Mon, 15 Mar 2021 16:55:36 -0400 Subject: [PATCH] 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 Commit-Queue: David Benjamin --- crypto/err/evp.errordata | 1 + crypto/hpke/hpke.c | 122 ++++++++++++++----- crypto/hpke/hpke_test.cc | 226 ++++++++++++++++++++++++++++++----- crypto/hpke/internal.h | 78 ++++++------ include/openssl/evp_errors.h | 1 + 5 files changed, 331 insertions(+), 97 deletions(-) diff --git a/crypto/err/evp.errordata b/crypto/err/evp.errordata index d0f09d4e1..a581b1b30 100644 --- a/crypto/err/evp.errordata +++ b/crypto/err/evp.errordata @@ -9,6 +9,7 @@ EVP,106,EXPECTING_AN_EC_KEY_KEY 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 d3e9c7c49..29f60fc52 100644 --- a/crypto/hpke/hpke.c +++ b/crypto/hpke/hpke.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -316,27 +317,44 @@ void EVP_HPKE_CTX_cleanup(EVP_HPKE_CTX *ctx) { 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 @@ int EVP_HPKE_CTX_setup_base_s_x25519_for_test( 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 @@ int EVP_HPKE_CTX_setup_base_r_x25519( 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_s_x25519_for_test( } 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 c007b3d82..d3f841ccb 100644 --- a/crypto/hpke/hpke_test.cc +++ b/crypto/hpke/hpke_test.cc @@ -62,13 +62,15 @@ class HPKETestVector { // 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 @@ class HPKETestVector { // 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 @@ TEST(HPKETest, RoundTrip) { 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 @@ TEST(HPKETest, X25519EncapSmallOrderPoint) { 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 @@ TEST(HPKETest, ReceiverInvalidSeal) { 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 @@ TEST(HPKETest, SenderInvalidOpen) { 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,11 +439,12 @@ TEST(HPKETest, EmptyPSK) { 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); + ASSERT_EQ( + 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); if (!kExpectSuccess) { uint32_t err = ERR_get_error(); @@ -446,12 +454,13 @@ TEST(HPKETest, EmptyPSK) { 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, - nullptr, 0, psk.data(), psk.size(), psk_id.data(), psk_id.size()), - kExpectSuccess); + 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(); @@ -463,6 +472,165 @@ TEST(HPKETest, EmptyPSK) { } } +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 3d2f4ba07..51a33130e 100644 --- a/crypto/hpke/internal.h +++ b/crypto/hpke/internal.h @@ -86,32 +86,35 @@ OPENSSL_EXPORT void EVP_HPKE_CTX_cleanup(EVP_HPKE_CTX *ctx); // 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 @@ OPENSSL_EXPORT int EVP_HPKE_CTX_setup_base_r_x25519( // 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 2482584aa..8583f521c 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