Skip to content

Update latest openmls#53

Merged
tylerhawkes merged 15 commits intomainfrom
update-latest-backward-incompat
Apr 30, 2026
Merged

Update latest openmls#53
tylerhawkes merged 15 commits intomainfrom
update-latest-backward-incompat

Conversation

@tylerhawkes
Copy link
Copy Markdown

@tylerhawkes tylerhawkes commented Apr 30, 2026

This includes the backwards incompatible changes that were breaking us previously, along with some updates to dependencies that had rust security advisories.

Note

Add MlsGroup::propose_self_update_with_new_signer for signature key rotation in MLS groups

  • Adds propose_self_update_with_new_signer to MlsGroup allowing a member to rotate their signature key via an Update proposal, with validation for ciphersuite and credential consistency.
  • Refactors MessageSecretsWithTimestamp wrapper away by moving the optional timestamp directly onto MessageSecrets via new timestamp() and with_timestamp() accessors.
  • Changes safe_export_secret parameter type from u16 to ComponentId across MlsGroup, StagedCommit, ProcessedMessage, and ApplicationExportTree.
  • Removes debug_assert!(false) panics in debug builds from confirmation tag mismatch and AEAD decryption error paths.
  • Updates PastEpochDeletionPolicy serde to use custom impls, encoding KeepAll as usize::MAX (u64) rather than an untagged enum.
  • Workspace now includes sqlite_storage instead of sqlx_storage; bumps rayon, rusqlite, tokio, clap, and RustCrypto dependencies (sha2, hmac, hkdf).
  • Risk: Serialization format for stored MessageSecrets and PastEpochDeletionPolicy has changed; existing persisted state may need migration.
📊 Macroscope summarized 3bb3e4b. 30 files reviewed, 4 issues evaluated, 0 issues filtered, 2 comments posted

🗂️ Filtered Issues

wysiwys and others added 15 commits April 7, 2026 13:12
* Store `Secret` directly in `PprfNode` instead of `Vec<u8>`, avoiding
  extra heap allocation and copy on each split.
* Implement custom `Serialize`/`Deserialize` for `PprfNode` that
  zeroizes any owned byte buffer produced during deserialization and
  support zero-copy deserialization.
* Rewrite `serialize_hashmap`/`deserialize_hashmap` to use
  `serialize_seq` and a custom `Visitor`, avoiding the intermediate
  `Vec` allocation.
Rust official blog changed the guidance on commiting Lockfiles in
<https://blog.rust-lang.org/2023/08/29/committing-lockfiles>.

There are several benefits of having a lockfile in the repository, even
for libraries:

* Each commit in repository is buildable, even after a long time because
  it tracks which dependencies where used *per* commit. In particular,
  it make bisecting possible.
* It allows for tooling to check for vulnerabilities in the
  dependencies.
* It is easy to test in CI with latest dependencies by just running
  `cargo update` (in case such job is needed).
* It gives a supply chain security: commited lockfile ensures that CI
  builds and tests exactly what is specified in the lockfile. Note that
  lockfile contains the hashes of the content of the dependencies not
  only their versions.
