KeyVault
Class: KeyVault
Defined in: packages/sealed-client/src/vault.ts:156
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:174
Create a new KeyVault instance
Parameters
options
user, server operations and local storage
Returns
KeyVault
Properties
options
protectedoptions:KeyVaultOptions
Defined in: packages/sealed-client/src/vault.ts:174
user, server operations and local storage
Accessors
isUnlocked
Get Signature
get isUnlocked():
boolean
Defined in: packages/sealed-client/src/vault.ts:180
Get true while the private keys are in memory
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:449
Re-wrap the keyring key under a new password and replace the password escrow with User.Keys.SetEscrow
(see KeyVault.createPasswordEscrow for the unlock rules).
The password escrow must follow the login password: a host whose password change does not take the escrow 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.
Parameters
newPassword
string
new password
opts?
options
oldPassword?
string
current password, needed while locked
Returns
Promise<void>
createPasswordEscrow()
createPasswordEscrow(
newPassword,opts?):Promise<EscrowBlob>
Defined in: packages/sealed-client/src/vault.ts:422
Build the password escrow of a new password without sending it: the keyring key is re-wrapped under the new
password, directly while unlocked, otherwise through the password escrow opened with the old password (a
throttled getEscrow, checked against the pin). The escrow carries the active key id (kid): the server refuses
it (412) when its active key changed meanwhile.
For a host whose login password change takes the escrow with it (Auth.Password.Change of @webda/auth refuses
a change without it once a password escrow exists): send the blob as its escrow input, both are then stored
together. KeyVault.changePassword sends it alone with User.Keys.SetEscrow.
While unlocked, the escrow 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<EscrowBlob>
the escrow of the keyring key under the new password
enroll()
enroll(
input):Promise<{recoveryCode?:string; }>
Defined in: packages/sealed-client/src/vault.ts:212
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
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:544
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.
This drops the only protection against a substituted public key, so it is for the user to call explicitly, never
automatically on a KeyringPinError: after a KeyVault.reset done on another device (its unlock fails with
KeyringPinError and the new key is refused), show KeyVault.pinnedFingerprint and
KeyVault.servedFingerprint, let the user compare the served one out of band with the device that did the
reset, then call forgetPin() and add the device again with the new escrow. A served fingerprint the user does
not recognise means a substituted key: keep the pin and stop
Returns
Promise<void>
lock()
lock():
void
Defined in: packages/sealed-client/src/vault.ts:660
Drop the keys from memory
Returns
void
open()
open<
T>(env,ctx):Promise<T>
Defined in: packages/sealed-client/src/vault.ts:375
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
sealed envelope
ctx
model type, uuid and field it is stored in (AAD)
Returns
Promise<T>
the value
pinnedFingerprint()
pinnedFingerprint():
Promise<string|undefined>
Defined in: packages/sealed-client/src/vault.ts:519
Fingerprint of the public key pinned on this device (base64url SHA-256 of the raw P-256 point, the kid is its
first 16 characters), to show to the user: compared out of band with the fingerprint shown on another device, it
tells a legitimate rotation or reset from a substituted key
Returns
Promise<string | undefined>
the pinned fingerprint, undefined on a device without pin (trust on first use at the next unlock)
removeRecoveryCode()
removeRecoveryCode():
Promise<void>
Defined in: packages/sealed-client/src/vault.ts:473
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:493
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:561
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:391
Seal a value to the user pinned public key (works while locked)
Parameters
value
unknown
JSON-encodable value
ctx
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
servedFingerprint()
servedFingerprint():
Promise<string>
Defined in: packages/sealed-client/src/vault.ts:529
Fingerprint of the active public key the server serves now, to compare with KeyVault.pinnedFingerprint before KeyVault.forgetPin: a device cut off by a reset shows both to the user, who checks the new one against the device that did the reset
Returns
Promise<string>
the served active fingerprint
setRecoveryCode()
setRecoveryCode():
Promise<string>
Defined in: packages/sealed-client/src/vault.ts:458
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:245
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
device KEK
Returns
Promise<void>
unlockWithEscrow()
unlockWithEscrow(
secret,register):Promise<void>
Defined in: packages/sealed-client/src/vault.ts:324
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
password or recovery code
register
device KEK and name
device
device KEK
deviceName
string
name registered for this device
Returns
Promise<void>