Skip to content

Commit

Permalink
Key Package Generation / Join API 1.x (#226)
Browse files Browse the repository at this point in the history
* Fix CI (#223)

* feat(mls-rs): Verify the update path even in case of a self removal (#224)

* Fix bug where double-hitting a ciphertext deleted the whole ratchet (#228)

Co-authored-by: Marta Mularczyk <[email protected]>

* Work around rust < 1.78 crash (#231)

Somehow the DWARF info generated by the compiler for the
`hash`-replacement assignment is confusing to LLVM, which crashes.

By using a different form for the same operation, the compiler is happy.

* Avoid intermediate Vec in TreeKemPublic::update_hashes (#230)

[slice, slice].concat() creates an intermediate Vec, which can be
avoided by chaining updated_leaves and trailing_blanks before the first
Vec is created.

* Add API for deleting exporters (#227)

* Add API for deleting exporters

* Apply suggestions from code review

Co-authored-by: Stephane Raux <[email protected]>

---------

Co-authored-by: Marta Mularczyk <[email protected]>
Co-authored-by: Tom Leavy <[email protected]>
Co-authored-by: Stephane Raux <[email protected]>

* Key package generation 1.x

* Fix clippy warnings

* Initial implementation of group join 1.x

* Add example for 1x API

* Apply suggestions from code review

* Add SigningData struct

* Fixup

* Add more tests

* Fixup

* Fixup

---------

Co-authored-by: Félix Lescaudey de Maneville <[email protected]>
Co-authored-by: Marta Mularczyk <[email protected]>
Co-authored-by: Mike Hommey <[email protected]>
Co-authored-by: Tom Leavy <[email protected]>
Co-authored-by: Stephane Raux <[email protected]>
  • Loading branch information
6 people committed Jan 14, 2025
1 parent 9aee7e6 commit 1c6cb11
Show file tree
Hide file tree
Showing 29 changed files with 1,114 additions and 363 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/native_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ jobs:
run: cargo test --no-default-features --features std,test_util,non-fips --verbose --workspace
- name: Examples
working-directory: mls-rs
run: cargo run --example basic_usage
run: |
cargo run --example basic_usage
cargo run --example api_1x
AsyncBuildAndTest:
strategy:
matrix:
Expand Down
9 changes: 9 additions & 0 deletions mls-rs-core/src/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,17 @@ mod x509;

pub use basic::*;
pub use credential::*;
use mls_rs_codec::{MlsDecode, MlsEncode, MlsSize};
pub use provider::*;
pub use signing_identity::*;

#[cfg(feature = "x509")]
pub use x509::*;

use crate::crypto::SignatureSecretKey;

#[derive(Clone, Debug, MlsEncode, MlsSize, MlsDecode, PartialEq)]
pub struct SigningData {
pub signing_identity: SigningIdentity,
pub signing_key: SignatureSecretKey,
}
4 changes: 4 additions & 0 deletions mls-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(mls_build_async)', 'cfg(co
name = "basic_usage"
required-features = []

[[example]]
name = "api_1x"
required-features = []

[[example]]
name = "x509"
required-features = ["x509"]
Expand Down
92 changes: 92 additions & 0 deletions mls-rs/examples/api_1x.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// Copyright by contributors to this project.
// SPDX-License-Identifier: (Apache-2.0 OR MIT)

use std::convert::Infallible;

use mls_rs::{
client_builder::MlsConfig,
error::MlsError,
identity::{
basic::{BasicCredential, BasicIdentityProvider},
SigningIdentity,
},
CipherSuite, CipherSuiteProvider, Client, CryptoProvider, ExtensionList, KeyPackageStorage,
};
use mls_rs_core::key_package::KeyPackageData;

const CIPHERSUITE: CipherSuite = CipherSuite::CURVE25519_AES128;

fn main() -> Result<(), MlsError> {
let crypto_provider = mls_rs_crypto_openssl::OpensslCryptoProvider::default();

// Create clients for Alice and Bob
let alice = make_client(crypto_provider.clone(), "alice")?;
let bob = make_client(crypto_provider.clone(), "bob")?;

// Bob generates key package. We store secrets in memory, no need for any storage.
let key_package_generation = bob
.key_package_builder(CIPHERSUITE, None)?
.valid_for_sec(123)
.build()?;

let stored_secrets = key_package_generation.key_package_data;

// Alice creates a group with Bob.
let mut alice_group = alice.create_group(ExtensionList::default(), Default::default())?;

let welcomes = alice_group
.commit_builder()
.add_member(key_package_generation.key_package_message)?
.build()?
.welcome_messages;

alice_group.apply_pending_commit()?;

// Bob joins
let mut bob_group = bob.group_joiner(&welcomes[0], stored_secrets)?.join()?.0;

// Alice and bob can chat
let msg = alice_group.encrypt_application_message(b"hello world", Default::default())?;
let msg = bob_group.process_incoming_message(msg)?;

println!("Received message: {:?}", msg);

Ok(())
}

#[derive(Clone)]
struct NoOpKeyPackageStorage;

impl KeyPackageStorage for NoOpKeyPackageStorage {
type Error = Infallible;

fn delete(&mut self, _: &[u8]) -> Result<(), Infallible> {
Ok(())
}

fn get(&self, _: &[u8]) -> Result<Option<KeyPackageData>, Infallible> {
Ok(None)
}

fn insert(&mut self, _: Vec<u8>, _: KeyPackageData) -> Result<(), Infallible> {
Ok(())
}
}

fn make_client<P: CryptoProvider + Clone>(
crypto_provider: P,
name: &str,
) -> Result<Client<impl MlsConfig>, MlsError> {
let cipher_suite = crypto_provider.cipher_suite_provider(CIPHERSUITE).unwrap();
let (secret, public) = cipher_suite.signature_key_generate().unwrap();
let basic_identity = BasicCredential::new(name.as_bytes().to_vec());
let signing_identity = SigningIdentity::new(basic_identity.into_credential(), public);

Ok(Client::builder()
.identity_provider(BasicIdentityProvider)
.crypto_provider(crypto_provider)
.signing_identity(signing_identity, secret, CIPHERSUITE)
.key_package_repo(NoOpKeyPackageStorage)
.build())
}
69 changes: 61 additions & 8 deletions mls-rs/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
use crate::cipher_suite::CipherSuite;
use crate::client_builder::{recreate_config, BaseConfig, ClientBuilder, MakeConfig};
use crate::client_config::ClientConfig;
use crate::group::framing::MlsMessage;
use crate::group::framing::{MlsMessage, MlsMessageDescription};

use crate::group::{cipher_suite_provider, validate_group_info_joiner, GroupInfo};
use crate::group::{
cipher_suite_provider, find_key_package_generation, validate_group_info_joiner, GroupInfo,
};
use crate::group::{
framing::MlsMessagePayload, snapshot::Snapshot, ExportedTree, Group, NewMemberInfo,
};
Expand All @@ -17,7 +19,9 @@ use crate::group::{
message_signature::AuthenticatedContent,
proposal::{AddProposal, Proposal},
};
use crate::group_joiner::GroupJoiner;
use crate::identity::SigningIdentity;
use crate::key_package::builder::KeyPackageBuilder;
use crate::key_package::{KeyPackageGeneration, KeyPackageGenerator};
use crate::protocol_version::ProtocolVersion;
use crate::tree_kem::node::NodeIndex;
Expand All @@ -27,8 +31,10 @@ use mls_rs_core::crypto::{CryptoProvider, SignatureSecretKey};
use mls_rs_core::error::{AnyError, IntoAnyError};
use mls_rs_core::extension::{ExtensionError, ExtensionList, ExtensionType};
use mls_rs_core::group::{GroupStateStorage, ProposalType};
use mls_rs_core::identity::{CredentialType, IdentityProvider, MemberValidationContext};
use mls_rs_core::key_package::KeyPackageStorage;
use mls_rs_core::identity::{
CredentialType, IdentityProvider, MemberValidationContext, SigningData,
};
use mls_rs_core::key_package::{KeyPackageData, KeyPackageStorage};

use crate::group::external_commit::ExternalCommitBuilder;

Expand Down Expand Up @@ -483,6 +489,24 @@ where
Ok(key_pkg_gen)
}

#[cfg_attr(all(feature = "ffi", not(test)), safer_ffi_gen::safer_ffi_gen_ignore)]
pub fn key_package_builder(
&self,
cipher_suite: CipherSuite,
signing_data: Option<SigningData>,
) -> Result<
KeyPackageBuilder<<C::CryptoProvider as CryptoProvider>::CipherSuiteProvider>,
MlsError,
> {
let cipher_suite_provider = self
.config
.crypto_provider()
.cipher_suite_provider(cipher_suite)
.ok_or(MlsError::UnsupportedCipherSuite(cipher_suite))?;

KeyPackageBuilder::new(self, cipher_suite_provider, signing_data)
}

/// Create a group with a specific group_id.
///
/// This function behaves the same way as
Expand Down Expand Up @@ -557,11 +581,40 @@ where
tree_data: Option<ExportedTree<'_>>,
welcome_message: &MlsMessage,
) -> Result<(Group<C>, NewMemberInfo), MlsError> {
Group::join(
welcome_message,
tree_data,
let MlsMessageDescription::Welcome {
key_package_refs, ..
} = welcome_message.description()
else {
return Err(MlsError::UnexpectedMessageType);
};

let key_package_data =
find_key_package_generation(&self.config.key_package_repo(), &key_package_refs).await?;

let mut joiner = self
.group_joiner(welcome_message, key_package_data)
.await?
.signature_secret_key(self.signer()?.clone());

if let Some(tree) = tree_data {
joiner = joiner.ratchet_tree(tree);
}

joiner.join().await
}

#[cfg_attr(all(feature = "ffi", not(test)), safer_ffi_gen::safer_ffi_gen_ignore)]
#[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
pub async fn group_joiner<'a, 'b>(
&self,
welcome_message: &'a MlsMessage,
key_package_data: KeyPackageData,
) -> Result<GroupJoiner<'a, 'b, C>, MlsError> {
GroupJoiner::new(
self.config.clone(),
self.signer()?.clone(),
welcome_message,
key_package_data,
self.signer.clone(),
)
.await
}
Expand Down
2 changes: 0 additions & 2 deletions mls-rs/src/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
pub use mls_rs_core::extension::{ExtensionType, MlsCodecExtension, MlsExtension};

pub(crate) use built_in::*;
#[cfg(feature = "last_resort_key_package_ext")]
pub(crate) use recommended::*;

/// Default extension types required by the MLS RFC.
pub mod built_in;
Expand Down
12 changes: 3 additions & 9 deletions mls-rs/src/external_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ mod config;
mod group;

pub(crate) use config::ExternalClientConfig;
use mls_rs_core::{
crypto::{CryptoProvider, SignatureSecretKey},
identity::SigningIdentity,
};
use mls_rs_core::{crypto::CryptoProvider, identity::SigningData};

use builder::{ExternalBaseConfig, ExternalClientBuilder};

Expand All @@ -39,7 +36,7 @@ pub use group::{ExternalGroup, ExternalReceivedMessage, ExternalSnapshot};
/// the resulting group state.
pub struct ExternalClient<C> {
config: C,
signing_data: Option<(SignatureSecretKey, SigningIdentity)>,
signing_data: Option<SigningData>,
}

impl ExternalClient<()> {
Expand All @@ -52,10 +49,7 @@ impl<C> ExternalClient<C>
where
C: ExternalClientConfig + Clone,
{
pub(crate) fn new(
config: C,
signing_data: Option<(SignatureSecretKey, SigningIdentity)>,
) -> Self {
pub(crate) fn new(config: C, signing_data: Option<SigningData>) -> Self {
Self {
config,
signing_data,
Expand Down
11 changes: 7 additions & 4 deletions mls-rs/src/external_client/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,10 @@ impl<C: IntoConfig> ExternalClientBuilder<C> {
signing_identity: SigningIdentity,
) -> ExternalClientBuilder<IntoConfigOutput<C>> {
let mut c = self.0.into_config();
c.0.signing_data = Some((signer, signing_identity));
c.0.signing_data = Some(SigningData {
signing_identity,
signing_key: signer,
});
ExternalClientBuilder(c)
}
}
Expand Down Expand Up @@ -520,7 +523,7 @@ impl Default for Settings {
/// Definitions meant to be private that are inaccessible outside this crate. They need to be marked
/// `pub` because they appear in public definitions.
mod private {
use mls_rs_core::{crypto::SignatureSecretKey, identity::SigningIdentity};
use mls_rs_core::identity::SigningData;

use super::{IntoConfigOutput, Settings};

Expand All @@ -533,7 +536,7 @@ mod private {
pub(crate) identity_provider: Ip,
pub(crate) mls_rules: Mpf,
pub(crate) crypto_provider: Cp,
pub(crate) signing_data: Option<(SignatureSecretKey, SigningIdentity)>,
pub(crate) signing_data: Option<SigningData>,
}

pub trait IntoConfig {
Expand All @@ -557,7 +560,7 @@ mod private {

use mls_rs_core::{
crypto::SignatureSecretKey,
identity::{IdentityProvider, SigningIdentity},
identity::{IdentityProvider, SigningData, SigningIdentity},
};
use private::{Config, ConfigInner, IntoConfig};

Expand Down
Loading

0 comments on commit 1c6cb11

Please sign in to comment.