Skip to content

Commit

Permalink
Merge pull request #18 from xmtp/nm/merge-upstream-feb-10
Browse files Browse the repository at this point in the history
  • Loading branch information
neekolas authored Mar 20, 2024
2 parents 0da7dcb + 4639f88 commit 4eee1fc
Show file tree
Hide file tree
Showing 139 changed files with 6,981 additions and 4,788 deletions.
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/grcov@v0.1

- 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

0 comments on commit 4eee1fc

Please sign in to comment.