-
Notifications
You must be signed in to change notification settings - Fork 314
Refuse to decrypt to-device messages from unverified devices (when in exclude insecure mode) #5319
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…o_device_event This will be used in the next commit, but it was very noisy, so I separated it out into this commit to make the next one easier to read.
… dehydrated devices
…ypted_to_device_test_helper This will allow us to re-use it in more tests.
…per in 2 more tests
…ypted_to_device_test_helper To allow passing in different values in future tests.
e273eba
to
6c47df0
Compare
Codecov ReportAttention: Patch coverage is
✅ All tests successful. No failed tests found. Additional details and impacted files@@ Coverage Diff @@
## main #5319 +/- ##
==========================================
+ Coverage 88.74% 88.75% +0.01%
==========================================
Files 332 332
Lines 90030 90141 +111
Branches 90030 90141 +111
==========================================
+ Hits 79895 80004 +109
- Misses 6316 6317 +1
- Partials 3819 3820 +1 ☔ View full report in Codecov by Sentry. |
6c47df0
to
a3065e2
Compare
…vices (when in exclude insecure mode)
a3065e2
to
b899348
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some comments, the biggest discussion point is if we should return these events as UTDs or as this new separate variant.
self.handle_decrypted_to_device_event(transaction.cache(), &mut decrypted, changes) | ||
.await?; | ||
// Return early if the sending device is decrypted | ||
self.check_to_device_event_is_not_from_dehydrated_device(&decrypted, &event.sender).await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's kinda tripping me up that we flattened out the branches here. A bit worried that we'll somehow miss this subtle ?
that prevents us from accepting secrets from dehydrated devices.
That being said, I don't have an idea how to improve it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I don't love it, but I think splitting into a separate function is good.
I could make it an explicit if
and return
but as the method name says "check" and we have a comment saying "Return early" maybe it's good enough?
- [**breaking**]: When in "exclude insecure devices" mode, refuse to decrypt | ||
incoming to-device messages from unverified devices, except for some | ||
exceptions for certain event types (see the documentation on | ||
`OlmMachine::decrypt_to_device_event` for details). To support this, a new |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OlmMachine::decrypt_to_device_event
is a private method, so it's gonna be a bit hard for users to look at the docs of that method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. Do you think it's worth repeating ourselves by listing the exceptions in a public method doc? I looked and it felt a bit over-detailed. Maybe I should just remove this part from the release notes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think removing it from the changelog is fine.
UnverifiedSender { | ||
/// The raw decrypted event | ||
raw: Raw<AnyToDeviceEvent>, | ||
/// The Olm encryption info | ||
encryption_info: EncryptionInfo, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, but is this something we want? In the case of Megolm we just give you the UTD.
I would have expected us to do the same here, though I'm happy to be convinced that we need to do something different for Olm/to-device messages.
If we want to explain to people why this is an UTD we could expand the UnableToDecrypt
variant.
If you agree with this, perhaps we should move all this logic into the Account
somewhere in the parse_decrypted_to_device_event()
. Not sure if we should also move the device dehydration check there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It just felt rude to decrypt a message and then throw away all we know about it, so it would be hard to debug why it failed to decrypt, so I wanted to include the decrypted event (mainly so you could see the real event type) and encryption info.
If you like we could add to UTD like:
struct DecryptedCandidate {
event: Raw<AnyToDeviceEvent>,
encryption_info: EncryptionInfo,
}
...
pub enum ProcessedToDeviceEvent {
UnableToDecrypt{
encrypted_event: Raw<AnyToDeviceEvent>,
decrypted_candidate: Option<SomeNewType>
}
...
But I'd also be happy to just return the existing UTD if you think that's sensible.
If you agree with this, perhaps we should move all this logic into the Account somewhere in the parse_decrypted_to_device_event(). Not sure if we should also move the device dehydration check there.
Happy to do that if you prefer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It just felt rude to decrypt a message
Yeah but that's what we do for room messages as well
and then throw away all we know about it, so it would be hard to debug why it failed to decrypt
We should probably return the error then. We can include more metadata i.e. the decrypted event type if you think that this is sensible.
If you like we could add to UTD like:
Yes, this seems sensible. It's also mimicking what we do for room events more or less. That is we can include the UTD reason/info like we did for room events:
matrix-rust-sdk/crates/matrix-sdk-common/src/deserialized_responses.rs
Lines 720 to 729 in 6de4032
/// An encrypted event which could not be decrypted. | |
UnableToDecrypt { | |
/// The `m.room.encrypted` event. Depending on the source of the event, | |
/// it could actually be an [`AnyTimelineEvent`] (i.e., it may | |
/// have a `room_id` property). | |
event: Raw<AnySyncTimelineEvent>, | |
/// Information on the reason we failed to decrypt | |
utd_info: UnableToDecryptInfo, | |
}, |
Happy to do that if you prefer.
Yeah, sounds like it would centralize this "refusing to decrypt" logic.
Co-authored-by: Damir Jelić <poljar@termina.org.uk> Signed-off-by: Andy Balaam <mail@artificialworlds.net>
I see that you re-requested review, but what about my other comments? Most importantly about #5319 (comment)? |
I'm waiting for replies from you on several comments including that one. |
Err, did you reply to any of my comments? Or do you expect me to reply to my own comments? I can't see any comments after my initial comments: ![]() Is there supposed to be something else there? I'm confused. |
D'oh, it was a pending review, sorry. I think I've clicked the relevant button now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hopefully I replied to all the outstanding comments. If I missed some, please ping me.
@@ -2816,6 +2939,28 @@ impl OlmMachine { | |||
} | |||
} | |||
|
|||
fn sending_device_is_unverified(encryption_info: &EncryptionInfo) -> bool { | |||
if let VerificationState::Unverified(level) = &encryption_info.verification_state { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think that a full match
with Verified
/Unverified
will be easier to read than the if let
and else
Also the name is_unverified
can be better? because now when UnverifiedIdentity
is true then is_unverified
is false.
Can we do something similar than for megolm? something around check_sender_trust_requirement
?
First half of #4147 - this is the receiving part.