additional validation of received secrets

This commit is contained in:
Sorunome 2020-05-30 13:13:42 +02:00
parent a7bb8375dc
commit 41a08d4c28
No known key found for this signature in database
GPG key ID: B19471D07FC9BE9C
4 changed files with 86 additions and 41 deletions

View file

@ -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()}');

View file

@ -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 &&

View file

@ -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 {

View file

@ -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);
}
}
}