Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/openmls/openmls/llms.txt

Use this file to discover all available pages before exploring further.

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 ensures that individual steps can’t be skipped, where each function takes a distinct type as input and produces a distinct type as output.

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 a PublicMessage or a PrivateMessage. Further syntax checks are applied for the latter case once the message is decrypted.

Semantic validation

Every function in the processing chain performs several semantic validation steps. The following sections describe 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. The function also performs several basic semantic validation steps, such as:
  • Consistency of Group id, Epoch, and Sender data between message and group (ValSem002-ValSem007)
  • Checks if the sender type (e.g., Member, NewMember, etc.) matches the type of the message (ValSem112)
  • 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 correctly authenticated by a 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 (ValSem101-ValSem112)
  • Commits are valid relative to the group state and the proposals it covers (ValSem200-ValSem205)
  • 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 policy (proposals and commits).
Proposals can 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 sections list the individual semantic validation steps performed by OpenMLS.

Semantic validation of message framing

Validation stepDescriptionImplementedTested
ValSem002Group id
ValSem003Epoch
ValSem004Sender: Member: check the sender points to a non-blank leaf
ValSem005Application messages must use ciphertext
ValSem006Ciphertext: decryption needs to work
ValSem007Membership tag presence
ValSem008Membership tag verification
ValSem009Confirmation tag presence
ValSem010Signature verification
ValSem011PrivateMessageContent padding must be all-zero

Semantic validation of proposals covered by a Commit

Validation stepDescriptionImplementedTested
ValSem101Add Proposal: Signature public key in proposals must be unique among proposals & members
ValSem102Add Proposal: Init key in proposals must be unique among proposals
ValSem103Add Proposal: Encryption key in proposals must be unique among proposals & members
ValSem104Add Proposal: Init key and encryption key must be different
ValSem105Add Proposal: Ciphersuite & protocol version must match the group
ValSem106Add Proposal: required capabilities
ValSem107Remove Proposal: Removed member must be unique among proposals
ValSem108Remove Proposal: Removed member must be an existing group member
ValSem109Update Proposal: required capabilities
ValSem110Update Proposal: Encryption key must be unique among proposals & members
ValSem111Update Proposal: The sender of a full Commit must not include own update proposals
ValSem112Update Proposal: The sender of a standalone update proposal must be of type member
ValSem113All Proposals: The proposal type must be supported by all members of the group

Commit message validation

Validation stepDescriptionImplementedTested
ValSem200Commit must not cover inline self Remove proposal
ValSem201Path must be present, if at least one proposal requires a path
ValSem202Path must be the right length
ValSem203Path secrets must decrypt correctly
ValSem204Public keys from Path must be verified and match the private keys from the direct path
ValSem205Confirmation tag must be successfully verified
ValSem206Path leaf node encryption key must be unique among proposals & members
ValSem207Path encryption keys must be unique among proposals & members
ValSem208Only one GroupContextExtensions proposal in a commit
ValSem209GroupContextExtensions proposals may only contain extensions support by all members

External Commit message validation

Validation stepDescriptionImplementedTested
ValSem240External Commit must cover at least one inline ExternalInit proposal
ValSem241External Commit must cover at most one inline ExternalInit proposal
ValSem242External Commit must only cover inline proposal in allowlist (ExternalInit, Remove, PreSharedKey)
ValSem244External Commit must not include any proposals by reference
ValSem245External Commit must contain a path
ValSem246External Commit signature must be verified using the credential in the path KeyPackage

Ratchet tree validation

Validation stepDescriptionImplementedTested
ValSem300Exported ratchet trees must not have trailing blank nodes

PSK validation

Validation stepDescriptionImplementedTested
ValSem400The application SHOULD specify an upper limit on the number of past epochs for which the resumption_psk may be stored
ValSem401The nonce of a PreSharedKeyID must have length KDF.Nh
ValSem402PSK in proposal must be of type Resumption (with usage Application) or External
ValSem403Proposal list must not contain multiple PreSharedKey proposals that reference the same PreSharedKeyID