implementent SecretStorage.load

This commit is contained in:
Bruno Windels 2023-04-07 16:35:01 +02:00
parent 67ad975377
commit caa65870f3
4 changed files with 45 additions and 15 deletions

View File

@ -536,12 +536,12 @@ export class Session {
} }
} }
if (this._olm && this._e2eeAccount) { if (this._olm && this._e2eeAccount) {
// try set up session backup and cross-signing if we stored the ssss key this._secretStorage = new SecretStorage({
const ssssKey = await ssssReadKey(txn); platform: this._platform,
if (ssssKey) { storage: this._storage,
// this will close the txn above, so we do it last olm: this._olm
await this._tryLoadSecretStorage(ssssKey, log); });
} await this._secretStorage.load(txn);
} }
} }

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import {BaseObservableValue, RetainedObservableValue} from "../../observable/value"; import {BaseObservableValue, RetainedObservableValue} from "../../observable/value";
import {KeyType} from "./index"; import {KeyType, SSSS_KEY} from "./index";
import {keyFromPassphrase} from "./passphrase"; import {keyFromPassphrase} from "./passphrase";
import {keyFromRecoveryKey} from "./recoveryKey"; import {keyFromRecoveryKey} from "./recoveryKey";
import {Key, KeyDescription, KeyDescriptionData} from "./common"; import {Key, KeyDescription, KeyDescriptionData} from "./common";
@ -48,11 +48,17 @@ class DecryptionError extends Error {
} }
} }
type KeyCredentials = { type StringKeyCredential = {
type: KeyType, type: KeyType.Passphrase | KeyType.RecoveryKey,
credential: string credential: string
} }
type BitsKeyCredential = {
type: KeyType.KeyBits,
credential: Uint8Array
}
type KeyCredentials = StringKeyCredential | BitsKeyCredential;
export class SecretStorage { export class SecretStorage {
// we know the id but don't have the description yet // we know the id but don't have the description yet
private keyId?: string; private keyId?: string;
@ -73,11 +79,32 @@ export class SecretStorage {
this.observedSecrets = new Map(); this.observedSecrets = new Map();
} }
load() { async load(txn: Transaction) {
// read key // first try to read the key bits from previously enabling 4S
const keyData = await txn.session.get(SSSS_KEY);
if (keyData) {
const keyAccountData = await txn.accountData.get(`m.secret_storage.key.${keyData.id}`);
if (keyAccountData) {
this.keyId = keyData.id;
this.keyDescription = new KeyDescription(keyData.id, keyAccountData.content as KeyDescriptionData);
this.keyCredentials = {type: KeyType.KeyBits, credential: keyData.binaryKey};
}
} else {
// then prepare to track the default key
const defaultKey = await txn.accountData.get("m.secret_storage.default_key");
const keyId = defaultKey?.content?.key;
if (keyId) {
this.keyId = keyId;
const keyData = await txn.accountData.get(`m.secret_storage.key.${keyId}`);
if (keyData) {
this.keyDescription = new KeyDescription(keyId, keyData.content as KeyDescriptionData);
}
}
}
this.updateKey(this.keyDescription, this.keyCredentials);
} }
async setKey(type: KeyType, credential: string) { async setKey(type: KeyType.Passphrase | KeyType.RecoveryKey, credential: string) {
const credentials: KeyCredentials = {type, credential}; const credentials: KeyCredentials = {type, credential};
this.keyCredentials = credentials; this.keyCredentials = credentials;
this.updateKey(this.keyDescription, this.keyCredentials); this.updateKey(this.keyDescription, this.keyCredentials);
@ -104,6 +131,8 @@ export class SecretStorage {
} else if (credentials.type === KeyType.RecoveryKey) { } else if (credentials.type === KeyType.RecoveryKey) {
this.key = await keyFromRecoveryKey(keyDescription, credentials.credential, this.olm, this.platform); this.key = await keyFromRecoveryKey(keyDescription, credentials.credential, this.olm, this.platform);
return true; return true;
} else if (credentials.type === KeyType.KeyBits) {
this.key = new Key(keyDescription, credentials.credential);
} }
} }
return false; return false;

View File

@ -26,12 +26,13 @@ import type * as OlmNamespace from "@matrix-org/olm"
type Olm = typeof OlmNamespace; type Olm = typeof OlmNamespace;
const SSSS_KEY = `${SESSION_E2EE_KEY_PREFIX}ssssKey`; export const SSSS_KEY = `${SESSION_E2EE_KEY_PREFIX}ssssKey`;
const BACKUPVERSION_KEY = `${SESSION_E2EE_KEY_PREFIX}keyBackupVersion`; const BACKUPVERSION_KEY = `${SESSION_E2EE_KEY_PREFIX}keyBackupVersion`;
export enum KeyType { export enum KeyType {
RecoveryKey, RecoveryKey,
Passphrase Passphrase,
KeyBits // decoded bits from either recovery key or passphrase, as stored on disk
} }
async function readDefaultKeyDescription(storage: Storage): Promise<KeyDescription | undefined> { async function readDefaultKeyDescription(storage: Storage): Promise<KeyDescription | undefined> {

View File

@ -27,7 +27,7 @@ const DEFAULT_BITSIZE = 256;
* @param {Platform} platform * @param {Platform} platform
* @return {Key} * @return {Key}
*/ */
export async function keyFromPassphrase(passphrase: string, platform: Platform): Promise<Key> { export async function keyFromPassphrase(keyDescription: KeyDescription, passphrase: string, platform: Platform): Promise<Key> {
const {passphraseParams} = keyDescription; const {passphraseParams} = keyDescription;
if (!passphraseParams) { if (!passphraseParams) {
throw new Error("not a passphrase key"); throw new Error("not a passphrase key");