Expand description
§OpenMLS
OpenMLS is a Rust implementation of the Messaging Layer Security (MLS) protocol, as specified in RFC 9420.
It is a software library that can serve as a building block in applications that require end-to-end encryption of messages. It has a safe and easy-to-use interface that hides the complexity of the underlying cryptographic operations.
§Supported ciphersuites
- MLS_128_HPKEX25519_AES128GCM_SHA256_Ed25519 (MTI)
- MLS_128_DHKEMP256_AES128GCM_SHA256_P256
- MLS_128_HPKEX25519_CHACHA20POLY1305_SHA256_Ed25519
§Supported platforms
OpenMLS is built and tested on the Github CI for the following rust targets.
- x86_64-unknown-linux-gnu
- i686-unknown-linux-gnu
- x86_64-pc-windows-msvc
- i686-pc-windows-msvc
- x86_64-apple-darwin
§Unsupported, but built on CI
The Github CI also builds (but doesn’t test) the following rust targets.
- aarch64-apple-darwin
- aarch64-unknown-linux-gnu
- aarch64-linux-android
- aarch64-apple-ios
- aarch64-apple-ios-sim
- wasm32-unknown-unknown
- armv7-linux-androideabi
- x86_64-linux-android
- i686-linux-android
OpenMLS supports 32 bit platforms and above.
§Cryptography Dependencies
OpenMLS does not implement its own cryptographic primitives. Instead, it relies on existing implementations of the cryptographic primitives used by MLS. There are two different cryptography providers implemented right now. But consumers can bring their own implementation. See traits for more details.
§Working on OpenMLS
For more details when working on OpenMLS itself please see the Developer.md.
§Maintenance & Support
OpenMLS is maintained and developed by Phoenix R&D and Cryspen.
§Acknowledgements
Zulip graciously provides the OpenMLS community with a “Zulip Cloud Standard” tier Zulip instance.
§Quick Start
For a quick start to learn how OpenMLS works here’s the basic code to set up to parties and have them create a group.
use openmls::{prelude::{*, tls_codec::*}};
use openmls_rust_crypto::{OpenMlsRustCrypto};
use openmls_basic_credential::SignatureKeyPair;
// Define ciphersuite ...
let ciphersuite = Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519;
// ... and the crypto provider to use.
let provider = &OpenMlsRustCrypto::default();
// Now let's create two participants.
// A helper to create and store credentials.
fn generate_credential_with_key(
identity: Vec<u8>,
credential_type: CredentialType,
signature_algorithm: SignatureScheme,
provider: &impl OpenMlsProvider,
) -> (CredentialWithKey, SignatureKeyPair) {
let credential = BasicCredential::new(identity);
let signature_keys =
SignatureKeyPair::new(signature_algorithm)
.expect("Error generating a signature key pair.");
// Store the signature key into the key store so OpenMLS has access
// to it.
signature_keys
.store(provider.storage())
.expect("Error storing signature keys in key store.");
(
CredentialWithKey {
credential: credential.into(),
signature_key: signature_keys.public().into(),
},
signature_keys,
)
}
// A helper to create key package bundles.
fn generate_key_package(
ciphersuite: Ciphersuite,
provider: &impl OpenMlsProvider,
signer: &SignatureKeyPair,
credential_with_key: CredentialWithKey,
) -> KeyPackageBundle {
// Create the key package
KeyPackage::builder()
.build(
ciphersuite,
provider,
signer,
credential_with_key,
)
.unwrap()
}
// First they need credentials to identify them
let (sasha_credential_with_key, sasha_signer) = generate_credential_with_key(
"Sasha".into(),
CredentialType::Basic,
ciphersuite.signature_algorithm(),
provider,
);
let (maxim_credential_with_key, maxim_signer) = generate_credential_with_key(
"Maxim".into(),
CredentialType::Basic,
ciphersuite.signature_algorithm(),
provider,
);
// Then they generate key packages to facilitate the asynchronous handshakes
// in MLS
// Generate KeyPackages
let maxim_key_package = generate_key_package(ciphersuite, provider, &maxim_signer, maxim_credential_with_key);
// Now Sasha starts a new group ...
let mut sasha_group = MlsGroup::new(
provider,
&sasha_signer,
&MlsGroupCreateConfig::default(),
sasha_credential_with_key,
)
.expect("An unexpected error occurred.");
// ... and invites Maxim.
// The key package has to be retrieved from Maxim in some way. Most likely
// via a server storing key packages for users.
let (mls_message_out, welcome_out, group_info) = sasha_group
.add_members(provider, &sasha_signer, &[maxim_key_package.key_package().clone()])
.expect("Could not add members.");
// Sasha merges the pending commit that adds Maxim.
sasha_group
.merge_pending_commit(provider)
.expect("error merging pending commit");
// Sascha serializes the [`MlsMessageOut`] containing the [`Welcome`].
let serialized_welcome = welcome_out
.tls_serialize_detached()
.expect("Error serializing welcome");
// Maxim can now de-serialize the message as an [`MlsMessageIn`] ...
let mls_message_in = MlsMessageIn::tls_deserialize(&mut serialized_welcome.as_slice())
.expect("An unexpected error occurred.");
// ... and inspect the message.
let welcome = match mls_message_in.extract() {
MlsMessageBodyIn::Welcome(welcome) => welcome,
// We know it's a welcome message, so we ignore all other cases.
_ => unreachable!("Unexpected message type."),
};
// Now Maxim can build a staged join for the group in order to inspect the welcome
let maxim_staged_join = StagedWelcome::new_from_welcome(
provider,
&MlsGroupJoinConfig::default(),
welcome,
// The public tree is need and transferred out of band.
// It is also possible to use the [`RatchetTreeExtension`]
Some(sasha_group.export_ratchet_tree().into()),
)
.expect("Error creating a staged join from Welcome");
// Finally, Maxim can create the group
let mut maxim_group = maxim_staged_join
.into_group(provider)
.expect("Error creating the group from the staged join");
Modules§
- Ciphersuites for MLS
- Credentials
- OpenMLS Errors
- Extensions
- Message framing
- Group API for MLS
- Key Packages
- Messages
- Single place, re-exporting the most used public functions. Prelude for OpenMLS. Include this to get access to all the public functions of OpenMLS.
- Key schedule
- OpenMLS Storage
- This module implements the ratchet tree component of MLS.
- MLS versions