[PM-27238] feat: Support v2 encryption on key connector signups#2648
[PM-27238] feat: Support v2 encryption on key connector signups#2648matt-livefront wants to merge 1 commit into
Conversation
🤖 Bitwarden Claude Code ReviewOverall Assessment: APPROVE This PR adds V2 account encryption support to the Key Connector new-user registration flow, gated behind the Code Review DetailsNo findings. |
quexten
left a comment
There was a problem hiding this comment.
@matt-livefront It's fine if that's out of scope for this PR, but the way iOS is storing the account cryptographic state as a custom model which is different from the public API surface of the SDK is weird and seems brittle / likely to introduce bugs. Is it not possible to just store the SDK's model, or even a string serialized version of it?
Specifically, mobile should not care about the internals of that object or individually set fields on it (i guess with the exception of sync, though we should work on moving that part to the SDK too).
| switch accountCryptographicState { | ||
| case let .v1(privateKey): | ||
| self.init( | ||
| accountKeys: nil, |
There was a problem hiding this comment.
AccountKeys should not be nil. It should be populated with a PrivateKeysResponseModel with with signature key pair and security state set to nil, but the publicKeyEncryptionKeyPair present.
There was a problem hiding this comment.
Do you know where that could come from in this key connector registration flow? It isn't returned in KeyConnectorRegistrationResult when calling postKeysForKeyConnectorRegistration? Given that the SDK is generating V2 encryption keys, is it possible to end up in this v1 case? Maybe the answer is, as you suggested, to persist WrappedAccountCryptographicState directly, but I was trying to make this work with we we already have in place to avoid additional changes.
There was a problem hiding this comment.
As mentioned, persisting the WrappedAccountCryptographicState is the correct solution.
IF needed, then you can make an accountKeys model in the same way you make the V2 model, only leave out the security state and signature key pair, and signed public key.
| self.init( | ||
| accountKeys: PrivateKeysResponseModel( | ||
| publicKeyEncryptionKeyPair: PublicKeyEncryptionKeyPairResponseModel( | ||
| publicKey: "", // Not returned by SDK at registration; will populate on next sync. |
There was a problem hiding this comment.
This feels like it has a high risk of introducing bugs. Can we not just store the accountCryptographicState? That's what the SDK takes for init, and KM expects clients to just store it instead of the response model.
| ), | ||
| signatureKeyPair: SignatureKeyPairResponseModel( | ||
| wrappedSigningKey: signingKey, | ||
| verifyingKey: "", // Not returned by SDK at registration; will populate on next sync. |
There was a problem hiding this comment.
Same comment as above, this seems like a high risk.
| /// - accountCryptographicState: The SDK's wrapped account cryptographic state. | ||
| /// - encryptedUserKey: An optional encrypted user key to store alongside the cryptographic state. | ||
| /// | ||
| init(accountCryptographicState: WrappedAccountCryptographicState, encryptedUserKey: String? = nil) { |
There was a problem hiding this comment.
I don't quite understand what we are doing here. We should just store the WrappedAccountCryptographicState, not a response model. On sync, the response model should get converted to WrappedAccountCryptographicState.
@quexten Thanks for your feedback! In Swift, the easiest way to support persistence is via Codable. The Swift bindings from the SDK don't include this, and it's a fair bit of extra work for us to implement it manually on our side. So I suspect that's how we ended up in this position; our response models are already Codable (for decoding JSON) so it's straightforward to persist those and then transform into the SDK types as needed. But you make a good point, do you know if the SDK could include the Codable conformance? It seems like it could just be a configuration option, but maybe there's more to it. https://mozilla.github.io/uniffi-rs/latest/swift/configuration.html#:~:text=generate_codable_conformance |
|
@matt-livefront I don't see a reason not to enable codable on the SDK. We want to keep the amount mobile implements to a minimum, so if this reduces it I support it. I'm opening a PR to enable it for crypto / core, which should cover anything on the key-management front. |
## 🎟️ Tracking <!-- Paste the link to the Jira or GitHub issue or otherwise describe / point to where this change is coming from. --> bitwarden/ios#2648 (comment) ## 📔 Objective <!-- Describe what the purpose of this PR is, for example what bug you're fixing or new feature you're adding. --> As per mobile's request, we are enabling codable for the uniffi bindings so that they can directly serialize the structs they get returned from the SDK without having to maintain a seprate copy. Maintaining a separate copy in the past has lead to bugs / incorrect state being saved (bitwarden/ios#2303). This is safer than mobiles current approach of persisting server request / response models, which do not match what the SDK returns. ## 🚨 Breaking Changes <!-- Does this PR introduce any breaking changes? If so, please describe the impact and migration path for clients. If you're unsure, the automated TypeScript compatibility check will run when you open/update this PR and provide feedback. For breaking changes: 1. Describe what changed in the client interface 2. Explain why the change was necessary 3. Provide migration steps for client developers 4. Link to any paired client PRs if needed Otherwise, you can remove this section. -->
|
@matt-livefront Merged the PR, codable should now be available. Please note I did not test the UNIFFI build locally. I have a separate PR adding swift integration tests, after which we could add those tests into there. Until then, please LMK if there are any issues on this front. |
🎟️ Tracking
PM-27238
📔 Objective
Enables support for V2 encryption on key connector signups. Most of the existing logic that was implemented in the app, including API requests, has been moved into the SDK (via the
postKeysForKeyConnectorRegistration(keyConnectorUrl:ssoOrgIdentifier:)function).These changes are behind the
enable-account-encryption-v2-key-connector-registrationfeature flag.