Skip to main content

KeyVault

@webda/sealed-client


Class: KeyVault

Defined in: packages/sealed-client/src/vault.ts:152

Client side of sealed fields: holds the user keyring on this device and opens sealed values.

The keyring (every private key of the user, by kid) is encrypted with a random keyring key; the keyring key is wrapped by the device KEK in the local storage and by the password / recovery code escrows on the server. Private keys live in memory, non-extractable, only while unlocked.

Public key pinning: the fingerprint of the active public key is pinned in the storage (webda-sealed:pin:<userId>). A served active key with another fingerprint is refused with a KeyringPinError, unless this device rotated it, or verified the rotation: a keyring opened with the keyring key (refreshed at unlock, or through an escrow) that still holds the pinned private key. Besides its own rotation, an explicit KeyVault.reset is the only pin change a device makes by itself; KeyVault.forgetPin lets the user trust a new key on first use again.

Constructors​

Constructor​

new KeyVault(options): KeyVault

Defined in: packages/sealed-client/src/vault.ts:160

Parameters​

options​

KeyVaultOptions

user, server operations and local storage

Returns​

KeyVault

Properties​

options​

protected options: KeyVaultOptions

Defined in: packages/sealed-client/src/vault.ts:160

user, server operations and local storage

Accessors​

isUnlocked​

Get Signature​

get isUnlocked(): boolean

Defined in: packages/sealed-client/src/vault.ts:163

Returns​

boolean

true while the private keys are in memory

Methods​

changePassword()​

changePassword(newPassword, opts?): Promise<void>

Defined in: packages/sealed-client/src/vault.ts:395

Re-wrap the keyring key under a new password and replace the password escrow: directly while unlocked, otherwise through the password escrow opened with the old password (a throttled getEscrow, checked against the pin).

The password escrow must follow the login password: the host changes both together (this call right after, or before, the login password change), otherwise the next device has to be added with the old password.

While unlocked, the change is refused with a KeyringPinError when the keyring changed on another device since the unlock (its keyring key may have been replaced): unlock again first.

Parameters​

newPassword​

string

new password

opts?​

options

oldPassword?​

string

current password, needed while locked

Returns​

Promise<void>


enroll()​

enroll(input): Promise<{ recoveryCode?: string; }>

Defined in: packages/sealed-client/src/vault.ts:189

First device: generate the user key pair and keyring, escrow the keyring key, keep it on this device and pin the public key. The device KEK is derived before anything is sent, so a failing KEK leaves nothing on the server; once the server accepted the keys, the device blob and the pin are stored before the device registration, which is retried by the next unlock when it fails.

Parameters​

input​

enrollment

device​

DeviceKek

device KEK

deviceName​

string

name registered for this device

password?​

string

password escrow (the login password, its KEK is derived locally with its own salt)

recovery?​

boolean

also create a recovery code escrow

Returns​

Promise<{ recoveryCode?: string; }>

the recovery code, to show once


forgetPin()​

forgetPin(): Promise<void>

Defined in: packages/sealed-client/src/vault.ts:474

Forget the public key pinned on this device and lock: the next KeyVault.unlockWithEscrow trusts the served key on first use, as on a new device. For the user to call explicitly after a KeyVault.reset done on another device, ideally once the new fingerprint was compared out of band

Returns​

Promise<void>


lock()​

lock(): void

Defined in: packages/sealed-client/src/vault.ts:588

Drop the keys from memory

Returns​

void


open()​

open<T>(env, ctx): Promise<T>

Defined in: packages/sealed-client/src/vault.ts:352

Open a sealed value with the private key of its kid (retired keys stay readable). The private keys all come from a keyring authenticated against the pinned active key (or a verified rotation of it), each checked against its served public key

Type Parameters​

T​

T = unknown

Parameters​

env​

SealedEnvelope

sealed envelope

ctx​

SealedContext

model type, uuid and field it is stored in (AAD)

Returns​

