Message Validation

OpenMLS implements a variety of syntactical and semantical checks, both when parsing and processing incoming commits and when creating own commits.

Validation steps

Validation is enforced using Rust's type system. The chain of functions used to process incoming messages is described in the chapter on Processing incoming messages, where each function takes a distinct type as input and produces a distinct type as output, thus ensuring that the individual steps can't be skipped. We now detail which step performs which validation checks.

Syntax validation

Incoming messages in the shape of a byte string can only be deserialized into a MlsMessageIn struct. Deserialization ensures that the message is a syntactically correct MLS message, i.e. either an MLSPlaintext or an MLSCiphertext. For the latter case, further syntax checks are applied once the message is decrypted.

Semantic validation

Every function in the processing chain performs a number of semantic validation steps. For a list of these steps, see below. In the following, we will give a brief overview over which function performs which category of checks.

Wire format policy and basic message consistency validation

MlsMessageIn struct instances can be passed into the .parse_message() function of the MlsGroup API, which validates that the message conforms to the group's wire format policy (ValSem001). The function also performs a number of basic semantic validation steps, such as consistency of Group id, Epoch and Sender data between message and group (ValSem002-ValSem007 and ValSem109). It also checks if the sender type (e.g. Member, NewMember, etc.) matches the type of the message (ValSem112), as well as the presence of a path in case of an External Commit (ValSem246).

.parse_message() then returns an UnverifiedMessage struct instance, which can in turn be used as input for .process_unverified_message().

Message-specific semantic validation

.process_unverified_message() performs all other semantic validation steps. In particular, it ensures that

  • the message is properly authenticated by signature (ValSem010), membership tag (ValSem008) and confirmation tag (ValSem205),
  • proposals are valid relative to one-another and the current group state, e.g. no redundant adds or removes targeting non-members (ValSem100-ValSem112),
  • commits are valid relative to the group state and the proposals it covers (ValSem200-ValSem205) and
  • external commits are valid according to the spec (ValSem240-ValSem245, ValSem247 is checked as part of ValSem010).

After performing these steps, messages are returned as ProcessedMessages that the application can either use immediately (application messages) or inspect and decide if they find them valid according to the application's own policy (proposals and commits). Proposals can then be stored in the proposal queue via .store_pending_proposal(), while commits can be merged into the group state via .merge_staged_commit().

Detailed list of validation steps

The following is a list of the individual semantic validation steps performed by OpenMLS, including the location of the tests.

Semantic validation of message framing

ValidationStepDescriptionImplementedTestedTest File
ValSem001Wire formatopenmls/src/group/tests/test_framing_validation.rs
ValSem002Group idopenmls/src/group/tests/test_framing_validation.rs
ValSem003Epochopenmls/src/group/tests/test_framing_validation.rs
ValSem004Sender: Member: check the sender points to a non-blank leafopenmls/src/group/tests/test_framing_validation.rs
ValSem005Application messages must use ciphertextopenmls/src/group/tests/test_framing_validation.rs
ValSem006Ciphertext: decryption needs to workopenmls/src/group/tests/test_framing_validation.rs
ValSem007Membership tag presenceopenmls/src/group/tests/test_framing_validation.rs
ValSem008Membership tag verificationopenmls/src/group/tests/test_framing_validation.rs
ValSem009Confirmation tag presenceopenmls/src/group/tests/test_framing_validation.rs
ValSem010Signature verificationopenmls/src/group/tests/test_framing_validation.rs

Semantic validation of proposals covered by a Commit

ValidationStepDescriptionImplementedTestedTest File
ValSem100Add Proposal: Identity in proposals must be unique among proposalsopenmls/src/group/tests/test_proposal_validation.rs
ValSem101Add Proposal: Signature public key in proposals must be unique among proposalsopenmls/src/group/tests/test_proposal_validation.rs
ValSem102Add Proposal: HPKE init key in proposals must be unique among proposalsopenmls/src/group/tests/test_proposal_validation.rs
ValSem103Add Proposal: Identity in proposals must be unique among existing group membersopenmls/src/group/tests/test_proposal_validation.rs
ValSem104Add Proposal: Signature public key in proposals must be unique among existing group membersopenmls/src/group/tests/test_proposal_validation.rs
ValSem105Add Proposal: HPKE init key in proposals must be unique among existing group membersopenmls/src/group/tests/test_proposal_validation.rs
ValSem106Add Proposal: required capabilitiesopenmls/src/group/tests/test_proposal_validation.rs
ValSem107Remove Proposal: Removed member must be unique among proposalsopenmls/src/group/tests/test_proposal_validation.rs
ValSem108Remove Proposal: Removed member must be an existing group memberopenmls/src/group/tests/test_proposal_validation.rs
ValSem109Update Proposal: Identity must be unchanged between existing member and new proposalopenmls/src/group/tests/test_proposal_validation.rs
ValSem110Update Proposal: HPKE init key must be unique among existing membersopenmls/src/group/tests/test_proposal_validation.rs
ValSem111Update Proposal: The sender of a full Commit must not include own update proposalsopenmls/src/group/tests/test_proposal_validation.rs
ValSem112Update Proposal: The sender of a standalone update proposal must be of type memberopenmls/src/group/tests/test_proposal_validation.rs

Commit message validation

ValidationStepDescriptionImplementedTestedTest File
ValSem200Commit must not cover inline self Remove proposalopenmls/src/group/tests/test_commit_validation.rs
ValSem201Path must be present, if Commit contains Removes or Updatesopenmls/src/group/tests/test_commit_validation.rs
ValSem202Path must be the right lengthopenmls/src/group/tests/test_commit_validation.rs
ValSem203Path secrets must decrypt correctlyopenmls/src/group/tests/test_commit_validation.rs
ValSem204Public keys from Path must be verified and match the private keys from the direct pathopenmls/src/group/tests/test_commit_validation.rs
ValSem205Confirmation tag must be successfully verifiedopenmls/src/group/tests/test_commit_validation.rs

External Commit message validation

ValidationStepDescriptionImplementedTestedTest File
ValSem240External Commit must cover at least one inline ExternalInit proposalopenmls/src/group/tests/test_external_commit_validation.rs
ValSem241External Commit must cover at most one inline ExternalInit proposalopenmls/src/group/tests/test_external_commit_validation.rs
ValSem242External Commit must not cover any inline Add proposalsopenmls/src/group/tests/test_external_commit_validation.rs
ValSem243External Commit must not cover any inline Update proposalsopenmls/src/group/tests/test_external_commit_validation.rs
ValSem244Identity of inline Remove proposal target and external committer must be the sameopenmls/src/group/tests/test_external_commit_validation.rs
ValSem245External Commit must not cover any ExternalInit proposals by referenceopenmls/src/group/tests/test_external_commit_validation.rs
ValSem246External Commit must contain a pathopenmls/src/group/tests/test_external_commit_validation.rs
ValSem247External Commit signature must be verified using the credential in the path KeyPackageopenmls/src/group/tests/test_external_commit_validation.rs