Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenMLS Updates #21

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5052cbe
Enable Wasm Tests (#1483)
keks Jan 25, 2024
a6b8e7d
docs(openmls): typo in rustdoc for MlsGroupJoinConfig (#1496)
TheDevMinerTV Feb 11, 2024
c178e41
Fix typo in documentation (#1497)
JonasVautherin Feb 11, 2024
8cad06d
build: bump codecov/codecov-action from 3 to 4 (#1492)
dependabot[bot] Feb 11, 2024
df1944c
Fix validation bug (#1491)
keks Feb 13, 2024
95664e4
Update codecov (#1501)
raphaelrobert Feb 14, 2024
af85443
Improve processing (#1495)
raphaelrobert Feb 14, 2024
4d6eb49
Remove unnecessary cloning of proposals (#1498)
raphaelrobert Feb 14, 2024
e7578f4
Cleanup unused CoreGroup methods (#1499)
raphaelrobert Feb 14, 2024
3a0e6c8
Introduce InitKey type for KeyPackages (#1500)
raphaelrobert Feb 19, 2024
1bd5821
Allow more credentials (#1488)
franziskuskiefer Feb 21, 2024
b572335
Check for last resort in core_group/new_from_welcome (#1503)
josephlukefahr Feb 21, 2024
6cea0a1
Add date for 0.5.0 release to changelog (#1507)
franziskuskiefer Feb 22, 2024
76335fc
Add StagedCoreWelcome and StagedWelcome (#1506)
keks Feb 28, 2024
bc3edbe
Add provider backed by libcrux (#1490)
keks Feb 29, 2024
85d18c9
Disable failing passive client tests (#1530)
franziskuskiefer Mar 12, 2024
ca9757f
Expose the whole tls_codec crate in prelude (#1528)
raphaelrobert Mar 12, 2024
b1b0a23
Add Basic Wasm Bindings and add CI Workflow to Measure Size (#1525)
keks Mar 12, 2024
8392840
Improve BasicCredential (#1527)
raphaelrobert Mar 13, 2024
f3c10c1
Small API improvements (#1531)
kkohbrok Mar 13, 2024
6469c50
Fix metadata and build profiles (#1532)
keks Mar 13, 2024
069c6f5
Make `MlsGroup::clear_pending_proposals` public (#1516)
josephlukefahr Mar 13, 2024
85bd5e7
Make StagedWelcome consume Welcome instead of MlsMessageIn (#1533)
keks Mar 14, 2024
656626a
Re-enable KATs after KeyPackage update (#1534)
raphaelrobert Mar 15, 2024
1007599
More KATs (#1535)
raphaelrobert Mar 16, 2024
df47a9a
Merge remote-tracking branch 'upstream/main' into em/openmls-updates
zombieobject Mar 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,9 @@ jobs:
else
echo "TEST_MODE=--release" >> $GITHUB_ENV
fi
- name: Build (wasm)
if: matrix.arch == 'wasm32-unknown-unknown'
run: cargo build $TEST_MODE --verbose --target ${{ matrix.arch }} -p openmls -F js
- name: Build
if: ${{ matrix.arch != 'wasm32-unknown-unknown' }}
run: cargo build $TEST_MODE --verbose --target ${{ matrix.arch }} -p openmls
4 changes: 3 additions & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ jobs:
uses: actions-rs/[email protected]

- name: Upload to codecov.io
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ${{ steps.coverage.outputs.report }}

16 changes: 15 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
ref: ${{ github.event.pull_request.head.sha }}
- uses: dtolnay/rust-toolchain@stable
with:
targets: i686-pc-windows-msvc, i686-unknown-linux-gnu
targets: i686-pc-windows-msvc, i686-unknown-linux-gnu, wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2

- name: Toggle rustc mode
Expand All @@ -44,6 +44,20 @@ jobs:
else
echo "TEST_MODE=--release" >> $GITHUB_ENV
fi
- name: Test with libcrux provider
if: matrix.os == 'ubuntu-latest'
run: |
cargo install wasm-bindgen-cli
cargo test $TEST_MODE -p openmls -vv -F libcrux-provider

- name: Tests Wasm32 on linux
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt update && sudo apt install nodejs
cargo install wasm-bindgen-cli
export CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER=$HOME/.cargo/bin/wasm-bindgen-test-runner
cargo test $TEST_MODE -p openmls -vv --target wasm32-unknown-unknown -F js

- name: Tests
if: matrix.os != 'windows-latest'
run: cargo test $TEST_MODE -p openmls --verbose
Expand Down
29 changes: 29 additions & 0 deletions .github/workflows/wasm-bench.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: wasm-bench

on:
push:
branches:
- main
pull_request:
workflow_dispatch:

env:
CARGO_TERM_COLOR: always


jobs:
measure-wasm-size:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Install the required target
- uses: dtolnay/rust-toolchain@stable
with:
target: ${{ matrix.arch }}
- uses: Swatinem/rust-cache@v2
- name: Build and measure size of wasm bindings
run: |
cargo install wasm-pack
sudo apt update && sudo apt install binaryen
export PATH=$PATH:$HOME/.cargo/bin
./openmls-wasm/check-size.sh
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- [#1506](https://github.com/openmls/openmls/pull/1506): Add `StagedWelcome` and `StagedCoreWelcome` to make joining a group staged in order to inspect the `Welcome` message. This was followed up with PR [#1533](https://github.com/openmls/openmls/pull/1533) to adjust the API.
- [#1516](https://github.com/openmls/openmls/pull/1516): Add `MlsGroup::clear_pending_proposals` to the public API; this allows users to clear a group's internal `ProposalStore`

### Changed

- [#1464](https://github.com/openmls/openmls/pull/1464): Add builder pattern for `MlsGroup`; split `MlsGroupJoinConfig` into `MlsGroupCreateConfig` and `MlsGroupJoinConfig`
Expand All @@ -15,8 +20,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#1477](https://github.com/openmls/openmls/pull/1477): Allow setting leaf node extensions and capabilities of the group creator when creating an MlsGroup(Config)
- [#1478](https://github.com/openmls/openmls/pull/1478): Remove explicit functions to set `RequiredCapabilitiesExtension` and `ExternalSendersExtension` when building an MlsGroup(Config) in favor of the more general function to set group context extensions
- [#1479](https://github.com/openmls/openmls/pull/1479): Allow the use of extensions with `ExtensionType::Unknown` in group context, key packages and leaf nodes
- [#1488](https://github.com/openmls/openmls/pull/1488): Allow unknown credentials. Credentials other than the basic credential or X.509 may be used now as long as they are encoded as variable-sized vectors.
- [#1527](https://github.com/openmls/openmls/pull/1527): CredentialType::Unknown is now called CredentialType::Other.

### Fixed

- [#1503](https://github.com/openmls/openmls/pull/1503): Fix `CoreGroup` to check for `LastResortExtension` before deleting leaf encryption keypair from the key store in `new_from_welcome`; this allows the same `KeyPackage` (with last resort extension) to be used to join multiple groups

## 0.5.0 (XXXX-XX-XX)
## 0.5.0 (2023-07-20)

This release has many breaking API changes, a few of them are listed below:

Expand Down
28 changes: 17 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
[workspace]
members = [
"openmls",
"traits",
"openmls_rust_crypto",
"fuzz",
"cli",
"interop_client",
"memory_keystore",
"delivery-service/ds",
"delivery-service/ds-lib",
"basic_credential",
"openmls",
"traits",
"openmls_rust_crypto",
"libcrux_crypto",
"fuzz",
"cli",
"interop_client",
"memory_keystore",
"delivery-service/ds",
"delivery-service/ds-lib",
"basic_credential",
"openmls-wasm",
]
resolver = "2"

# Central dependency management for some crates
[workspace.dependencies]
tls_codec = { version = "0.4.0", features = ["derive", "serde", "mls"] }
tls_codec = { version = "0.4.2-pre.1", features = [
"derive",
"serde",
"mls",
], git = "https://github.com/rustcrypto/formats" }
12 changes: 6 additions & 6 deletions basic_credential/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use std::fmt::Debug;

use openmls_traits::{
key_store::{MlsEntity, MlsEntityId, OpenMlsKeyStore},
signatures::Signer,
types::{CryptoError, Error, SignatureScheme},
signatures::{Signer, SignerError},
types::{CryptoError, SignatureScheme},
};

use p256::ecdsa::{signature::Signer as P256Signer, Signature, SigningKey};
Expand Down Expand Up @@ -42,21 +42,21 @@ impl Debug for SignatureKeyPair {
}

impl Signer for SignatureKeyPair {
fn sign(&self, payload: &[u8]) -> Result<Vec<u8>, Error> {
fn sign(&self, payload: &[u8]) -> Result<Vec<u8>, SignerError> {
match self.signature_scheme {
SignatureScheme::ECDSA_SECP256R1_SHA256 => {
let k = SigningKey::from_bytes(self.private.as_slice().into())
.map_err(|_| Error::SigningError)?;
.map_err(|_| SignerError::SigningError)?;
let signature: Signature = k.sign(payload);
Ok(signature.to_der().to_bytes().into())
}
SignatureScheme::ED25519 => {
let k = ed25519_dalek::SigningKey::try_from(self.private.as_slice())
.map_err(|_| Error::SigningError)?;
.map_err(|_| SignerError::SigningError)?;
let signature = k.sign(payload);
Ok(signature.to_bytes().into())
}
_ => Err(Error::SigningError),
_ => Err(SignerError::SigningError),
}
}

Expand Down
2 changes: 2 additions & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
- [Processing incoming messages](user_manual/processing.md)
- [Persistence of group state](user_manual/persistence.md)
- [Credential validation](user_manual/credential_validation.md)
- [WebAssembly](user_manual/wasm.md)
- [Traits & External Types](./traits/README.md)
- [Traits](./traits/traits.md)
- [Types](./traits/types.md)
- [Message Validation](./message_validation.md)
- [App Validation](./app_validation.md)
- [Performance](./performance.md)
- [Forward Secrecy](./forward_secrecy.md)
- [Release management](./release_management.md)
26 changes: 26 additions & 0 deletions book/src/app_validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# App Validation

> **NOTE:** This chapter described the validation steps an application, using OpenMLS, has to perform for safe operation of the MLS protocol.
>
> **⚠️** This chapter is work in progress (see [#1504](https://github.com/openmls/openmls/issues/1504)).

## Proposal Validation

When processing a commit, the application has to ensure that the application
specific semantic checks for the validity of the committed proposals are performed.

This should be done on the `StagedCommit`. Also see the [Message Processing](./user_manual/processing.md)
chapter

```rust,no_run,noplayground
{{#include ../../openmls/tests/book_code.rs:inspect_staged_commit}}
```

### External Commits

The RFC requires the following check

> At most one Remove proposal, with which the joiner removes an old version of themselves. If a Remove proposal is present, then the LeafNode in the path field of the external Commit MUST meet the same criteria as would the LeafNode in an Update for the removed leaf (see Section 12.1.2). In particular, the credential in the LeafNode MUST present a set of identifiers that is acceptable to the application for the removed participant.

Since OpenMLS does not know the relevant policies, the application MUST ensure
that the credentials are checked according to the policy.
1 change: 0 additions & 1 deletion book/src/message_validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ The following is a list of the individual semantic validation steps performed by
| `ValSem240` | External Commit must cover at least one inline ExternalInit proposal | ✅ | ✅ | `openmls/src/group/tests/test_external_commit_validation.rs` |
| `ValSem241` | External Commit must cover at most one inline ExternalInit proposal | ✅ | ✅ | `openmls/src/group/tests/test_external_commit_validation.rs` |
| `ValSem242` | External Commit must only cover inline proposal in allowlist (ExternalInit, Remove, PreSharedKey) | ✅ | ✅ | `openmls/src/group/tests/test_external_commit_validation.rs` |
| `ValSem243` | Identity of inline Remove proposal target and external committer must be the same | ✅ | ✅ | `openmls/src/group/tests/test_external_commit_validation.rs` |
| `ValSem244` | External Commit must not include any proposals by reference | ✅ | ✅ | `openmls/src/group/tests/test_external_commit_validation.rs` |
| `ValSem245` | External Commit must contain a path | ✅ | ✅ | `openmls/src/group/tests/test_external_commit_validation.rs` |
| `ValSem246` | External Commit signature must be verified using the credential in the path KeyPackage | ✅ | ✅ | `openmls/src/group/tests/test_external_commit_validation.rs` |
Expand Down
15 changes: 11 additions & 4 deletions book/src/traits/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,20 @@
> Please ensure you know what you're doing when implementing your own versions.**

Because implementing the `OpenMLSCryptoProvider` is challenging, requires
tremendous care, and is not what the average OpenMLS consumer wants to (or should) do,
we provide an implementation that can be used.
tremendous care, and is not what the average OpenMLS consumer wants to (or should)
do, we provide two implementations that can be used.

- [Rust Crypto]
- [Libcrux Crypto]

**Rust Crypto Provider**
The go-to default at the moment is an implementation using commonly used, native Rust
crypto implementations.
The go-to default at the moment is an implementation using commonly used, native
Rust crypto implementations.

**Libcrux Crypto Provider**
A crypto provider backed by the high-assurance cryptography library [libcrux].
Currently only supports relatively modern x86 and amd64 CPUs, as it requires
AES-NI, SIMD and AVX.

## The Traits

Expand Down Expand Up @@ -78,5 +84,6 @@ It is not necessary to implement all sub-traits if one functionality is missing.
Suppose you want to use a persisting key store. In that case, it is sufficient to do a new implementation of the key store trait and combine it with one of the provided crypto and randomness trait implementations.

[rust crypto]: https://crates.io/crates/openmls_rust_crypto
[libcrux crypto]: https://crates.io/crates/openmls_libcrux_crypto
[openmls traits crate]: https://crates.io/crates/openmls_traits
[rand crate]: https://crates.io/crates/rand
15 changes: 12 additions & 3 deletions book/src/user_manual/join_from_welcome.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
# Join a group from a Welcome message

To join a group from a `Welcome` message, a new `MlsGroup` can be instantiated directly from the `Welcome` message and an `MlsGroupJoinConfig` (see [Group configuration](./group_config.md) for more details). If the group configuration does not use the ratchet tree extension, the ratchet tree needs to be provided.
To join a group from a `Welcome` message, a new `MlsGroup` can be instantiated from
the `MlsMessageIn` message containing the `Welcome` and an `MlsGroupJoinConfig`
(see [Group configuration](./group_config.md) for more details). This is a
two-step process: a `StagedWelcome` is constructed from the `Welcome`
and can then be turned into an `MlsGroup`. If the group configuration does not
use the ratchet tree extension, the ratchet tree needs to be provided.

```rust,no_run,noplayground
{{#include ../../../openmls/tests/book_code.rs:bob_joins_with_welcome}}
```

Pay attention not to forward a Welcome message to a client before its associated commit has been accepted by the
Delivery Service. Otherwise, you would end up with an invalid MLS group instance.
The reason for this two-phase process is to allow the recipient of a `Welcome`
to inspect the message, e.g. to determine the identity of the sender.

Pay attention not to forward a Welcome message to a client before its associated
commit has been accepted by the Delivery Service. Otherwise, you would end up
with an invalid MLS group instance.
29 changes: 24 additions & 5 deletions book/src/user_manual/processing.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,30 @@ Incoming messages can be deserialized from byte slices into an `MlsMessageIn`:

If the message is malformed, the function will fail with an error.

## Processing messages

In the next step, the message needs to be processed. If the message was
encrypted, it will be decrypted automatically. This step performs all syntactic
and semantic validation checks and verifies the message's signature:
## Processing messages in groups

In the next step, the message needs to be processed in the context of the
corresponding group.

`MlsMessageIn` can carry all MLS messages, but only `PrivateMessageIn` and
`PublicMessageIn` are processed in the context of a group. In OpenMLS these two
message types are combined into a `ProtocolMessage` `enum`. There are 3 ways to
extract the messages from an `MlsMessageIn`:

1. `MlsMessageIn.try_into_protocol_message()` returns a `Result<ProtocolMessage, ProtocolMessageError>`
2. `ProtocolMessage::try_from(m: MlsMessageIn)` returns a `Result<ProtocolMessage, ProtocolMessageError>`
3. `MlsMessageIn.extract()` returns an `MlsMessageBodyIn` `enum` that has two
variants for `PrivateMessageIn` and `PublicMessageIn`

`MlsGroup.process_message()` accepts either a `ProtocolMessage`, a
`PrivateMessageIn`, or a `PublicMessageIn` and processes the message.
`ProtocolMessage.group_id()` exposes the group ID that can help the application
find the right group.

If the message was encrypted (i.e. if it was a `PrivateMessageIn`), it will be
decrypted automatically. The processing performs all syntactic and semantic
validation checks and verifies the message's signature. The function finally
returns a `ProcessedMessage` object if all checks are successful.

```rust,no_run,noplayground
{{#include ../../../openmls/tests/book_code.rs:process_message}}
Expand Down
4 changes: 4 additions & 0 deletions book/src/user_manual/wasm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# WebAssembly

OpenMLS can be built for WebAssembly. However, it does require two features that WebAssembly itself does not provide: access to secure randomness and the current time. Currently, this means that it can only run in a runtime that provides common JavaScript APIs (e.g. in the browser or node.js), accessed through the `web_sys` crate.
You can enable the `js` feature on the `openmls` crate to signal that the APIs are available.
4 changes: 1 addition & 3 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,18 @@ reqwest = { version = "0.11", features = ["blocking", "json"] }
base64 = "0.13"
log = "0.4"
pretty_env_logger = "0.4"
tls_codec = { workspace = true }

openmls = { path = "../openmls", features = ["test-utils"] }
ds-lib = { path = "../delivery-service/ds-lib" }
openmls_traits = { path = "../traits" }
openmls_rust_crypto = { path = "../openmls_rust_crypto" }
openmls_memory_keystore = { path = "../memory_keystore" }
openmls_basic_credential = { path = "../basic_credential" }
serde = { version = "^1.0"}
serde = { version = "^1.0" }
thiserror = "1.0"
serde_json = "1.0"
rand_chacha = { version = "0.3.1" }


[dependencies.termion]
version = "1.5"
git = "https://gitlab.redox-os.org/Jezza/termion.git"
Expand Down
6 changes: 3 additions & 3 deletions cli/src/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ impl Identity {
crypto: &OpenMlsRustPersistentCrypto,
id: &[u8],
) -> Self {
let credential = Credential::new(id.to_vec(), CredentialType::Basic).unwrap();
let credential = BasicCredential::new(id.to_vec()).unwrap();
let signature_keys = SignatureKeyPair::new(ciphersuite.signature_algorithm()).unwrap();
let credential_with_key = CredentialWithKey {
credential,
credential: credential.into(),
signature_key: signature_keys.to_public_vec().into(),
};
signature_keys.store(crypto.key_store()).unwrap();
Expand Down Expand Up @@ -88,6 +88,6 @@ impl Identity {

/// Get the plain identity as byte vector.
pub fn identity(&self) -> &[u8] {
self.credential_with_key.credential.identity()
self.credential_with_key.credential.serialized_content()
}
}
2 changes: 1 addition & 1 deletion cli/src/networking.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use reqwest::{self, blocking::Client, StatusCode};
use url::Url;

use tls_codec::Serialize;
use openmls::prelude::tls_codec::Serialize;

// TODO: return objects not bytes.

Expand Down
Loading
Loading