-
Notifications
You must be signed in to change notification settings - Fork 1.3k
CVE‐2026‐71885
Title: MLS X.509 credential not bound to the LeafNode signature key.
Issue affecting: BC before 1.86.
Fixed versions: BC 1.86.
Platform affected: Java 8 and later.
RFC 9420 sec. 5.3 makes a member's signature_key and its credential two views of the same identity: for an X.509 credential the leaf's signature_key is the public key certified by the credential's end-entity certificate. Bouncy Castle's MLS implementation never enforced that binding.
LeafNode.verify() verified a leaf's signature against the signature_key carried in the leaf itself, and its x509 branch was an empty placeholder. The credential's certificate chain was decoded onto the Credential object but never parsed, validated, or compared to anything — there was no accessor for it and no code read it — so the end-entity certificate's public key was never required to match signature_key. An X.509 credential therefore authenticated nothing.
A party could present another party's certificate as its credential while signing the leaf, and the enclosing KeyPackage, with an unrelated key of its own. Both KeyPackage.verify() and the Group leaf-validation path authenticate a leaf through LeafNode.verify(), so the forged leaf was accepted under the certificate subject's identity. In a deployment that publishes a current GroupInfo and ratchet tree for external joining and feeds external commits to Group.handle(...) without an independent credential-admission check, an unauthenticated attacker could be admitted under a victim's X.509 identity and evict the victim — resynchronization compares whole encoded credentials, not signing keys, so the attacker's leaf was treated as the same participant — then derive the current epoch, decrypt subsequent group messages, and send messages accepted as the victim.
TreeKEM.LeafNode.verify() now requires the end-entity certificate's subject public key, serialised in the cipher suite's signature encoding, to equal signature_key for an X.509 credential, and rejects the leaf otherwise — including an empty chain or a certificate whose key type does not match the cipher suite. Certificate-chain and identity validation to a trust anchor remain the application's responsibility per RFC 9420 sec. 5.3.1. A public org.bouncycastle.mls.codec.Certificate(byte[]) constructor and a Credential.getCertificates() accessor were added so callers can build and inspect X.509 credentials. Deployments using only basic credentials are unaffected.
The fix was introduced in commit 77632a57ed.
Credit: Joshua Rogers and Khaled Suliman of AISLE Research.