additional validation of received secrets
This commit is contained in:
parent
a7bb8375dc
commit
41a08d4c28
|
@ -97,8 +97,8 @@ class Client {
|
|||
/// enableE2eeRecovery: Enable additional logic to try to recover from bad e2ee sessions
|
||||
Client(this.clientName,
|
||||
{this.debug = false, this.database, this.enableE2eeRecovery = false}) {
|
||||
keyManager = KeyManager(this);
|
||||
ssss = SSSS(this);
|
||||
keyManager = KeyManager(this);
|
||||
crossSigning = CrossSigning(this);
|
||||
onLoginStateChanged.stream.listen((loginState) {
|
||||
print('LoginState: ${loginState.toString()}');
|
||||
|
|
|
@ -12,7 +12,28 @@ const MASTER_KEY = 'm.cross_signing.master';
|
|||
|
||||
class CrossSigning {
|
||||
final Client client;
|
||||
CrossSigning(this.client);
|
||||
CrossSigning(this.client) {
|
||||
client.ssss.setValidator(SELF_SIGNING_KEY, (String secret) async {
|
||||
final keyObj = olm.PkSigning();
|
||||
try {
|
||||
return keyObj.init_with_seed(base64.decode(secret)) == client.userDeviceKeys[client.userID].selfSigningKey.ed25519Key;
|
||||
} catch (_) {
|
||||
return false;
|
||||
} finally {
|
||||
keyObj.free();
|
||||
}
|
||||
});
|
||||
client.ssss.setValidator(USER_SIGNING_KEY, (String secret) async {
|
||||
final keyObj = olm.PkSigning();
|
||||
try {
|
||||
return keyObj.init_with_seed(base64.decode(secret)) == client.userDeviceKeys[client.userID].userSigningKey.ed25519Key;
|
||||
} catch (_) {
|
||||
return false;
|
||||
} finally {
|
||||
keyObj.free();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool get enabled =>
|
||||
client.accountData[SELF_SIGNING_KEY] != null &&
|
||||
|
|
|
@ -15,7 +15,19 @@ class KeyManager {
|
|||
final outgoingShareRequests = <String, KeyManagerKeyShareRequest>{};
|
||||
final incomingShareRequests = <String, KeyManagerKeyShareRequest>{};
|
||||
|
||||
KeyManager(this.client);
|
||||
KeyManager(this.client) {
|
||||
client.ssss.setValidator(MEGOLM_KEY, (String secret) async {
|
||||
final keyObj = olm.PkDecryption();
|
||||
try {
|
||||
final info = await getRoomKeysInfo();
|
||||
return keyObj.init_with_private_key(base64.decode(secret)) == info['auth_data']['public_key'];
|
||||
} catch (_) {
|
||||
return false;
|
||||
} finally {
|
||||
keyObj.free();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool get enabled => client.accountData[MEGOLM_KEY] != null;
|
||||
|
||||
|
@ -42,15 +54,13 @@ class KeyManager {
|
|||
}
|
||||
final privateKey = base64.decode(await client.ssss.getCached(MEGOLM_KEY));
|
||||
final decryption = olm.PkDecryption();
|
||||
final info = await getRoomKeysInfo();
|
||||
String backupPubKey;
|
||||
try {
|
||||
backupPubKey = decryption.init_with_private_key(privateKey);
|
||||
} catch (_) {
|
||||
decryption.free();
|
||||
rethrow;
|
||||
}
|
||||
if (backupPubKey == null) {
|
||||
decryption.free();
|
||||
|
||||
if (backupPubKey == null || !info.containsKey('auth_data') || !(info['auth_data'] is Map) || info['auth_data']['public_key'] != backupPubKey) {
|
||||
|
||||
return;
|
||||
}
|
||||
// TODO: check if pubkey is valid
|
||||
|
@ -87,6 +97,9 @@ class KeyManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
decryption.free();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> loadSingleKey(String roomId, String sessionId) async {
|
||||
|
|
|
@ -27,6 +27,7 @@ const OLM_PRIVATE_KEY_LENGTH = 32; // TODO: fetch from dart-olm
|
|||
class SSSS {
|
||||
final Client client;
|
||||
final pendingShareRequests = <String, _ShareRequest>{};
|
||||
final _validators = <String, Future<bool> Function(String)>{};
|
||||
SSSS(this.client);
|
||||
|
||||
static _DerivedKeys deriveKeys(Uint8List key, String name) {
|
||||
|
@ -119,6 +120,10 @@ class SSSS {
|
|||
info.iterations, info.bits != null ? info.bits / 8 : 32));
|
||||
}
|
||||
|
||||
void setValidator(String type, Future<bool> Function(String) validator) {
|
||||
_validators[type] = validator;
|
||||
}
|
||||
|
||||
String get defaultKeyId {
|
||||
final keyData = client.accountData['m.secret_storage.default_key'];
|
||||
if (keyData == null || !(keyData.content['key'] is String)) {
|
||||
|
@ -312,11 +317,17 @@ class SSSS {
|
|||
print('[SSSS] Someone else replied?');
|
||||
return; // someone replied whom we didn't send the share request to
|
||||
}
|
||||
pendingShareRequests.remove(request.requestId);
|
||||
final secret = event.content['secret'];
|
||||
if (!(event.content['secret'] is String)) {
|
||||
print('[SSSS] Secret wasn\'t a string');
|
||||
return; // the secret wasn't a string....wut?
|
||||
}
|
||||
// let's validate if the secret is, well, valid
|
||||
if (_validators.containsKey(request.type) && !(await _validators[request.type](secret))) {
|
||||
print('[SSSS] The received secret was invalid');
|
||||
return; // didn't pass the validator
|
||||
}
|
||||
pendingShareRequests.remove(request.requestId);
|
||||
if (request.start.add(Duration(minutes: 15)).isBefore(DateTime.now())) {
|
||||
print('[SSSS] Request is too far in the past');
|
||||
return; // our request is more than 15min in the past...better not trust it anymore
|
||||
|
@ -326,7 +337,7 @@ class SSSS {
|
|||
final keyId = keyIdFromType(request.type);
|
||||
if (keyId != null) {
|
||||
await client.database.storeSSSSCache(
|
||||
client.id, request.type, keyId, event.content['secret']);
|
||||
client.id, request.type, keyId, secret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue