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
readonlykind:"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
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
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
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.