-
Notifications
You must be signed in to change notification settings - Fork 285
crypto: rewrite check_sender_trust_requirement
to use VerificationState
#5044
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
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #5044 +/- ##
=======================================
Coverage 85.85% 85.85%
=======================================
Files 325 325
Lines 35936 35938 +2
=======================================
+ Hits 30853 30855 +2
Misses 5083 5083 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
727b356
to
2a4b503
Compare
check_sender_trust_requirement
to use VerficationState
check_sender_trust_requirement
to use VerificationState
…tate` There are two reasons for this. Firstly. we've already done a bunch of work to map `SenderData` into a `VerificationState`, and the decision tree from `VerificationState` to allow/reject is simpler than going from `SenderData`, even if we have to fudge it a bit to get the "legacy" flag. (Note that it allows us to get rid of an `unreachable!` panic.) Secondly, `VerficationState` represents the state of an *event*, whereas `SenderData` is about the session as a whole. A session can be fine, whilst event (claiming to be) encrypted with it can be suspect. What we want here is to check a specific message. Currently, this doesn't make any functional difference, but conceptually it's cleaner to check the `VerificationState`.
2a4b503
to
ad99431
Compare
matches!( | ||
(verification_level, legacy_session), | ||
(VerificationLevel::UnverifiedIdentity, _) | ||
| (VerificationLevel::UnsignedDevice, true) | ||
| (VerificationLevel::None(_), true) | ||
) |
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.
correspondances between VerificationLevel
and SenderData
:
SenderData::VerificationViolation
-> VerificationLevel::VerificationViolation
SenderData::SenderUnverified
-> VerificationLevel::UnverifiedIdentity
SenderData::DeviceInfo
-> VerificationLevel::UnsignedDevice
SenderData::UnknownDevice
-> VerificationLevel::None
There is no equivalent to SenderData::SenderVerified
; that is handled as VerificationState::Verified
above.
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 left some small suggestions, I think the logic is fine.
// respectively, and those cases may be acceptable if the reason | ||
// for the lack of data is that the sessions were established | ||
// before we started collecting SenderData. | ||
let legacy_session = match &session.sender_data { |
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.
let legacy_session = match &session.sender_data { | |
let legacy_session = match session.sender_data { |
let legacy_session = match &session.sender_data { | ||
SenderData::DeviceInfo { legacy_session, .. } => legacy_session, | ||
SenderData::UnknownDevice { legacy_session, .. } => legacy_session, | ||
_ => &false, |
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.
_ => &false, | |
_ => false, |
TrustRequirement::CrossSigned => { | ||
matches!(verification_level, VerificationLevel::UnverifiedIdentity) |
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.
Again, listing all cases makes sense to me:
// If cross-signing of identities is required, the only acceptable unverified case
// is when the identity is signed but not yet verified by us.
TrustRequirement::CrossSigned => match verification_level {
VerificationLevel::UnverifiedIdentity => true,
VerificationLevel::VerificationViolation
| VerificationLevel::UnsignedDevice
| VerificationLevel::None(_) => false,
},
matches!( | ||
(verification_level, legacy_session), | ||
(VerificationLevel::UnverifiedIdentity, _) | ||
| (VerificationLevel::UnsignedDevice, true) | ||
| (VerificationLevel::None(_), true) | ||
) |
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 don't like using matches!()
in crypto related code, it's very easy to forget to modify the statement once new variants are added to the enum. I know it's concise and looks neat, it still makes me worry for the future.
What do you think about listing it all out like so:
// In the CrossSignedOrLegacy case the following rules apply:
//
// 1. Identities we have not yet verified can be decrypted regardless of the
// legacy state of the session.
// 2. Devices that aren't signed by the owning identity of the device can only
// be decrypted if it's a legacy session.
// 3. If we have no information about the device, we should only decrypt if it's
// a legacy session.
// 4. Anything else, should throw an error.
match (verification_level, legacy_session) {
// Case 1
(VerificationLevel::UnverifiedIdentity, _) => true,
// Case 2
(VerificationLevel::UnsignedDevice, true) => true,
// Case 3
(VerificationLevel::None(_), true) => true,
// Case 4
(VerificationLevel::VerificationViolation, _)
| (VerificationLevel::UnsignedDevice, _)
| (VerificationLevel::None(_), false) => false,
}
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 agree it's clearer. I started with that, but I got a lint failure. I'll disable the lint, I guess.
…nder_trust_requirement
There are two reasons for this.
Firstly. we've already done a bunch of work to map
SenderData
into aVerificationState
, and the decision tree fromVerificationState
to allow/reject is simpler than going fromSenderData
, even if we have to fudge it a bit to get the "legacy" flag. (Note that it allows us to get rid of anunreachable!
panic.)Secondly,
VerficationState
represents the state of an event, whereasSenderData
is about the session as a whole. A session can be fine, whilst events (claiming to be) encrypted with it can be suspect. What we want here is to check a specific message. Currently, this doesn't make any functional difference, but conceptually it's cleaner to check theVerificationState
.Note that there are a bunch of tests for this method in
matrix-sdk-crypto/src/machine/tests/decryption_verification_state.rs
, calledtest_decryption_trust_requirement
.