Skip to content
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

Migrate own identity local trust to rust crypto #4090

Merged
merged 20 commits into from
Mar 18, 2024

Conversation

BillCarsonFr
Copy link
Member

@BillCarsonFr BillCarsonFr commented Mar 4, 2024

Fixes: element-hq/element-web#27079

When you log in with a new session, that session will do a /keys/query to see if the user has existing published cross-signing keys. The new login has now to decide if these published keys can be trusted.

This is done by performing verification:

  • Using 4S if available: the user enters the 4S passphrase/key, then can retrieve the private parts of the cross-signing keys to see if they match the public parts.
  • By using another already trusted session. At the end of this process the js-sdk will mark the cross-signing keys as trusted. This is done by storing the public keys using storeTrustedSelfKeys. Later on the the new session will request the private keys from the existing session via secret gossiping.

There are several cases where you can end up with a trusted session that doesn't have the private MSK, for example it can happen if the session you verified against don't have it, or if secret gossiping failed for some reason.

The problem is that rust crypto will only consider the current session as trusted if we import the private MSK itself.
That means that a legacy trusted session that does not have the MSK in cache will revert to untrusted after migration.

This PR adds a way to detect that case, and then mark the migrated session as trusted (mark_as_verified) if the legacy session was trusted. (aka migration of local trust of own identity).

Checklist

  • Tests written for new code (and old code if feasible)
  • Linter and other CI checks pass
  • Sign-off given on the changes (see CONTRIBUTING.md)

@BillCarsonFr BillCarsonFr changed the title Migrate own identity trust to rust crypto Migrate own identity local trust to rust crypto Mar 4, 2024
src/rust-crypto/libolm_migration.ts Outdated Show resolved Hide resolved
src/rust-crypto/libolm_migration.ts Outdated Show resolved Hide resolved
src/rust-crypto/libolm_migration.ts Outdated Show resolved Hide resolved
@richvdh
Copy link
Member

richvdh commented Mar 6, 2024

This is done by performing verification:

  • Using 4S if available, the user enters the 4S passphrase/key, then can retrieve the private parts of the cross-signing keys to see if they match the public parts.

I might be confused, but I don't think that is what we normally mean by "verification"? Or is it?

@richvdh
Copy link
Member

richvdh commented Mar 6, 2024

By using another already trusted session. At the end of this process the js-sdk will mark the cross-signing keys as trusted. This is done by storing the public keys using storeTrustedSelfKeys. Later on the the new session will request the private keys from the existing session via secret gossiping.

Am I right in understanding that this only applies to legacy crypto? When I read the description in the PR I assumed it was a general description of how MSK trust works in both legacy and ER -- is that not correct?

@dkasak
Copy link
Member

dkasak commented Mar 6, 2024

I might be confused, but I don't think that is what we normally mean by "verification"? Or is it?

It's a bit ambiguous. I think we generally lack a great term for the concept that encompasses both

  1. obtaining the user identity from an authenticated storage where we've previously stashed it ourselves
  2. obtaining it from an existing device which we have verified in the spec sense of Device Verification

Semantically, this is authentication of the user identity. We're also referring to this as "trusting" or "establishing trust" in various places, but some people found that confusing for whatever reason.

This is an area which would benefit from some spec work, in order to introduce and define sensible terms and consolidate all public resources to use them consistently.

