Skip to main content
In MLS, every group member is identified by a credential. CoreCrypto supports two credential types:
  • Basic — a self-asserted key pair. The client ID is embedded directly in the credential. No external PKI required.
  • X.509 — a certificate chain issued through the Wire end-to-end identity (E2EI) ACME flow. Provides verifiable identity including display name, handle, and domain.
Credentials are stored in the keystore and referenced by CredentialRef, which is a thin handle that can safely cross the FFI boundary.

Types

CredentialType

pub enum CredentialType {
    Basic,
    X509,
}
Basic
variant
A self-asserted credential containing only a key pair. The client ID (bytes) is the sole identity claim. No expiry.
X509
variant
An X.509 certificate chain obtained through the E2EI enrollment process. Contains verifiable identity claims (display name, handle, domain) and an expiry date.

Credential

The full credential object. Stores the ciphersuite, credential type, MLS credential value, signature key pair, and earliest validity timestamp.
pub struct Credential {
    pub(crate) ciphersuite: Ciphersuite,
    pub(crate) credential_type: CredentialType,
    pub(crate) mls_credential: MlsCredential,
    pub(crate) signature_key_pair: SignatureKeyPair, // contains private key
    pub(crate) earliest_validity: u64,
}
Public methods
MethodReturnDescription
credential_type()CredentialTypeBasic or X509
ciphersuite()CiphersuiteAssociated ciphersuite
signature_scheme()SignatureSchemeDerived from ciphersuite
client_id()&ClientIdRefThe client identity bytes
earliest_validity()u64Unix timestamp; only meaningful for X.509
mls_credential()&MlsCredentialThe underlying OpenMLS credential
Constructors
// Create a Basic credential (in-memory, not yet persisted)
pub fn basic(ciphersuite: Ciphersuite, client_id: ClientId) -> Result<Self>

// Create an X.509 credential from a certificate bundle
pub fn x509(ciphersuite: Ciphersuite, cert: CertificateBundle) -> Result<Self>

CredentialRef

A lightweight reference to a stored Credential. Safe to pass across the FFI boundary. Resolves back to the full Credential via credential_ref.load(&database).await. The CredentialRef encodes the client ID and a hash of the credential for O(1) lookup in the keystore.

CertificateBundle

Packages the DER-encoded certificate chain and private key for creating an X.509 credential.
pub struct CertificateBundle {
    /// x509 certificate chain.
    /// First entry is the leaf certificate; each subsequent entry is its issuer.
    pub certificate_chain: Vec<Vec<u8>>,
    /// Leaf certificate private key (zeroized on drop)
    pub private_key: CertificatePrivateKey,
    /// Signature scheme of the private key
    pub signature_scheme: SignatureScheme,
}
certificate_chain
Vec<Vec<u8>>
DER-encoded certificates. Index 0 is the leaf (end-entity) certificate. Subsequent entries are intermediate CA certificates up to (but not including) the root CA.
private_key
CertificatePrivateKey
The private signing key corresponding to the leaf certificate’s public key. Zeroized on drop.
signature_scheme
SignatureScheme
The signature scheme of the private key (e.g. ECDSA_SECP256R1_SHA256, ED25519).
Methods
MethodReturnDescription
get_client_id()Result<ClientId>Reads the Wire client ID from the leaf certificate’s subject
get_created_at()Result<u64>Reads the NotBefore claim as a Unix timestamp

TransactionContext methods

add_credential

pub async fn add_credential(
    &self,
    credential: Credential,
) -> Result<CredentialRef>
Persists a credential to the keystore and returns a CredentialRef. The credential’s embedded client ID must match the session’s client ID.
credential
Credential
required
A Credential value created with Credential::basic or Credential::x509.
CredentialRef
CredentialRef
A lightweight reference to the stored credential.
Example
// Basic credential
let cred = Credential::basic(
    Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519,
    client_id.clone(),
)?;
let tx = cc.new_transaction().await?;
let cred_ref = tx.add_credential(cred).await?;
tx.finish().await?;

remove_credential

pub async fn remove_credential(
    &self,
    credential_ref: &CredentialRef,
) -> Result<()>
Removes a credential and all key packages that were generated from it. Fails with CredentialStillInUse if the credential is referenced by any current conversation’s leaf node. You must first rotate the credential out of all conversations with set_credential_by_ref.
credential_ref
&CredentialRef
required
Reference to the credential to remove.
Credential rotation workflow
// 1. Enroll new X.509 credential
let (new_cred_ref, _crl_dps) = tx.save_x509_credential(
    &mut enrollment,
    certificate_chain,
).await?;

// 2. Rotate into every conversation
for conv_id in my_conversation_ids {
    let mut guard = tx.conversation(&conv_id).await?;
    guard.set_credential_by_ref(&new_cred_ref).await?;
}

// 3. Generate fresh key packages from the new credential
let kp = tx.generate_keypackage(&new_cred_ref, None).await?;

// 4. Remove the old credential (and its key packages)
tx.remove_credential(&old_cred_ref).await?;

tx.finish().await?;

find_credentials

pub async fn find_credentials(
    &self,
    find_filters: CredentialFindFilters<'_>,
) -> Result<Vec<CredentialRef>>
Searches session credentials matching the supplied filter criteria. Use CredentialFindFilters::builder() to construct filters (by credential type, ciphersuite, etc.).

get_credentials

pub async fn get_credentials(&self) -> Result<Vec<CredentialRef>>
Returns all credentials belonging to the current session.

Credential and MLS identity

Each MLS leaf node carries exactly one credential. When a commit adds a member, their key package’s credential is embedded in the ratchet tree and becomes visible to all other members. CoreCrypto uses the credential to:
  1. Sign outgoing commits, proposals, and application messages.
  2. Identify group members via get_client_ids and get_device_identities.
  3. Compute E2EI conversation state — whether all members hold valid X.509 credentials.
For X.509 credentials, CoreCrypto validates the certificate chain against the configured PkiEnvironment at the time the credential is used in a commit or proposal.

Build docs developers (and LLMs) love