From aaaf63a0b821dad7ceea1841f0b07e173c37df98 Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Mon, 21 Nov 2022 10:12:12 +0100 Subject: [PATCH 1/8] feat: Check if a key is verified by any master key To check if a device is cross signed by any master key can be useful to know which device can give us the bootstrap keys on login. --- lib/src/utils/device_keys_list.dart | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/src/utils/device_keys_list.dart b/lib/src/utils/device_keys_list.dart index a18c90be..77a494f8 100644 --- a/lib/src/utils/device_keys_list.dart +++ b/lib/src/utils/device_keys_list.dart @@ -216,10 +216,14 @@ abstract class SignableKey extends MatrixSignableKey { return valid; } - bool hasValidSignatureChain( - {bool verifiedOnly = true, - Set? visited, - Set? onlyValidateUserIds}) { + bool hasValidSignatureChain({ + bool verifiedOnly = true, + Set? visited, + Set? onlyValidateUserIds, + + /// Only check if this key is verified by any Master key. + bool verifiedByAnyMasterKey = false, + }) { if (!client.encryptionEnabled) { return false; } @@ -300,8 +304,8 @@ abstract class SignableKey extends MatrixSignableKey { if ((verifiedOnly && key.directVerified) || (key is CrossSigningKey && key.usage.contains('master') && - key.directVerified && - key.userId == client.userID)) { + (verifiedByAnyMasterKey || + (key.directVerified && key.userId == client.userID)))) { return true; // we verified this key and it is valid...all checks out! } // or else we just recurse into that key and chack if it works out From ffb37e834f5e7f7e946fd5e1a6e5a1166324321c Mon Sep 17 00:00:00 2001 From: Reza Date: Tue, 22 Nov 2022 17:22:04 +0100 Subject: [PATCH 2/8] feat: check if the key is verified by any master key --- lib/src/utils/device_keys_list.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/utils/device_keys_list.dart b/lib/src/utils/device_keys_list.dart index 77a494f8..a5ead5b8 100644 --- a/lib/src/utils/device_keys_list.dart +++ b/lib/src/utils/device_keys_list.dart @@ -312,7 +312,8 @@ abstract class SignableKey extends MatrixSignableKey { final haveChain = key.hasValidSignatureChain( verifiedOnly: verifiedOnly, visited: visited_, - onlyValidateUserIds: onlyValidateUserIds); + onlyValidateUserIds: onlyValidateUserIds, + verifiedByAnyMasterKey: verifiedByAnyMasterKey); if (haveChain) { return true; } From 44f862b9668129631ac3f7d97c8587acad9c6074 Mon Sep 17 00:00:00 2001 From: Reza Date: Wed, 23 Nov 2022 13:43:57 +0100 Subject: [PATCH 3/8] feat: start verification with the verified device --- lib/encryption/utils/key_verification.dart | 37 ++++++++++++++++------ lib/src/utils/device_keys_list.dart | 7 ++-- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/lib/encryption/utils/key_verification.dart b/lib/encryption/utils/key_verification.dart index c0cdcfc1..ea8ca442 100644 --- a/lib/encryption/utils/key_verification.dart +++ b/lib/encryption/utils/key_verification.dart @@ -159,17 +159,21 @@ class KeyVerification { return methods; } - Future sendStart() async { - await send(EventTypes.KeyVerificationRequest, { - 'methods': knownVerificationMethods, - if (room == null) 'timestamp': DateTime.now().millisecondsSinceEpoch, - }); + Future sendStart({List? verifiedDevices}) async { + await send( + EventTypes.KeyVerificationRequest, + { + 'methods': knownVerificationMethods, + if (room == null) 'timestamp': DateTime.now().millisecondsSinceEpoch, + }, + verifiedDevices: verifiedDevices, + ); startedVerification = true; setState(KeyVerificationState.waitingAccept); lastActivity = DateTime.now(); } - Future start() async { + Future start({List? verifiedDevices}) async { if (room == null) { transactionId = client.generateUniqueTransactionId(); } @@ -179,7 +183,9 @@ class KeyVerification { setState(KeyVerificationState.askSSSS); _nextAction = 'request'; } else { - await sendStart(); + await sendStart( + verifiedDevices: verifiedDevices, + ); } } @@ -604,7 +610,8 @@ class KeyVerification { } } - Future send(String type, Map payload) async { + Future send(String type, Map payload, + {List? verifiedDevices}) async { makePayload(payload); Logs().i('[Key Verification] Sending type $type: $payload'); if (room != null) { @@ -628,7 +635,19 @@ class KeyVerification { EventTypes.KeyVerificationRequest, EventTypes.KeyVerificationCancel, }.contains(type)) { - await client.sendToDevicesOfUserIds({userId}, type, payload); + if (verifiedDevices == null || verifiedDevices.isEmpty) { + await client.sendToDevicesOfUserIds({userId}, type, payload); + } else { + final deviceKeys = client.userDeviceKeys[userId]?.deviceKeys; + deviceKeys?.removeWhere((key, value) => + verifiedDevices.map((e) => e.deviceId).toList().contains(key) == + false); + await client.sendToDeviceEncrypted( + deviceKeys!.values.toList(), + type, + payload, + ); + } } else { Logs().e( '[Key Verification] Tried to broadcast and un-broadcastable type: $type'); diff --git a/lib/src/utils/device_keys_list.dart b/lib/src/utils/device_keys_list.dart index a5ead5b8..4289eb81 100644 --- a/lib/src/utils/device_keys_list.dart +++ b/lib/src/utils/device_keys_list.dart @@ -70,6 +70,7 @@ class DeviceKeysList { Future startVerification({ bool? newDirectChatEnableEncryption, List? newDirectChatInitialState, + List? verifiedDevice, }) async { final encryption = client.encryption; if (encryption == null) { @@ -93,10 +94,12 @@ class DeviceKeysList { // verification request that'll happen automatically once we know the transaction id return request; } else { - // broadcast self-verification + // start verification with verified devices final request = KeyVerification( encryption: encryption, userId: userId, deviceId: '*'); - await request.start(); + await request.start( + verifiedDevices: verifiedDevice, + ); encryption.keyVerificationManager.addRequest(request); return request; } From 10cf979877cffe5bfde5f33de2bd51d0c5569d63 Mon Sep 17 00:00:00 2001 From: Reza Date: Wed, 23 Nov 2022 19:28:08 +0100 Subject: [PATCH 4/8] fix: minor stuff --- lib/encryption/utils/key_verification.dart | 7 ++++--- lib/src/utils/device_keys_list.dart | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/encryption/utils/key_verification.dart b/lib/encryption/utils/key_verification.dart index ea8ca442..4d85dcc6 100644 --- a/lib/encryption/utils/key_verification.dart +++ b/lib/encryption/utils/key_verification.dart @@ -639,9 +639,10 @@ class KeyVerification { await client.sendToDevicesOfUserIds({userId}, type, payload); } else { final deviceKeys = client.userDeviceKeys[userId]?.deviceKeys; - deviceKeys?.removeWhere((key, value) => - verifiedDevices.map((e) => e.deviceId).toList().contains(key) == - false); + deviceKeys?.removeWhere((key, _) => !verifiedDevices + .map((device) => device.deviceId) + .toList() + .contains(key)); await client.sendToDeviceEncrypted( deviceKeys!.values.toList(), type, diff --git a/lib/src/utils/device_keys_list.dart b/lib/src/utils/device_keys_list.dart index 4289eb81..f26cc4e1 100644 --- a/lib/src/utils/device_keys_list.dart +++ b/lib/src/utils/device_keys_list.dart @@ -70,7 +70,7 @@ class DeviceKeysList { Future startVerification({ bool? newDirectChatEnableEncryption, List? newDirectChatInitialState, - List? verifiedDevice, + List? verifiedDevices, }) async { final encryption = client.encryption; if (encryption == null) { @@ -98,7 +98,7 @@ class DeviceKeysList { final request = KeyVerification( encryption: encryption, userId: userId, deviceId: '*'); await request.start( - verifiedDevices: verifiedDevice, + verifiedDevices: verifiedDevices, ); encryption.keyVerificationManager.addRequest(request); return request; From 8f37466295398c87f9a84c0c399c9a2e05f2c630 Mon Sep 17 00:00:00 2001 From: Reza Date: Thu, 24 Nov 2022 09:33:36 +0100 Subject: [PATCH 5/8] fix: minor stuff --- lib/encryption/utils/key_verification.dart | 12 +++++++----- lib/src/utils/device_keys_list.dart | 8 ++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/encryption/utils/key_verification.dart b/lib/encryption/utils/key_verification.dart index 4d85dcc6..1a125524 100644 --- a/lib/encryption/utils/key_verification.dart +++ b/lib/encryption/utils/key_verification.dart @@ -643,11 +643,13 @@ class KeyVerification { .map((device) => device.deviceId) .toList() .contains(key)); - await client.sendToDeviceEncrypted( - deviceKeys!.values.toList(), - type, - payload, - ); + if (deviceKeys != null && deviceKeys.isNotEmpty) { + await client.sendToDeviceEncrypted( + deviceKeys.values.toList(), + type, + payload, + ); + } } } else { Logs().e( diff --git a/lib/src/utils/device_keys_list.dart b/lib/src/utils/device_keys_list.dart index f26cc4e1..1e0ec099 100644 --- a/lib/src/utils/device_keys_list.dart +++ b/lib/src/utils/device_keys_list.dart @@ -225,7 +225,7 @@ abstract class SignableKey extends MatrixSignableKey { Set? onlyValidateUserIds, /// Only check if this key is verified by any Master key. - bool verifiedByAnyMasterKey = false, + bool verifiedByTheirMasterKey = false, }) { if (!client.encryptionEnabled) { return false; @@ -307,16 +307,16 @@ abstract class SignableKey extends MatrixSignableKey { if ((verifiedOnly && key.directVerified) || (key is CrossSigningKey && key.usage.contains('master') && - (verifiedByAnyMasterKey || + (verifiedByTheirMasterKey || (key.directVerified && key.userId == client.userID)))) { return true; // we verified this key and it is valid...all checks out! } - // or else we just recurse into that key and chack if it works out + // or else we just recurse into that key and check if it works out final haveChain = key.hasValidSignatureChain( verifiedOnly: verifiedOnly, visited: visited_, onlyValidateUserIds: onlyValidateUserIds, - verifiedByAnyMasterKey: verifiedByAnyMasterKey); + verifiedByTheirMasterKey: verifiedByTheirMasterKey); if (haveChain) { return true; } From dd4d0696b32a7e15bedc88258d34725d163f7de3 Mon Sep 17 00:00:00 2001 From: Reza Date: Thu, 24 Nov 2022 10:19:52 +0100 Subject: [PATCH 6/8] fix: do not pass the verified device list --- lib/encryption/utils/key_verification.dart | 41 ++++++++++------------ lib/src/utils/device_keys_list.dart | 5 +-- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/lib/encryption/utils/key_verification.dart b/lib/encryption/utils/key_verification.dart index 1a125524..9aba6999 100644 --- a/lib/encryption/utils/key_verification.dart +++ b/lib/encryption/utils/key_verification.dart @@ -159,21 +159,20 @@ class KeyVerification { return methods; } - Future sendStart({List? verifiedDevices}) async { + Future sendStart() async { await send( EventTypes.KeyVerificationRequest, { 'methods': knownVerificationMethods, if (room == null) 'timestamp': DateTime.now().millisecondsSinceEpoch, }, - verifiedDevices: verifiedDevices, ); startedVerification = true; setState(KeyVerificationState.waitingAccept); lastActivity = DateTime.now(); } - Future start({List? verifiedDevices}) async { + Future start() async { if (room == null) { transactionId = client.generateUniqueTransactionId(); } @@ -183,9 +182,7 @@ class KeyVerification { setState(KeyVerificationState.askSSSS); _nextAction = 'request'; } else { - await sendStart( - verifiedDevices: verifiedDevices, - ); + await sendStart(); } } @@ -610,8 +607,11 @@ class KeyVerification { } } - Future send(String type, Map payload, - {List? verifiedDevices}) async { + Future send( + String type, + Map payload, + ) async { + Logs().e('payload is ', payload); makePayload(payload); Logs().i('[Key Verification] Sending type $type: $payload'); if (room != null) { @@ -635,21 +635,16 @@ class KeyVerification { EventTypes.KeyVerificationRequest, EventTypes.KeyVerificationCancel, }.contains(type)) { - if (verifiedDevices == null || verifiedDevices.isEmpty) { - await client.sendToDevicesOfUserIds({userId}, type, payload); - } else { - final deviceKeys = client.userDeviceKeys[userId]?.deviceKeys; - deviceKeys?.removeWhere((key, _) => !verifiedDevices - .map((device) => device.deviceId) - .toList() - .contains(key)); - if (deviceKeys != null && deviceKeys.isNotEmpty) { - await client.sendToDeviceEncrypted( - deviceKeys.values.toList(), - type, - payload, - ); - } + final deviceKeys = client.userDeviceKeys[userId]?.deviceKeys; + deviceKeys?.removeWhere((_, value) => + value.hasValidSignatureChain(verifiedByTheirMasterKey: true) == + false); + if (deviceKeys != null) { + await client.sendToDeviceEncrypted( + deviceKeys.values.toList(), + type, + payload, + ); } } else { Logs().e( diff --git a/lib/src/utils/device_keys_list.dart b/lib/src/utils/device_keys_list.dart index 1e0ec099..6362db30 100644 --- a/lib/src/utils/device_keys_list.dart +++ b/lib/src/utils/device_keys_list.dart @@ -70,7 +70,6 @@ class DeviceKeysList { Future startVerification({ bool? newDirectChatEnableEncryption, List? newDirectChatInitialState, - List? verifiedDevices, }) async { final encryption = client.encryption; if (encryption == null) { @@ -97,9 +96,7 @@ class DeviceKeysList { // start verification with verified devices final request = KeyVerification( encryption: encryption, userId: userId, deviceId: '*'); - await request.start( - verifiedDevices: verifiedDevices, - ); + await request.start(); encryption.keyVerificationManager.addRequest(request); return request; } From f969a733f1a2e9703c4cfa124f4d37552780fd5b Mon Sep 17 00:00:00 2001 From: Reza Date: Thu, 24 Nov 2022 10:48:17 +0100 Subject: [PATCH 7/8] fix: minor stuff --- lib/encryption/utils/key_verification.dart | 3 +-- lib/src/utils/device_keys_list.dart | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/encryption/utils/key_verification.dart b/lib/encryption/utils/key_verification.dart index 9aba6999..91548da3 100644 --- a/lib/encryption/utils/key_verification.dart +++ b/lib/encryption/utils/key_verification.dart @@ -637,8 +637,7 @@ class KeyVerification { }.contains(type)) { final deviceKeys = client.userDeviceKeys[userId]?.deviceKeys; deviceKeys?.removeWhere((_, value) => - value.hasValidSignatureChain(verifiedByTheirMasterKey: true) == - false); + !value.hasValidSignatureChain(verifiedByTheirMasterKey: true)); if (deviceKeys != null) { await client.sendToDeviceEncrypted( deviceKeys.values.toList(), diff --git a/lib/src/utils/device_keys_list.dart b/lib/src/utils/device_keys_list.dart index 6362db30..fb66e91e 100644 --- a/lib/src/utils/device_keys_list.dart +++ b/lib/src/utils/device_keys_list.dart @@ -221,7 +221,7 @@ abstract class SignableKey extends MatrixSignableKey { Set? visited, Set? onlyValidateUserIds, - /// Only check if this key is verified by any Master key. + /// Only check if this key is verified by their Master key. bool verifiedByTheirMasterKey = false, }) { if (!client.encryptionEnabled) { From 7da56ee212d77f89c625a34c1813a4b4998c765f Mon Sep 17 00:00:00 2001 From: Reza Date: Thu, 24 Nov 2022 11:00:10 +0100 Subject: [PATCH 8/8] fix: minor stuff --- lib/encryption/utils/key_verification.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/encryption/utils/key_verification.dart b/lib/encryption/utils/key_verification.dart index 91548da3..489638e3 100644 --- a/lib/encryption/utils/key_verification.dart +++ b/lib/encryption/utils/key_verification.dart @@ -611,7 +611,6 @@ class KeyVerification { String type, Map payload, ) async { - Logs().e('payload is ', payload); makePayload(payload); Logs().i('[Key Verification] Sending type $type: $payload'); if (room != null) { @@ -635,12 +634,13 @@ class KeyVerification { EventTypes.KeyVerificationRequest, EventTypes.KeyVerificationCancel, }.contains(type)) { - final deviceKeys = client.userDeviceKeys[userId]?.deviceKeys; - deviceKeys?.removeWhere((_, value) => - !value.hasValidSignatureChain(verifiedByTheirMasterKey: true)); + final deviceKeys = client.userDeviceKeys[userId]?.deviceKeys.values + .where((deviceKey) => deviceKey.hasValidSignatureChain( + verifiedByTheirMasterKey: true)); + if (deviceKeys != null) { await client.sendToDeviceEncrypted( - deviceKeys.values.toList(), + deviceKeys.toList(), type, payload, );