fix(marmot): pass encrypted_group_info as HPKE context for Welcome

RFC 9420 §12.4.3.1 specifies the HPKE context for encrypted_group_secrets
must be the encrypted_group_info field of the Welcome:

    encrypted_group_secrets = EncryptWithLabel(init_key, "Welcome",
                                encrypted_group_info, group_secrets)

Both our buildWelcome and processWelcome were passing an empty context,
which let Amethyst↔Amethyst round-trips work, but made Welcome messages
sent by RFC-compliant implementations (MDK/OpenMLS, used by whitenoise)
fail with BAD_DECRYPT inside the HPKE AEAD open.

https://claude.ai/code/session_01HfHdd5S5rvxUW2ihEpLGJr
This commit is contained in:
Claude
2026-04-21 03:28:12 +00:00
parent f859449aba
commit 38b0c681d1
@@ -1472,12 +1472,13 @@ class MlsGroup private constructor(
)
val gsBytes = groupSecrets.toTlsBytes()
// HPKE-encrypt to the member's init_key
// HPKE-encrypt to the member's init_key. Per RFC 9420
// §12.4.3.1, the HPKE context is the encrypted_group_info.
val hpkeCt =
MlsCryptoProvider.encryptWithLabel(
kp.initKey,
"Welcome",
ByteArray(0),
encryptedGroupInfo,
gsBytes,
)
@@ -1715,12 +1716,13 @@ class MlsGroup private constructor(
welcome.secrets.find { it.newMember.contentEquals(myRef) }
?: throw IllegalArgumentException("Welcome does not contain secrets for our KeyPackage")
// HPKE-decrypt group secrets
// HPKE-decrypt group secrets. Per RFC 9420 §12.4.3.1, the HPKE
// context is the encrypted_group_info field of the Welcome.
val gsBytes =
MlsCryptoProvider.decryptWithLabel(
bundle.initPrivateKey,
"Welcome",
ByteArray(0),
welcome.encryptedGroupInfo,
mySecrets.encryptedGroupSecrets.kemOutput,
mySecrets.encryptedGroupSecrets.ciphertext,
)