Documentation Index
Fetch the complete documentation index at: https://mintlify.com/openmls/openmls/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Key packages are pre-published public keys that enable asynchronous addition of clients to MLS groups. They contain:
- Protocol version and ciphersuite
- Public HPKE init key for key agreement
- Credential authenticating the client
- Leaf node with encryption key
- Extensions for additional metadata
Key packages should be used only once. Reuse should be avoided except as a last resort when no other key package is available.
KeyPackage
The main key package structure representing a client’s published public keys.
A signed key package containing client public keys and identity
The unsigned key package data
Signature over the payload using the credential’s signature key
KeyPackageTbs (Payload)
The unsigned payload of a key package
The MLS protocol version (defaults to MLS 1.0)
The ciphersuite this key package supports
The HPKE public init key (must be unique among the client’s key packages)
The leaf node containing the credential and encryption key
Methods
builder
fn() -> KeyPackageBuilder
Creates a new key package builderpub fn builder() -> KeyPackageBuilder
Returns the ciphersuitepub fn ciphersuite(&self) -> Ciphersuite
Returns a reference to the leaf nodepub fn leaf_node(&self) -> &LeafNode
Returns the HPKE init keypub fn hpke_init_key(&self) -> &InitKey
extensions
fn(&self) -> &Extensions<KeyPackage>
Returns the key package extensionspub fn extensions(&self) -> &Extensions<KeyPackage>
hash_ref
fn(&self, &impl OpenMlsCrypto) -> Result<KeyPackageRef, LibraryError>
Computes the hash reference for this key packagepub fn hash_ref(&self, crypto: &impl OpenMlsCrypto) -> Result<KeyPackageRef, LibraryError>
The KeyPackageRef is used to identify members when adding them to groups.
Checks if this is a last-resort key packagepub fn last_resort(&self) -> bool
Returns the lifetime of the key packagepub fn life_time(&self) -> &Lifetime
check_extension_support
fn(&self, &[ExtensionType]) -> Result<(), KeyPackageExtensionSupportError>
Checks if this key package supports all required extensionspub fn check_extension_support(
&self,
required_extensions: &[ExtensionType],
) -> Result<(), KeyPackageExtensionSupportError>
KeyPackageBuilder
Builder for creating and configuring key packages.
Builder for constructing key packages with custom configuration
key_package_extensions
Option<Extensions<KeyPackage>>
Optional key package extensions
Optional leaf node capabilities
leaf_node_extensions
Option<Extensions<LeafNode>>
Optional leaf node extensions
Whether to mark as last-resort
Methods
Creates a new key package builder
key_package_lifetime
fn(self, Lifetime) -> Self
Sets the key package lifetimepub fn key_package_lifetime(mut self, lifetime: Lifetime) -> Self
key_package_extensions
fn(self, Extensions<KeyPackage>) -> Self
Sets the key package extensionspub fn key_package_extensions(mut self, extensions: Extensions<KeyPackage>) -> Self
Marks the key package as a last-resort packagepub fn mark_as_last_resort(mut self) -> Self
leaf_node_capabilities
fn(self, Capabilities) -> Self
Sets the leaf node capabilitiespub fn leaf_node_capabilities(mut self, capabilities: Capabilities) -> Self
leaf_node_extensions
fn(self, Extensions<LeafNode>) -> Self
Sets the leaf node extensionspub fn leaf_node_extensions(mut self, extensions: Extensions<LeafNode>) -> Self
build
fn(self, Ciphersuite, &impl OpenMlsProvider, &impl Signer, CredentialWithKey) -> Result<KeyPackageBundle, KeyPackageNewError>
Builds and signs the key package, storing it in the provider’s storagepub fn build(
self,
ciphersuite: Ciphersuite,
provider: &impl OpenMlsProvider,
signer: &impl Signer,
credential_with_key: CredentialWithKey,
) -> Result<KeyPackageBundle, KeyPackageNewError>
provider
&impl OpenMlsProvider
required
The cryptographic and storage provider
The signer for the credential
credential_with_key
CredentialWithKey
required
The credential and signature key
KeyPackageBundle
A key package together with its private keys. This is what clients store locally.
Complete key package with private keys
The private HPKE init key
The private encryption key for the leaf node
Methods
Returns a reference to the public key packagepub fn key_package(&self) -> &KeyPackage
init_private_key
fn(&self) -> &HpkePrivateKey
Returns a reference to the private init keypub fn init_private_key(&self) -> &HpkePrivateKey
InitKey
The HPKE init key used for key agreement.
HPKE public init key
The HPKE public key bytes
Methods
key
fn(&self) -> &HpkePublicKey
Returns the internal HPKE public keypub fn key(&self) -> &HpkePublicKey
Returns the key as a byte slicepub fn as_slice(&self) -> &[u8]
Lifetime
Specifies the validity period of a key package.
Key package validity period
Timestamp before which the key package is not valid (seconds since Unix epoch)
Timestamp after which the key package is not valid (seconds since Unix epoch)
KeyPackageIn
A deserialized but unverified key package. Must be validated before use.
Unverified key package from the wire
Methods
validate
fn(self, &impl OpenMlsCrypto, ProtocolVersion) -> Result<KeyPackage, KeyPackageVerifyError>
Validates the key package and returns a verified KeyPackagepub fn validate(
self,
crypto: &impl OpenMlsCrypto,
protocol_version: ProtocolVersion,
) -> Result<KeyPackage, KeyPackageVerifyError>
Errors
KeyPackageNewError
Errors when creating key packages
CiphersuiteSignatureSchemeMismatch
The ciphersuite doesn’t match the signature scheme
Signature generation failed
KeyPackageVerifyError
Errors when verifying key packages
The lifetime is not valid
An extension is not supported in the leaf’s capabilities
The key package signature is invalid
The leaf node signature is invalid
InvalidLeafNodeSourceType
Invalid LeafNode source type
InitKeyEqualsEncryptionKey
The init key and encryption key are equal (forbidden)
The protocol version is not valid
KeyPackageExtensionSupportError
KeyPackageExtensionSupportError
Errors when checking extension support
The key package doesn’t support all required extensions
Usage Examples
Creating a Basic Key Package
use openmls::prelude::*;
use openmls_rust_crypto::OpenMlsRustCrypto;
use openmls_basic_credential::SignatureKeyPair;
let ciphersuite = Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519;
let provider = OpenMlsRustCrypto::default();
// Create credential
let credential = BasicCredential::new(b"alice@example.com".to_vec());
let signer = SignatureKeyPair::new(ciphersuite.signature_algorithm())
.expect("Error generating signature key pair");
let credential_with_key = CredentialWithKey {
credential: credential.into(),
signature_key: signer.public().into(),
};
// Build key package
let key_package_bundle = KeyPackage::builder()
.build(ciphersuite, &provider, &signer, credential_with_key)
.unwrap();
let key_package = key_package_bundle.key_package();
Creating a Last-Resort Key Package
use openmls::prelude::*;
let key_package_bundle = KeyPackage::builder()
.mark_as_last_resort()
.build(ciphersuite, &provider, &signer, credential_with_key)
.unwrap();
assert!(key_package_bundle.key_package().last_resort());
Setting Custom Lifetime
use openmls::prelude::*;
use std::time::{SystemTime, UNIX_EPOCH, Duration};
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
let lifetime = Lifetime {
not_before: now,
not_after: now + 86400 * 30, // 30 days
};
let key_package_bundle = KeyPackage::builder()
.key_package_lifetime(lifetime)
.build(ciphersuite, &provider, &signer, credential_with_key)
.unwrap();
Loading and Validating a Key Package
use openmls::prelude::*;
use tls_codec::*;
let provider = OpenMlsRustCrypto::default();
// Deserialize from bytes
let key_package_in = KeyPackageIn::tls_deserialize(&mut bytes.as_slice())
.expect("Could not deserialize KeyPackage");
// Validate
let key_package = key_package_in
.validate(provider.crypto(), ProtocolVersion::Mls10)
.expect("Invalid KeyPackage");
// Compute hash reference for storage/lookup
let key_package_ref = key_package.hash_ref(provider.crypto())
.expect("Failed to compute hash reference");
Adding Custom Extensions
use openmls::prelude::*;
let extensions = Extensions::single(
Extension::ApplicationId(ApplicationIdExtension::new(b"my-app"))
).unwrap();
let key_package_bundle = KeyPackage::builder()
.key_package_extensions(extensions)
.build(ciphersuite, &provider, &signer, credential_with_key)
.unwrap();
Best Practices
- Generate a new key package for each group join operation
- Store KeyPackageBundle securely with its private keys
- Validate received key packages before using them
- Set appropriate lifetimes to enable key rotation
- Use the last-resort extension sparingly for backup key packages
- Verify that init keys are unique across your key packages