mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 07:58:22 -05:00
Change validator password (#5869)
* Created merge command * Key merging * Merge branch 'master' into db-manage-validators * flag comments * fixed compilation errors * added comment to Merge function * Tested that merging copies keys * Created command to change password for keys * Merge branch 'master' into change-validator-password * Merge branch 'master' into change-validator-password * cleanup after code review * Merge remote-tracking branch 'rkapka/change-validator-password' into change-validator-password * Merge branch 'master' into change-validator-password * Merge branch 'master' into change-validator-password * Merge branch 'master' into change-validator-password * Merge branch 'master' into change-validator-password
This commit is contained in:
@@ -26,10 +26,9 @@ var log = logrus.WithField("prefix", "accounts")
|
||||
|
||||
// DecryptKeysFromKeystore extracts a set of validator private keys from
|
||||
// an encrypted keystore directory and a password string.
|
||||
func DecryptKeysFromKeystore(directory string, password string) (map[string]*keystore.Key, error) {
|
||||
validatorPrefix := params.BeaconConfig().ValidatorPrivkeyFileName
|
||||
func DecryptKeysFromKeystore(directory string, filePrefix string, password string) (map[string]*keystore.Key, error) {
|
||||
ks := keystore.NewKeystore(directory)
|
||||
validatorKeys, err := ks.GetKeys(directory, validatorPrefix, password, true /* warnOnFail */)
|
||||
validatorKeys, err := ks.GetKeys(directory, filePrefix, password, true)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get private key")
|
||||
}
|
||||
@@ -47,10 +46,10 @@ func VerifyAccountNotExists(directory string, password string) error {
|
||||
// First, if the keystore already exists, throws an error as there can only be
|
||||
// one keystore per validator client.
|
||||
ks := keystore.NewKeystore(directory)
|
||||
if _, err := ks.GetKeys(directory, shardWithdrawalKeyFile, password, false /* warnOnFail */); err == nil {
|
||||
if _, err := ks.GetKeys(directory, shardWithdrawalKeyFile, password, false); err == nil {
|
||||
return fmt.Errorf("keystore at path already exists: %s", shardWithdrawalKeyFile)
|
||||
}
|
||||
if _, err := ks.GetKeys(directory, validatorKeyFile, password, false /* warnOnFail */); err == nil {
|
||||
if _, err := ks.GetKeys(directory, validatorKeyFile, password, false); err == nil {
|
||||
return fmt.Errorf("keystore at path already exists: %s", validatorKeyFile)
|
||||
}
|
||||
return nil
|
||||
@@ -158,7 +157,7 @@ func CreateValidatorAccount(path string, passphrase string) (string, string, err
|
||||
|
||||
// PrintPublicAndPrivateKeys uses the passed in path and prints out the public and private keys in that directory.
|
||||
func PrintPublicAndPrivateKeys(path string, passphrase string) error {
|
||||
keystores, err := DecryptKeysFromKeystore(path, passphrase)
|
||||
keystores, err := DecryptKeysFromKeystore(path, params.BeaconConfig().ValidatorPrivkeyFileName, passphrase)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to decrypt keystore keys at path %s", path)
|
||||
}
|
||||
@@ -185,8 +184,8 @@ func DefaultValidatorDir() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// HandleEmptyFlags checks what the set flags are and allows the user to manually enter them if they're empty.
|
||||
func HandleEmptyFlags(cliCtx *cli.Context, confirmPassword bool) (string, string, error) {
|
||||
// HandleEmptyKeystoreFlags checks what the set flags are and allows the user to manually enter them if they're empty.
|
||||
func HandleEmptyKeystoreFlags(cliCtx *cli.Context, confirmPassword bool) (string, string, error) {
|
||||
path := cliCtx.String(flags.KeystorePathFlag.Name)
|
||||
passphrase := cliCtx.String(flags.PasswordFlag.Name)
|
||||
|
||||
@@ -215,6 +214,42 @@ func HandleEmptyFlags(cliCtx *cli.Context, confirmPassword bool) (string, string
|
||||
return path, passphrase, nil
|
||||
}
|
||||
|
||||
// ChangePassword changes the password for all keys located in a keystore.
|
||||
// Password is changed only for keys that can be decrypted using the old password.
|
||||
func ChangePassword(keystorePath string, oldPassword string, newPassword string) error {
|
||||
err := changePasswordForKeyType(
|
||||
keystorePath,
|
||||
params.BeaconConfig().ValidatorPrivkeyFileName,
|
||||
oldPassword,
|
||||
newPassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return changePasswordForKeyType(
|
||||
keystorePath,
|
||||
params.BeaconConfig().WithdrawalPrivkeyFileName,
|
||||
oldPassword,
|
||||
newPassword)
|
||||
}
|
||||
|
||||
func changePasswordForKeyType(keystorePath string, filePrefix string, oldPassword string, newPassword string) error {
|
||||
keys, err := DecryptKeysFromKeystore(keystorePath, filePrefix, oldPassword)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to decrypt keys")
|
||||
}
|
||||
|
||||
keyStore := keystore.NewKeystore(keystorePath)
|
||||
for _, key := range keys {
|
||||
keyFileName := keystorePath + filePrefix + hex.EncodeToString(key.PublicKey.Marshal())[:12]
|
||||
if err := keyStore.StoreKey(keyFileName, key, newPassword); err != nil {
|
||||
return errors.Wrapf(err, "Failed to encrypt key %s with the new password", keyFileName)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// homeDir returns home directory path.
|
||||
func homeDir() string {
|
||||
if home := os.Getenv("HOME"); home != "" {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@@ -62,7 +63,7 @@ func TestHandleEmptyFlags_FlagsSet(t *testing.T) {
|
||||
set.String(flags.KeystorePathFlag.Name, passedPath, "set keystore path")
|
||||
set.String(flags.PasswordFlag.Name, passedPassword, "set keystore password")
|
||||
ctx := cli.NewContext(app, set, nil)
|
||||
path, passphrase, err := HandleEmptyFlags(ctx, false)
|
||||
path, passphrase, err := HandleEmptyKeystoreFlags(ctx, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -74,3 +75,69 @@ func TestHandleEmptyFlags_FlagsSet(t *testing.T) {
|
||||
t.Fatalf("Expected set password to be unchanged, expected %s, received %s", passedPassword, passphrase)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChangePassword_KeyEncryptedWithNewPassword(t *testing.T) {
|
||||
directory := testutil.TempDir() + "/testkeystore"
|
||||
defer func() {
|
||||
if err := os.RemoveAll(directory); err != nil {
|
||||
t.Logf("Could not remove directory: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
oldPassword := "old"
|
||||
newPassword := "new"
|
||||
|
||||
validatorKey, err := keystore.NewKey()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot create new key: %v", err)
|
||||
}
|
||||
ks := keystore.NewKeystore(directory)
|
||||
if err := ks.StoreKey(directory+params.BeaconConfig().ValidatorPrivkeyFileName, validatorKey, oldPassword); err != nil {
|
||||
t.Fatalf("Unable to store key %v", err)
|
||||
}
|
||||
|
||||
if err := ChangePassword(directory, oldPassword, newPassword); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
keys, err := DecryptKeysFromKeystore(directory, params.BeaconConfig().ValidatorPrivkeyFileName, newPassword)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := keys[hex.EncodeToString(validatorKey.PublicKey.Marshal())]; !ok {
|
||||
t.Error("Key not encrypted using the new password")
|
||||
}
|
||||
}
|
||||
|
||||
func TestChangePassword_KeyNotMatchingOldPasswordNotEncryptedWithNewPassword(t *testing.T) {
|
||||
directory := testutil.TempDir() + "/testkeystore"
|
||||
defer func() {
|
||||
if err := os.RemoveAll(directory); err != nil {
|
||||
t.Logf("Could not remove directory: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
oldPassword := "old"
|
||||
newPassword := "new"
|
||||
|
||||
validatorKey, err := keystore.NewKey()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot create new key: %v", err)
|
||||
}
|
||||
ks := keystore.NewKeystore(directory)
|
||||
if err := ks.StoreKey(directory+params.BeaconConfig().ValidatorPrivkeyFileName, validatorKey, "notmatching"); err != nil {
|
||||
t.Fatalf("Unable to store key %v", err)
|
||||
}
|
||||
|
||||
if err := ChangePassword(directory, oldPassword, newPassword); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
keys, err := DecryptKeysFromKeystore(directory, params.BeaconConfig().ValidatorPrivkeyFileName, newPassword)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := keys[hex.EncodeToString(validatorKey.PublicKey.Marshal())]; ok {
|
||||
t.Error("Key incorrectly encrypted using the new password")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ go_library(
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/interop:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//validator/accounts:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts"
|
||||
@@ -73,7 +75,7 @@ func NewKeystore(input string) (KeyManager, string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
keyMap, err := accounts.DecryptKeysFromKeystore(opts.Path, opts.Passphrase)
|
||||
keyMap, err := accounts.DecryptKeysFromKeystore(opts.Path, params.BeaconConfig().ValidatorPrivkeyFileName, opts.Passphrase)
|
||||
if err != nil {
|
||||
return nil, keystoreOptsHelp, err
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ contract in order to activate the validator client`,
|
||||
params.UseMinimalConfig()
|
||||
}
|
||||
|
||||
keystorePath, passphrase, err := accounts.HandleEmptyFlags(cliCtx, true /*confirmPassword*/)
|
||||
keystorePath, passphrase, err := accounts.HandleEmptyKeystoreFlags(cliCtx, true)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not list keys")
|
||||
}
|
||||
@@ -125,7 +125,7 @@ contract in order to activate the validator client`,
|
||||
flags.PasswordFlag,
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
keystorePath, passphrase, err := accounts.HandleEmptyFlags(cliCtx, false /*confirmPassword*/)
|
||||
keystorePath, passphrase, err := accounts.HandleEmptyKeystoreFlags(cliCtx, false)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not list keys")
|
||||
}
|
||||
@@ -135,6 +135,35 @@ contract in order to activate the validator client`,
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "change-password",
|
||||
Description: "changes password for all keys located in a keystore",
|
||||
Flags: []cli.Flag{
|
||||
flags.KeystorePathFlag,
|
||||
flags.PasswordFlag,
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
keystorePath, oldPassword, err := accounts.HandleEmptyKeystoreFlags(cliCtx, false)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not read keystore path and/or the old password")
|
||||
}
|
||||
|
||||
log.Info("Please enter the new password")
|
||||
newPassword, err := cmd.EnterPassword(true, cmd.StdInPasswordReader{})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not read the new password")
|
||||
}
|
||||
|
||||
err = accounts.ChangePassword(keystorePath, oldPassword, newPassword)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Changing password failed")
|
||||
} else {
|
||||
log.Info("Password changed successfully")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user