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

WIP: NSS managed logins key storage #6362

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jo
Copy link

@jo jo commented Sep 3, 2024

⚠️ 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:

  1. Feature Flag keydb:
    • A new feature flag keydb has been added, which provides the additional functionalities listed below.
  2. New Struct ManagedLoginStore:
    • Implements a new struct ManagedLoginStore, responsible for generating, persisting, and retrieving the key, providing the same API as LoginStore, but with transparent key management.
  3. 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;
  4. 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.
  5. Adjustment of NSS Initialization:
    • The initialization of NSS via ensure_nss_initialized has been adjusted based on the new feature flag, allowing keys to be persisted.

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 the PROFILE_DIR environment variable based on the feature flag. This approach might not be optimal. We need to explore better ways to pass the path.
  • Feature Flag and UDL Integration:
    • This version just compiles a different UDL, depending on the keydb feature flag. I bet there is a better way?
  • Further Implementation in ManagedLoginStore:
    • Functions still need to be implemented (this concerns Arc handling):
      • reset
      • register_with_sync_manager
      • create_logins_sync_engine
  • Naming of ManagedStore:
    • We might want to consider a better name for the ManagedStore struct.
  • Architecture Review:
    • The architecture and code structure implemented here should be reviewed and discussed.
  • Abstraction of Key Management:
    • The LoginStore should be modified to accept a LoginManager trait implementation, allowing key management to be abstracted

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
  • 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.
  • 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-commenter
Copy link

codecov-commenter commented Sep 3, 2024

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.

Files with missing lines Patch % Lines
...mponents/support/rc_crypto/nss/src/pk11/sym_key.rs 0.00% 89 Missing ⚠️
components/logins/src/managed_store.rs 0.00% 67 Missing ⚠️
components/support/rc_crypto/nss/src/util.rs 0.00% 31 Missing ⚠️
components/support/rc_crypto/nss/src/pk11/slot.rs 0.00% 3 Missing ⚠️
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     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jo jo force-pushed the managed-login-store branch 4 times, most recently from cf850b8 to efc9553 Compare September 4, 2024 10:56
Copy link
Member

@mhammond mhammond left a comment

Choose a reason for hiding this comment

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

This is great - maybe we could lean into it further :)

Note that only makes sense once you are actually moving ahead rather than exploring.

The existing sig for mobile is, eg:

pub fn update(&self, id: &str, entry: LoginEntry, enc_key: &str)

where you have removed that key. Which is much better for a public api.

Alternatively, we could have, say

trait KeyStore { ... } - there would be a few options for what this should do, but it could start with just get_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)

Or really, it seems like EncryptorDecryptor could be a trait?

We could probably change many rust signatures here but avoid a breaking change for consumers by updating the wrappers.

There would be a few hiccups, but we might be able to end up with a great api that we can use everywhere. But as above, that's more for once you lean into this :)

* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

namespace logins {
Copy link
Member

Choose a reason for hiding this comment

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

we are very very close to being able to use procmacros, which would remove the need for all this duplication :)

@bendk
Copy link
Contributor

bendk commented Sep 5, 2024

trait KeyStore { ... } - there would be a few options for what this should do, but it could start with just get_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.

@jo jo force-pushed the managed-login-store branch 3 times, most recently from 55d752c to 6387e2b Compare September 10, 2024 09:29
Run the test via
```
cd components/logins
mkdir profile
PROFILE_DIR=profile cargo test test_managed_store::test_general --features keydb
```
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.

4 participants