Add an EVP_HPKE_KEM_enc_len API.

OHTTP concatenates enc to the ciphertext without any length prefix
(unlike ECH), so an implementation would want to know the length of enc
for the chosen KEM. Add an accessor to help with that.

While I'm here, fix a couple places where we assumed a specific KEM in
the HPKE implementation (although we still only support the one KEM so
this is all moot).

There's probably something to be said for lifting the length checks out
of the KEM-specific code and into the wrappers, as we're assuming
fixed-width fields anyway. But I've left it alone for now.

Change-Id: I634a053faa5e3b35d846b690140333bdc741f92a
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/54065
Reviewed-by: Adam Langley <agl@google.com>
Auto-Submit: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/hpke/hpke.c b/crypto/hpke/hpke.c
index 827ffaa..6e3d5e8 100644
--- a/crypto/hpke/hpke.c
+++ b/crypto/hpke/hpke.c
@@ -40,6 +40,7 @@
   size_t public_key_len;
   size_t private_key_len;
   size_t seed_len;
+  size_t enc_len;
   int (*init_key)(EVP_HPKE_KEY *key, const uint8_t *priv_key,
                   size_t priv_key_len);
   int (*generate_key)(EVP_HPKE_KEY *key);
@@ -216,6 +217,7 @@
       /*public_key_len=*/X25519_PUBLIC_VALUE_LEN,
       /*private_key_len=*/X25519_PRIVATE_KEY_LEN,
       /*seed_len=*/X25519_PRIVATE_KEY_LEN,
+      /*enc_len=*/X25519_PUBLIC_VALUE_LEN,
       x25519_init_key,
       x25519_generate_key,
       x25519_encap_with_seed,
@@ -226,6 +228,8 @@
 
 uint16_t EVP_HPKE_KEM_id(const EVP_HPKE_KEM *kem) { return kem->id; }
 
+size_t EVP_HPKE_KEM_enc_len(const EVP_HPKE_KEM *kem) { return kem->enc_len; }
+
 void EVP_HPKE_KEY_zero(EVP_HPKE_KEY *key) {
   OPENSSL_memset(key, 0, sizeof(EVP_HPKE_KEY));
 }