Promise<T>

the value


removeRecoveryCode()​

removeRecoveryCode(): Promise<void>

Defined in: packages/sealed-client/src/vault.ts:429

Remove the recovery code escrow (User.Keys.RemoveEscrow). The server refuses to remove the last escrow while no device is registered (409, surfaced as the api error)

Returns​

Promise<void>


reset()​

reset(input): Promise<{ recoveryCode?: string; }>

Defined in: packages/sealed-client/src/vault.ts:449

Keys lost (no device left, password and recovery code forgotten): start over with a new key pair and a new keyring key, through User.Keys.Rotate (fresh authentication required, the vault does not need to be unlocked).

The new keyring holds the new private key only: values sealed to the older keys stay unreadable, new values open. The requested escrows replace the old ones, this device keeps the new keyring key and is registered (kept when already registered), and the pin moves to the new key: an explicit reset by the user is, with its own rotation, the only pin change a device makes by itself. The other devices are cut off (their unlock fails with a KeyringPinError); they are added again with the new escrow after KeyVault.forgetPin.

Parameters​

input​

EscrowRequest & object

reset

Returns​

Promise<{ recoveryCode?: string; }>

the recovery code when one was requested, to show once


rotate()​

rotate(options?): Promise<{ recoveryCode?: string; }>

Defined in: packages/sealed-client/src/vault.ts:491

Rotate: a new active key pair added to the keyring, the keyring re-encrypted for it, and the pin moved to it. Values sealed to older keys stay readable.

By default the keyring key is kept, so the escrows stay valid: a device that kept its blob (lost or revoked) can still open the keyring. With newKeyringKey, a fresh keyring key encrypts the keyring, the requested escrows are rebuilt and replace the old ones, and this device re-wraps its blob with its KEK: the answer to a lost or revoked device.

Parameters​

options?​

rotation options

newKeyringKey?​

EscrowRequest & object

replace the keyring key: the device KEK of this device and the escrows to create

Returns​

Promise<{ recoveryCode?: string; }>

the new recovery code when one was requested, to show once


seal()​

seal(value, ctx, recipient?): Promise<SealedEnvelope>

Defined in: packages/sealed-client/src/vault.ts:368

Seal a value to the user pinned public key (works while locked)

Parameters​

value​

unknown

JSON-encodable value

ctx​

SealedContext

model type, uuid and field it will be stored in (AAD)

recipient?​

PublicKeyEntry

public key to seal to, refused unless it is the pinned key (default: the active key)

Returns​

Promise<SealedEnvelope>

the envelope


setRecoveryCode()​

setRecoveryCode(): Promise<string>

Defined in: packages/sealed-client/src/vault.ts:414

Create or replace the recovery code escrow; refused with a KeyringPinError when the keyring changed on another device since the unlock (unlock again first)

Returns​

Promise<string>

the recovery code, to show once


unlock()​

unlock(device): Promise<void>

Defined in: packages/sealed-client/src/vault.ts:222

Unlock this device with its KEK; the server is only asked for the public keys, checked against the pin, and the devices: a device revoked on the server deletes its local blob (DeviceRevokedError).

A stale local keyring (rotated on another device) is refreshed with User.Keys.GetKeyring: the served keyring must open with the keyring key of this device and still hold the pinned private key, otherwise the unlock fails with a KeyringPinError (the keyring key was replaced: unlock with an escrow).

Parameters​

device​

DeviceKek

device KEK

Returns​

Promise<void>


unlockWithEscrow()​

unlockWithEscrow(secret, register): Promise<void>

Defined in: packages/sealed-client/src/vault.ts:301

Open the keyring with an escrow and keep it on this device (adds a device, or verifies a rotation done on another device: the new keyring must hold the pinned private key)

Parameters​

secret​

EscrowSecret

password or recovery code

register​

device KEK and name

device​

DeviceKek

device KEK

deviceName​

string

name registered for this device

Returns​

Promise<void>