-
Notifications
You must be signed in to change notification settings - Fork 25
[PM-27232] Implement Registration for TDE Users #596
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
|
Great job! No new security vulnerabilities introduced in this pull request |
|
๐ SDK Breaking Change Detection ResultsSDK Version:
Breaking change detection completed. View SDK workflow |
Codecov Reportโ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #596 +/- ##
==========================================
- Coverage 78.67% 78.51% -0.17%
==========================================
Files 283 283
Lines 29285 29345 +60
==========================================
- Hits 23041 23039 -2
- Misses 6244 6306 +62 โ View full report in Codecov by Sentry. ๐ New features to boost your workflow:
|
7e40878 to
7fe5d69
Compare
This comment was marked as resolved.
This comment was marked as resolved.
Thomas-Avery
left a comment
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.
Looking good. A few things to take a look at and some questions from my side.
Also I think claude is wanting to have a chat on this one ๐
| org_id: String, | ||
| org_public_key: B64, | ||
| // Note: Ideally these would be set for the register client, however no such functionality | ||
| // exists at the moment | ||
| user_id: String, | ||
| device_id: String, | ||
| trust_device: bool, |
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.
โ
For these ID parameters can we use the OrganizationId UserId etc., from crates/bitwarden-core/src/ids.rs, as the input types? Or is there some limitation for those?
| &self, | ||
| org_id: String, | ||
| org_public_key: B64, | ||
| // Note: Ideally these would be set for the register client, however no such functionality | ||
| // exists at the moment | ||
| user_id: String, | ||
| device_id: String, | ||
| trust_device: bool, |
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 with Jared on this, mostly just a style/preference thing having a bunch of primitives is hard to keep track of when reading the method.
Vs just seeing request.<some_input_name> lets me know right away it's coming from the request input.
| // Note: This property is deprecated and will be removed | ||
| public_key: account_cryptographic_state_request | ||
| .account_public_key | ||
| .ok_or(UserRegistrationError::Crypto)?, | ||
| // Note: This property is deprecated and will be removed |
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.
For these notes do we have a ticket tracking that, that we can reference here in the comments?
| pub device_key: String, | ||
| /// The decrypted user key. This can be used to get the consuming client to an unlocked state. | ||
| pub user_key: B64, |
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.
โ Why do we use String for device_key and B64 for user_key?
Since they're both symmetric crypto keys I would expect the same return type.
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.
+1 for unit tests
| let mut ctx = self.client.internal.get_key_store().context_mut(); | ||
| let (user_key, wrapped_state) = | ||
| WrappedAccountCryptographicState::make(&mut ctx, user_id) | ||
| .map_err(MakeKeysError::AccountCryptographyInitialization)?; | ||
| #[expect(deprecated)] | ||
| let user_key = ctx.dangerous_get_symmetric_key(user_key)?; | ||
|
|
||
| // TDE unlock method | ||
| let device_key = DeviceKey::trust_device(user_key)?; | ||
|
|
||
| // Account recovery enrollment | ||
| let public_key = | ||
| AsymmetricPublicCryptoKey::from_der(&SpkiPublicKeyBytes::from(&org_public_key)) | ||
| .map_err(MakeKeysError::Crypto)?; | ||
| let admin_reset = UnsignedSharedKey::encapsulate_key_unsigned(user_key, &public_key) | ||
| .map_err(MakeKeysError::Crypto)?; | ||
|
|
||
| let store = KeyStore::default(); | ||
| let mut ctx = store.context_mut(); | ||
| let user_key_id = ctx.add_local_symmetric_key(user_key.to_owned()); | ||
| let security_state = RwLock::new(None); | ||
| wrapped_state | ||
| .set_to_context(&security_state, user_key_id, &store, ctx) | ||
| .map_err(MakeKeysError::AccountCryptographyInitialization)?; | ||
|
|
||
| let cryptography_state_request_model = wrapped_state | ||
| .to_request_model(&store) | ||
| .map_err(|_| MakeKeysError::RequestModelCreation)?; | ||
|
|
||
| Ok(( | ||
| wrapped_state, | ||
| user_key.to_owned(), | ||
| cryptography_state_request_model, | ||
| device_key, | ||
| admin_reset, | ||
| )) |
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 mut ctx = self.client.internal.get_key_store().context_mut(); | |
| let (user_key, wrapped_state) = | |
| WrappedAccountCryptographicState::make(&mut ctx, user_id) | |
| .map_err(MakeKeysError::AccountCryptographyInitialization)?; | |
| #[expect(deprecated)] | |
| let user_key = ctx.dangerous_get_symmetric_key(user_key)?; | |
| // TDE unlock method | |
| let device_key = DeviceKey::trust_device(user_key)?; | |
| // Account recovery enrollment | |
| let public_key = | |
| AsymmetricPublicCryptoKey::from_der(&SpkiPublicKeyBytes::from(&org_public_key)) | |
| .map_err(MakeKeysError::Crypto)?; | |
| let admin_reset = UnsignedSharedKey::encapsulate_key_unsigned(user_key, &public_key) | |
| .map_err(MakeKeysError::Crypto)?; | |
| let store = KeyStore::default(); | |
| let mut ctx = store.context_mut(); | |
| let user_key_id = ctx.add_local_symmetric_key(user_key.to_owned()); | |
| let security_state = RwLock::new(None); | |
| wrapped_state | |
| .set_to_context(&security_state, user_key_id, &store, ctx) | |
| .map_err(MakeKeysError::AccountCryptographyInitialization)?; | |
| let cryptography_state_request_model = wrapped_state | |
| .to_request_model(&store) | |
| .map_err(|_| MakeKeysError::RequestModelCreation)?; | |
| Ok(( | |
| wrapped_state, | |
| user_key.to_owned(), | |
| cryptography_state_request_model, | |
| device_key, | |
| admin_reset, | |
| )) | |
| let mut ctx = self.client.internal.get_key_store().context_mut(); | |
| let (user_key_id, wrapped_state) = | |
| WrappedAccountCryptographicState::make(&mut ctx, user_id) | |
| .map_err(MakeKeysError::AccountCryptographyInitialization)?; | |
| #[expect(deprecated)] | |
| let user_key = ctx.dangerous_get_symmetric_key(user_key_id)?; | |
| // TDE unlock method | |
| let device_key = DeviceKey::trust_device(user_key)?; | |
| // Account recovery enrollment | |
| let public_key = | |
| AsymmetricPublicCryptoKey::from_der(&SpkiPublicKeyBytes::from(&org_public_key)) | |
| .map_err(MakeKeysError::Crypto)?; | |
| let admin_reset = UnsignedSharedKey::encapsulate_key_unsigned(user_key, &public_key) | |
| .map_err(MakeKeysError::Crypto)?; | |
| let cryptography_state_request_model = wrapped_state | |
| .to_request_model(self.client.internal.get_key_store()) | |
| .map_err(|_| MakeKeysError::RequestModelCreation)?; | |
| Ok(( | |
| wrapped_state, | |
| user_key.to_owned(), | |
| cryptography_state_request_model, | |
| device_key, | |
| admin_reset, | |
| )) |
๐ญ It would seem like we would want to continue using the ctx and key store from the client?
Maybe I'm missing something important or a side effect making the other key store is desired for. If so could we add a comment about what that is.
## ๐๏ธ Tracking <!-- Paste the link to the Jira or GitHub issue or otherwise describe / point to where this change is coming from. --> n/a but blocks #549 and #596 ## ๐ Objective <!-- Describe what the purpose of this PR is, for example what bug you're fixing or new feature you're adding. --> To add UNIFFI support to the bw-auth crate ## โฐ Reminders before review - Contributor guidelines followed - All formatters and local linters executed and passed - Written new unit and / or integration tests where applicable - Protected functional changes with optionality (feature flags) - Used internationalization (i18n) for all UI strings - CI builds passed - Communicated to DevOps any deployment requirements - Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team ## ๐ฆฎ Reviewer guidelines <!-- Suggested interactions but feel free to use (or not) as you desire! --> - ๐ (`:+1:`) or similar for great changes - ๐ (`:memo:`) or โน๏ธ (`:information_source:`) for notes or general info - โ (`:question:`) for questions - ๐ค (`:thinking:`) or ๐ญ (`:thought_balloon:`) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion - ๐จ (`:art:`) for suggestions / improvements - โ (`:x:`) orโ ๏ธ (`:warning:`) for more significant problems or concerns needing attention - ๐ฑ (`:seedling:`) or โป๏ธ (`:recycle:`) for future improvements or indications of technical debt - โ (`:pick:`) for minor or nitpick changes




๐๏ธ Tracking
https://bitwarden.atlassian.net/browse/PM-27232
bitwarden/server#6671
๐ Objective
Implements registration for TDE users. This uses v2 encryption.
Note
The API changes here are not final and need an update to the automatic API bindings, after the corresponding server change is merged. This PR will only be merged once the binding changes are already in
mainand removed from this PR.๐จ Breaking Changes
โฐ Reminders before review
team
๐ฆฎ Reviewer guidelines
:+1:) or similar for great changes:memo:) or โน๏ธ (:information_source:) for notes or general info:question:) for questions:thinking:) or ๐ญ (:thought_balloon:) for more open inquiry that's not quite a confirmedissue and could potentially benefit from discussion
:art:) for suggestions / improvements:x:) or:warning:) for more significant problems or concerns needing attention:seedling:) or โป๏ธ (:recycle:) for future improvements or indications of technical debt:pick:) for minor or nitpick changes