src/rust-crypto/index.ts Outdated Show resolved Hide resolved
src/rust-crypto/libolm_migration.ts Outdated Show resolved Hide resolved
src/rust-crypto/libolm_migration.ts Outdated Show resolved Hide resolved
src/rust-crypto/libolm_migration.ts Outdated Show resolved Hide resolved
src/rust-crypto/libolm_migration.ts Outdated Show resolved Hide resolved
spec/integ/crypto/rust-crypto.spec.ts Outdated Show resolved Hide resolved
spec/integ/crypto/rust-crypto.spec.ts Outdated Show resolved Hide resolved
spec/integ/crypto/rust-crypto.spec.ts Outdated Show resolved Hide resolved
src/rust-crypto/libolm_migration.ts Outdated Show resolved Hide resolved
src/rust-crypto/libolm_migration.ts Outdated Show resolved Hide resolved
src/rust-crypto/libolm_migration.ts Outdated Show resolved Hide resolved
/** The logger to use */
logger: Logger;
}): Promise<void> {
const { legacyCryptoStore, rustCrypto, logger } = args;
// Now get the cross-signing identity from rust.
// If this is null that means that there are no cross-signing keys published server side.
Copy link
Member

Choose a reason for hiding this comment

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

this line is redundant to the comment on line 416 now: that's why I asked you to split out the if statements, and why my suggestion removed this comment.

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// If this is null that means that there are no cross-signing keys published server side.

@@ -197,6 +201,14 @@ async function initOlmMachine(
// It will be retried by the sdk.
Copy link
Member

@richvdh richvdh Mar 8, 2024

Choose a reason for hiding this comment

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

It's a bit more annoying for migrating local trust, as if it fails we wont migrate local trust. But worst case you'll have to verify manually after?

Right, this is my point. We decided that having to re-verify was unacceptable, didn't we? Especially given we don't actually tell the user they have to re-verify.

Tbh, I feel like it would be a lesser evil to block the application here - ie, sit in a loop repeatedly retrying userHasCrossSigningKeys until it works. [We know that the server is reachable, because we've already done a /room_keys/version request?] Or we could try once, and if that doesn't work, fire off a background thread to keep retrying in a loop?

spec/test-utils/test_indexeddb_cryptostore_dump/README.md Outdated Show resolved Hide resolved
spec/integ/crypto/rust-crypto.spec.ts Outdated Show resolved Hide resolved
spec/integ/crypto/rust-crypto.spec.ts Outdated Show resolved Hide resolved
Copy link
Member

@richvdh richvdh left a comment

Choose a reason for hiding this comment

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

Still a few comments I'm afraid. Some of this is getting a bit nit-picky so feel free to push back if you think it's excessive. The only thing that I think really matters is the part about updating the trust if the initial /keys/query request fails.

Also please look above: there are a few unresolved threads.

Co-authored-by: Richard van der Hoff <[email protected]>
BillCarsonFr and others added 3 commits March 14, 2024 12:16
Co-authored-by: Richard van der Hoff <[email protected]>
Co-authored-by: Richard van der Hoff <[email protected]>
Co-authored-by: Richard van der Hoff <[email protected]>
Co-authored-by: Richard van der Hoff <[email protected]>
Copy link
Member

@richvdh richvdh left a comment

Choose a reason for hiding this comment

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

LGTM other than a couple of nits

/** The logger to use */
logger: Logger;
}): Promise<void> {
const { legacyCryptoStore, rustCrypto, logger } = args;
// Now get the cross-signing identity from rust.
// If this is null that means that there are no cross-signing keys published server side.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// If this is null that means that there are no cross-signing keys published server side.

spec/test-utils/test_indexeddb_cryptostore_dump/index.ts Outdated Show resolved Hide resolved
Comment on lines +152 to +153
/** Additional dump info specific for some tests.*/
[key: string]: any;
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is necessary: a class can have additional fields which aren't specified in an interface.

Suggested change
/** Additional dump info specific for some tests.*/
[key: string]: any;

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 am getting that error Object literal may only specify known properties if it's not there

@BillCarsonFr BillCarsonFr added this pull request to the merge queue Mar 18, 2024
Merged via the queue into develop with commit 3e98900 Mar 18, 2024
23 checks passed
@BillCarsonFr BillCarsonFr deleted the valere/element-r/migrate_local_trust_if_needed branch March 18, 2024 09:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

WebR: Sometimes after migrating to rust crypto the existing session reverts back to untrusted
4 participants