This commit is contained in:
Sorunome 2020-05-22 13:18:45 +02:00
parent 29721f00a8
commit c9a0c5302a
No known key found for this signature in database
GPG Key ID: B19471D07FC9BE9C
5 changed files with 91 additions and 48 deletions

View File

@ -1664,7 +1664,8 @@ class Client {
if (entry.isValid) {
// is this a new key or the same one as an old one?
// better store an update - the signatures might have changed!
if (!oldKeys.containsKey(deviceId) || oldKeys[deviceId].ed25519Key == entry.ed25519Key) {
if (!oldKeys.containsKey(deviceId) ||
oldKeys[deviceId].ed25519Key == entry.ed25519Key) {
if (oldKeys.containsKey(deviceId)) {
// be sure to save the verified status
entry.setDirectVerified(oldKeys[deviceId].directVerified);
@ -1681,7 +1682,8 @@ class Client {
// This shouldn't ever happen. The same device ID has gotten
// a new public key. So we ignore the update. TODO: ask krille
// if we should instead use the new key with unknown verified / blocked status
_userDeviceKeys[userId].deviceKeys[deviceId] = oldKeys[deviceId];
_userDeviceKeys[userId].deviceKeys[deviceId] =
oldKeys[deviceId];
}
if (database != null) {
dbActions.add(() => database.storeUserDeviceKey(
@ -1713,24 +1715,33 @@ class Client {
}
}
// next we parse and persist the cross signing keys
for (final keyType in ['master_keys', 'self_signing_keys', 'user_signing_keys']) {
for (final keyType in [
'master_keys',
'self_signing_keys',
'user_signing_keys'
]) {
if (!(response[keyType] is Map)) {
continue;
}
for (final rawDeviceKeyListEntry in response[keyType].entries) {
final String userId = rawDeviceKeyListEntry.key;
final oldKeys = Map<String, CrossSigningKey>.from(_userDeviceKeys[userId].crossSigningKeys);
final oldKeys = Map<String, CrossSigningKey>.from(
_userDeviceKeys[userId].crossSigningKeys);
_userDeviceKeys[userId].crossSigningKeys = {};
// add the types we arne't handling atm back
for (final oldEntry in oldKeys.entries) {
if (!oldEntry.value.usage.contains(keyType.substring(0, keyType.length - '_keys'.length))) {
_userDeviceKeys[userId].crossSigningKeys[oldEntry.key] = oldEntry.value;
if (!oldEntry.value.usage.contains(
keyType.substring(0, keyType.length - '_keys'.length))) {
_userDeviceKeys[userId].crossSigningKeys[oldEntry.key] =
oldEntry.value;
}
}
final entry = CrossSigningKey.fromJson(rawDeviceKeyListEntry.value, this);
final entry =
CrossSigningKey.fromJson(rawDeviceKeyListEntry.value, this);
if (entry.isValid) {
final publicKey = entry.publicKey;
if (!oldKeys.containsKey(publicKey) || oldKeys[publicKey].ed25519Key == entry.ed25519Key) {
if (!oldKeys.containsKey(publicKey) ||
oldKeys[publicKey].ed25519Key == entry.ed25519Key) {
if (oldKeys.containsKey(publicKey)) {
// be sure to save the verification status
entry.setDirectVerified(oldKeys[publicKey].directVerified);
@ -1742,34 +1753,37 @@ class Client {
// This shouldn't ever happen. The same device ID has gotten
// a new public key. So we ignore the update. TODO: ask krille
// if we should instead use the new key with unknown verified / blocked status
_userDeviceKeys[userId].crossSigningKeys[publicKey] = oldKeys[publicKey];
_userDeviceKeys[userId].crossSigningKeys[publicKey] =
oldKeys[publicKey];
}
if (database != null) {
dbActions.add(() => database.storeUserCrossSigningKey(
id,
userId,
publicKey,
json.encode(entry.toJson()),
entry.directVerified,
entry.blocked,
));
id,
userId,
publicKey,
json.encode(entry.toJson()),
entry.directVerified,
entry.blocked,
));
}
}
// delete old/unused entries
if (database != null) {
for (final oldCrossSigningKeyEntry in oldKeys.entries) {
final publicKey = oldCrossSigningKeyEntry.key;
if (!_userDeviceKeys[userId].crossSigningKeys.containsKey(publicKey)) {
if (!_userDeviceKeys[userId]
.crossSigningKeys
.containsKey(publicKey)) {
// we need to remove an old key
dbActions.add(
() => database.removeUserCrossSigningKey(id, userId, publicKey));
dbActions.add(() => database.removeUserCrossSigningKey(
id, userId, publicKey));
}
}
}
_userDeviceKeys[userId].outdated = false;
if (database != null) {
dbActions
.add(() => database.storeUserDeviceKeysInfo(id, userId, false));
dbActions.add(
() => database.storeUserDeviceKeysInfo(id, userId, false));
}
}
}

View File

@ -47,7 +47,8 @@ class Database extends _$Database {
await m.createTable(userCrossSigningKeys);
await m.createIndex(userCrossSigningKeysIndex);
// mark all keys as outdated so that the cross signing keys will be fetched
await m.issueCustomQuery('UPDATE user_device_keys SET outdated = true');
await m.issueCustomQuery(
'UPDATE user_device_keys SET outdated = true');
from++;
}
},
@ -59,7 +60,8 @@ class Database extends _$Database {
return res.first;
}
Future<Map<String, sdk.DeviceKeysList>> getUserDeviceKeys(sdk.Client client) async {
Future<Map<String, sdk.DeviceKeysList>> getUserDeviceKeys(
sdk.Client client) async {
final deviceKeys = await getAllUserDeviceKeys(client.id).get();
if (deviceKeys.isEmpty) {
return {};
@ -68,10 +70,11 @@ class Database extends _$Database {
final crossSigningKeys = await getAllUserCrossSigningKeys(client.id).get();
final res = <String, sdk.DeviceKeysList>{};
for (final entry in deviceKeys) {
res[entry.userId] = sdk.DeviceKeysList.fromDb(entry,
deviceKeysKeys.where((k) => k.userId == entry.userId).toList(),
crossSigningKeys.where((k) => k.userId == entry.userId).toList(),
client);
res[entry.userId] = sdk.DeviceKeysList.fromDb(
entry,
deviceKeysKeys.where((k) => k.userId == entry.userId).toList(),
crossSigningKeys.where((k) => k.userId == entry.userId).toList(),
client);
}
return res;
}

View File

@ -3,7 +3,8 @@ import 'package:canonical_json/canonical_json.dart';
import 'package:olm/olm.dart' as olm;
import '../client.dart';
import '../database/database.dart' show DbUserDeviceKey, DbUserDeviceKeysKey, DbUserCrossSigningKey;
import '../database/database.dart'
show DbUserDeviceKey, DbUserDeviceKeysKey, DbUserCrossSigningKey;
import '../event.dart';
import 'key_verification.dart';
@ -14,7 +15,11 @@ class DeviceKeysList {
Map<String, DeviceKeys> deviceKeys = {};
Map<String, CrossSigningKey> crossSigningKeys = {};
DeviceKeysList.fromDb(DbUserDeviceKey dbEntry, List<DbUserDeviceKeysKey> childEntries, List<DbUserCrossSigningKey> crossSigningEntries, Client cl) {
DeviceKeysList.fromDb(
DbUserDeviceKey dbEntry,
List<DbUserDeviceKeysKey> childEntries,
List<DbUserCrossSigningKey> crossSigningEntries,
Client cl) {
client = cl;
userId = dbEntry.userId;
outdated = dbEntry.outdated;
@ -93,7 +98,9 @@ abstract class _SignedKey {
try {
return hasValidSignatureChain();
} catch (err, stacktrace) {
print('[Cross Signing] Error during trying to determine signature chain: ' + err.toString());
print(
'[Cross Signing] Error during trying to determine signature chain: ' +
err.toString());
print(stacktrace);
return false;
}
@ -134,7 +141,8 @@ abstract class _SignedKey {
visited.add(setKey);
for (final signatureEntries in signatures.entries) {
final otherUserId = signatureEntries.key;
if (!(signatureEntries.value is Map) || !client.userDeviceKeys.containsKey(otherUserId)) {
if (!(signatureEntries.value is Map) ||
!client.userDeviceKeys.containsKey(otherUserId)) {
continue;
}
for (final signatureEntry in signatureEntries.value.entries) {
@ -147,7 +155,8 @@ abstract class _SignedKey {
_SignedKey key;
if (client.userDeviceKeys[otherUserId].deviceKeys.containsKey(keyId)) {
key = client.userDeviceKeys[otherUserId].deviceKeys[keyId];
} else if (client.userDeviceKeys[otherUserId].crossSigningKeys.containsKey(keyId)) {
} else if (client.userDeviceKeys[otherUserId].crossSigningKeys
.containsKey(keyId)) {
key = client.userDeviceKeys[otherUserId].crossSigningKeys[keyId];
} else {
continue;
@ -157,7 +166,9 @@ abstract class _SignedKey {
}
var haveValidSignature = false;
var gotSignatureFromCache = false;
if (validSignatures != null && validSignatures.containsKey(otherUserId) && validSignatures[otherUserId].containsKey(fullKeyId)) {
if (validSignatures != null &&
validSignatures.containsKey(otherUserId) &&
validSignatures[otherUserId].containsKey(fullKeyId)) {
if (validSignatures[otherUserId][fullKeyId] == true) {
haveValidSignature = true;
gotSignatureFromCache = true;
@ -209,16 +220,19 @@ class CrossSigningKey extends _SignedKey {
String get publicKey => identifier;
List<String> usage;
bool get isValid => userId != null && publicKey != null && keys != null && ed25519Key != null;
bool get isValid =>
userId != null && publicKey != null && keys != null && ed25519Key != null;
Future<void> setVerified(bool newVerified) {
_verified = newVerified;
return client.database?.setVerifiedUserCrossSigningKey(newVerified, client.id, userId, publicKey);
return client.database?.setVerifiedUserCrossSigningKey(
newVerified, client.id, userId, publicKey);
}
Future<void> setBlocked(bool newBlocked) {
blocked = newBlocked;
return client.database?.setBlockedUserCrossSigningKey(newBlocked, client.id, userId, publicKey);
return client.database?.setBlockedUserCrossSigningKey(
newBlocked, client.id, userId, publicKey);
}
CrossSigningKey.fromDb(DbUserCrossSigningKey dbEntry, Client cl) {
@ -229,7 +243,9 @@ class CrossSigningKey extends _SignedKey {
identifier = dbEntry.publicKey;
usage = json['usage'].cast<String>();
keys = json['keys'] != null ? Map<String, String>.from(json['keys']) : null;
signatures = json['signatures'] != null ? Map<String, dynamic>.from(json['signatures']) : null;
signatures = json['signatures'] != null
? Map<String, dynamic>.from(json['signatures'])
: null;
_verified = dbEntry.verified;
blocked = dbEntry.blocked;
}

View File

@ -291,7 +291,8 @@ class KeyVerification {
return [];
}
Future<void> verifyKeys(Map<String, String> keys, Future<bool> Function(String, dynamic) verifier) async {
Future<void> verifyKeys(Map<String, String> keys,
Future<bool> Function(String, dynamic) verifier) async {
final verifiedDevices = <String>[];
if (!client.userDeviceKeys.containsKey(userId)) {
@ -310,9 +311,11 @@ class KeyVerification {
return;
}
verifiedDevices.add(verifyDeviceId);
} else if (client.userDeviceKeys[userId].crossSigningKeys.containsKey(verifyDeviceId)) {
} else if (client.userDeviceKeys[userId].crossSigningKeys
.containsKey(verifyDeviceId)) {
// this is a cross signing key!
if (!(await verifier(keyInfo, client.userDeviceKeys[userId].crossSigningKeys[verifyDeviceId]))) {
if (!(await verifier(keyInfo,
client.userDeviceKeys[userId].crossSigningKeys[verifyDeviceId]))) {
await cancel('m.key_mismatch');
return;
}
@ -321,10 +324,14 @@ class KeyVerification {
}
// okay, we reached this far, so all the devices are verified!
for (final verifyDeviceId in verifiedDevices) {
if (client.userDeviceKeys[userId].deviceKeys.containsKey(verifyDeviceId)) {
await client.userDeviceKeys[userId].deviceKeys[verifyDeviceId].setVerified(true);
} else if (client.userDeviceKeys[userId].crossSigningKeys.containsKey(verifyDeviceId)) {
await client.userDeviceKeys[userId].crossSigningKeys[verifyDeviceId].setVerified(true);
if (client.userDeviceKeys[userId].deviceKeys
.containsKey(verifyDeviceId)) {
await client.userDeviceKeys[userId].deviceKeys[verifyDeviceId]
.setVerified(true);
} else if (client.userDeviceKeys[userId].crossSigningKeys
.containsKey(verifyDeviceId)) {
await client.userDeviceKeys[userId].crossSigningKeys[verifyDeviceId]
.setVerified(true);
// TODO: sign the other persons master key
}
}
@ -708,9 +715,13 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
}
await request.verifyKeys(mac, (String mac, dynamic device) async {
if (device is DeviceKeys) {
return mac == _calculateMac(device.ed25519Key, baseInfo + 'ed25519:' + device.deviceId);
return mac ==
_calculateMac(
device.ed25519Key, baseInfo + 'ed25519:' + device.deviceId);
} else if (device is CrossSigningKey) {
return mac == _calculateMac(device.ed25519Key, baseInfo + 'ed25519:' + device.publicKey);
return mac ==
_calculateMac(
device.ed25519Key, baseInfo + 'ed25519:' + device.publicKey);
}
return false;
});

View File

@ -65,8 +65,7 @@ void main() {
final key = DeviceKeys.fromJson(rawJson, null);
rawJson.remove('verified');
rawJson.remove('blocked');
expect(json.encode(key.toJson()),
json.encode(rawJson));
expect(json.encode(key.toJson()), json.encode(rawJson));
expect(key.verified, false);
expect(key.blocked, true);
expect(json.encode(DeviceKeysList.fromJson(rawListJson, null).toJson()),