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

feat: lockPrivateKeys and unlockPrivateKeys #78

Merged
merged 21 commits into from
Apr 8, 2024

Conversation

andrejborstnik
Copy link
Contributor

Motivation

We want an operational mode, that would allow the wallet using the keychain to keep operating, e.g. keep generating addresses & adding portfolios/accounts, but not allow any signing unless the user reenters their authentication. E.g. block sending until password is entered on the send screen.

What this PR adds

Adds a semi-locked state, which blocks external usage of private keys, but still allows internal usage to generate new public keys. To start using private keys again the keychain needs to be "unlocked". To achieve that securely we force the user to re-add the seeds previously inserted into the keychain, which inherently proves that the user has the permission to view the seeds.

For a use-case where we would also want to remove the seeds from memory for improved security we can use the existing removeAllSeeds instead.

@mvayngrib
Copy link
Collaborator

mvayngrib commented Apr 1, 2024

For a use-case where we would also want to remove the seeds from memory for improved security we can use the existing removeAllSeeds instead.

given we require seeds to be passed in to unlockPrivateKeys, why don't we always use removeAllSeeds instead? (and keep the public master keys). remove privateKeys from memory and only keep the master public keys

@andrejborstnik
Copy link
Contributor Author

For a use-case where we would also want to remove the seeds from memory for improved security we can use the existing removeAllSeeds instead.

given we require seeds to be passed in to unlockPrivateKeys, why don't we always use removeAllSeeds instead? (and keep the public master keys). remove privateKeys from memory and only keep the master public keys

We could keep only the public keys if we wanted - I assume you meant we would derive the master/toplevel public key and derive addresses from that? Should work, but might need a bigger refactor, since right now we derive everything from private keys

@mvayngrib
Copy link
Collaborator

@exodus/slip10 and @exodus/hd-key-slip-10 would need to support derivation without the private key present and we'd need this in lockPrivateKeys:

    for (const seedId in this.#masters) {
      for (const derivationAlgorithm in this.#masters[seedId]) {
        const key = this.#masters[seedId][derivationAlgorithm]
        key.wipePrivateData()
      }
    }

seems safer though 🤔

@andrejborstnik
Copy link
Contributor Author

@exodus/slip10 and @exodus/hd-key-slip-10 would need to support derivation without the private key present and we'd need this in lockPrivateKeys:

    for (const seedId in this.#masters) {
      for (const derivationAlgorithm in this.#masters[seedId]) {
        const key = this.#masters[seedId][derivationAlgorithm]
        key.wipePrivateData()
      }
    }

seems safer though 🤔

@mvayngrib reading the SLIP10 spec it seems that slip10 doesn't support continued derivation of child public keys since each step is hardened https://github.com/satoshilabs/slips/blob/master/slip-0010.md. My understanding is that means that we can continue deriving new addresses on existing xpubs, but could not derive new xpubs for new accounts of new coins.

Similar for BIP32 when we do hardening, child public keys cannot be derived.

Lmk if I am misunderstanding & if you still think it is worth moving forward with the pubkey approach.

features/keychain/module/keychain.js Outdated Show resolved Hide resolved
features/keychain/module/keychain.js Outdated Show resolved Hide resolved
features/keychain/module/keychain.js Show resolved Hide resolved
features/keychain/module/keychain.js Outdated Show resolved Hide resolved
features/keychain/module/keychain.js Outdated Show resolved Hide resolved
features/keychain/module/keychain.js Outdated Show resolved Hide resolved
features/keychain/module/keychain.js Outdated Show resolved Hide resolved
mvayngrib
mvayngrib previously approved these changes Apr 2, 2024
Copy link
Collaborator

@mvayngrib mvayngrib left a comment

Choose a reason for hiding this comment

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

utACK

prob need to export api hasLockedPrivateKeys() (or maybe arePrivateKeysLocked), but separate PR is ok

@andrejborstnik
Copy link
Contributor Author

utACK

prob need to export api hasLockedPrivateKeys() (or maybe arePrivateKeysLocked), but separate PR is ok

Done in 1de6179

mvayngrib
mvayngrib previously approved these changes Apr 2, 2024
@andrejborstnik andrejborstnik force-pushed the andrej/lock-for-private-keys branch from 1de6179 to 58412d5 Compare April 4, 2024 06:54
@andrejborstnik andrejborstnik requested a review from mvayngrib April 4, 2024 07:03
sparten11740
sparten11740 previously approved these changes Apr 4, 2024
features/keychain/module/keychain.js Show resolved Hide resolved
@andrejborstnik andrejborstnik dismissed stale reviews from sparten11740 and mvayngrib via a1d8283 April 4, 2024 07:24
Copy link
Contributor

@kewde kewde left a comment

Choose a reason for hiding this comment

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

My preference goes to moving this locking mechanism into the transaction & message signer modules. "Locking the private keys" will impact every feature and we're not going to change every feature to accommodate this, instead we'll be sticking some callbacks to open up the UI in the transactionSigner and messagSigner to cover all the cases. At which point we can just do it at that level.

@andrejborstnik
Copy link
Contributor Author

andrejborstnik commented Apr 4, 2024

My preference goes to moving this locking mechanism into the transaction & message signer modules. "Locking the private keys" will impact every feature and we're not going to change every feature to accommodate this,

If a feature can use private keys while the keychain is locked for signing then that defeats the purpose of the check. Why would we implement a less secure solution?

instead we'll be sticking some callbacks to open up the UI in the transactionSigner and messagSigner to cover all the cases. At which point we can just do it at that level.

Even if we only added UI support for unlocking in transactionSigner and messageSigner having signing throw for other cases is preferred to it working while the app is supposed to be locked imo. Don't you agree?

@andrejborstnik
Copy link
Contributor Author

hard lock and wipe private keys
cache public keys at the publicKeyProvider level

is that an option for the desired use cases @andrejborstnik ?

No, will clarify on slack

@andrejborstnik andrejborstnik force-pushed the andrej/lock-for-private-keys branch from a1d8283 to 12bb541 Compare April 8, 2024 12:29
@andrejborstnik
Copy link
Contributor Author

re-pushed so that commits are signed (likely pressed the rebase button in UI in the past, which broke that). Can you re-review @mvayngrib (should be no changes)

@andrejborstnik andrejborstnik requested a review from mvayngrib April 8, 2024 12:30
Copy link
Collaborator

@mvayngrib mvayngrib left a comment

Choose a reason for hiding this comment

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

utACK

@mvayngrib mvayngrib merged commit 9753ae9 into master Apr 8, 2024
7 checks passed
@mvayngrib mvayngrib deleted the andrej/lock-for-private-keys branch April 8, 2024 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants