-
Notifications
You must be signed in to change notification settings - Fork 4
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
Implementing BIP39 recovery, Unattended Bootstrap and Agent Start and Status #283
Conversation
The new keygeneration functions like so.
We don't want to overwrite the keypair with a different one since that will corrupt the keynode. to check if the new keypair matches we can check that the NodeIds match. more importantly we need to check that the keypair matches. Roger mentioned we can do this with a signed message. we can store a message that contains the NodeId and sign that. and verify it with the new recovered keypair. though we need to validate the private key not the public key so we likely need to decrypt the message and check that the NodeID matches. |
Small problem with the |
That makes a worthy candidate for |
@tegefaulkes please update the task list for this PR, copy initial task list from #202 and then expand it as you go along. This is something @joshuakarp can help with tomorrow? |
The keyManager does use the workerManager but that is currently set after creation so I'll need to make some changes to that. Also, will the worker manager actually speed this up at all? I made a checklist in the Issue. I can copy that over here. |
The worker manager will enable other tasks to be done at the same time. But 15s it will still take unless the actual algorithm can be parallelized.
Still good idea to use the worker manager. If you make sure to use ArrayBuffer.
On 1 November 2021 5:55:41 pm AEDT, Brian Botha ***@***.***> wrote:
The keyManager does use the workerManager but that is currently set after creation so I'll need to make some changes to that. Also, will the worker manager actually speed this up at all?
I made a checklist in the Issue. I can copy that over here.
--
You are receiving this because you commented.
Reply to this email directly or view it on GitHub:
#283 (comment)
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.
|
I am now checking the root cert to see if the keyPair generated from a mnemonic matches the node. |
Is this the process you're using?:
I'm assuming then that the certificate is in plaintext, and we can just query the OID fields? |
That pretty much sums it up. |
Looks like It's not so much a problem when using polykey. generating the keypair only happens when creating the keynode or resetting/renewing the keypair. but it's blowing out the KeyManager test times. I need to add an optional keyPair parameter to the createKeyManager so we can override the generation just for testing. |
Will have some changes regarding async-init coming from https://gitlab.com/MatrixAI/Engineering/Polykey/js-polykey/-/merge_requests/213. Will be merging MR 213 prior to this and #266. The CLI is situation is quite messy and has to go through a proper review. So I'm bundling my CLI review with the sessions MR merge. So some of the points discussed with @joshuakarp I'll include in that MR. |
I added the ability to override the keypair generation when starting the KeyManager. this is mainly for testing so we can provide a keyPair generated without the mnemonic to speed up the testing. most tests should run just as fast except for the We do need to see if we can speed up deterministic key generation at all. 15secs is not the end of the world when it only happens when creating a new node but it's still pretty bad. |
While updating the keyPair files doesn't have any locking applied, the function I'm using to do it writes to temp files and then does an atomic rename. this is what's being used already when creating the files and when doing a keyPair renew/reset. However that is expected to be protected by the PolykeyAgent lockfile. so the recovery function still needs to check for that and do it safely. |
Does this PR also apply the env variables to Any other things here to be done? |
Yeah - there's already support for acquiring both password and recovery code on However, I can't seem to see whether the usage of the recovery code has been integrated into pk bootstrap --fresh # bootstrap a new node state
# this we can do later
pk recover --recovery-code-file=./rcf --password-file=./pf # just recovers the key (but doesn't start the agent)
# FOR: empty node state
# deterministic node state generation
pk agent start --recovery-code-file=./rcf
# should also be done with bootstrapping
pk bootstrap --recovery-code-file=./rcf
# generate key pair, and then set the password
pk agent start --recovery-code-file=./rcf --password-file=./pf
# should also be done with bootstrapping
pk bootstrap --recovery-code-file=./rcf --password-file=./pf
# FOR: non-empty node state
# generate a keypair deterministically, check if the public key is correct, and if so, prompt for password (this is the new password)
pk agent start --recovery-code-file=./rcf
# unnecessary for pk bootstrap - only occurs on empty node state
# recover the key pair, if the public key is correct, set the password
pk agent start --recovery-code-file=./rcf --password-file=./pf
# unnecessary for pk bootstrap - only occurs on empty node state
# the --fresh option ignores existing state (but not any existing lock)
pk agent start --recovery-code-file=./rcf --password-file=./pf --fresh
# should also be done with bootstrapping - force renewal (fails if agent running)
pk bootstrap --recovery-code-file=./rcf --password-file=./pf --fresh Originally from #202 (comment) @tegefaulkes am I missing this somewhere? Still in process of reviewing. |
I'm looking at it and fixing it now. |
I had to do a small fix to it, but it's getting the env variables at line 54 const password = await binUtils.getPassword(options.passwordFile);
const recoveryCode = await binUtils.getRecoveryCode(options.recoveryFile);
const fresh = !!options.fresh; |
The |
I've added |
I came across a situation where if we had structured error logging we would better see what the problem is... Right now starting in the background with {"name":"ErrorRootKeysParse","description":"Polykey error","message":"Only 8, 16, 24, or 32 bits supported: 888","exitCode":1,"data":{},"stack":"ErrorRootKeysParse: Only 8, 16, 24, or 32 bits supported: 888\n at Object.readRootKeyPair (/home/cmcdragonkai/Projects/js-polykey/src/keys/KeyManager.ts:665:13)\n at async Object.setupRootKeyPair (/home/cmcdragonkai/Projects/js-polykey/src/keys/KeyManager.ts:597:23)\n at async Object.start (/home/cmcdragonkai/Projects/js-polykey/src/keys/KeyManager.ts:164:35)\n at async Object.start (/home/cmcdragonkai/Projects/js-polykey/node_modules/@matrixai/async-init/src/CreateDestroyStartStop.ts:75:20)\n at async Function.createKeyManager (/home/cmcdragonkai/Projects/js-polykey/src/keys/KeyManager.ts:90:5)\n at async Function.createPolykeyAgent (/home/cmcdragonkai/Projects/js-polykey/src/PolykeyAgent.ts:169:8)\n at async main (/home/cmcdragonkai/Projects/js-polykey/src/bin/polykey-agent.ts:49:15)\n at async /home/cmcdragonkai/Projects/js-polykey/src/bin/polykey-agent.ts:128:5"} |
The reason is because this was missing: const nodePath = new commander.Option(
'-np, --node-path <path>',
'Path to Node State',
).env('PK_NODE_PATH')
.default(config.defaults.nodePath); So it was attempting to use the |
This means this |
It'd be worthwhile to do a whole review of the error message displays as a whole when we get to that stage. There's similar ambiguities with thrown exceptions that wouldn't necessarily correlate to the actions of a user (e.g. |
Accidentally wrote the |
…nd and concurrent coalescing, propagate log level to background agent
Pushed up my latest test fixes for |
Current state now:
|
The pk agent tests are getting pretty comprehensive now. I think a few other ones:
I'll fix up the bootstrap tests too, and then this will be merged. All other test issues are to be fixed in downstream PRs. |
I actually reversed this decision. This does make sense for the I've also added the |
Instead of having a separate test for each signal, I've just embedded them into each individual test to save some time. So some tests I'm using SIGTERM, another SIGINT... etc. |
…upted start and bootstrap tests
While testing the recovery code system, I came across a problem. If the root key already exists, and the recovery code is passed in. The way we check if our recovery code is correct is by doing:
But this relies on the If the user selected a different bit size, they would have to remember the bit size and the recovery code together. Instead of doing this, we need to instead save the bit size, or derive it from the saved public key. Another problem with this mechanism is that if the root key files is in fact lost, and not just the password was forgotten, then this actually goes into generating a new root key pair, which would then be attempted to be used to decrypt the other key files like the db key and the vault key. In this scenario, if the recovery code is in fact wrong, then it would generate the wrong root key pair, and there would likely to be a decryption failure that occurs with the db key or vault key subsequently. This of course requires that both db key and vault key still exist on the filesystem. In #164 an old issue, we explored the idea of hierarchical keys. This basically means the seed (recovery code) is used to generate all the keys in a hierarchical way which means we can recover all keys. However right now db keys and vault keys are just random separated keys, so the recovery code has limited utility. We'll have to address this later. So basically the issue is that:
|
Turns out by reading the public key pem, we can acquire the public key bit size using our utility function that we already have in function publicKeyBitSize(publicKey: PublicKey): number {
return publicKey.n.bitLength();
} |
This is solved by using the above function and having a protected method called |
|
…it size from existing key pair, and using testBinUtils.processExit
Bootstrap tests all done:
Important that when testing concurrent work, do not use |
Both agent/start tests and bootstrap tests are passing. The only thing left is the additional agent subcommands to be refactored in This is being merged now! @joshuakarp @emmacasolin rebase on top of master! |
FYI @CMCDragonkai running
|
And the same on my own laptop:
|
Ah great that timing is the same as mine. |
Description
This PR adds in the BIP39 recovery seed functionality
Issues Fixed
pk agent start
andpk bootstrap
withPK_RECOVERY_CODE
andPK_PASSWORD
#202pk agent start
#286checklist
generateKeyPair
to use the worker manager properlly.KeyManager
for each tests, it's too slow.recoverKeyManager
respects lockfile.PolykeyAgent.createPolykeyAgent
to do faster keypair generation to speed up tests.Status
domain for replacing the agent locking mechanism based on theSession
in https://gitlab.com/MatrixAI/Engineering/Polykey/js-polykey/-/merge_requests/213starting
,running
andstopping
status to the info.Status
tests to match the new API, make sure to test all the relevant error conditions as well as thewaitFor
functionStatus
into thebootstrapState
inbootstrap/utils.ts
bootstrap
tests with the newbootstrapState
functionbeforeAll
. This means allkeyPair
override parameters PLUSkeyPair
environment variables are not neededmnemonic
torecoveryCode
.bootstrapState
can be called in the CLI process and therefore not require process IPC to communicate the recovery key being used. However this only works withpk bootstrap
and notpk agent start
. If we usepk agent start
, thenbootstrapState
again can be used at the CLI process instead, but when callingpk agent start
, it will be essential to run it with the root password that was used. This can eliminate any usage of child process IPC, and simplify our execution stack, and means our code will be more portable.parseFilePath
Implementing BIP39 recovery, Unattended Bootstrap and Agent Start and Status #283 (comment)ErrorCLIFileRead
for general file reading Implementing BIP39 recovery, Unattended Bootstrap and Agent Start and Status #283 (comment)finally
clause and the exit handler registration forpkClient
usage[ ] Use jest mocking on child process fork so that it actually uses- not required due to usingts-node
directly when executingpolykeyAgent.ts
pkSpawn
ExitHandler
when usingsrc/polykey.ts
Final checklist
Review checklist
pk agent start
andpk bootstrap
withPK_RECOVERY_CODE
andPK_PASSWORD
#202 and Host and port binding environment variables forpk agent start
#286)TODOs
/FIXMEs
? If so, comment to contributor to move them to an issue