tendermint / tmkms

Key Management service for Tendermint Validator nodes
Apache License 2.0
140 stars 45 forks source link

YubiHSM2 Provisioning ("tmkms yubihsm setup") #174

Closed tarcieri closed 5 years ago

tarcieri commented 5 years ago

This is a tracking issue for building YubiHSM2 provisioning functionality directly into tmkms.

Design

The YubiHSM2 provides the following functionality, which this proposal intends to leverage:

This proposal seeks to leverage all of the above by creating a number of roles which each have fine-grained capabilities.

The basic workflow:

Roles

The following are the suggested "roles" (i.e. access control levels) which will be provisioned in the YubiHSM2. These are loosely based off operational practices for other HSMs.

The specific lists of capabilities are intentionally not enumerated here and are open for debate. I'd be particularly curious to hear people's thoughts on what capabilities operators should have.

Key Derivation

The proposed key derivation scheme follows BIP39, generating a root derivation secret and encoding it using the BIP39 wordlist as a recovery phrase, and deterministically generating the passwords of the other roles from the master phrase.

This proposal suggests using that root phrase for the admin password. Since the admin password confers absolute authority, deriving the passwords to more constrained accounts from it poses little security risk.

Both the YubiHSM2 and BIP39 hash the password using PBKDF2 to derive keys from it. Though PBKDF2 is not a particularly good password-based KDF, the input phrase will be high entropy, therefore obviating the benefits of using a stronger password-hashing algorithm (e.g. Argon2). For parsimony's sake, the suggested approach is to use PBKDF2 for key derivation in compliance with the existing Yubico tooling and BIP39.

Deriving passwords for the other roles can be accomplished using [BIP32] hardened derivation. Alternatively, HKDF could be used, as it is a standard cryptographic primitive for this purpose.

Briefly foregoing the selection of a specific KDF primitive, we can assume the following abstractly:

Given this, the "raw" passwords for the other roles can be deterministically derived as follows, possibly with an additional version "tweak" to allow subsequent passwords to be generated if the initial one is exposed:

ikm = PBKDF(admin_password)
operator_password_raw = KDF(ikm, "v0 operator password domain separation string")
validator_password_raw = KDF(ikm, "v0 validator password domain separation string")
auditor_password_raw = KDF(ikm, "v0 auditor password domain separation string")

(Note: The v0 above could just as easily be a parameter in a [BIP49] derivation path)

There are a few options for serializing these passwords as text. One is to use the BIP39 method, but this may be overkill to use for each of these passwords. Alternatively they could be serialized as Bech32, which would provide human meaningful prefixes to identify them (e.g. admin-pw-v0, oper-pw-v0, val-pw-v0) and checksums to detect if they are typoed.

Furthermore, we can generate the initial wrap key / KEK using the same method:

wrap_key = KDF(ikm, "v0 wrap key")

This wrap key can be used to backup / export keys from the initial YubiHSM2, and to provision and restore backups on new YubiHSM2s.

In conclusion, I don't have strong opinions about the specifics of the key derivation approach, and would be happy to follow existing precedent. The above is a sketch of how a deterministic derivation scheme could work.

Implementation

Alternatives

The yubihsm-setup utility provides functionality similar to what is described above. The main motivations for building functionality into tmkms are:

tarcieri commented 5 years ago

PR to add yubihsm crate support for low-level provisioning here (WIP):

https://github.com/tendermint/yubihsm-rs/pull/174