Skip to main content

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.
KeyPackage
struct
A signed key package containing client public keys and identity

KeyPackageTbs (Payload)

KeyPackageTbs
struct
The unsigned payload of a key package

Methods

builder
fn() -> KeyPackageBuilder
Creates a new key package builder
pub fn builder() -> KeyPackageBuilder
ciphersuite
fn(&self) -> Ciphersuite
Returns the ciphersuite
pub fn ciphersuite(&self) -> Ciphersuite
leaf_node
fn(&self) -> &LeafNode
Returns a reference to the leaf node
pub fn leaf_node(&self) -> &LeafNode
hpke_init_key
fn(&self) -> &InitKey
Returns the HPKE init key
pub fn hpke_init_key(&self) -> &InitKey
extensions
fn(&self) -> &Extensions<KeyPackage>
Returns the key package extensions
pub fn extensions(&self) -> &Extensions<KeyPackage>
hash_ref
fn(&self, &impl OpenMlsCrypto) -> Result<KeyPackageRef, LibraryError>
Computes the hash reference for this key package
pub fn hash_ref(&self, crypto: &impl OpenMlsCrypto) -> Result<KeyPackageRef, LibraryError>
The KeyPackageRef is used to identify members when adding them to groups.
last_resort
fn(&self) -> bool
Checks if this is a last-resort key package
pub fn last_resort(&self) -> bool
life_time
fn(&self) -> &Lifetime
Returns the lifetime of the key package
pub fn life_time(&self) -> &Lifetime
check_extension_support
fn(&self, &[ExtensionType]) -> Result<(), KeyPackageExtensionSupportError>
Checks if this key package supports all required extensions
pub fn check_extension_support(
    &self,
    required_extensions: &[ExtensionType],
) -> Result<(), KeyPackageExtensionSupportError>

KeyPackageBuilder

Builder for creating and configuring key packages.
KeyPackageBuilder
struct
Builder for constructing key packages with custom configuration

Methods

new
fn() -> Self
Creates a new key package builder
pub fn new() -> Self
key_package_lifetime
fn(self, Lifetime) -> Self
Sets the key package lifetime
pub fn key_package_lifetime(mut self, lifetime: Lifetime) -> Self
key_package_extensions
fn(self, Extensions<KeyPackage>) -> Self
Sets the key package extensions
pub fn key_package_extensions(mut self, extensions: Extensions<KeyPackage>) -> Self
mark_as_last_resort
fn(self) -> Self
Marks the key package as a last-resort package
pub fn mark_as_last_resort(mut self) -> Self
leaf_node_capabilities
fn(self, Capabilities) -> Self
Sets the leaf node capabilities
pub fn leaf_node_capabilities(mut self, capabilities: Capabilities) -> Self
leaf_node_extensions
fn(self, Extensions<LeafNode>) -> Self
Sets the leaf node extensions
pub 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 storage
pub fn build(
    self,
    ciphersuite: Ciphersuite,
    provider: &impl OpenMlsProvider,
    signer: &impl Signer,
    credential_with_key: CredentialWithKey,
) -> Result<KeyPackageBundle, KeyPackageNewError>

KeyPackageBundle

A key package together with its private keys. This is what clients store locally.
KeyPackageBundle
struct
Complete key package with private keys

Methods

key_package
fn(&self) -> &KeyPackage
Returns a reference to the public key package
pub fn key_package(&self) -> &KeyPackage
init_private_key
fn(&self) -> &HpkePrivateKey
Returns a reference to the private init key
pub fn init_private_key(&self) -> &HpkePrivateKey

InitKey

The HPKE init key used for key agreement.
InitKey
struct
HPKE public init key

Methods

key
fn(&self) -> &HpkePublicKey
Returns the internal HPKE public key
pub fn key(&self) -> &HpkePublicKey
as_slice
fn(&self) -> &[u8]
Returns the key as a byte slice
pub fn as_slice(&self) -> &[u8]

Lifetime

Specifies the validity period of a key package.
Lifetime
struct
Key package validity period

KeyPackageIn

A deserialized but unverified key package. Must be validated before use.
KeyPackageIn
struct
Unverified key package from the wire

Methods

validate
fn(self, &impl OpenMlsCrypto, ProtocolVersion) -> Result<KeyPackage, KeyPackageVerifyError>
Validates the key package and returns a verified KeyPackage
pub fn validate(
    self,
    crypto: &impl OpenMlsCrypto,
    protocol_version: ProtocolVersion,
) -> Result<KeyPackage, KeyPackageVerifyError>

Errors

KeyPackageNewError

KeyPackageNewError
enum
Errors when creating key packages

KeyPackageVerifyError

KeyPackageVerifyError
enum
Errors when verifying key packages

KeyPackageExtensionSupportError

KeyPackageExtensionSupportError
enum
Errors when checking extension support

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