Bumps [actix-http](https://github.com/actix/actix-web) from 3.12.0 to 3.12.1.
- [Release notes](https://github.com/actix/actix-web/releases)
- [Changelog](https://github.com/actix/actix-web/blob/main/CHANGES.md)
- [Commits](actix/actix-web@http-v3.12.0...http-v3.12.1)

---
updated-dependencies:
- dependency-name: actix-http
  dependency-version: 3.12.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…ls#2010)

Resolves openmls#2008

Adds `propose_self_update_with_new_signer`. I opted to refactor the internals of `propose_self_update` to plumb in an optional new signer. The new public function and the existing propose now defer to the same internal helper (which differs only by an optional signer).
* Fix backward incompatible changes as the contract is with serde and not just serde_json

* Return SystemTime instead of &SystemTime
Bumps [rustls-webpki](https://github.com/rustls/webpki) from 0.103.12 to 0.103.13.
- [Release notes](https://github.com/rustls/webpki/releases)
- [Commits](rustls/webpki@v/0.103.12...v/0.103.13)

---
updated-dependencies:
- dependency-name: rustls-webpki
  dependency-version: 0.103.13
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5 to 6.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](codecov/codecov-action@v5...v6)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…h 13 updates (openmls#2014)

* chore(deps): bump the cargo-dependencies group across 1 directory with 13 updates
* keep some rand versions
* import `hmac::KeyInit` trait in RustCrypto provider

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: wysiwys <clara@cryspen.com>
Comment on lines +74 to +78
let usize = match self {
Self::MaxEpochs(epochs) => *epochs,
Self::KeepAll => usize::MAX,
};
serializer.serialize_u64(usize as u64)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium mls_group/config.rs:74

Serializing KeepAll uses usize::MAX cast to u64, which produces different values on 32-bit (4294967295) vs 64-bit (18446744073709551615) platforms. When serialized on 32-bit and deserialized on 64-bit, 4294967295 != usize::MAX, so KeepAll incorrectly becomes MaxEpochs(4294967295). Conversely, serializing on 64-bit produces u64::MAX which fails usize::try_from() on 32-bit. Consider using a fixed sentinel value like u64::MAX in serialization, checking for that sentinel explicitly during deserialization.

-        let usize = match self {
-            Self::MaxEpochs(epochs) => *epochs,
-            Self::KeepAll => usize::MAX,
-        };
-        serializer.serialize_u64(usize as u64)
+        let value = match self {
+            Self::MaxEpochs(epochs) => *epochs as u64,
+            Self::KeepAll => u64::MAX,
+        };
+        serializer.serialize_u64(value)
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file openmls/src/group/mls_group/config.rs around lines 74-78:

Serializing `KeepAll` uses `usize::MAX` cast to `u64`, which produces different values on 32-bit (`4294967295`) vs 64-bit (`18446744073709551615`) platforms. When serialized on 32-bit and deserialized on 64-bit, `4294967295 != usize::MAX`, so `KeepAll` incorrectly becomes `MaxEpochs(4294967295)`. Conversely, serializing on 64-bit produces `u64::MAX` which fails `usize::try_from()` on 32-bit. Consider using a fixed sentinel value like `u64::MAX` in serialization, checking for that sentinel explicitly during deserialization.

Evidence trail:
openmls/src/group/mls_group/config.rs lines 71-93 at REVIEWED_COMMIT: Serialize impl at line 74 uses `usize::MAX as u64` for KeepAll; Deserialize impl at line 84 uses `usize::try_from(epochs)` then compares to `usize::MAX`. usize::MAX differs between 32-bit (2^32-1) and 64-bit (2^64-1) platforms, causing cross-platform serialization/deserialization mismatch.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium

pub(crate) fn delete_past_epoch_secrets(&mut self, policy: PastEpochDeletion) {

In delete_past_epoch_secrets, when policy.config is None (from PastEpochDeletion::delete_all()), the max_past_epochs field is silently ignored. Calling PastEpochDeletion::delete_all().max_past_epochs(5) deletes all entries instead of preserving 5, because the max_past_epochs handling is only inside the if let Some(config) branch. Move the max_past_epochs check outside the if/else so it applies regardless of whether config is None.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file openmls/src/group/mls_group/past_secrets.rs around line 299:

In `delete_past_epoch_secrets`, when `policy.config` is `None` (from `PastEpochDeletion::delete_all()`), the `max_past_epochs` field is silently ignored. Calling `PastEpochDeletion::delete_all().max_past_epochs(5)` deletes all entries instead of preserving 5, because the `max_past_epochs` handling is only inside the `if let Some(config)` branch. Move the `max_past_epochs` check outside the `if/else` so it applies regardless of whether `config` is `None`.

Evidence trail:
openmls/src/group/mls_group/past_secrets.rs lines 299-322 (delete_past_epoch_secrets function where max_past_epochs check is inside the if-let branch); openmls/src/group/mls_group/config.rs lines 114-167 (PastEpochDeletion struct definition, delete_all() returns config: None, and max_past_epochs() builder method is public and chainable)

@macroscopeapp
Copy link
Copy Markdown

macroscopeapp Bot commented Apr 30, 2026

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces new signature key rotation functionality, changes serialization formats affecting backwards compatibility, and has two unresolved review comments identifying bugs. Additionally, the author does not own any of the modified files which are all designated to @openmls/core.

You can customize Macroscope's approvability policy. Learn more.

@tylerhawkes tylerhawkes merged commit f850fdf into main Apr 30, 2026
86 checks passed
@tylerhawkes tylerhawkes deleted the update-latest-backward-incompat branch April 30, 2026 19:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants