انتقل إلى المحتوى الرئيسي

Interface: KeyCustodian

Defined in: packages/key-custodian/src/port.ts:214

The port through which a module generates and uses keys that never leave their token.

Handles, never keys. No method returns or accepts the private half of a signing key or the bytes of a wrapping key, and no adapter may add one. That is what lets a development adapter over SoftHSM and a production adapter over a vendor's module share every caller unchanged. A data key does cross the interface, in KeyCustodian.wrap and out of KeyCustodian.unwrap: it is the caller's key, not the token's.

null means "not mine". Every method that takes an id answers null, without touching the token, for an id that lacks this adapter's hsm: prefix (chapter 28, section 4). A caller holding ids from more than one custody uses that to dispatch; a caller that only ever stores hsm: ids should treat null as a defect.

Two families, never mixed. A signing handle given to wrap or unwrap, or a wrapping handle given to sign or publicKey, is unsupported_algorithm: the key is there and is the wrong kind, which is a different fault from a key that is gone.

The handle names its backend, and there is no fallback. A handle whose token is not present raises backend_missing. No adapter searches another token or another custody for the key.

Never inside a database transaction. Every method may wait on a device or a session pool. Generate before the transaction that stores the handle, and sign before the transaction that records what was signed (chapter 28, section 3); a transaction held open across a slow token exhausts the pool for everyone else.

Whoever writes the second adapter must preserve all five.

Extended by​

Properties​

kind​

readonly kind: "pkcs11"

Defined in: packages/key-custodian/src/port.ts:216

Which adapter this is. Only pkcs11 exists; cloud KMS adapters come later (07).

Methods​

destroy()​

destroy(handle): Promise<DestroyOutcome | null>

Defined in: packages/key-custodian/src/port.ts:277

Destroys both halves of a signing key. Irreversible: anything the key signed stays verifiable only through copies of its public key held elsewhere.

A wrapping key is not destroyed through this port, and its handle is refused as policy_refused rather than answered absent. Destroying one makes every data key wrapped under it unrecoverable, which is the erasure of everyone at once; an operator retires a wrapping key on the token, after a re-wrap has moved every row off it.

Parameters​

handle​

string

Returns​

Promise<DestroyOutcome | null>

destroyed, absent when the token holds no such key (a retried destroy sees this), or null for an id without the hsm: prefix.

Throws​

invalid_handle, backend_missing, policy_refused (a wrapping key's handle), duplicate_key, login_failed or custody_unavailable.


generate()​

generate(spec): Promise<KeyHandle>

Defined in: packages/key-custodian/src/port.ts:232

Creates a key pair on the token. The private key is created sensitive, non-extractable, persistent and able to sign only; the adapter reads those attributes back, with the token's CKA_ALWAYS_SENSITIVE and CKA_NEVER_EXTRACTABLE, and destroys and refuses a key the token did not honour them on.

The outcome of a custody_unavailable failure is indeterminate: the token may have created objects that no handle names. Retrying is safe (it makes a new key under a new id); the orphan is harmless and an operator can remove it.

Parameters​

spec​

KeySpec

Returns​

Promise<KeyHandle>

Throws​

invalid_request, policy_refused, unsupported_algorithm, backend_missing, login_failed or custody_unavailable.


generateWrappingKey()​

generateWrappingKey(spec): Promise<WrappingKeyHandle>

Defined in: packages/key-custodian/src/port.ts:293

Creates an AES-256 key on the token, for KeyCustodian.wrap and KeyCustodian.unwrap and nothing else. It is created sensitive, non-extractable and persistent, able to encrypt and decrypt, and unable to wrap or unwrap key objects, sign, verify or derive; the adapter reads those attributes back, with the key's length and the token's own record of its history, and destroys and refuses a key the token did not honour them on.

As with KeyCustodian.generate, a custody_unavailable failure may leave an object on the token that no handle names. Retrying is safe.

Parameters​

spec​

WrappingKeySpec

Returns​

Promise<WrappingKeyHandle>

Throws​

invalid_request, policy_refused, unsupported_algorithm (the token has no AES-GCM), backend_missing, login_failed or custody_unavailable.


publicKey()​

publicKey(handle): Promise<Jwk | null>

Defined in: packages/key-custodian/src/port.ts:260

Reads the public half of the key the handle names.

Parameters​

handle​

string

Returns​

Promise<Jwk | null>

The JWK, or null for an id without the hsm: prefix.

Throws​

As KeyCustodian.sign, less unsupported_algorithm.


sign()​

sign(handle, data, alg): Promise<Uint8Array<ArrayBufferLike> | null>

Defined in: packages/key-custodian/src/port.ts:248

Signs data with the key the handle names. ES256 hashes data with SHA-256 in process and has the token sign the digest, returning the 64-byte r || s that a JWS carries; EdDSA passes data whole and returns 64 bytes. A module that answers with any other length raises custody_unavailable rather than a bad signature.

Parameters​

handle​

string

The id KeyCustodian.generate returned, unchanged.

data​

Uint8Array

The bytes to sign, typically a JWS signing input.

alg​

SigningAlgorithm

Must be the key's own algorithm.

Returns​

Promise<Uint8Array<ArrayBufferLike> | null>

The signature, or null for an id without the hsm: prefix.

Throws​

invalid_handle, backend_missing, unsupported_algorithm (also for a wrapping key's handle), duplicate_key, login_failed or custody_unavailable.


unwrap()​

unwrap(handle, wrapped): Promise<Uint8Array<ArrayBufferLike> | null>

Defined in: packages/key-custodian/src/port.ts:340

Recovers a data key. All of it or none: a value that is not in the wrapped form, or that the token does not authenticate (damaged, truncated, wrapped under another key or under another handle), is unwrap_failed with no output.

A value not in the wrapped form is refused in process, without a call into the module. A module failure that is not a verdict on the value stays custody_unavailable: "could not check" is never reported as "did not authenticate".

Parameters​

handle​

string

The id stored beside wrapped, unchanged.

wrapped​

Uint8Array

What KeyCustodian.wrap returned.

Returns​

Promise<Uint8Array<ArrayBufferLike> | null>

The data key, which the caller owns and should neither log nor persist; or null for an id without the hsm: prefix.

Throws​

invalid_handle, unwrap_failed, backend_missing, unsupported_algorithm, duplicate_key, login_failed or custody_unavailable.


wrap()​

wrap(handle, dataKey): Promise<Uint8Array<ArrayBufferLike> | null>

Defined in: packages/key-custodian/src/port.ts:322

Encrypts a data key under the wrapping key the handle names, on the token, with AES-256-GCM. The nonce is 12 random bytes generated in this process for each call, the tag is 128 bits, and the handle id (its UTF-8 bytes) is the additional authenticated data, so a value wrapped under one handle does not unwrap under another.

This is encryption of bytes, not PKCS#11 key wrapping (C_WrapKey): that call wraps key objects, so the data key would first have to be imported onto the token as an extractable object, which is a second copy of it for nothing (D3.14).

A random nonce bounds how often one key may be used: keep a wrapping key under 2^32 wraps, which is where the chance of a repeated nonce reaches 2^-32. The custodian does not count; whoever rotates the key encryption key owns that bound.

Parameters​

handle​

string

The id KeyCustodian.generateWrappingKey returned, unchanged.

dataKey​

Uint8Array

1 to MAX_DATA_KEY_BYTES bytes. Not retained and not altered.

Returns​

Promise<Uint8Array<ArrayBufferLike> | null>

0x02 || nonce || ciphertext || tag (WRAPPED_KEY_FORMAT), 29 bytes longer than dataKey; or null for an id without the hsm: prefix.

Throws​

invalid_handle, invalid_request (the data key's length), backend_missing, unsupported_algorithm (no AES-GCM on the token, or the handle names a signing key), policy_refused (the key on the token is not sensitive and non-extractable, or the token does not record it as always having been, which is how an imported key reads), duplicate_key, login_failed or custody_unavailable. Never unwrap_failed: a module that answers a write with a ciphertext verdict has failed, and nothing stored is in question.