Skip to content

import_key_package admits a key package with an arbitrarily long lifetime #396

Description

@bahdotsh

What

MlsManager::import_key_package (crates/offline-protocol-mls/src/manager.rs:632) accepts a contact key package whose lifetime range is arbitrarily long, e.g. not_after decades out or u64::MAX. The same applies to the re-validation in get_contact_key_package, which re-runs the identical checks on every cache read.

Both paths validate via OpenMLS KeyPackageIn::validate. That checks the window against now (not_before < now < not_after), but it never enforces the range width: OpenMLS declares MAX_LEAF_NODE_LIFETIME_RANGE_SECONDS (1 hour + 3 months) and never calls the predicate. Verified empirically during the leaf-crypto Stage 0 interop work (PR #394): a 1-year-lifetime package sails through OpenMLS validation.

Why it matters

The lifetime bound is what ages a key package out cryptographically. A package with an unbounded window, once cached in the install-scoped protocol-state store, is importable and usable for new session establishment forever. That extends the useful window of a leaked or compromised init/leaf private key from weeks to unlimited, and it defeats the intent behind bounding our own packages: outbound packages are minted with DEFAULT_KEY_PACKAGE_LIFETIME_SECS = 30 days (manager.rs:24), and the leaf profile pins LEAF_KEY_PACKAGE_LIFETIME = 28 days in offline-protocol-sealed. We bound what we emit and accept anything inbound.

This becomes more load-bearing with the leaf work (ADR 0021/0022): pairing trust for a leaf is "fresh key package over the pairing radio", and freshness is only meaningful if the importer enforces a bound.

Proposed fix

At both validation sites (import and cache re-read), after validate, reject a package whose not_after - not_before exceeds a cap. The natural cap is the OpenMLS declared constant (1h + 3 months), which both our 30-day default and the leaf's 28 days clear with margin. New error variant note: the FFI error enum is append-only (docs/bridges C2), and a new variant needs arms in both bridge mappers, so mapping to the existing InvalidKeyPackage variant with a distinct message is the cheap correct shape.

Provenance

Found during Stage 0 of the leaf payload crypto plan (roadmap item 1); recorded there as an SDK gap deserving its own issue, untouched by the Stage 2 relocation (PR #395).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions