Fix https://github.com/status-im/nim-beacon-chain/issues/1701 + raise concerns in keystore secrets protection (#1726)

This commit is contained in:
Mamy Ratsimbazafy 2020-09-24 07:27:56 +02:00 committed by GitHub
parent d7bfef3c78
commit 4e23b0ef23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 16 deletions

View File

@ -6,10 +6,13 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
math, strutils, strformat, typetraits, algorithm,
# Standard library
std/[math, strutils, parseutils, strformat, typetraits, algorithm],
# Status libraries
stew/[results, byteutils, bitseqs, bitops2], stew/shims/macros,
bearssl, eth/keyfile/uuid, blscurve, faststreams/textio, json_serialization,
nimcrypto/[sha2, rijndael, pbkdf2, bcmode, hash, utils, scrypt],
# Internal
./datatypes, ./crypto, ./digest, ./signatures
export
@ -202,24 +205,34 @@ const
static:
doAssert englishWords.len == wordListLen
iterator pathNodesImpl(path: string): Natural
{.raises: [ValueError].} =
for elem in path.split("/"):
if elem == "m": continue
yield parseInt(elem)
func append*(path: KeyPath, pathNode: Natural): KeyPath =
KeyPath(path.string & "/" & $pathNode)
func validateKeyPath*(path: TaintedString): KeyPath
{.raises: [ValueError].} =
for elem in pathNodesImpl(path.string): discard elem
KeyPath path
func validateKeyPath*(path: TaintedString): Result[KeyPath, cstring] =
var digitCount: int
var number: BiggestUint
try:
for elem in path.string.split("/"):
# TODO: doesn't "m" have to be the first character and is it the only place where it is valid?
if elem == "m":
continue
# parseBiggestUInt can raise if overflow
digitCount = elem.parseBiggestUInt(number)
if digitCount == 0:
return err("Invalid derivation path")
except ValueError:
return err("KeyPath contains invalid number(s)")
return ok(KeyPath path)
iterator pathNodes(path: KeyPath): Natural =
# TODO: we have exceptions there
# and this iterator is used to derive secret keys
# if we fail we want to scrub secrets from memory
try:
for elem in pathNodesImpl(path.string):
yield elem
for elem in path.string.split("/"):
if elem == "m": continue
yield parseBiggestUInt(elem)
except ValueError:
doAssert false, "Make sure you've validated the key path with `validateKeyPath`"
@ -340,6 +353,10 @@ proc deriveChildKey*(masterKey: ValidatorPrivKey,
path: KeyPath): ValidatorPrivKey =
result = masterKey
for idx in pathNodes(path):
# TODO: we have exceptions in pathNodes unless `validateKeyPath`
# was called,
# and this iterator is used to derive secret keys
# if we fail we want to scrub secrets from memory
result = deriveChildKey(result, idx)
proc keyFromPath*(mnemonic: Mnemonic,
@ -619,4 +636,3 @@ proc prepareDeposit*(preset: RuntimePreset,
res.signature = preset.get_deposit_signature(res, signingKey)
return res

View File

@ -123,7 +123,7 @@ suiteReport "Keystore":
KeystorePass password,
salt=salt, iv=iv,
description = "This is a test keystore that uses PBKDF2 to secure the secret.",
path = validateKeyPath "m/12381/60/0/0")
path = validateKeyPath("m/12381/60/0/0").expect("Valid Keypath"))
var
encryptJson = parseJson Json.encode(keystore)
pbkdf2Json = parseJson(pbkdf2Vector)
@ -137,7 +137,7 @@ suiteReport "Keystore":
KeystorePass password,
salt=salt, iv=iv,
description = "This is a test keystore that uses scrypt to secure the secret.",
path = validateKeyPath "m/12381/60/3141592653/589793238")
path = validateKeyPath("m/12381/60/3141592653/589793238").expect("Valid keypath"))
var
encryptJson = parseJson Json.encode(keystore)
scryptJson = parseJson(scryptVector)