Skip to content

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

Merged
merged 3 commits into from
May 19, 2025

Conversation

richvdh
Copy link
Member

@richvdh richvdh commented May 15, 2025

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 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 the VerificationState.

Note that there are a bunch of tests for this method in matrix-sdk-crypto/src/machine/tests/decryption_verification_state.rs, called test_decryption_trust_requirement.

Copy link

codecov bot commented May 15, 2025

Codecov Report

Attention: Patch coverage is 94.73684% with 1 line in your changes missing coverage. Please review.

Project coverage is 85.85%. Comparing base (c0d6e87) to head (351d1ea).
Report is 22 commits behind head on main.

Files with missing lines Patch % Lines
crates/matrix-sdk-crypto/src/machine/mod.rs 94.73% 1 Missing ⚠️
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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@richvdh richvdh force-pushed the rav/refactor_check_sender_trust_requirement branch from 727b356 to 2a4b503 Compare May 15, 2025 12:20
@richvdh richvdh changed the title crypto: rewrite check_sender_trust_requirement to use VerficationState crypto: rewrite check_sender_trust_requirement to use VerificationState May 15, 2025
…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`.
@richvdh richvdh force-pushed the rav/refactor_check_sender_trust_requirement branch from 2a4b503 to ad99431 Compare May 15, 2025 12:23
Comment on lines 1827 to 1832
matches!(
(verification_level, legacy_session),
(VerificationLevel::UnverifiedIdentity, _)
| (VerificationLevel::UnsignedDevice, true)
| (VerificationLevel::None(_), true)
)
Copy link
Member Author

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.

@richvdh richvdh marked this pull request as ready for review May 15, 2025 15:02
@richvdh richvdh requested review from a team as code owners May 15, 2025 15:02
@richvdh richvdh requested review from stefanceriu and poljar and removed request for a team May 15, 2025 15:02
Copy link
Contributor

@poljar poljar left a 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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
_ => &false,
_ => false,

Comment on lines 1835 to 1836
TrustRequirement::CrossSigned => {
matches!(verification_level, VerificationLevel::UnverifiedIdentity)
Copy link
Contributor

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,
},

Comment on lines 1827 to 1832
matches!(
(verification_level, legacy_session),
(VerificationLevel::UnverifiedIdentity, _)
| (VerificationLevel::UnsignedDevice, true)
| (VerificationLevel::None(_), true)
)
Copy link
Contributor

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,
}

Copy link
Member Author

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.

@poljar poljar removed the request for review from stefanceriu May 16, 2025 09:57
@poljar
Copy link
Contributor

poljar commented May 16, 2025

The CI failures are unrelated, they are being fixed by @Hywan here: #5048.

@richvdh richvdh merged commit 4d2c261 into main May 19, 2025
42 checks passed
@richvdh richvdh deleted the rav/refactor_check_sender_trust_requirement branch May 19, 2025 17:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants