fix: handle external join in processCommit and relax KeyPackage ciphersuite check

processCommit now detects ExternalInit proposals and allows the sender
leaf index to equal tree.leafCount (the new joiner's slot), matching
RFC 9420 Section 12.4.3.2 external commit semantics.

MlsKeyPackage.decodeTls no longer rejects non-0x0001 ciphersuites so
that interop test vectors with other suites round-trip correctly.

https://claude.ai/code/session_01LpR6qsF6nep1RnXA9KbXGs
This commit is contained in:
Claude
2026-04-08 14:14:24 +00:00
parent b5ee266169
commit 91eef089dc
2 changed files with 21 additions and 8 deletions
@@ -637,15 +637,28 @@ class MlsGroup private constructor(
senderLeafIndex: Int,
confirmationTag: ByteArray? = null,
) {
require(senderLeafIndex >= 0 && senderLeafIndex < tree.leafCount) {
"Invalid sender leaf index: $senderLeafIndex"
}
require(tree.getLeaf(senderLeafIndex) != null) {
"Sender leaf is blank at index $senderLeafIndex"
}
val commit = Commit.decodeTls(TlsReader(commitBytes))
// External commits (containing ExternalInit) have a sender that is not
// yet in the tree — their leaf will be added via the UpdatePath below.
val isExternalCommit =
commit.proposals.any {
it is ProposalOrRef.Inline && it.proposal is Proposal.ExternalInit
}
if (isExternalCommit) {
require(senderLeafIndex >= 0 && senderLeafIndex <= tree.leafCount) {
"Invalid sender leaf index for external commit: $senderLeafIndex"
}
} else {
require(senderLeafIndex >= 0 && senderLeafIndex < tree.leafCount) {
"Invalid sender leaf index: $senderLeafIndex"
}
require(tree.getLeaf(senderLeafIndex) != null) {
"Sender leaf is blank at index $senderLeafIndex"
}
}
// Apply proposals (resolve references from pending pool)
for (proposalOrRef in commit.proposals) {
when (proposalOrRef) {
@@ -122,7 +122,7 @@ data class MlsKeyPackage(
val version = reader.readUint16()
require(version == 1) { "Unsupported MLS version: $version" }
val cipherSuite = reader.readUint16()
require(cipherSuite == 1) { "Unsupported ciphersuite: $cipherSuite" }
require(cipherSuite in 1..0xFFFF) { "Invalid ciphersuite: $cipherSuite" }
return MlsKeyPackage(
version = version,
cipherSuite = cipherSuite,