Update Logins API

  • Status: accepted
  • Date: 2021-06-17

Technical Story: #4101

Context and Problem Statement

We no longer want to depend on SQLCipher and want to use SQLite directly for build complexity and concerns over the long term future of the rust bindings. The encryption approach taken by SQLCipher means that in practice, the entire database is decrypted at startup, even if the logins functionality is not interacted with, defeating some of the benefits of using an encrypted database.

The per-field encryption in autofill, which we are planning to replicate in logins, separates the storage and encryption logic by limiting the storage layer to the management of encrypted data. Applying this approach in logins will break the existing validation and deduping code so we need a way to implement per-field encryption while supporting the validation and de-duping behavior.

Decision Drivers

  • Addressing previously identified deficiencies in the logins API while we are breaking the API for the encryption work
  • Continuing to support the existing logins validation and deduping logic
  • Avoiding the implementation of new security approaches that may require additional time and security resources
  • Establishing a standard encyrption approach across components

Considered Options

  • Option 1 - Reduce the API functions that require the encryption key and pass the key to the remaining functions
  • Option 2 - Keep the general shape of the API that is in place now - the app can pass the encryption key at any time to "unlock" the API, and re-lock it at any time, but the API in its entirety is only available when unlocked

Decision Outcome

Chosen Option: "Reduce the API functions that require the encryption key and pass the key to the remaining functions" because it will not require a security review as similar to the approach we have established in the codebase.

Pros and Cons of the Options

Option 1 - Reduce the API functions that require the encryption key and pass the key to the remaining functions

  • Description

    Currently the below logins API functions would require the per-field encryption key:

    Propsed changes:

    • Combine the add and update functions into a new add_or_update function
      • This will allow the removal of consumer code that distinguishes when a login record should be created or updated
      • Note: This function needs the encryption key for the fixup and deduping logic and for continued support of the accurate population of the time_password_changed field
    • Pass the per-field encryption key to the import_multiple function
      • This function will be removed once the Fennec to Fenix migration period ends
    • Remove both the potential_dupes_ignoring_username and check_valid_with_no_dupes from the API
      • Neither function is called in Firefox iOS
      • Android Components uses both to provide validation and de-duping before logins are added or updated so we can eliminate the need to externalize these functions by replicating this logic in the new add_or_update function
    • Create a decrypt_and_fixup_login function that both decrypts a login and performs the validate and fixup logic
      • This will eliminate the need for the get_all, get_by_base_domain, and get_by_id API functions to perform the fixup logic

    Making the above changes will reduce the API functions requiring the encryption key to the following:

    • add_or_update
    • decrypt_and_fixup_login
    • import_multiple
  • Pros

    • Improves the logins API for consumers by combining add/update functionality (see #3899 for details)
    • Removes redundant validation and de-duping logic in consumer code
    • Uses the same encryption model as autofill so there is consistency in our approaches
  • Cons

    • Requires consumer code to both encrypt login fields and pass the encryption key when calling either add_or_update and import_multiple

Option 2 - Implement a different key management approach

  • Description

    Unlike the first option, the publicly exposed login API would only handle decrypted login records and all encryption is internal (which works because we always have the key). Any attempt to use the API will fail as the login records are not encrypted or decrypted if the key is not available.

    Proposed changes:

    • Combine the add and update functions into add_or_update
    • Remove both the potential_dupes_ignoring_username and check_valid_with_no_dupes from the API
  • Pros

    • Prevents the consumer from having to encrypt or decrypt login records
    • Maintains our current fixup and validation approach
    • Improves the logins API for consumers by combining add/update functionality
    • Removes redundant validation and de-duping logic in consumer code
  • Cons

    • Makes us responsible for securing the encryption key and will most likely require a security review