Block 1 from #194 (comment)
Aims to provide support for a Polykey instance to run unattended (i.e. without user prompt) when both the PK_RECOVERY_CODE and PK_PASSWORD variables are set.
Requirements of this design
- User has to supply a root password in order to encrypt a root key that is automatically generated
- If the user loses or forgets the root password, there is no way to decrypt the root key, there is no "Forget Password" functionality for decentralised application
- Provider an alternative way of recovering the root key
- The alternative is to store a BIP39 seed phrase that is used to generate the root key. If the user can supply a BIP39 seed phrase, this can be used to deterministically generate the root key, which doesn't require decrypting the root key and thus unlocking the keynode
- In an extreme case, the root key ciphertext file on disk is corrupted, and so decrypting it produces an incorrect root key, the seed phrase represents a backup of the root key
- Users must be notified to securely backup/store their root key, offer users to print it out as a "paper key" (like https://www.jabberwocky.com/software/paperkey/, we can even do funny things like QR codes)
Additional context
Note that the core function to generate a root key from a BIP39 seed is already available in our keys/utils.ts, see the function: generateDeterministicKeyPair. However it is not currently used by KeyManager, and not well tested.
Screenshot from Figma GUI design:

Specification
- Get the KeyManager to use the
generateDeterministicKeyPair
- Make sure that this function
generateDeterministicKeyPair is well tested
- Users are presented with a 24 word phrase to store and remember (prompt the user to store/print it)
- During the startup of the PK agent, the user has to supply the root password OR the seed phrase
- During session unlock, the user can supply the root password OR the seed phrase
- When a seed phrase is supplied, the root key is regenerated from the seed phrase, the root key ciphertext is not touched
- We must have a root key acceptance condition to know whether the root key has legitmately opened up a vault
- If it has, we can save/rewrite the root key as ciphertext over the ciphertext in the node state, which will resolve any root key ciphertext corruption
Regarding the root key acceptance, consider this idea:
- Create a signed-message
- Encrypt the message and save the message
- If you can later decrypt the message, and check the the signature was signed by the root key and the message is what you expect
- Then the root key is correct!
- This message will need to be stored in the DB (as this is what is decrypted by the root key)
CLI command variables
Variables for CLI commands can be retrieved from:
- file parameters
- environment variables
src/config.ts
- user prompt in STDIN
We require functions to retrieve the variables from each of these locations (created in src/bin/utils).
Variable precedence should be as follows: file parameters > environment variables/src/config.ts > default (STDIN prompt). We can use a sequence of coalescing operations to emulate this: for example, to retrieve the password, password = getFromParams() ?? getFromEnv ?? getFromStdin(). getFromStdin() here is expected to be the default, where we assume that a value will always be provided. If a default cannot exist for a particular variable, then throw an exception if none of the sources of variables can produce one.
See point 1 at #202 (comment) for further information.
Bootstrap process
Some components of the bootstrapping process need to be simplified:
Sub-Issues & Sub-PRs created
#283
checklist
Block 1 from #194 (comment)
Aims to provide support for a Polykey instance to run unattended (i.e. without user prompt) when both the
PK_RECOVERY_CODEandPK_PASSWORDvariables are set.Requirements of this design
Additional context
pki.rsa.generateKeyPairdigitalbazaar/forge#865Note that the core function to generate a root key from a BIP39 seed is already available in our
keys/utils.ts, see the function:generateDeterministicKeyPair. However it is not currently used by KeyManager, and not well tested.Screenshot from Figma GUI design:
Specification
generateDeterministicKeyPairgenerateDeterministicKeyPairis well testedRegarding the root key acceptance, consider this idea:
CLI command variables
Variables for CLI commands can be retrieved from:
src/config.tsWe require functions to retrieve the variables from each of these locations (created in
src/bin/utils).Variable precedence should be as follows: file parameters > environment variables/
src/config.ts> default (STDIN prompt). We can use a sequence of coalescing operations to emulate this: for example, to retrieve the password,password = getFromParams() ?? getFromEnv ?? getFromStdin().getFromStdin()here is expected to be the default, where we assume that a value will always be provided. If a default cannot exist for a particular variable, then throw an exception if none of the sources of variables can produce one.See point 1 at #202 (comment) for further information.
Bootstrap process
Some components of the bootstrapping process need to be simplified:
bootstrapPolykeyState(see 3 Enable un-attended bootstrapping forpk agent startandpk bootstrapwithPK_RECOVERY_CODEandPK_PASSWORD#202 (comment))writeTokeninSession.ts- discuss with @CMCDragonkaicheckKeynodeState(see 4 Enable un-attended bootstrapping forpk agent startandpk bootstrapwithPK_RECOVERY_CODEandPK_PASSWORD#202 (comment))nodePath: if any state exists besides the lockfile, throw an exceptionSub-Issues & Sub-PRs created
#283
checklist
bin/utilsfunctions for variable retrievalgetFromParams(): get variable from file parameter. Usestr.trim()to remove trailing newlines/whitespace from the file (see 2 at Enable un-attended bootstrapping forpk agent startandpk bootstrapwithPK_RECOVERY_CODEandPK_PASSWORD#202 (comment) for further information) ~~getFromEnv(): get variable from environment variablegetFromConfig(): get variable fromsrc/config.tsgetFromStdin(): get variable from user promptbinUtils.getPasswordandbinUtils.getRecoveryCode. options for hosts and ports was created insrc/bin/options.tswith their own defaults and env.bootstrapprocessbootstrapPolykeyState2x pk bootstrap2x pk agent startpk bootstrap+pk agent startcheckKeynodeState--freshflag: forces new keynode state, even if it already existspk agent startpk bootstrap