Skip to content

Commit

Permalink
MlsGroup: Builder, CreateConfig and JoinConfig (openmls#1464)
Browse files Browse the repository at this point in the history
  • Loading branch information
kkohbrok authored Jan 10, 2024
1 parent 3291f0d commit 741316d
Show file tree
Hide file tree
Showing 38 changed files with 676 additions and 293 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- [#1464](https://github.com/openmls/openmls/pull/1464): Add builder pattern for `MlsGroup`; split `MlsGroupJoinConfig` into `MlsGroupCreateConfig` and `MlsGroupJoinConfig`

## 0.5.0 (XXXX-XX-XX)

This release has many breaking API changes, a few of them are listed below:
Expand Down
6 changes: 3 additions & 3 deletions book/src/forward_secrecy.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ When an encrypted message is received, the corresponding decryption key is deriv

OpenMLS can address 3 scenarios:

- The Delivery Service cannot guarantee that application messages from one epoch are sent before the beginning of the next epoch. To address this, applications can configure their groups to keep the necessary key material around for past epochs by setting the `max_past_epochs` field in the `MlsGroupConfig` to the desired number of epochs.
- The Delivery Service cannot guarantee that application messages from one epoch are sent before the beginning of the next epoch. To address this, applications can configure their groups to keep the necessary key material around for past epochs by setting the `max_past_epochs` field in the `MlsGroupCreateConfig` to the desired number of epochs.

- The Delivery Service cannot guarantee that application messages will arrive in order within the same epoch. To address this, applications can configure the `out_of_order_tolerance` parameter of the `SenderRatchetConfiguration`. The configuration can be set as the `sender_ratchet_configuration` parameter of the `MlsGroupConfig`.
- The Delivery Service cannot guarantee that application messages will arrive in order within the same epoch. To address this, applications can configure the `out_of_order_tolerance` parameter of the `SenderRatchetConfiguration`. The configuration can be set as the `sender_ratchet_configuration` parameter of the `MlsGroupCreateConfig`.

- The Delivery Service cannot guarantee that application messages won't be dropped within the same epoch. To address this, applications can configure the `maximum_forward_distance` parameter of the `SenderRatchetConfiguration`. The configuration can be set as the `sender_ratchet_configuration` parameter of the `MlsGroupConfig`.
- The Delivery Service cannot guarantee that application messages won't be dropped within the same epoch. To address this, applications can configure the `maximum_forward_distance` parameter of the `SenderRatchetConfiguration`. The configuration can be set as the `sender_ratchet_configuration` parameter of the `MlsGroupCreateConfig`.
10 changes: 8 additions & 2 deletions book/src/user_manual/create_group.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Creating groups

Before a group can be created, a group configuration (`MlsGroupConfiguration`) needs to be defined. The default values of configuration parameters are picked for safety. However, check all parameters carefully to ascertain if they match your implementation's requirements. See [Group configuration](group_config.md) for more details.
There are two ways to create a group: Either by building an `MlsGroup` directly, or by using an `MlsGroupCreateConfig`. The former is slightly simpler, while the latter allows the creating of multiple groups using the same configuration. See [Group configuration](./group_config.md) for more details on group parameters.

In addition to the group configuration, the client should define all supported and required extensions for the group. The negotiation mechanism for extension in MLS consists in setting an initial list of extensions at group creation time and choosing key packages of subsequent new members accordingly.

Expand All @@ -10,12 +10,18 @@ In practice, the supported and required extensions are set by adding them to the
{{#include ../../../openmls/tests/book_code.rs:create_key_package}}
```

After that, the group can be created:
After that, the group can be created either using a config:

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

... or using the builder pattern:

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

Note: Every group is assigned a random group ID during creation. The group ID cannot be changed and remains immutable throughout the group's lifetime. Choosing it randomly makes sure that the group ID doesn't collide with any other group ID in the same system.

If someone else already gave you a group ID, e.g., a provider server, you can also create a group using a specific group ID:
Expand Down
22 changes: 18 additions & 4 deletions book/src/user_manual/group_config.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Group configuration

The group configuration can be specified by building a `MlsGroupConfig` object or choosing the default value. The default value contains safe values for all parameters and is suitable for scenarios without particular requirements.
Two very similar structs can help configure groups upon their creation: `MlsGroupJoinConfig` and `MlsGroupCreateConfig`.

The following parameters can be set:
`MlsGroupJoinConfig` contains the following runtime-relevant configuration options for an `MlsGroup` and can be set on a per-client basis when a group is joined.

| Name | Type | Explanation |
| ------------------------------ | ------------------------------- | ------------------------------------------------------------------------------------------------ |
Expand All @@ -11,11 +11,25 @@ The following parameters can be set:
| `max_past_epochs` | `usize` | Maximum number of past epochs for which application messages can be decrypted. The default is 0. |
| `number_of_resumption_psks` | `usize` | Number of resumption psks to keep. The default is 0. |
| `use_ratchet_tree_extension` | `bool` | Flag indicating the Ratchet Tree Extension should be used. The default is `false`. |
| `required_capabilities` | `RequiredCapabilitiesExtension` | Required capabilities (extensions and proposal types). |
| `sender_ratchet_configuration` | `SenderRatchetConfiguration` | Sender ratchet configuration. |

Example configuration:
`MlsGroupCreateConfig` contains an `MlsGroupJoinConfig`, as well as a few additional parameters that are part of the group state that is agreed-upon by all group members. It can be set at the time of a group's creation and contains the following additional configuration options.

| Name | Type | Explanation |
| ------------------------------ | ------------------------------- | ------------------------------------------------------------------------------------------------ |
| `required_capabilities` | `RequiredCapabilitiesExtension` | Required capabilities (extensions and proposal types). |
| `external_senders` | `ExternalSendersExtensions` | List credentials of non-group members that are allowed to send proposals to the group. |

Both ways of group configurations can be specified by using the struct's builder pattern, or choosing their default values. The default value contains safe values for all parameters and is suitable for scenarios without particular requirements.

Example join configuration:

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

Example create configuration:

```rust,no_run,noplayground
{{#include ../../../openmls/tests/book_code.rs:mls_group_create_config_example}}
```
4 changes: 2 additions & 2 deletions book/src/user_manual/join_from_external_commit.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

To join a group with an external commit message, a new `MlsGroup` can be instantiated directly from the `GroupInfo`.
The `GroupInfo`/Ratchet Tree should be shared over a secure channel.
If the RatchetTree extension is not in the required capabilities, then the ratchet tree needs to be provided.
If the RatchetTree extension is not included in the `GroupInfo` as a `GroupInfoExtension`, then the ratchet tree needs to be provided.

The `GroupInfo` can be obtained either from a call to `export_group_info`from the `MlsGroup`:

Expand All @@ -16,7 +16,7 @@ Or from a call to a function that results in a staged commit:
{{#include ../../../openmls/tests/book_code.rs:alice_exports_group_info}}
```

Calling `join_by_external_commit` will join the group and leave it with a commit pending to be merged.
Calling `join_by_external_commit` requires an `MlsGroupJoinConfig` (see [Group configuration](./group_config.md) for more details). The function creates an `MlsGroup` and leave it with a commit pending to be merged.

```rust,no_run,noplayground
{{#include ../../../openmls/tests/book_code.rs:charlie_joins_external_commit}}
Expand Down
3 changes: 1 addition & 2 deletions book/src/user_manual/join_from_welcome.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# 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.
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 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.

```rust,no_run,noplayground
{{#include ../../../openmls/tests/book_code.rs:bob_joins_with_welcome}}
Expand Down
4 changes: 2 additions & 2 deletions cli/src/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ impl User {

// NOTE: Since the DS currently doesn't distribute copies of the group's ratchet
// tree, we need to include the ratchet_tree_extension.
let group_config = MlsGroupConfig::builder()
let group_config = MlsGroupCreateConfig::builder()
.use_ratchet_tree_extension(true)
.build();

Expand Down Expand Up @@ -672,7 +672,7 @@ impl User {
}
// NOTE: Since the DS currently doesn't distribute copies of the group's ratchet
// tree, we need to include the ratchet_tree_extension.
let group_config = MlsGroupConfig::builder()
let group_config = MlsGroupJoinConfig::builder()
.use_ratchet_tree_extension(true)
.build();
let mut mls_group = MlsGroup::new_from_welcome(&self.crypto, &group_config, welcome, None)
Expand Down
6 changes: 3 additions & 3 deletions delivery-service/ds/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ async fn test_list_clients() {
#[actix_rt::test]
async fn test_group() {
let crypto = &OpenMlsRustCrypto::default();
let mls_group_config = MlsGroupConfig::default();
let mls_group_create_config = MlsGroupCreateConfig::default();
let data = web::Data::new(DsData::default());
let app = test::init_service(
App::new()
Expand Down Expand Up @@ -257,7 +257,7 @@ async fn test_group() {
let mut group = MlsGroup::new_with_group_id(
crypto,
&signer_1,
&mls_group_config,
&mls_group_create_config,
group_id,
credential_with_key_1,
)
Expand Down Expand Up @@ -317,7 +317,7 @@ async fn test_group() {

let mut group_on_client2 = MlsGroup::new_from_welcome(
crypto,
&mls_group_config,
mls_group_create_config.join_config(),
welcome_msg
.into_welcome()
.expect("Unexpected message type."),
Expand Down
14 changes: 7 additions & 7 deletions interop_client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use openmls::{
credentials::{Credential, CredentialType, CredentialWithKey},
framing::{MlsMessageIn, MlsMessageInBody, MlsMessageOut, ProcessedMessageContent},
group::{
GroupEpoch, GroupId, MlsGroup, MlsGroupConfig, WireFormatPolicy,
GroupEpoch, GroupId, MlsGroup, MlsGroupCreateConfig, MlsGroupJoinConfig, WireFormatPolicy,
PURE_CIPHERTEXT_WIRE_FORMAT_POLICY, PURE_PLAINTEXT_WIRE_FORMAT_POLICY,
},
key_packages::KeyPackage,
Expand Down Expand Up @@ -230,7 +230,7 @@ impl MlsClient for MlsClientImpl {
// Note: We just use some values here that make live testing work.
// There is nothing special about the used numbers and they
// can be increased (or decreased) depending on the available scenarios.
let mls_group_config = MlsGroupConfig::builder()
let mls_group_config = MlsGroupCreateConfig::builder()
.crypto_config(CryptoConfig::with_default_version(ciphersuite))
.max_past_epochs(32)
.number_of_resumption_psks(32)
Expand Down Expand Up @@ -375,7 +375,7 @@ impl MlsClient for MlsClientImpl {
// Note: We just use some values here that make live testing work.
// There is nothing special about the used numbers and they
// can be increased (or decreased) depending on the available scenarios.
let mls_group_config = MlsGroupConfig::builder()
let mls_group_config = MlsGroupJoinConfig::builder()
.max_past_epochs(32)
.number_of_resumption_psks(32)
.sender_ratchet_configuration(SenderRatchetConfiguration::default())
Expand Down Expand Up @@ -521,7 +521,7 @@ impl MlsClient for MlsClientImpl {
let mls_group_config = {
let wire_format_policy = wire_format_policy(request.encrypt_handshake);

MlsGroupConfig::builder()
MlsGroupJoinConfig::builder()
.max_past_epochs(32)
.number_of_resumption_psks(32)
.sender_ratchet_configuration(SenderRatchetConfiguration::default())
Expand Down Expand Up @@ -818,7 +818,7 @@ impl MlsClient for MlsClientImpl {
// Note: We just use some values here that make live testing work.
// There is nothing special about the used numbers and they
// can be increased (or decreased) depending on the available scenarios.
let mls_group_config = MlsGroupConfig::builder()
let mls_group_config = MlsGroupJoinConfig::builder()
.use_ratchet_tree_extension(true)
.max_past_epochs(32)
.number_of_resumption_psks(32)
Expand Down Expand Up @@ -866,7 +866,7 @@ impl MlsClient for MlsClientImpl {
// Note: We just use some values here that make live testing work.
// There is nothing special about the used numbers and they
// can be increased (or decreased) depending on the available scenarios.
let mls_group_config = MlsGroupConfig::builder()
let mls_group_config = MlsGroupJoinConfig::builder()
.max_past_epochs(32)
.number_of_resumption_psks(32)
.use_ratchet_tree_extension(true)
Expand Down Expand Up @@ -920,7 +920,7 @@ impl MlsClient for MlsClientImpl {
// Note: We just use some values here that make live testing work.
// There is nothing special about the used numbers and they
// can be increased (or decreased) depending on the available scenarios.
let mls_group_config = MlsGroupConfig::builder()
let mls_group_config = MlsGroupJoinConfig::builder()
.max_past_epochs(32)
.number_of_resumption_psks(32)
.use_ratchet_tree_extension(true)
Expand Down
6 changes: 3 additions & 3 deletions openmls/src/extensions/test_extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,15 +299,15 @@ fn last_resort_extension(ciphersuite: Ciphersuite, provider: &impl OpenMlsProvid
provider,
);

let mls_group_config = MlsGroupConfigBuilder::new()
let mls_group_create_config = MlsGroupCreateConfig::builder()
.crypto_config(CryptoConfig::with_default_version(ciphersuite))
.build();

// === Alice creates a group ===
let mut alice_group = MlsGroup::new(
provider,
&alice_credential_with_key_and_signer.signer,
&mls_group_config,
&mls_group_create_config,
alice_credential_with_key_and_signer.credential_with_key,
)
.expect("An unexpected error occurred.");
Expand All @@ -326,7 +326,7 @@ fn last_resort_extension(ciphersuite: Ciphersuite, provider: &impl OpenMlsProvid

let _bob_group = MlsGroup::new_from_welcome(
provider,
&mls_group_config,
mls_group_create_config.join_config(),
welcome.into_welcome().expect("Unexpected MLS message"),
Some(alice_group.export_ratchet_tree().into()),
)
Expand Down
21 changes: 14 additions & 7 deletions openmls/src/group/core_group/kat_passive_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,7 @@ pub fn run_test_vector(test_vector: PassiveClientWelcomeTestVector) {
return;
}

let group_config = MlsGroupConfig::builder()
.crypto_config(CryptoConfig::with_default_version(cipher_suite))
let group_config = MlsGroupJoinConfig::builder()
.use_ratchet_tree_extension(true)
.wire_format_policy(WireFormatPolicy::new(
OutgoingWireFormatPolicy::AlwaysPlaintext,
Expand All @@ -128,7 +127,11 @@ pub fn run_test_vector(test_vector: PassiveClientWelcomeTestVector) {
.number_of_resumption_psks(16)
.build();

let mut passive_client = PassiveClient::new(group_config, test_vector.external_psks.clone());
let mut passive_client = PassiveClient::new(
group_config,
cipher_suite,
test_vector.external_psks.clone(),
);

passive_client.inject_key_package(
test_vector.key_package,
Expand Down Expand Up @@ -198,12 +201,16 @@ fn test_write_vectors() {

struct PassiveClient {
provider: OpenMlsRustCrypto,
group_config: MlsGroupConfig,
group_config: MlsGroupJoinConfig,
group: Option<MlsGroup>,
}

impl PassiveClient {
fn new(group_config: MlsGroupConfig, psks: Vec<ExternalPskTest>) -> Self {
fn new(
group_config: MlsGroupJoinConfig,
ciphersuite: Ciphersuite,
psks: Vec<ExternalPskTest>,
) -> Self {
let provider = OpenMlsRustCrypto::default();

// Load all PSKs into key store.
Expand All @@ -213,7 +220,7 @@ impl PassiveClient {
// The nonce is not saved, so it can be empty...
let psk_id = PreSharedKeyId::external(psk.psk_id, vec![]);
psk_id
.write_to_key_store(&provider, group_config.crypto_config.ciphersuite, &psk.psk)
.write_to_key_store(&provider, ciphersuite, &psk.psk)
.unwrap();
}

Expand Down Expand Up @@ -333,7 +340,7 @@ impl PassiveClient {
}

pub fn generate_test_vector(cipher_suite: Ciphersuite) -> PassiveClientWelcomeTestVector {
let group_config = MlsGroupConfig::builder()
let group_config = MlsGroupCreateConfig::builder()
.crypto_config(CryptoConfig::with_default_version(cipher_suite))
.use_ratchet_tree_extension(true)
.build();
Expand Down
Loading

0 comments on commit 741316d

Please sign in to comment.