-
Notifications
You must be signed in to change notification settings - Fork 315
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
Conversation
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.85% 88.86% +0.01%
==========================================
Files 333 333
Lines 91587 91731 +144
Branches 91587 91731 +144
==========================================
+ Hits 81379 81520 +141
Misses 6382 6382
- Partials 3826 3829 +3 ☔ View full report in Codecov by Sentry. |
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?
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.
Attempted to make it clearer in e5fac47
- [**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.
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.
Removed in 3924042
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.
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 was thinking about that in the context of element-call.
EC uses to-device messages to send the key to decrypt the video stream.
I initialy thought that it would be good for me to know that the incoming message was a call key even if we decided to not decrypt it because of trust settings. This could allow me to put some feedback on screen.
But actually I think I don't really need it. The call membership event has the sender device info in it, so I already know the verification state of the device, so I will know that it will be impossible to receive a key from it.
So the refusing to decrypt
logic is ok for me.
If we really need some info maybe the UnableToDecryptInfo
could hold the clear type? but not sure how useful it would be (appart for some metrics/analytics)
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'm fine with adding the clear type to the info if necessary, just not the whole content.
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.
Updated to make this a UTD in 56a51a4 . Working on moving the logic to Account.
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.
Updated to move the logic to Account in e6748a0
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'm fine with adding the clear type to the info if necessary, just not the whole content.
I have not done this since we don't see a clear need but it should be simple to do in future.
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
?
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 I addressed everything - let me know if not. Thanks! |
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.
Alright, I think that this is good now.
There's an incomplete commit message in 550fa11.
Not sure if you want to clean up the history and the commit message or if you'd like to just squash merge or something else.
…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.
…vices (when in exclude insecure mode)
0416539
to
a597752
Compare
First half of #4147 - this is the receiving part.