Skip to content

IKeyCustodian Interface

Host-implemented custodian for the external private keys the library never holds in process: they live in an HSM, a cloud KMS, or a vault transit engine, and only the private operations cross the boundary. A key published public-only routes its private operation here by kid: SIGNING for a signing key, and for a decryption key an RSA/symmetric UNWRAP or an ECDH-ES AGREEMENT. The public operations - signature verification, and wrapping a CEK with the recipient's public half - stay in process and never reach the custodian. Wire it with AddCustodian and a placement call; a host with no external keys leaves it unregistered.

C#
public interface IKeyCustodian

Remarks

Every private operation is addressed by kid, the custodian's handle for that exact key version, identical to the published key's kid - there is no separate identifier and no mapping. The public halves the library publishes come from GetKeyVersionsAsync(string, CancellationToken), which enumerates a named key's versions so a rotation can overlap. The implementation never receives or returns private key material, and only needs to implement the private operations its own keys require: a signing-only custodian leaves unwrap and agree unreachable, and a decryption-only custodian leaves sign unreachable. Direct encryption (dir) and password-based key management (PBES2) have no external form - the CEK is the secret itself, or is derived from it by a password KDF - so they are never routed here and fail closed. Every operation is a round-trip to the custodian, so the contract returns System.Threading.Tasks.Task<> throughout.

Methods

IKeyCustodian.AgreeKeyAsync(string, string, JsonWebKey, CancellationToken) Method

Performs the ECDH-ES key agreement between the recipient's static private key (held by the custodian) and the originator's ephemeral public key, returning the raw shared secret Z. The library runs the Concat KDF over Z and any AES key unwrap, so those steps never leave it.

C#
System.Threading.Tasks.Task<byte[]> AgreeKeyAsync(string keyId, string algorithm, Abblix.Jwt.JsonWebKey ephemeralPublicKey, System.Threading.CancellationToken cancellationToken);

Parameters

keyId System.String

The custodian's handle for the recipient key version.

algorithm System.String

The JWE alg value (ECDH-ES or an ECDH-ES+A*KW variant).

ephemeralPublicKey JsonWebKey

The originator's ephemeral public key from the epk header.

cancellationToken System.Threading.CancellationToken

Cancels the round-trip to the custodian.

Returns

System.Threading.Tasks.Task<System.Byte[]>
The raw ECDH shared secret Z (the agreement's field-sized X-coordinate).

IKeyCustodian.GetKeyVersionsAsync(string, CancellationToken) Method

Enumerates every current version of the key named keyName as its public half, each carrying the version-specific kid that routes a private operation back to that exact version, plus the custodian's creation time for that version. A custodian that does not version its keys yields a single element; a version-aware custodian (Vault Transit, Azure Key Vault) yields every version, which a rotation policy overlaps for zero-downtime key rollover. Called at publication time, so JWKS publishing and local signature verification run against the returned public halves and never touch the custodian on the hot path.

C#
System.Collections.Generic.IAsyncEnumerable<Abblix.Jwt.KeyVersion> GetKeyVersionsAsync(string keyName, System.Threading.CancellationToken cancellationToken);

Parameters

keyName System.String

The custodian's name for the logical key whose versions to enumerate.

cancellationToken System.Threading.CancellationToken

Cancels the round-trip to the custodian.

Returns

System.Collections.Generic.IAsyncEnumerable<KeyVersion>
The key's versions, each a public-only KeyVersion.

IKeyCustodian.SignAsync(string, string, byte[], CancellationToken) Method

Signs data with a signing key held by the custodian, returning the signature in the JWS wire format for algorithm. Called for a signing key the library holds public-only.

C#
System.Threading.Tasks.Task<byte[]> SignAsync(string keyId, string algorithm, byte[] data, System.Threading.CancellationToken cancellationToken);

Parameters

keyId System.String

The custodian's handle for the signing key version.

algorithm System.String

The JWS algorithm identifier (e.g. RS256, ES256) the signature must use.

data System.Byte[]

The signing input bytes, BASE64URL(header) + '.' + BASE64URL(payload).

cancellationToken System.Threading.CancellationToken

Cancels the round-trip to the custodian.

Returns

System.Threading.Tasks.Task<System.Byte[]>
The raw signature bytes in JWS wire format for the algorithm.

IKeyCustodian.UnwrapKeyAsync(string, string, JsonWebTokenHeader, byte[], CancellationToken) Method

Recovers a Content Encryption Key: an RSA decryption (RSA-OAEP / RSA-OAEP-256 / RSA1_5) or a symmetric unwrap (AES-KW / AES-GCM-KW), selected by algorithm.

C#
System.Threading.Tasks.Task<byte[]?> UnwrapKeyAsync(string keyId, string algorithm, Abblix.Jwt.JsonWebTokenHeader header, byte[] encryptedKey, System.Threading.CancellationToken cancellationToken);

Parameters

keyId System.String

The custodian's handle for the recipient key version.

algorithm System.String

The JWE alg value identifying the key-management operation.

header JsonWebTokenHeader

The JWE header; AES-GCM-KW reads its iv / tag parameters from it.

encryptedKey System.Byte[]

The wrapped or RSA-encrypted CEK from the JWE Encrypted Key.

cancellationToken System.Threading.CancellationToken

Cancels the round-trip to the custodian.

Returns

System.Threading.Tasks.Task<System.Byte[]>
The recovered CEK, or null on any failure. Returning null rather than throwing keeps a decryption failure indistinguishable from a wrong key, which the RFC 7516 §11.5 mitigation upstream relies on to close the Bleichenbacher / padding-oracle side channel.