Key packages

To enable asynchronous establishment of groups through pre-publishing key material, as well as to represent clients in group, MLS relies on key packages. Key packages hold a number of pieces of information:

  • a public HPKE encryption key to enable MLS' basic group key distribution feature
  • the life time throughout which the key package is valid
  • information about the client's capabilities (i.e. which features of MLS it supports)
  • any extension that the client wants to include
  • one of the client's credentials, as well as a signature over the whole key package using the private key corresponding to the credential's signature public key

Creating key packages

Before clients can communicate with each other using OpenMLS they need to generate key packages and publish them with the Delivery Service. Clients can generate an arbitrary number of key packages ahead of time.

Clients keep the private key material corresponding to a key package locally in the key store and fetch it from there when a key package was used to add them to a new group.

Clients need to choose a few parameters to create a KeyPackageBundle:

  • ciphersuites: &[CiphersuiteName]: A list of ciphersuites supported by the client.
  • extensions: Vec<Extensions>: A list of supported extensions.

Clients must specify at least one ciphersuite, and must not advertize ciphersuites they do not support.

Clients should specify all extensions they support. Mandatory extensions, like the LifetimeExtension can be specified here with specific values. If no extensions are specified, mandatory extensions are created on the fly with default values. See the documentation of extensions for more details.

    // Define extensions
    let extensions = vec![Extension::LifeTime(LifetimeExtension::new(
        60 * 60 * 24 * 90, // Maximum lifetime of 90 days, expressed in seconds
    ))];

    // Fetch the credential bundle from the key store
    let credential_bundle = backend
        .key_store()
        .read(
            &credential
                .signature_key()
                .tls_serialize_detached()
                .expect("Error serializing signature key."),
        )
        .expect("An unexpected error occurred.");

    // Create the key package bundle
    let key_package_bundle =
        KeyPackageBundle::new(ciphersuites, &credential_bundle, backend, extensions)?;

After creating the key package bundle, clients should store it in the key store so that it can be reused during group operations:

    let key_package = key_package_bundle.key_package().clone();

    // Store it in the key store
    backend
        .key_store()
        .store(
            key_package
                .hash_ref(backend.crypto())
                .expect("Could not hash KeyPackage.")
                .value(),
            &key_package_bundle,
        )
        .expect("An unexpected error occurred.");

All functions and structs related to key packages can be found in the key_packages module.