Skip to content

Commit

Permalink
Store Hashed Password to Wallet Path (#7295)
Browse files Browse the repository at this point in the history
* store wallet pass on creation
* store wallet hash
* save hash to wallet dir
* initialize wallet hash
* gaz
* imports spacing
* remove mentions of hashed pass from db schema
* simplify the wallet hash code
* comment removal
* Merge branch 'master' into fix-password-override
* pass tests
* test fix
* Merge branch 'fix-password-override' of github.com:prysmaticlabs/prysm into fix-password-override
* remove extraneous printfs
* tests passing
* require auth for create wallet
* gaz
* fix signup logic
* Merge refs/heads/master into fix-password-override
* Merge refs/heads/master into fix-password-override
* Merge refs/heads/master into fix-password-override
* Merge refs/heads/master into fix-password-override
* Merge branch 'master' into fix-password-override
  • Loading branch information
rauljordan authored Sep 22, 2020
1 parent 09640ae commit ba440ab
Show file tree
Hide file tree
Showing 22 changed files with 162 additions and 135 deletions.
7 changes: 5 additions & 2 deletions validator/accounts/v2/accounts_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (p *passwordReader) passwordReaderFunc(file *os.File) ([]byte, error) {
func Test_KeysConsistency_Direct(t *testing.T) {
walletDir, passwordsDir, walletPasswordFile := setupWalletAndPasswordsDir(t)

//Specify the 'initial'/correct password locally to this file for convenience.
// Specify the 'initial'/correct password locally to this file for convenience.
require.NoError(t, ioutil.WriteFile(walletPasswordFile, []byte("Pa$sW0rD0__Fo0xPr"), os.ModePerm))

cliCtx := setupWalletCtx(t, &testWalletConfig{
Expand All @@ -106,7 +106,10 @@ func Test_KeysConsistency_Direct(t *testing.T) {

// Now we change the password to "SecoNDxyzPass__9!@#"
require.NoError(t, ioutil.WriteFile(walletPasswordFile, []byte("SecoNDxyzPass__9!@#"), os.ModePerm))
// OpenWalletOrElseCli() doesn't really 'challenge' the wrong password
w, err = wallet.OpenWalletOrElseCli(cliCtx, CreateAndSaveWalletCli)
require.ErrorContains(t, "wrong password for wallet", err)

require.NoError(t, ioutil.WriteFile(walletPasswordFile, []byte("Pa$sW0rD0__Fo0xPr"), os.ModePerm))
w, err = wallet.OpenWalletOrElseCli(cliCtx, CreateAndSaveWalletCli)
require.NoError(t, err)

Expand Down
2 changes: 1 addition & 1 deletion validator/accounts/v2/accounts_exit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,5 +125,5 @@ func TestPrepareWallet_EmptyWalletReturnsError(t *testing.T) {
})
require.NoError(t, err)
_, _, err = prepareWallet(cliCtx)
assert.ErrorContains(t, "wallet is empty, no accounts to perform voluntary exit", err)
assert.ErrorContains(t, "please recreate your wallet", err)
}
4 changes: 4 additions & 0 deletions validator/accounts/v2/accounts_import.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ func ImportAccountsCli(cliCtx *cli.Context) error {
if err = createDirectKeymanagerWallet(cliCtx.Context, w); err != nil {
return nil, errors.Wrap(err, "could not create keymanager")
}
// We store the hashed password to disk.
if err := w.SaveHashedPassword(cliCtx.Context); err != nil {
return nil, err
}
log.WithField("wallet-path", cfg.WalletCfg.WalletDir).Info(
"Successfully created new wallet",
)
Expand Down
1 change: 1 addition & 0 deletions validator/accounts/v2/wallet/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ go_library(
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_urfave_cli_v2//:go_default_library",
"@org_golang_x_crypto//bcrypt:go_default_library",
],
)

Expand Down
45 changes: 45 additions & 0 deletions validator/accounts/v2/wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@ import (
"github.com/prysmaticlabs/prysm/validator/keymanager/v2/remote"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
"golang.org/x/crypto/bcrypt"
)

var log = logrus.WithField("prefix", "wallet")

const (
// KeymanagerConfigFileName for the keymanager used by the wallet: direct, derived, or remote.
KeymanagerConfigFileName = "keymanageropts.json"
// HashedPasswordFileName for the wallet.
HashedPasswordFileName = "hash"
// DirectoryPermissions for directories created under the wallet path.
DirectoryPermissions = os.ModePerm
// NewWalletPasswordPromptText for wallet creation.
Expand All @@ -38,6 +41,7 @@ const (
WalletPasswordPromptText = "Wallet password"
// ConfirmPasswordPromptText for confirming a wallet password.
ConfirmPasswordPromptText = "Confirm password"
hashCost = 8
)

var (
Expand Down Expand Up @@ -136,6 +140,16 @@ func OpenWalletOrElseCli(cliCtx *cli.Context, otherwise func(cliCtx *cli.Context
false, /* Do not confirm password */
ValidateExistingPass,
)
if fileutil.FileExists(filepath.Join(walletDir, HashedPasswordFileName)) {
hashedPassword, err := fileutil.ReadFileAsBytes(filepath.Join(walletDir, HashedPasswordFileName))
if err != nil {
return nil, err
}
// Compare the wallet password here.
if err := bcrypt.CompareHashAndPassword(hashedPassword, []byte(walletPassword)); err != nil {
return nil, errors.Wrap(err, "wrong password for wallet")
}
}
return OpenWallet(cliCtx.Context, &Config{
WalletDir: walletDir,
WalletPassword: walletPassword,
Expand Down Expand Up @@ -217,6 +231,18 @@ func (w *Wallet) InitializeKeymanager(
if err != nil {
return nil, errors.Wrap(err, "could not initialize direct keymanager")
}
if !fileutil.FileExists(filepath.Join(w.walletDir, HashedPasswordFileName)) {
keys, err := keymanager.FetchValidatingPublicKeys(ctx)
if err != nil {
return nil, err
}
if keys == nil || len(keys) == 0 {
return nil, errors.New("please recreate your wallet with wallet-v2 create")
}
if err := w.SaveHashedPassword(ctx); err != nil {
return nil, errors.Wrap(err, "could not save hashed password to disk")
}
}
case v2keymanager.Derived:
opts, err := derived.UnmarshalOptionsFile(configFile)
if err != nil {
Expand All @@ -230,6 +256,11 @@ func (w *Wallet) InitializeKeymanager(
if err != nil {
return nil, errors.Wrap(err, "could not initialize derived keymanager")
}
if !fileutil.FileExists(filepath.Join(w.walletDir, HashedPasswordFileName)) {
if err := w.SaveHashedPassword(ctx); err != nil {
return nil, errors.Wrap(err, "could not save hashed password to disk")
}
}
case v2keymanager.Remote:
opts, err := remote.UnmarshalOptionsFile(configFile)
if err != nil {
Expand Down Expand Up @@ -375,6 +406,20 @@ func (w *Wallet) WriteEncryptedSeedToDisk(ctx context.Context, encoded []byte) e
return nil
}

// SaveHashedPassword to disk for the wallet.
func (w *Wallet) SaveHashedPassword(ctx context.Context) error {
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(w.walletPassword), hashCost)
if err != nil {
return errors.Wrap(err, "could not generate hashed password")
}
hashFilePath := filepath.Join(w.walletDir, HashedPasswordFileName)
// Write the config file to disk.
if err := ioutil.WriteFile(hashFilePath, hashedPassword, params.BeaconIoConfig().ReadWritePermissions); err != nil {
return errors.Wrap(err, "could not write hashed password for wallet to disk")
}
return nil
}

func readKeymanagerKindFromWalletPath(walletPath string) (v2keymanager.Kind, error) {
walletItem, err := os.Open(walletPath)
if err != nil {
Expand Down
10 changes: 9 additions & 1 deletion validator/accounts/v2/wallet_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,15 @@ func CreateAndSaveWalletCli(cliCtx *cli.Context) (*wallet.Wallet, error) {
return nil, errors.New("a wallet of this type already exists at this location. Please input an" +
" alternative location for the new wallet or remove the current wallet")
}
return CreateWalletWithKeymanager(cliCtx.Context, createWalletConfig)
w, err := CreateWalletWithKeymanager(cliCtx.Context, createWalletConfig)
if err != nil {
return nil, errors.Wrap(err, "could not create wallet with keymanager")
}
// We store the hashed password to disk.
if err := w.SaveHashedPassword(cliCtx.Context); err != nil {
return nil, errors.Wrap(err, "could not save hashed password to database")
}
return w, nil
}

// CreateWalletWithKeymanager specified by configuration options.
Expand Down
9 changes: 7 additions & 2 deletions validator/accounts/v2/wallet_recover.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,17 @@ func RecoverWalletCli(cliCtx *cli.Context) error {
if err != nil {
return errors.Wrap(err, "could not get number of accounts to recover")
}
if _, err := RecoverWallet(cliCtx.Context, &RecoverWalletConfig{
w, err := RecoverWallet(cliCtx.Context, &RecoverWalletConfig{
WalletDir: walletDir,
WalletPassword: walletPassword,
Mnemonic: mnemonic,
NumAccounts: numAccounts,
}); err != nil {
})
if err != nil {
return err
}
// We store the hashed password to disk.
if err := w.SaveHashedPassword(cliCtx.Context); err != nil {
return err
}
log.Infof(
Expand Down
3 changes: 2 additions & 1 deletion validator/accounts/v2/wallet_recover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ func TestRecoverDerivedWallet(t *testing.T) {

ctx := context.Background()
w, err := wallet.OpenWallet(cliCtx.Context, &wallet.Config{
WalletDir: walletDir,
WalletDir: walletDir,
WalletPassword: password,
})
assert.NoError(t, err)

Expand Down
3 changes: 0 additions & 3 deletions validator/db/iface/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,4 @@ type ValidatorDB interface {
// Attester protection related methods.
AttestationHistoryForPubKeys(ctx context.Context, publicKeys [][48]byte) (map[[48]byte]*slashpb.AttestationHistory, error)
SaveAttestationHistoryForPubKeys(ctx context.Context, historyByPubKey map[[48]byte]*slashpb.AttestationHistory) error
// Validator RPC authentication methods.
SaveHashedPasswordForAPI(ctx context.Context, hashedPassword []byte) error
HashedPasswordForAPI(ctx context.Context) ([]byte, error)
}
2 changes: 0 additions & 2 deletions validator/db/kv/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ go_library(
"new_proposal_history.go",
"proposal_history.go",
"schema.go",
"web_api.go",
],
importpath = "github.com/prysmaticlabs/prysm/validator/db/kv",
visibility = ["//validator:__subpackages__"],
Expand All @@ -36,7 +35,6 @@ go_test(
"manage_test.go",
"new_proposal_history_test.go",
"proposal_history_test.go",
"web_api_test.go",
],
embed = [":go_default_library"],
deps = [
Expand Down
1 change: 0 additions & 1 deletion validator/db/kv/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ func NewKVStore(dirPath string, pubKeys [][48]byte) (*Store, error) {
tx,
historicProposalsBucket,
historicAttestationsBucket,
validatorAPIBucket,
newhistoricProposalsBucket,
)
}); err != nil {
Expand Down
6 changes: 0 additions & 6 deletions validator/db/kv/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,4 @@ var (
newhistoricProposalsBucket = []byte("proposal-history-bucket-interchange")
// Validator slashing protection from slashable attestations.
historicAttestationsBucket = []byte("attestation-history-bucket")
// Bucket for storing important information regarding the validator API
// such as a password hash for API authentication.
validatorAPIBucket = []byte("validator-api-bucket")
// Bucket key for retrieving the hashed password used for
// authentication to the validator API.
apiHashedPasswordKey = []byte("hashed-password")
)
29 changes: 0 additions & 29 deletions validator/db/kv/web_api.go

This file was deleted.

26 changes: 0 additions & 26 deletions validator/db/kv/web_api_test.go

This file was deleted.

10 changes: 4 additions & 6 deletions validator/keymanager/v2/derived/derived.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ type SetupConfig struct {
Opts *KeymanagerOpts
Wallet iface.Wallet
SkipMnemonicConfirm bool
WalletPassword string
Mnemonic string
}

Expand Down Expand Up @@ -99,9 +98,8 @@ func NewKeymanager(
// Check if the wallet seed file exists. If it does not, we initialize one
// by creating a new mnemonic and writing the encrypted file to disk.
var encodedSeedFile []byte
cfg.WalletPassword = cfg.Wallet.Password()
if !fileutil.FileExists(filepath.Join(cfg.Wallet.AccountsDir(), EncryptedSeedFileName)) {
seedConfig, err := initializeWalletSeedFile(cfg.WalletPassword, cfg.SkipMnemonicConfirm)
seedConfig, err := initializeWalletSeedFile(cfg.Wallet.Password(), cfg.SkipMnemonicConfirm)
if err != nil {
return nil, errors.Wrap(err, "could not initialize new wallet seed file")
}
Expand Down Expand Up @@ -132,7 +130,7 @@ func NewKeymanager(
return nil, errors.Wrap(err, "could not unmarshal seed configuration")
}
decryptor := keystorev4.New()
seed, err := decryptor.Decrypt(seedConfig.Crypto, cfg.WalletPassword)
seed, err := decryptor.Decrypt(seedConfig.Crypto, cfg.Wallet.Password())
if err != nil {
return nil, errors.Wrap(err, "could not decrypt seed configuration with password")
}
Expand Down Expand Up @@ -162,7 +160,7 @@ func KeymanagerForPhrase(
// Check if the wallet seed file exists. If it does not, we initialize one
// by creating a new mnemonic and writing the encrypted file to disk.
var encodedSeedFile []byte
seedConfig, err := seedFileFromMnemonic(cfg.Mnemonic, cfg.WalletPassword)
seedConfig, err := seedFileFromMnemonic(cfg.Mnemonic, cfg.Wallet.Password())
if err != nil {
return nil, errors.Wrap(err, "could not initialize new wallet seed file")
}
Expand All @@ -174,7 +172,7 @@ func KeymanagerForPhrase(
return nil, errors.Wrap(err, "could not write encrypted wallet seed config to disk")
}
decryptor := keystorev4.New()
seed, err := decryptor.Decrypt(seedConfig.Crypto, cfg.WalletPassword)
seed, err := decryptor.Decrypt(seedConfig.Crypto, cfg.Wallet.Password())
if err != nil {
return nil, errors.Wrap(err, "could not decrypt seed configuration with password")
}
Expand Down
6 changes: 5 additions & 1 deletion validator/rpc/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ go_library(
deps = [
"//proto/validator/accounts/v2:go_default_library",
"//shared/event:go_default_library",
"//shared/fileutil:go_default_library",
"//shared/params:go_default_library",
"//shared/petnames:go_default_library",
"//shared/promptutil:go_default_library",
"//shared/rand:go_default_library",
Expand Down Expand Up @@ -64,6 +66,8 @@ go_test(
"//proto/validator/accounts/v2:go_default_library",
"//shared/bls:go_default_library",
"//shared/event:go_default_library",
"//shared/fileutil:go_default_library",
"//shared/params:go_default_library",
"//shared/testutil:go_default_library",
"//shared/testutil/assert:go_default_library",
"//shared/testutil/require:go_default_library",
Expand All @@ -72,7 +76,7 @@ go_test(
"//validator/client:go_default_library",
"//validator/db/testing:go_default_library",
"//validator/keymanager/v2:go_default_library",
"//validator/keymanager/v2/direct:go_default_library",
"//validator/keymanager/v2/derived:go_default_library",
"@com_github_gogo_protobuf//types:go_default_library",
"@com_github_google_uuid//:go_default_library",
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
Expand Down
8 changes: 4 additions & 4 deletions validator/rpc/accounts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
v2 "github.com/prysmaticlabs/prysm/validator/accounts/v2"
"github.com/prysmaticlabs/prysm/validator/accounts/v2/wallet"
v2keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v2"
"github.com/prysmaticlabs/prysm/validator/keymanager/v2/direct"
"github.com/prysmaticlabs/prysm/validator/keymanager/v2/derived"
)

func TestServer_CreateAccount(t *testing.T) {
Expand All @@ -23,7 +23,7 @@ func TestServer_CreateAccount(t *testing.T) {
w, err := v2.CreateWalletWithKeymanager(ctx, &v2.CreateWalletConfig{
WalletCfg: &wallet.Config{
WalletDir: defaultWalletPath,
KeymanagerKind: v2keymanager.Direct,
KeymanagerKind: v2keymanager.Derived,
WalletPassword: strongPass,
},
SkipMnemonicConfirm: true,
Expand All @@ -50,7 +50,7 @@ func TestServer_ListAccounts(t *testing.T) {
w, err := v2.CreateWalletWithKeymanager(ctx, &v2.CreateWalletConfig{
WalletCfg: &wallet.Config{
WalletDir: defaultWalletPath,
KeymanagerKind: v2keymanager.Direct,
KeymanagerKind: v2keymanager.Derived,
WalletPassword: strongPass,
},
SkipMnemonicConfirm: true,
Expand All @@ -66,7 +66,7 @@ func TestServer_ListAccounts(t *testing.T) {
numAccounts := 5
keys := make([][]byte, numAccounts)
for i := 0; i < numAccounts; i++ {
key, err := km.(*direct.Keymanager).CreateAccount(ctx)
key, err := km.(*derived.Keymanager).CreateAccount(ctx, false /* log account info */)
require.NoError(t, err)
keys[i] = key
}
Expand Down
Loading

0 comments on commit ba440ab

Please sign in to comment.