Skip to content

Commit

Permalink
Abstract generate-root authentication into the strategy interface
Browse files Browse the repository at this point in the history
  • Loading branch information
vishalnayak committed Oct 18, 2019
1 parent ad3f31d commit fed7bcf
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 62 deletions.
81 changes: 19 additions & 62 deletions vault/generate_root.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,28 @@ var (
// create a token upon completion of the generate root process.
type GenerateRootStrategy interface {
generate(context.Context, *Core) (string, func(), error)
authenticate(context.Context, *Core, []byte) error
}

// generateStandardRootToken implements the GenerateRootStrategy and is in
// charge of creating standard root tokens.
type generateStandardRootToken struct{}

func (g generateStandardRootToken) authenticate(ctx context.Context, c *Core, key []byte) error {
switch {
case c.seal.RecoveryKeySupported():
if err := c.seal.VerifyRecoveryKey(ctx, key); err != nil {
return errwrap.Wrapf("recovery key verification failed: {{err}}", err)
}
default:
if err := c.barrier.VerifyMaster(key); err != nil {
return errwrap.Wrapf("master key verification failed: {{err}}", err)
}
}

return nil
}

func (g generateStandardRootToken) generate(ctx context.Context, c *Core) (string, func(), error) {
te, err := c.tokenStore.rootToken(ctx)
if err != nil {
Expand Down Expand Up @@ -294,68 +310,9 @@ func (c *Core) GenerateRootUpdate(ctx context.Context, key []byte, nonce string,
}
}

switch {
case c.seal.RecoveryKeySupported():
// Ensure that the combined recovery key is valid
if err := c.seal.VerifyRecoveryKey(ctx, combinedKey); err != nil {
c.logger.Error("root generation aborted, recovery key verification failed", "error", err)
return nil, err
}
// If we are in recovery mode, then retrieve
// the stored keys and unseal the barrier
if c.recoveryMode {
if !c.seal.StoredKeysSupported() {
c.logger.Error("root generation aborted, recovery key verified but stored keys unsupported")
return nil, errors.New("recovery key verified but stored keys unsupported")
}
masterKeyShares, err := c.seal.GetStoredKeys(ctx)
if err != nil {
return nil, errwrap.Wrapf("unable to retrieve stored keys in recovery mode: {{err}}", err)
}

switch len(masterKeyShares) {
case 0:
return nil, errors.New("seal returned no master key shares in recovery mode")
case 1:
combinedKey = masterKeyShares[0]
default:
combinedKey, err = shamir.Combine(masterKeyShares)
if err != nil {
return nil, errwrap.Wrapf("failed to compute master key in recovery mode: {{err}}", err)
}
}

// Use the retrieved master key to unseal the barrier
if err := c.barrier.Unseal(ctx, combinedKey); err != nil {
c.logger.Error("root generation aborted, recovery operation token verification failed", "error", err)
return nil, err
}
}
default:
switch {
case c.recoveryMode:
// If we are in recovery mode, being able to unseal
// the barrier is how we establish authentication
if err := c.barrier.Unseal(ctx, combinedKey); err != nil {
c.logger.Error("root generation aborted, recovery operation token verification failed", "error", err)
return nil, err
}
default:
if err := c.barrier.VerifyMaster(combinedKey); err != nil {
c.logger.Error("root generation aborted, master key verification failed", "error", err)
return nil, err
}
}
}

// Authentication in recovery mode is successful
if c.recoveryMode {
// Run any post unseal functions that are set
for _, v := range c.postRecoveryUnsealFuncs {
if err := v(); err != nil {
return nil, errwrap.Wrapf("failed to run post unseal func: {{err}}", err)
}
}
if err := strategy.authenticate(ctx, c, combinedKey); err != nil {
c.logger.Error("root generation aborted", "error", err.Error())
return nil, errwrap.Wrapf("root generation aborted: {{err}}", err)
}

// Run the generate strategy
Expand Down
45 changes: 45 additions & 0 deletions vault/generate_root_recovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package vault

import (
"context"
"errors"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/vault/shamir"

"github.com/hashicorp/vault/sdk/helper/base62"
"go.uber.org/atomic"
Expand All @@ -19,6 +22,48 @@ type generateRecoveryToken struct {
token *atomic.String
}

func (g *generateRecoveryToken) authenticate(ctx context.Context, c *Core, key []byte) error {
// If recovery keys are supported, verify the recovery key and fetch the stored keys
if c.seal.RecoveryKeySupported() {
if err := c.seal.VerifyRecoveryKey(ctx, key); err != nil {
return errwrap.Wrapf("recovery key verification failed: {{err}}", err)
}

if !c.seal.StoredKeysSupported() {
return errors.New("recovery key verified but stored keys unsupported")
}

masterKeyShares, err := c.seal.GetStoredKeys(ctx)
if err != nil {
return errwrap.Wrapf("unable to retrieve stored keys: {{err}}", err)
}

switch len(masterKeyShares) {
case 0:
return errors.New("seal returned no master key shares")
case 1:
key = masterKeyShares[0]
default:
key, err = shamir.Combine(masterKeyShares)
if err != nil {
return errwrap.Wrapf("failed to compute master key: {{err}}", err)
}
}
}

if err := c.barrier.Unseal(ctx, key); err != nil {
return errwrap.Wrapf("recovery operation token verification failed: {{err}}", err)
}

for _, v := range c.postRecoveryUnsealFuncs {
if err := v(); err != nil {
return errwrap.Wrapf("failed to run post unseal func: {{err}}", err)
}
}

return nil
}

func (g *generateRecoveryToken) generate(ctx context.Context, c *Core) (string, func(), error) {
id, err := base62.Random(TokenLength)
if err != nil {
Expand Down

0 comments on commit fed7bcf

Please sign in to comment.