Skip to content

Commit

Permalink
Improve documentation on various secret-storage related methods (#4585)
Browse files Browse the repository at this point in the history
* Improve documentation on various secret-storage related methods

* fix link

* Apply suggestions from code review
  • Loading branch information
richvdh authored Dec 16, 2024
1 parent 693bb22 commit aba4e69
Showing 1 changed file with 86 additions and 20 deletions.
106 changes: 86 additions & 20 deletions src/crypto-api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import type { ToDeviceBatch, ToDevicePayload } from "../models/ToDeviceMessage.t
import { Room } from "../models/room.ts";
import { DeviceMap } from "../models/device.ts";
import { UIAuthCallback } from "../interactive-auth.ts";
import { PassphraseInfo, SecretStorageCallbacks, SecretStorageKeyDescription } from "../secret-storage.ts";
import { PassphraseInfo, SecretStorageKeyDescription } from "../secret-storage.ts";
import { VerificationRequest } from "./verification.ts";
import {
BackupTrustInfo,
Expand Down Expand Up @@ -268,9 +268,9 @@ export interface CryptoApi {
* - is enabled on this account and trusted by this device
* - has private keys either cached locally or stored in secret storage
*
* If this function returns false, bootstrapCrossSigning() can be used
* If this function returns false, {@link bootstrapCrossSigning()} can be used
* to fix things such that it returns true. That is to say, after
* bootstrapCrossSigning() completes successfully, this function should
* `bootstrapCrossSigning()` completes successfully, this function should
* return true.
*
* @returns True if cross-signing is ready to be used on this device
Expand Down Expand Up @@ -317,27 +317,30 @@ export interface CryptoApi {
* - is storing cross-signing private keys
* - is storing session backup key (if enabled)
*
* If this function returns false, bootstrapSecretStorage() can be used
* If this function returns false, {@link bootstrapSecretStorage()} can be used
* to fix things such that it returns true. That is to say, after
* bootstrapSecretStorage() completes successfully, this function should
* `bootstrapSecretStorage()` completes successfully, this function should
* return true.
*
* @returns True if secret storage is ready to be used on this device
*/
isSecretStorageReady(): Promise<boolean>;

/**
* Bootstrap the secret storage by creating a new secret storage key, add it in the secret storage and
* store the cross signing keys in the secret storage.
* Bootstrap [secret storage](https://spec.matrix.org/v1.12/client-server-api/#storage).
*
* - Generate a new key {@link GeneratedSecretStorageKey} with `createSecretStorageKey`.
* Only if `setupNewSecretStorage` is set or if there is no AES key in the secret storage
* - Store this key in the secret storage and set it as the default key.
* - Call `cryptoCallbacks.cacheSecretStorageKey` if provided.
* - Store the cross signing keys in the secret storage if
* - the cross signing is ready
* - a new key was created during the previous step
* - or the secret storage already contains the cross signing keys
* - If secret storage is not already set up, or {@link CreateSecretStorageOpts.setupNewSecretStorage} is set:
* * Calls {@link CreateSecretStorageOpts.createSecretStorageKey} to generate a new key.
* * Stores the metadata of the new key in account data and sets it as the default secret storage key.
* * Calls {@link CryptoCallbacks.cacheSecretStorageKey} if provided.
* - Stores the private cross signing keys in the secret storage if they are known, and they are not
* already stored in secret storage.
* - If {@link CreateSecretStorageOpts.setupNewKeyBackup} is set, calls {@link CryptoApi.resetKeyBackup}; otherwise,
* stores the key backup decryption key in secret storage if it is known, and it is not
* already stored in secret storage.
*
* Note that there may be multiple accesses to secret storage during the course of this call, each of which will
* result in a call to {@link CryptoCallbacks.getSecretStorageKey}.
*
* @param opts - Options object.
*/
Expand Down Expand Up @@ -562,9 +565,10 @@ export interface CryptoApi {
*
* If there are existing backups they will be replaced.
*
* The decryption key will be saved in Secret Storage (the {@link matrix.SecretStorage.SecretStorageCallbacks.getSecretStorageKey} Crypto
* callback will be called)
* and the backup engine will be started.
* If secret storage is set up, the new decryption key will be saved (the {@link CryptoCallbacks.getSecretStorageKey}
* callback will be called to obtain the secret storage key).
*
* The backup engine will be started using the new backup version (i.e., {@link checkKeyBackupAndEnable} is called).
*/
resetKeyBackup(): Promise<void>;

Expand Down Expand Up @@ -995,15 +999,77 @@ export interface CrossSigningStatus {
/**
* Crypto callbacks provided by the application
*/
export interface CryptoCallbacks extends SecretStorageCallbacks {
export interface CryptoCallbacks {
/**
* Called to retrieve a secret storage encryption key.
*
* [Server-side secret storage](https://spec.matrix.org/v1.12/client-server-api/#key-storage)
* is, as the name implies, a mechanism for storing secrets which should be shared between
* clients on the server. For example, it is typically used for storing the
* [key backup decryption key](https://spec.matrix.org/v1.12/client-server-api/#decryption-key)
* and the private [cross-signing keys](https://spec.matrix.org/v1.12/client-server-api/#cross-signing).
*
* The secret storage mechanism encrypts the secrets before uploading them to the server using a
* secret storage key. The schema supports multiple keys, but in practice only one tends to be used
* at once; this is the "default secret storage key" and may be known as the "recovery key" (or, sometimes,
* the "security key").
*
* Secret storage can be set up by calling {@link CryptoApi.bootstrapSecretStorage}. Having done so, when
* the crypto stack needs to access secret storage (for example, when setting up a new device, or to
* store newly-generated secrets), it will use this callback (`getSecretStorageKey`).
*
* Note that the secret storage key may be needed several times in quick succession: it is recommended
* that applications use a temporary cache to avoid prompting the user multiple times for the key. See
* also {@link cacheSecretStorageKey} which is called when a new key is created.
*
* The helper method {@link deriveRecoveryKeyFromPassphrase} may be useful if the secret storage key
* was derived from a passphrase.
*
* @param opts - An options object.
*
* @param name - the name of the *secret* (NB: not the encryption key) being stored or retrieved.
* When the item is stored in account data, it will have this `type`.
*
* @returns a pair [`keyId`, `privateKey`], where `keyId` is one of the keys from the `keys` parameter,
* and `privateKey` is the raw private encryption key, as appropriate for the encryption algorithm.
* (For `m.secret_storage.v1.aes-hmac-sha2`, it is the input to an HKDF as defined in the
* [specification](https://spec.matrix.org/v1.6/client-server-api/#msecret_storagev1aes-hmac-sha2).)
*
* Alternatively, if none of the keys are known, may return `null` — in which case the original
* operation that requires access to a secret in secret storage may fail with an exception.
*/
getSecretStorageKey?: (
opts: {
/**
* Details of the secret storage keys required: a map from the key ID
* (excluding the `m.secret_storage.key.` prefix) to details of the key.
*
* When storing a secret, `keys` will contain exactly one entry.
*
* For secret retrieval, `keys` may contain several entries, and the application can return
* any one of the requested keys. Unless your application specifically wants to offer the
* user the ability to have more than one secret storage key active at a time, it is recommended
* to call {@link matrix.SecretStorage.ServerSideSecretStorage.getDefaultKeyId | ServerSideSecretStorage.getDefaultKeyId}
* to figure out which is the current default key, and to return `null` if the default key is not listed in `keys`.
*/
keys: Record<string, SecretStorageKeyDescription>;
},
name: string,
) => Promise<[string, Uint8Array] | null>;

/** @deprecated: unused with the Rust crypto stack. */
getCrossSigningKey?: (keyType: string, pubKey: string) => Promise<Uint8Array | null>;
/** @deprecated: unused with the Rust crypto stack. */
saveCrossSigningKeys?: (keys: Record<string, Uint8Array>) => void;
/** @deprecated: unused with the Rust crypto stack. */
shouldUpgradeDeviceVerifications?: (users: Record<string, any>) => Promise<string[]>;

/**
* Called by {@link CryptoApi#bootstrapSecretStorage}
* Called by {@link CryptoApi.bootstrapSecretStorage} when a new default secret storage key is created.
*
* Applications can use this to (temporarily) cache the secret storage key, for later return by
* {@link getSecretStorageKey}.
*
* @param keyId - secret storage key id
* @param keyInfo - secret storage key info
* @param key - private key to store
Expand Down

0 comments on commit aba4e69

Please sign in to comment.