@@ -351,9 +355,9 @@
                                uint8_t out[HPKE_SUITE_ID_LEN]) {
   CBB cbb;
   int ret = CBB_init_fixed(&cbb, out, HPKE_SUITE_ID_LEN) &&
-            add_label_string(&cbb, "HPKE") &&
-            CBB_add_u16(&cbb, EVP_HPKE_DHKEM_X25519_HKDF_SHA256) &&
-            CBB_add_u16(&cbb, ctx->kdf->id) &&
+            add_label_string(&cbb, "HPKE") &&   //
+            CBB_add_u16(&cbb, ctx->kem->id) &&  //
+            CBB_add_u16(&cbb, ctx->kdf->id) &&  //
             CBB_add_u16(&cbb, ctx->aead->id);
   CBB_cleanup(&cbb);
   return ret;
@@ -487,6 +491,7 @@
     size_t seed_len) {
   EVP_HPKE_CTX_zero(ctx);
   ctx->is_sender = 1;
+  ctx->kem = kem;
   ctx->kdf = kdf;
   ctx->aead = aead;
   uint8_t shared_secret[MAX_SHARED_SECRET_LEN];
@@ -509,12 +514,13 @@
                                  size_t info_len) {
   EVP_HPKE_CTX_zero(ctx);
   ctx->is_sender = 0;
+  ctx->kem = key->kem;
   ctx->kdf = kdf;
   ctx->aead = aead;
   uint8_t shared_secret[MAX_SHARED_SECRET_LEN];
   size_t shared_secret_len;
   if (!key->kem->decap(key, shared_secret, &shared_secret_len, enc, enc_len) ||
-      !hpke_key_schedule(ctx, shared_secret, sizeof(shared_secret), info,
+      !hpke_key_schedule(ctx, shared_secret, shared_secret_len, info,
                          info_len)) {
     EVP_HPKE_CTX_cleanup(ctx);
     return 0;
@@ -609,6 +615,10 @@
   return EVP_AEAD_max_overhead(EVP_AEAD_CTX_aead(&ctx->aead_ctx));
 }
 
+const EVP_HPKE_KEM *EVP_HPKE_CTX_kem(const EVP_HPKE_CTX *ctx) {
+  return ctx->kem;
+}
+
 const EVP_HPKE_AEAD *EVP_HPKE_CTX_aead(const EVP_HPKE_CTX *ctx) {
   return ctx->aead;
 }
diff --git a/include/openssl/hpke.h b/include/openssl/hpke.h
index e2c9855..5b0373d 100644
--- a/include/openssl/hpke.h
+++ b/include/openssl/hpke.h
@@ -51,6 +51,14 @@
 // will be one of the |EVP_HPKE_KEM_*| constants.
 OPENSSL_EXPORT uint16_t EVP_HPKE_KEM_id(const EVP_HPKE_KEM *kem);
 
+// EVP_HPKE_MAX_ENC_LENGTH is the maximum length of "enc", the encapsulated
+// shared secret, for all supported KEMs in this library.
+#define EVP_HPKE_MAX_ENC_LENGTH 32
+
+// EVP_HPKE_KEM_enc_len returns the length of the "enc", the encapsulated shared
+// secret, for |kem|. This value will be at most |EVP_HPKE_MAX_ENC_LENGTH|.
+OPENSSL_EXPORT size_t EVP_HPKE_KEM_enc_len(const EVP_HPKE_KEM *kem);
+
 // The following constants are KDF identifiers.
 #define EVP_HPKE_HKDF_SHA256 0x0001
 
@@ -182,16 +190,13 @@
 // created with |EVP_HPKE_CTX_new|.
 OPENSSL_EXPORT void EVP_HPKE_CTX_free(EVP_HPKE_CTX *ctx);
 
-// EVP_HPKE_MAX_ENC_LENGTH is the maximum length of "enc", the encapsulated
-// shared secret, for all supported KEMs in this library.
-#define EVP_HPKE_MAX_ENC_LENGTH 32
-
 // EVP_HPKE_CTX_setup_sender implements the SetupBaseS HPKE operation. It
 // encapsulates a shared secret for |peer_public_key| and sets up |ctx| as a
 // sender context. It 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. Setting |max_enc| to at
-// least |EVP_HPKE_MAX_ENC_LENGTH| will ensure the buffer is large enough.
+// least |EVP_HPKE_MAX_ENC_LENGTH| will ensure the buffer is large enough. An
+// exact size may also be determined by |EVP_PKEY_KEM_enc_len|.
 //
 // This function returns one on success and zero on error. Note that
 // |peer_public_key| may be invalid, in which case this function will return an
@@ -292,6 +297,10 @@
 // up as a sender.
 OPENSSL_EXPORT size_t EVP_HPKE_CTX_max_overhead(const EVP_HPKE_CTX *ctx);
 
+// EVP_HPKE_CTX_kem returns |ctx|'s configured KEM, or NULL if the context has
+// not been set up.
+OPENSSL_EXPORT const EVP_HPKE_KEM *EVP_HPKE_CTX_kem(const EVP_HPKE_CTX *ctx);
+
 // EVP_HPKE_CTX_aead returns |ctx|'s configured AEAD, or NULL if the context has
 // not been set up.
 OPENSSL_EXPORT const EVP_HPKE_AEAD *EVP_HPKE_CTX_aead(const EVP_HPKE_CTX *ctx);
@@ -307,6 +316,7 @@
 // but accessing or modifying their fields is forbidden.
 
 struct evp_hpke_ctx_st {
+  const EVP_HPKE_KEM *kem;
   const EVP_HPKE_AEAD *aead;
   const EVP_HPKE_KDF *kdf;
   EVP_AEAD_CTX aead_ctx;