@@ -845,9 +845,17 @@ impl OlmMachine {
845
845
846
846
/// Decrypt and handle a to-device event.
847
847
///
848
- /// If decryption (or checking the sender device) fails, returns
848
+ /// If decryption (or checking the sender device) fails, returns an
849
849
/// `Err(DecryptToDeviceError::OlmError)`.
850
850
///
851
+ /// If we are in strict "exclude insecure devices" mode and the sender
852
+ /// device is not verified, and the decrypted event type is not on the
853
+ /// allow list, returns `Err(DecryptToDeviceError::UnverifiedSender)`
854
+ ///
855
+ /// (The allow list of types that are processed even if the sender is
856
+ /// unverified is: `m.room_key`, `m.room_key.withheld`,
857
+ /// `m.room_key_request`, `m.secret.request` and `m.key.verification.*`.)
858
+ ///
851
859
/// If the sender device is dehydrated, does no handling and immediately
852
860
/// returns `Err(DecryptToDeviceError::FromDehydratedDevice)`.
853
861
///
@@ -862,12 +870,17 @@ impl OlmMachine {
862
870
transaction : & mut StoreTransaction ,
863
871
event : & EncryptedToDeviceEvent ,
864
872
changes : & mut Changes ,
865
- _decryption_settings : & DecryptionSettings ,
873
+ decryption_settings : & DecryptionSettings ,
866
874
) -> Result < OlmDecryptionInfo , DecryptToDeviceError > {
867
875
// Decrypt the event
868
- let mut decrypted =
876
+ let decrypted =
869
877
transaction. account ( ) . await ?. decrypt_to_device_event ( & self . inner . store , event) . await ?;
870
878
879
+ let mut decrypted = self . check_to_device_is_from_verified_device_or_allowed_type (
880
+ decryption_settings,
881
+ decrypted,
882
+ ) ?;
883
+
871
884
// Return early if the sending device is decrypted
872
885
self . check_to_device_event_is_not_from_dehydrated_device ( & decrypted, & event. sender ) . await ?;
873
886
@@ -1324,7 +1337,10 @@ impl OlmMachine {
1324
1337
1325
1338
match event {
1326
1339
// These are handled here because we accept them either plaintext or
1327
- // encrypted
1340
+ // encrypted.
1341
+ //
1342
+ // Note: this list should match the allowed types in
1343
+ // check_to_device_is_from_verified_device_or_allowed_type
1328
1344
RoomKeyRequest ( e) => self . inner . key_request_machine . receive_incoming_key_request ( e) ,
1329
1345
SecretRequest ( e) => self . inner . key_request_machine . receive_incoming_secret_request ( e) ,
1330
1346
RoomKeyWithheld ( e) => self . add_withheld_info ( changes, e) ,
@@ -1426,8 +1442,14 @@ impl OlmMachine {
1426
1442
///
1427
1443
/// Return the same event, decrypted if possible.
1428
1444
///
1429
- /// If we can identify that this to-device event came from a dehydrated
1430
- /// device, this method does not process it, and returns `None`.
1445
+ /// If we are in strict "exclude insecure devices" mode and the sender
1446
+ /// device is not verified, and the decrypted event type is not on the
1447
+ /// allow list, or if this event comes from a dehydrated device, this method
1448
+ /// does not process it, and returns `None`.
1449
+ ///
1450
+ /// (The allow list of types that are processed even if the sender is
1451
+ /// unverified is: `m.room_key`, `m.room_key.withheld`,
1452
+ /// `m.room_key_request`, `m.secret.request` and `m.key.verification.*`.)
1431
1453
async fn receive_encrypted_to_device_event (
1432
1454
& self ,
1433
1455
transaction : & mut StoreTransaction ,
@@ -1456,6 +1478,12 @@ impl OlmMachine {
1456
1478
return Some ( ProcessedToDeviceEvent :: UnableToDecrypt ( raw_event) ) ;
1457
1479
}
1458
1480
Err ( DecryptToDeviceError :: FromDehydratedDevice ) => return None ,
1481
+ Err ( DecryptToDeviceError :: UnverifiedSender ( olm_decryption_info) ) => {
1482
+ return Some ( ProcessedToDeviceEvent :: UnverifiedSender {
1483
+ raw : olm_decryption_info. result . raw_event ,
1484
+ encryption_info : olm_decryption_info. result . encryption_info ,
1485
+ } )
1486
+ }
1459
1487
} ;
1460
1488
1461
1489
// New sessions modify the account so we need to save that
@@ -1493,6 +1521,66 @@ impl OlmMachine {
1493
1521
} )
1494
1522
}
1495
1523
1524
+ fn check_to_device_is_from_verified_device_or_allowed_type (
1525
+ & self ,
1526
+ decryption_settings : & DecryptionSettings ,
1527
+ decrypted : OlmDecryptionInfo ,
1528
+ ) -> Result < OlmDecryptionInfo , DecryptToDeviceError > {
1529
+ let event_type = decrypted. result . event . event_type ( ) ;
1530
+
1531
+ // If we're in "exclude insecure devices" mode, we prevent most
1532
+ // to-device events with unverified senders from being allowed
1533
+ // through here, but there are some exceptions:
1534
+ //
1535
+ // * m.room_key - we hold on to these until later, so if the sender becomes
1536
+ // verified later we can still use the key.
1537
+ //
1538
+ // * m.room_key_request, m.room_key.withheld, m.key.verification.*,
1539
+ // m.secret.request - these are allowed as plaintext events, so we also allow
1540
+ // them encrypted from insecure devices. Note: the list of allowed types here
1541
+ // should match with what is allowed in handle_to_device_event.
1542
+ match event_type {
1543
+ "m.room_key"
1544
+ | "m.room_key.withheld"
1545
+ | "m.room_key_request"
1546
+ | "m.secret.request"
1547
+ | "m.key.verification.key"
1548
+ | "m.key.verification.mac"
1549
+ | "m.key.verification.done"
1550
+ | "m.key.verification.ready"
1551
+ | "m.key.verification.start"
1552
+ | "m.key.verification.accept"
1553
+ | "m.key.verification.cancel"
1554
+ | "m.key.verification.request" => {
1555
+ // This is one of the exception types - we allow it even if the sender device is
1556
+ // not verified.
1557
+ Ok ( decrypted)
1558
+ }
1559
+ _ => {
1560
+ // This is not an exception type - check for "exclude insecure devices" mode,
1561
+ // and whether the sender is verified.
1562
+
1563
+ let exclude_unverified_devices = match decryption_settings
1564
+ . sender_device_trust_requirement
1565
+ {
1566
+ TrustRequirement :: Untrusted => false ,
1567
+ TrustRequirement :: CrossSignedOrLegacy | TrustRequirement :: CrossSigned => true ,
1568
+ } ;
1569
+
1570
+ if exclude_unverified_devices
1571
+ && sending_device_is_unverified ( & decrypted. result . encryption_info )
1572
+ {
1573
+ // Refuse to decrypt - the sender is unverified
1574
+ Err ( DecryptToDeviceError :: UnverifiedSender ( Box :: new ( decrypted) ) )
1575
+ } else {
1576
+ // Either we're not excluding insecure devices, or the sender is verified, so
1577
+ // allow decryption to continue.
1578
+ Ok ( decrypted)
1579
+ }
1580
+ }
1581
+ }
1582
+ }
1583
+
1496
1584
/// Return an error if the supplied to-device event was sent from a
1497
1585
/// dehydrated device.
1498
1586
async fn check_to_device_event_is_not_from_dehydrated_device (
@@ -1594,6 +1682,15 @@ impl OlmMachine {
1594
1682
/// If any of the to-device events in the supplied changes were sent from
1595
1683
/// dehydrated devices, these are not processed, and are omitted from
1596
1684
/// the returned list, as per MSC3814.
1685
+ ///
1686
+ /// If we are in strict "exclude insecure devices" mode and the sender
1687
+ /// device of any event is not verified, and the decrypted event type is not
1688
+ /// on the allow list, these events are not processed and are omitted from
1689
+ /// the returned list.
1690
+ ///
1691
+ /// (The allow list of types that are processed even if the sender is
1692
+ /// unverified is: `m.room_key`, `m.room_key.withheld`,
1693
+ /// `m.room_key_request`, `m.secret.request` and `m.key.verification.*`.)
1597
1694
pub ( crate ) async fn preprocess_sync_changes (
1598
1695
& self ,
1599
1696
transaction : & mut StoreTransaction ,
@@ -2842,6 +2939,28 @@ impl OlmMachine {
2842
2939
}
2843
2940
}
2844
2941
2942
+ fn sending_device_is_unverified ( encryption_info : & EncryptionInfo ) -> bool {
2943
+ if let VerificationState :: Unverified ( level) = & encryption_info. verification_state {
2944
+ // Sender is not fully verified
2945
+ match level {
2946
+ VerificationLevel :: UnverifiedIdentity => {
2947
+ // The user's identity is only pinned: fine
2948
+ false
2949
+ }
2950
+ VerificationLevel :: VerificationViolation
2951
+ | VerificationLevel :: UnsignedDevice
2952
+ | VerificationLevel :: None ( _)
2953
+ | VerificationLevel :: MismatchedSender => {
2954
+ // The device is not verified or the user is in verification violation: not fine
2955
+ true
2956
+ }
2957
+ }
2958
+ } else {
2959
+ // Verified sender: fine
2960
+ false
2961
+ }
2962
+ }
2963
+
2845
2964
fn sender_data_to_verification_state (
2846
2965
sender_data : SenderData ,
2847
2966
session_has_been_imported : bool ,
@@ -2960,14 +3079,27 @@ fn megolm_error_to_utd_info(
2960
3079
Ok ( UnableToDecryptInfo { session_id, reason } )
2961
3080
}
2962
3081
2963
- /// An error that can occur during [`OlmMachine::decrypt_to_device_event`] -
2964
- /// either because decryption failed, or because the sender device was a
2965
- /// dehydrated device, which should never send any to-device messages.
3082
+ /// An error that can occur during [`OlmMachine::decrypt_to_device_event`]:
3083
+ ///
3084
+ /// * because decryption failed, or
3085
+ ///
3086
+ /// * because the sender device was not verified when we are in strict "exclude
3087
+ /// insecure devices" mode, or
3088
+ ///
3089
+ /// * because the sender device was a dehydrated device, which should never send
3090
+ /// any to-device messages.
2966
3091
#[ derive( Debug , thiserror:: Error ) ]
2967
3092
pub ( crate ) enum DecryptToDeviceError {
2968
3093
#[ error( "An Olm error occurred meaning we failed to decrypt the event" ) ]
2969
3094
OlmError ( #[ from] OlmError ) ,
2970
3095
3096
+ #[ error(
3097
+ "We were able to decrypt the event, but the sender device was not \
3098
+ verified, and we have 'exclude insecure devices' enabled, so we \
3099
+ choose not to use this event."
3100
+ ) ]
3101
+ UnverifiedSender ( Box < OlmDecryptionInfo > ) ,
3102
+
2971
3103
#[ error( "The event was sent from a dehydrated device" ) ]
2972
3104
FromDehydratedDevice ,
2973
3105
}
@@ -2988,6 +3120,9 @@ impl From<DecryptToDeviceError> for OlmError {
2988
3120
DecryptToDeviceError :: FromDehydratedDevice => {
2989
3121
panic ! ( "Expected an OlmError but found FromDehydratedDevice" )
2990
3122
}
3123
+ DecryptToDeviceError :: UnverifiedSender ( _) => {
3124
+ panic ! ( "Expected and OlmError but found UnverifiedSender" )
3125
+ }
2991
3126
}
2992
3127
}
2993
3128
}
0 commit comments