WIP: NSS managed logins key storage
:warning: Work in Progress - Please Do Not Merge
This pull request is a proof of concept, representing an initial approach to integrating key management for the logins component in Firefox’s desktop password manager. The implementation is still in its early stages and serves as a foundation for further discussion and refinement.
Objective
To integrate the logins component into the desktop environment and replace the existing logins backend with the Rust implementation, key management must be incorporated. Currently, NSS handles this, ensuring that the application code doesn't directly interact with key management. Instead, it simply uses the encrypt and decrypt endpoints provided by NSS, which internally access the corresponding keys stored in the slot.
Another approach would be to handle this integration on the JavaScript side, but it would present similar challenges due to the absence of the necessary bindings. Here, I have pursued the Rust path.
Contents of the Pull Request
This pull request includes the following changes:
- Feature Flag
keydb:- A new feature flag
keydbhas been added, which provides the additional functionalities listed below.
- A new feature flag
- New Struct
ManagedLoginStore:- Implements a new struct
ManagedLoginStore, responsible for generating, persisting, and retrieving the key, providing the same API asLoginStore, but with transparent key management.
- Implements a new struct
- Extended NSS Bindings:
- New NSS bindings have been added, necessary for the tasks mentioned above:
- pub fn PK11_GetInternalKeySlot() -> *mut PK11SlotInfo;
- pub fn PK11_SetSymKeyNickname(key: *mut PK11SymKey, name: *const c_uchar);
- pub fn PK11_ImportSymKeyWithFlags(...) -> *mut PK11SymKey; pub fn PK11_ListFixedKeysInSlot(...) -> *mut PK11SymKey;
- New NSS bindings have been added, necessary for the tasks mentioned above:
- New Function
nss::pk11::sym_key::retrieve_or_create_and_import_and_persist_aes256_key_data(name: &str) -> Result<Vec<u8>>:- This function checks if an existing key can be found.
- If no key is found, it generates and stores a new one.
- Finally, it returns the key data for use with Logins component.
- Adjustment of NSS Initialization:
- The initialization of NSS via
ensure_nss_initializedhas been adjusted based on the new feature flag, allowing keys to be persisted.
- The initialization of NSS via
Open Questions/Problems/TODOs
- Binding Signatures:
- We need to double check whether binding signatures are written correctly, especially in regards to mutability.
- Profile Directory Path:
- When initializing NSS via
ensure_nss_initialized, this patch reads the path to the profile (where the NSS key databases are located) from thePROFILE_DIRenvironment variable based on the feature flag. This approach might not be optimal. We need to explore better ways to pass the path.
- When initializing NSS via
- Feature Flag and
UDLIntegration:- This version just compiles a different UDL, depending on the
keydbfeature flag. I bet there is a better way?
- This version just compiles a different UDL, depending on the
- Further Implementation in
ManagedLoginStore:- Functions still need to be implemented (this concerns
Archandling):resetregister_with_sync_managercreate_logins_sync_engine
- Functions still need to be implemented (this concerns
- Naming of
ManagedStore:- We might want to consider a better name for the
ManagedStorestruct.
- We might want to consider a better name for the
- Architecture Review:
- The architecture and code structure implemented here should be reviewed and discussed.
- Abstraction of Key Management:
- The
LoginStoreshould be modified to accept aLoginManagertrait implementation, allowing key management to be abstracted
- The
Pull Request checklist
- Breaking changes: This PR follows our breaking change policy
- [ ] This PR follows the breaking change policy:
- This PR has no breaking API changes, or
- There are corresponding PRs for our consumer applications that resolve the breaking changes and have been approved
- [ ] This PR follows the breaking change policy:
- [ ] Quality: This PR builds and tests run cleanly
- Note:
- For changes that need extra cross-platform testing, consider adding
[ci full]to the PR title. - If this pull request includes a breaking change, consider cutting a new release after merging.
- For changes that need extra cross-platform testing, consider adding
- Note:
- [ ] Tests: This PR includes thorough tests or an explanation of why it does not
- [ ] Changelog: This PR includes a changelog entry in CHANGELOG.md or an explanation of why it does not need one
- Any breaking changes to Swift or Kotlin binding APIs are noted explicitly
- [ ] Dependencies: This PR follows our dependency management guidelines
- Any new dependencies are accompanied by a summary of the due diligence applied in selecting them.
Branch builds: add [firefox-android: branch-name] to the PR title.
Codecov Report
Attention: Patch coverage is 0% with 190 lines in your changes missing coverage. Please review.
Project coverage is 21.86%. Comparing base (
eee6c27) to head (dc116a5). Report is 7 commits behind head on main.
Additional details and impacted files
@@ Coverage Diff @@
## main #6362 +/- ##
==========================================
- Coverage 22.00% 21.86% -0.14%
==========================================
Files 342 343 +1
Lines 30712 30907 +195
==========================================
Hits 6759 6759
- Misses 23953 24148 +195
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
trait KeyStore { ... }- there would be a few options for what this should do, but it could start with justget_key().The public API could use
Arc<dyn KeyStore>and maybe could be passed to the constructors. You could impl that trait like done here and mobile could impl that trait wrapping their string key (or however they like, we just don't want to hold it ourselves)
+1 to this design. I really like the pattern of using traits for functionality that we can't always handle in Rust and giving consumers multiple options for constructing an implementation.
This has been a spike, which is completed. Actual implementation work continues in https://github.com/mozilla/application-services/pull/6469 (introduction of EncryptorDecryptor trait)