2016-01-14 22:01:04 +00:00
package vault
import (
"bytes"
2018-01-19 06:44:44 +00:00
"context"
2018-05-18 01:17:52 +00:00
"crypto/subtle"
2016-01-14 22:01:04 +00:00
"encoding/hex"
"encoding/json"
"fmt"
2018-05-20 03:43:48 +00:00
"net/http"
2016-01-14 22:01:04 +00:00
2018-04-05 15:49:21 +00:00
"github.com/hashicorp/errwrap"
2019-01-09 00:48:57 +00:00
uuid "github.com/hashicorp/go-uuid"
2017-02-16 20:15:02 +00:00
"github.com/hashicorp/vault/helper/consts"
2016-07-06 16:25:40 +00:00
"github.com/hashicorp/vault/helper/jsonutil"
2016-01-14 22:01:04 +00:00
"github.com/hashicorp/vault/helper/pgpkeys"
2018-05-20 03:43:48 +00:00
"github.com/hashicorp/vault/logical"
2016-01-14 22:01:04 +00:00
"github.com/hashicorp/vault/physical"
"github.com/hashicorp/vault/shamir"
)
2016-04-04 14:44:22 +00:00
const (
2018-03-20 18:54:10 +00:00
// coreUnsealKeysBackupPath is the path used to backup encrypted unseal
2016-04-04 14:44:22 +00:00
// keys if specified during a rekey operation. This is outside of the
// barrier.
coreBarrierUnsealKeysBackupPath = "core/unseal-keys-backup"
2018-03-20 18:54:10 +00:00
// coreRecoveryUnsealKeysBackupPath is the path used to backup encrypted
2016-04-04 14:44:22 +00:00
// recovery keys if specified during a rekey operation. This is outside of
// the barrier.
coreRecoveryUnsealKeysBackupPath = "core/recovery-keys-backup"
)
2016-01-14 22:01:04 +00:00
// RekeyResult is used to provide the key parts back after
// they are generated as part of the rekey.
type RekeyResult struct {
2018-05-18 01:17:52 +00:00
SecretShares [ ] [ ] byte
PGPFingerprints [ ] string
Backup bool
RecoveryKey bool
VerificationRequired bool
VerificationNonce string
}
type RekeyVerifyResult struct {
2018-05-22 00:54:20 +00:00
Complete bool
Nonce string
2016-01-14 22:01:04 +00:00
}
// RekeyBackup stores the backup copy of PGP-encrypted keys
type RekeyBackup struct {
Nonce string
Keys map [ string ] [ ] string
}
2017-10-23 18:59:37 +00:00
// RekeyThreshold returns the secret threshold for the current seal
// config. This threshold can either be the barrier key threshold or
// the recovery key threshold, depending on whether rekey is being
// performed on the recovery key, or whether the seal supports
// recovery keys.
2018-05-20 03:43:48 +00:00
func ( c * Core ) RekeyThreshold ( ctx context . Context , recovery bool ) ( int , logical . HTTPCodedError ) {
2016-04-04 14:44:22 +00:00
c . stateLock . RLock ( )
defer c . stateLock . RUnlock ( )
2018-07-24 20:57:25 +00:00
if c . Sealed ( ) {
2018-05-20 03:43:48 +00:00
return 0 , logical . CodedError ( http . StatusServiceUnavailable , consts . ErrSealed . Error ( ) )
2016-04-04 14:44:22 +00:00
}
if c . standby {
2018-05-20 03:43:48 +00:00
return 0 , logical . CodedError ( http . StatusBadRequest , consts . ErrStandby . Error ( ) )
2016-04-04 14:44:22 +00:00
}
c . rekeyLock . RLock ( )
defer c . rekeyLock . RUnlock ( )
var config * SealConfig
var err error
2017-10-23 18:59:37 +00:00
// If we are rekeying the recovery key, or if the seal supports
// recovery keys and we are rekeying the barrier key, we use the
// recovery config as the threshold instead.
2018-01-19 08:44:06 +00:00
if recovery || c . seal . RecoveryKeySupported ( ) {
2018-01-19 06:44:44 +00:00
config , err = c . seal . RecoveryConfig ( ctx )
2016-04-04 14:44:22 +00:00
} else {
2018-01-19 06:44:44 +00:00
config , err = c . seal . BarrierConfig ( ctx )
2016-04-04 14:44:22 +00:00
}
if err != nil {
2018-05-20 03:43:48 +00:00
return 0 , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "unable to look up config: {{err}}" , err ) . Error ( ) )
}
if config == nil {
return 0 , logical . CodedError ( http . StatusBadRequest , ErrNotInit . Error ( ) )
2016-04-04 14:44:22 +00:00
}
return config . SecretThreshold , nil
}
2017-10-23 18:59:37 +00:00
// RekeyProgress is used to return the rekey progress (num shares).
2018-05-28 04:39:53 +00:00
func ( c * Core ) RekeyProgress ( recovery , verification bool ) ( bool , int , logical . HTTPCodedError ) {
2016-01-14 22:01:04 +00:00
c . stateLock . RLock ( )
defer c . stateLock . RUnlock ( )
2018-07-24 20:57:25 +00:00
if c . Sealed ( ) {
2018-05-28 04:39:53 +00:00
return false , 0 , logical . CodedError ( http . StatusServiceUnavailable , consts . ErrSealed . Error ( ) )
2016-01-14 22:01:04 +00:00
}
if c . standby {
2018-05-28 04:39:53 +00:00
return false , 0 , logical . CodedError ( http . StatusBadRequest , consts . ErrStandby . Error ( ) )
2016-01-14 22:01:04 +00:00
}
2016-04-04 14:44:22 +00:00
c . rekeyLock . RLock ( )
defer c . rekeyLock . RUnlock ( )
2018-05-21 21:46:32 +00:00
var conf * SealConfig
2016-04-04 14:44:22 +00:00
if recovery {
2018-05-21 21:46:32 +00:00
conf = c . recoveryRekeyConfig
} else {
conf = c . barrierRekeyConfig
2016-04-04 14:44:22 +00:00
}
2016-01-14 22:01:04 +00:00
2018-05-28 04:39:53 +00:00
if conf == nil {
return false , 0 , logical . CodedError ( http . StatusBadRequest , "rekey operation not in progress" )
}
2018-05-21 21:46:32 +00:00
if verification {
2018-05-28 04:39:53 +00:00
return len ( conf . VerificationKey ) > 0 , len ( conf . VerificationProgress ) , nil
2018-05-18 01:17:52 +00:00
}
2018-05-28 04:39:53 +00:00
return true , len ( conf . RekeyProgress ) , nil
2018-05-18 01:17:52 +00:00
}
2016-01-14 22:01:04 +00:00
// RekeyConfig is used to read the rekey configuration
2018-05-20 03:43:48 +00:00
func ( c * Core ) RekeyConfig ( recovery bool ) ( * SealConfig , logical . HTTPCodedError ) {
2016-01-14 22:01:04 +00:00
c . stateLock . RLock ( )
defer c . stateLock . RUnlock ( )
2018-07-24 20:57:25 +00:00
if c . Sealed ( ) {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusServiceUnavailable , consts . ErrSealed . Error ( ) )
2016-01-14 22:01:04 +00:00
}
if c . standby {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , consts . ErrStandby . Error ( ) )
2016-01-14 22:01:04 +00:00
}
c . rekeyLock . Lock ( )
defer c . rekeyLock . Unlock ( )
// Copy the seal config if any
var conf * SealConfig
2016-04-04 14:44:22 +00:00
if recovery {
if c . recoveryRekeyConfig != nil {
conf = c . recoveryRekeyConfig . Clone ( )
}
} else {
if c . barrierRekeyConfig != nil {
conf = c . barrierRekeyConfig . Clone ( )
}
2016-01-14 22:01:04 +00:00
}
2016-04-04 14:44:22 +00:00
2016-01-14 22:01:04 +00:00
return conf , nil
}
2017-10-23 18:59:37 +00:00
// RekeyInit will either initialize the rekey of barrier or recovery key.
// recovery determines whether this is a rekey on the barrier or recovery key.
2018-05-20 03:43:48 +00:00
func ( c * Core ) RekeyInit ( config * SealConfig , recovery bool ) logical . HTTPCodedError {
2018-05-29 22:38:14 +00:00
if config . SecretThreshold > config . SecretShares {
return logical . CodedError ( http . StatusBadRequest , "provided threshold greater than the total shares" )
}
2016-04-04 14:44:22 +00:00
if recovery {
2018-01-19 08:44:06 +00:00
return c . RecoveryRekeyInit ( config )
2016-04-04 14:44:22 +00:00
}
2018-01-19 08:44:06 +00:00
return c . BarrierRekeyInit ( config )
2016-04-04 14:44:22 +00:00
}
// BarrierRekeyInit is used to initialize the rekey settings for the barrier key
2018-05-20 03:43:48 +00:00
func ( c * Core ) BarrierRekeyInit ( config * SealConfig ) logical . HTTPCodedError {
2018-05-29 17:13:47 +00:00
if c . seal . StoredKeysSupported ( ) {
c . logger . Warn ( "stored keys supported, forcing rekey shares/threshold to 1" )
config . SecretShares = 1
config . SecretThreshold = 1
config . StoredShares = 1
}
2016-04-04 14:44:22 +00:00
if config . StoredShares > 0 {
2018-01-19 08:44:06 +00:00
if ! c . seal . StoredKeysSupported ( ) {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusBadRequest , "storing keys not supported by barrier seal" )
2016-04-04 14:44:22 +00:00
}
if len ( config . PGPKeys ) > 0 {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusBadRequest , "PGP key encryption not supported when using stored keys" )
2016-04-04 14:44:22 +00:00
}
if config . Backup {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusBadRequest , "key backup not supported when using stored keys" )
2016-04-04 14:44:22 +00:00
}
2018-05-20 04:02:45 +00:00
if c . seal . RecoveryKeySupported ( ) {
if config . VerificationRequired {
return logical . CodedError ( http . StatusBadRequest , "requiring verification not supported when rekeying the barrier key with recovery keys" )
}
c . logger . Debug ( "using recovery seal configuration to rekey barrier key" )
2018-05-18 01:17:52 +00:00
}
2017-10-23 18:59:37 +00:00
}
2016-05-15 16:58:36 +00:00
// Check if the seal configuration is valid
2016-01-14 22:01:04 +00:00
if err := config . Validate ( ) ; err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "invalid rekey seal configuration" , "error" , err )
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "invalid rekey seal configuration: {{err}}" , err ) . Error ( ) )
2016-01-14 22:01:04 +00:00
}
c . stateLock . RLock ( )
defer c . stateLock . RUnlock ( )
2018-07-24 20:57:25 +00:00
if c . Sealed ( ) {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusServiceUnavailable , consts . ErrSealed . Error ( ) )
2016-01-14 22:01:04 +00:00
}
if c . standby {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusBadRequest , consts . ErrStandby . Error ( ) )
2016-01-14 22:01:04 +00:00
}
2016-04-04 14:44:22 +00:00
c . rekeyLock . Lock ( )
defer c . rekeyLock . Unlock ( )
2016-01-14 22:01:04 +00:00
// Prevent multiple concurrent re-keys
2016-04-04 14:44:22 +00:00
if c . barrierRekeyConfig != nil {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusBadRequest , "rekey already in progress" )
2016-01-14 22:01:04 +00:00
}
// Copy the configuration
2016-04-04 14:44:22 +00:00
c . barrierRekeyConfig = config . Clone ( )
2016-01-14 22:01:04 +00:00
// Initialize the nonce
nonce , err := uuid . GenerateUUID ( )
if err != nil {
2016-04-04 14:44:22 +00:00
c . barrierRekeyConfig = nil
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "error generating nonce for procedure: {{err}}" , err ) . Error ( ) )
2016-01-14 22:01:04 +00:00
}
2016-04-04 14:44:22 +00:00
c . barrierRekeyConfig . Nonce = nonce
2016-01-14 22:01:04 +00:00
2016-08-19 20:45:17 +00:00
if c . logger . IsInfo ( ) {
2018-05-18 01:17:52 +00:00
c . logger . Info ( "rekey initialized" , "nonce" , c . barrierRekeyConfig . Nonce , "shares" , c . barrierRekeyConfig . SecretShares , "threshold" , c . barrierRekeyConfig . SecretThreshold , "validation_required" , c . barrierRekeyConfig . VerificationRequired )
2016-08-19 20:45:17 +00:00
}
2016-01-14 22:01:04 +00:00
return nil
}
2016-04-04 14:44:22 +00:00
// RecoveryRekeyInit is used to initialize the rekey settings for the recovery key
2018-05-20 03:43:48 +00:00
func ( c * Core ) RecoveryRekeyInit ( config * SealConfig ) logical . HTTPCodedError {
2016-04-04 14:44:22 +00:00
if config . StoredShares > 0 {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusBadRequest , "stored shares not supported by recovery key" )
2016-01-14 22:01:04 +00:00
}
2016-04-04 14:44:22 +00:00
2016-05-15 16:58:36 +00:00
// Check if the seal configuration is valid
2016-04-04 14:44:22 +00:00
if err := config . Validate ( ) ; err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "invalid recovery configuration" , "error" , err )
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "invalid recovery configuration: {{err}}" , err ) . Error ( ) )
2016-01-14 22:01:04 +00:00
}
2018-01-19 08:44:06 +00:00
if ! c . seal . RecoveryKeySupported ( ) {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusBadRequest , "recovery keys not supported" )
2016-04-04 14:44:22 +00:00
}
c . stateLock . RLock ( )
defer c . stateLock . RUnlock ( )
2018-07-24 20:57:25 +00:00
if c . Sealed ( ) {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusServiceUnavailable , consts . ErrSealed . Error ( ) )
2016-04-04 14:44:22 +00:00
}
if c . standby {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusBadRequest , consts . ErrStandby . Error ( ) )
2016-04-04 14:44:22 +00:00
}
c . rekeyLock . Lock ( )
defer c . rekeyLock . Unlock ( )
// Prevent multiple concurrent re-keys
if c . recoveryRekeyConfig != nil {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusBadRequest , "rekey already in progress" )
2016-04-04 14:44:22 +00:00
}
// Copy the configuration
c . recoveryRekeyConfig = config . Clone ( )
// Initialize the nonce
nonce , err := uuid . GenerateUUID ( )
2016-01-14 22:01:04 +00:00
if err != nil {
2016-04-04 14:44:22 +00:00
c . recoveryRekeyConfig = nil
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "error generating nonce for procedure: {{err}}" , err ) . Error ( ) )
2016-01-14 22:01:04 +00:00
}
2016-04-04 14:44:22 +00:00
c . recoveryRekeyConfig . Nonce = nonce
2016-01-14 22:01:04 +00:00
2016-08-19 20:45:17 +00:00
if c . logger . IsInfo ( ) {
2018-05-18 01:17:52 +00:00
c . logger . Info ( "rekey initialized" , "nonce" , c . recoveryRekeyConfig . Nonce , "shares" , c . recoveryRekeyConfig . SecretShares , "threshold" , c . recoveryRekeyConfig . SecretThreshold , "validation_required" , c . recoveryRekeyConfig . VerificationRequired )
2016-08-19 20:45:17 +00:00
}
2016-04-04 14:44:22 +00:00
return nil
}
2017-10-23 18:59:37 +00:00
// RekeyUpdate is used to provide a new key part for the barrier or recovery key.
2018-05-20 03:43:48 +00:00
func ( c * Core ) RekeyUpdate ( ctx context . Context , key [ ] byte , nonce string , recovery bool ) ( * RekeyResult , logical . HTTPCodedError ) {
2016-04-04 14:44:22 +00:00
if recovery {
2018-01-19 06:44:44 +00:00
return c . RecoveryRekeyUpdate ( ctx , key , nonce )
2016-01-14 22:01:04 +00:00
}
2018-01-19 06:44:44 +00:00
return c . BarrierRekeyUpdate ( ctx , key , nonce )
2016-04-04 14:44:22 +00:00
}
2016-01-14 22:01:04 +00:00
2017-10-23 18:59:37 +00:00
// BarrierRekeyUpdate is used to provide a new key part. Barrier rekey can be done
// with unseal keys, or recovery keys if that's supported and we are storing the barrier
// key.
//
// N.B.: If recovery keys are used to rekey, the new barrier key shares are not returned.
2018-05-20 03:43:48 +00:00
func ( c * Core ) BarrierRekeyUpdate ( ctx context . Context , key [ ] byte , nonce string ) ( * RekeyResult , logical . HTTPCodedError ) {
2016-01-14 22:01:04 +00:00
// Ensure we are already unsealed
c . stateLock . RLock ( )
defer c . stateLock . RUnlock ( )
2018-07-24 20:57:25 +00:00
if c . Sealed ( ) {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusServiceUnavailable , consts . ErrSealed . Error ( ) )
2016-01-14 22:01:04 +00:00
}
if c . standby {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , consts . ErrStandby . Error ( ) )
2016-01-14 22:01:04 +00:00
}
2016-04-04 14:44:22 +00:00
// Verify the key length
min , max := c . barrier . KeyLength ( )
max += shamir . ShareOverhead
if len ( key ) < min {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , fmt . Sprintf ( "key is shorter than minimum %d bytes" , min ) )
2016-04-04 14:44:22 +00:00
}
if len ( key ) > max {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , fmt . Sprintf ( "key is longer than maximum %d bytes" , max ) )
2016-04-04 14:44:22 +00:00
}
2016-01-14 22:01:04 +00:00
c . rekeyLock . Lock ( )
defer c . rekeyLock . Unlock ( )
2016-04-04 14:44:22 +00:00
// Get the seal configuration
2017-10-23 18:59:37 +00:00
var existingConfig * SealConfig
var err error
var useRecovery bool // Determines whether recovery key is being used to rekey the master key
2018-01-19 08:44:06 +00:00
if c . seal . StoredKeysSupported ( ) && c . seal . RecoveryKeySupported ( ) {
2018-01-19 06:44:44 +00:00
existingConfig , err = c . seal . RecoveryConfig ( ctx )
2017-10-23 18:59:37 +00:00
useRecovery = true
} else {
2018-01-19 06:44:44 +00:00
existingConfig , err = c . seal . BarrierConfig ( ctx )
2017-10-23 18:59:37 +00:00
}
2016-04-04 14:44:22 +00:00
if err != nil {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to fetch existing config: {{err}}" , err ) . Error ( ) )
2016-04-04 14:44:22 +00:00
}
// Ensure the barrier is initialized
if existingConfig == nil {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , ErrNotInit . Error ( ) )
2016-04-04 14:44:22 +00:00
}
2016-01-14 22:01:04 +00:00
// Ensure a rekey is in progress
2016-04-04 14:44:22 +00:00
if c . barrierRekeyConfig == nil {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , "no barrier rekey in progress" )
2016-01-14 22:01:04 +00:00
}
2018-05-22 01:02:45 +00:00
if len ( c . barrierRekeyConfig . VerificationKey ) > 0 {
return nil , logical . CodedError ( http . StatusBadRequest , fmt . Sprintf ( "rekey operation already finished; verification must be performed; nonce for the verification operation is %q" , c . barrierRekeyConfig . VerificationNonce ) )
}
2016-04-04 14:44:22 +00:00
if nonce != c . barrierRekeyConfig . Nonce {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , fmt . Sprintf ( "incorrect nonce supplied; nonce for this rekey operation is %q" , c . barrierRekeyConfig . Nonce ) )
2016-01-14 22:01:04 +00:00
}
// Check if we already have this piece
2018-05-21 21:46:32 +00:00
for _ , existing := range c . barrierRekeyConfig . RekeyProgress {
2018-05-18 01:30:39 +00:00
if subtle . ConstantTimeCompare ( existing , key ) == 1 {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , "given key has already been provided during this generation operation" )
2016-01-14 22:01:04 +00:00
}
}
// Store this key
2018-05-21 21:46:32 +00:00
c . barrierRekeyConfig . RekeyProgress = append ( c . barrierRekeyConfig . RekeyProgress , key )
2016-01-14 22:01:04 +00:00
// Check if we don't have enough keys to unlock
2018-05-21 21:46:32 +00:00
if len ( c . barrierRekeyConfig . RekeyProgress ) < existingConfig . SecretThreshold {
2016-08-19 20:45:17 +00:00
if c . logger . IsDebug ( ) {
2018-05-21 21:46:32 +00:00
c . logger . Debug ( "cannot rekey yet, not enough keys" , "keys" , len ( c . barrierRekeyConfig . RekeyProgress ) , "threshold" , existingConfig . SecretThreshold )
2016-08-19 20:45:17 +00:00
}
2016-01-14 22:01:04 +00:00
return nil , nil
}
2017-10-23 18:59:37 +00:00
// Recover the master key or recovery key
var recoveredKey [ ] byte
2016-04-04 14:44:22 +00:00
if existingConfig . SecretThreshold == 1 {
2018-05-21 21:46:32 +00:00
recoveredKey = c . barrierRekeyConfig . RekeyProgress [ 0 ]
2018-11-20 01:03:07 +00:00
c . barrierRekeyConfig . RekeyProgress = nil
2016-01-14 22:01:04 +00:00
} else {
2018-05-21 21:46:32 +00:00
recoveredKey , err = shamir . Combine ( c . barrierRekeyConfig . RekeyProgress )
2018-11-20 01:03:07 +00:00
c . barrierRekeyConfig . RekeyProgress = nil
2016-01-14 22:01:04 +00:00
if err != nil {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to compute master key: {{err}}" , err ) . Error ( ) )
2016-01-14 22:01:04 +00:00
}
}
2017-10-23 18:59:37 +00:00
if useRecovery {
2018-01-19 06:44:44 +00:00
if err := c . seal . VerifyRecoveryKey ( ctx , recoveredKey ) ; err != nil {
2018-05-20 03:43:48 +00:00
c . logger . Error ( "rekey recovery key verification failed" , "error" , err )
2018-05-22 01:06:38 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , errwrap . Wrapf ( "recovery key verification failed: {{err}}" , err ) . Error ( ) )
2017-10-23 18:59:37 +00:00
}
} else {
if err := c . barrier . VerifyMaster ( recoveredKey ) ; err != nil {
2018-05-20 03:43:48 +00:00
c . logger . Error ( "master key verification failed" , "error" , err )
2018-05-22 01:06:38 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , errwrap . Wrapf ( "master key verification failed: {{err}}" , err ) . Error ( ) )
2017-10-23 18:59:37 +00:00
}
2016-01-14 22:01:04 +00:00
}
// Generate a new master key
newMasterKey , err := c . barrier . GenerateKey ( )
if err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "failed to generate master key" , "error" , err )
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "master key generation failed: {{err}}" , err ) . Error ( ) )
2016-01-14 22:01:04 +00:00
}
results := & RekeyResult {
2016-04-04 14:44:22 +00:00
Backup : c . barrierRekeyConfig . Backup ,
2016-01-14 22:01:04 +00:00
}
2017-10-23 18:59:37 +00:00
// Set result.SecretShares to the master key if only a single key
// part is used -- no Shamir split required.
2016-04-04 14:44:22 +00:00
if c . barrierRekeyConfig . SecretShares == 1 {
2016-01-14 22:01:04 +00:00
results . SecretShares = append ( results . SecretShares , newMasterKey )
} else {
// Split the master key using the Shamir algorithm
2016-04-04 14:44:22 +00:00
shares , err := shamir . Split ( newMasterKey , c . barrierRekeyConfig . SecretShares , c . barrierRekeyConfig . SecretThreshold )
2016-01-14 22:01:04 +00:00
if err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "failed to generate shares" , "error" , err )
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to generate shares: {{err}}" , err ) . Error ( ) )
2016-01-14 22:01:04 +00:00
}
results . SecretShares = shares
}
2016-04-04 14:44:22 +00:00
// If we are storing any shares, add them to the shares to store and remove
// from the returned keys
var keysToStore [ ] [ ] byte
2018-01-19 08:44:06 +00:00
if c . seal . StoredKeysSupported ( ) && c . barrierRekeyConfig . StoredShares > 0 {
2016-04-04 14:44:22 +00:00
for i := 0 ; i < c . barrierRekeyConfig . StoredShares ; i ++ {
keysToStore = append ( keysToStore , results . SecretShares [ 0 ] )
results . SecretShares = results . SecretShares [ 1 : ]
}
}
2017-10-23 18:59:37 +00:00
// If PGP keys are passed in, encrypt shares with corresponding PGP keys.
2016-04-04 14:44:22 +00:00
if len ( c . barrierRekeyConfig . PGPKeys ) > 0 {
2016-01-20 00:19:07 +00:00
hexEncodedShares := make ( [ ] [ ] byte , len ( results . SecretShares ) )
for i , _ := range results . SecretShares {
hexEncodedShares [ i ] = [ ] byte ( hex . EncodeToString ( results . SecretShares [ i ] ) )
}
2016-04-04 14:44:22 +00:00
results . PGPFingerprints , results . SecretShares , err = pgpkeys . EncryptShares ( hexEncodedShares , c . barrierRekeyConfig . PGPKeys )
2016-01-14 22:01:04 +00:00
if err != nil {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to encrypt shares: {{err}}" , err ) . Error ( ) )
2016-01-14 22:01:04 +00:00
}
2017-10-23 18:59:37 +00:00
// If backup is enabled, store backup info in vault.coreBarrierUnsealKeysBackupPath
2016-04-04 14:44:22 +00:00
if c . barrierRekeyConfig . Backup {
2016-01-14 22:01:04 +00:00
backupInfo := map [ string ] [ ] string { }
for i := 0 ; i < len ( results . PGPFingerprints ) ; i ++ {
encShare := bytes . NewBuffer ( results . SecretShares [ i ] )
if backupInfo [ results . PGPFingerprints [ i ] ] == nil {
backupInfo [ results . PGPFingerprints [ i ] ] = [ ] string { hex . EncodeToString ( encShare . Bytes ( ) ) }
} else {
backupInfo [ results . PGPFingerprints [ i ] ] = append ( backupInfo [ results . PGPFingerprints [ i ] ] , hex . EncodeToString ( encShare . Bytes ( ) ) )
}
}
backupVals := & RekeyBackup {
2016-04-04 14:44:22 +00:00
Nonce : c . barrierRekeyConfig . Nonce ,
2016-01-14 22:01:04 +00:00
Keys : backupInfo ,
}
buf , err := json . Marshal ( backupVals )
if err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "failed to marshal unseal key backup" , "error" , err )
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to marshal unseal key backup: {{err}}" , err ) . Error ( ) )
2016-01-14 22:01:04 +00:00
}
pe := & physical . Entry {
2016-04-04 14:44:22 +00:00
Key : coreBarrierUnsealKeysBackupPath ,
2016-01-14 22:01:04 +00:00
Value : buf ,
}
2018-01-19 06:44:44 +00:00
if err = c . physical . Put ( ctx , pe ) ; err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "failed to save unseal key backup" , "error" , err )
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to save unseal key backup: {{err}}" , err ) . Error ( ) )
2016-01-14 22:01:04 +00:00
}
}
}
2016-04-04 14:44:22 +00:00
if keysToStore != nil {
2018-01-19 06:44:44 +00:00
if err := c . seal . SetStoredKeys ( ctx , keysToStore ) ; err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "failed to store keys" , "error" , err )
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to store keys: {{err}}" , err ) . Error ( ) )
2016-04-04 14:44:22 +00:00
}
2016-01-14 22:01:04 +00:00
}
2018-05-18 01:17:52 +00:00
// If we are requiring validation, return now; otherwise rekey the barrier
if c . barrierRekeyConfig . VerificationRequired {
nonce , err := uuid . GenerateUUID ( )
if err != nil {
c . barrierRekeyConfig = nil
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to generate verification nonce: {{err}}" , err ) . Error ( ) )
2018-05-18 01:17:52 +00:00
}
c . barrierRekeyConfig . VerificationNonce = nonce
c . barrierRekeyConfig . VerificationKey = newMasterKey
results . VerificationRequired = true
results . VerificationNonce = nonce
return results , nil
}
if err := c . performBarrierRekey ( ctx , newMasterKey ) ; err != nil {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to perform barrier rekey: {{err}}" , err ) . Error ( ) )
2018-05-18 01:17:52 +00:00
}
c . barrierRekeyConfig = nil
return results , nil
}
2018-05-20 03:43:48 +00:00
func ( c * Core ) performBarrierRekey ( ctx context . Context , newMasterKey [ ] byte ) logical . HTTPCodedError {
2016-01-14 22:01:04 +00:00
// Rekey the barrier
2018-01-19 06:44:44 +00:00
if err := c . barrier . Rekey ( ctx , newMasterKey ) ; err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "failed to rekey barrier" , "error" , err )
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to rekey barrier: {{err}}" , err ) . Error ( ) )
2016-01-14 22:01:04 +00:00
}
2016-08-19 20:45:17 +00:00
if c . logger . IsInfo ( ) {
2018-04-03 00:46:59 +00:00
c . logger . Info ( "security barrier rekeyed" , "shares" , c . barrierRekeyConfig . SecretShares , "threshold" , c . barrierRekeyConfig . SecretThreshold )
2016-08-19 20:45:17 +00:00
}
2018-05-18 01:17:52 +00:00
c . barrierRekeyConfig . VerificationKey = nil
2018-01-19 06:44:44 +00:00
if err := c . seal . SetBarrierConfig ( ctx , c . barrierRekeyConfig ) ; err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "error saving rekey seal configuration" , "error" , err )
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to save rekey seal configuration: {{err}}" , err ) . Error ( ) )
2016-04-04 14:44:22 +00:00
}
2017-02-24 15:45:29 +00:00
// Write to the canary path, which will force a synchronous truing during
// replication
2019-01-31 14:25:18 +00:00
if err := c . barrier . Put ( ctx , & logical . StorageEntry {
2017-02-24 15:45:29 +00:00
Key : coreKeyringCanaryPath ,
Value : [ ] byte ( c . barrierRekeyConfig . Nonce ) ,
} ) ; err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "error saving keyring canary" , "error" , err )
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to save keyring canary: {{err}}" , err ) . Error ( ) )
2017-02-24 15:45:29 +00:00
}
2018-05-29 17:13:47 +00:00
c . barrierRekeyConfig . RekeyProgress = nil
2018-05-18 01:17:52 +00:00
return nil
2016-04-04 14:44:22 +00:00
}
2016-01-14 22:01:04 +00:00
2016-04-04 14:44:22 +00:00
// RecoveryRekeyUpdate is used to provide a new key part
2018-05-20 03:43:48 +00:00
func ( c * Core ) RecoveryRekeyUpdate ( ctx context . Context , key [ ] byte , nonce string ) ( * RekeyResult , logical . HTTPCodedError ) {
2016-04-04 14:44:22 +00:00
// Ensure we are already unsealed
c . stateLock . RLock ( )
defer c . stateLock . RUnlock ( )
2018-07-24 20:57:25 +00:00
if c . Sealed ( ) {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusServiceUnavailable , consts . ErrSealed . Error ( ) )
2016-01-14 22:01:04 +00:00
}
2016-04-04 14:44:22 +00:00
if c . standby {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , consts . ErrStandby . Error ( ) )
2016-04-04 14:44:22 +00:00
}
// Verify the key length
min , max := c . barrier . KeyLength ( )
max += shamir . ShareOverhead
if len ( key ) < min {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , fmt . Sprintf ( "key is shorter than minimum %d bytes" , min ) )
2016-04-04 14:44:22 +00:00
}
if len ( key ) > max {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , fmt . Sprintf ( "key is longer than maximum %d bytes" , max ) )
2016-04-04 14:44:22 +00:00
}
c . rekeyLock . Lock ( )
defer c . rekeyLock . Unlock ( )
// Get the seal configuration
2018-01-19 06:44:44 +00:00
existingConfig , err := c . seal . RecoveryConfig ( ctx )
2016-04-04 14:44:22 +00:00
if err != nil {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to fetch existing recovery config: {{err}}" , err ) . Error ( ) )
2016-04-04 14:44:22 +00:00
}
2017-10-23 18:59:37 +00:00
// Ensure the seal is initialized
if existingConfig == nil {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , ErrNotInit . Error ( ) )
2016-04-04 14:44:22 +00:00
}
// Ensure a rekey is in progress
if c . recoveryRekeyConfig == nil {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , "no recovery rekey in progress" )
2016-04-04 14:44:22 +00:00
}
2018-05-22 01:02:45 +00:00
if len ( c . recoveryRekeyConfig . VerificationKey ) > 0 {
return nil , logical . CodedError ( http . StatusBadRequest , fmt . Sprintf ( "rekey operation already finished; verification must be performed; nonce for the verification operation is %q" , c . recoveryRekeyConfig . VerificationNonce ) )
}
2016-04-04 14:44:22 +00:00
if nonce != c . recoveryRekeyConfig . Nonce {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , fmt . Sprintf ( "incorrect nonce supplied; nonce for this rekey operation is %q" , c . recoveryRekeyConfig . Nonce ) )
2016-04-04 14:44:22 +00:00
}
// Check if we already have this piece
2018-05-21 21:46:32 +00:00
for _ , existing := range c . recoveryRekeyConfig . RekeyProgress {
2018-05-18 01:30:39 +00:00
if subtle . ConstantTimeCompare ( existing , key ) == 1 {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , "given key has already been provided during this rekey operation" )
2016-04-04 14:44:22 +00:00
}
}
// Store this key
2018-05-21 21:46:32 +00:00
c . recoveryRekeyConfig . RekeyProgress = append ( c . recoveryRekeyConfig . RekeyProgress , key )
2016-04-04 14:44:22 +00:00
// Check if we don't have enough keys to unlock
2018-05-21 21:46:32 +00:00
if len ( c . recoveryRekeyConfig . RekeyProgress ) < existingConfig . SecretThreshold {
2016-08-19 20:45:17 +00:00
if c . logger . IsDebug ( ) {
2018-05-21 21:46:32 +00:00
c . logger . Debug ( "cannot rekey yet, not enough keys" , "keys" , len ( c . recoveryRekeyConfig . RekeyProgress ) , "threshold" , existingConfig . SecretThreshold )
2016-08-19 20:45:17 +00:00
}
2016-04-04 14:44:22 +00:00
return nil , nil
}
// Recover the master key
2017-10-23 18:59:37 +00:00
var recoveryKey [ ] byte
2016-04-04 14:44:22 +00:00
if existingConfig . SecretThreshold == 1 {
2018-05-21 21:46:32 +00:00
recoveryKey = c . recoveryRekeyConfig . RekeyProgress [ 0 ]
2018-11-20 01:03:07 +00:00
c . recoveryRekeyConfig . RekeyProgress = nil
2016-04-04 14:44:22 +00:00
} else {
2018-05-21 21:46:32 +00:00
recoveryKey , err = shamir . Combine ( c . recoveryRekeyConfig . RekeyProgress )
2018-11-20 01:03:07 +00:00
c . recoveryRekeyConfig . RekeyProgress = nil
2016-04-04 14:44:22 +00:00
if err != nil {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to compute recovery key: {{err}}" , err ) . Error ( ) )
2016-04-04 14:44:22 +00:00
}
}
// Verify the recovery key
2018-01-19 06:44:44 +00:00
if err := c . seal . VerifyRecoveryKey ( ctx , recoveryKey ) ; err != nil {
2018-05-20 03:43:48 +00:00
c . logger . Error ( "recovery key verification failed" , "error" , err )
2018-05-22 01:06:38 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , errwrap . Wrapf ( "recovery key verification failed: {{err}}" , err ) . Error ( ) )
2016-04-04 14:44:22 +00:00
}
// Generate a new master key
newMasterKey , err := c . barrier . GenerateKey ( )
if err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "failed to generate recovery key" , "error" , err )
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "recovery key generation failed: {{err}}" , err ) . Error ( ) )
2016-04-04 14:44:22 +00:00
}
// Return the master key if only a single key part is used
results := & RekeyResult {
Backup : c . recoveryRekeyConfig . Backup ,
}
if c . recoveryRekeyConfig . SecretShares == 1 {
results . SecretShares = append ( results . SecretShares , newMasterKey )
} else {
// Split the master key using the Shamir algorithm
shares , err := shamir . Split ( newMasterKey , c . recoveryRekeyConfig . SecretShares , c . recoveryRekeyConfig . SecretThreshold )
if err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "failed to generate shares" , "error" , err )
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to generate shares: {{err}}" , err ) . Error ( ) )
2016-04-04 14:44:22 +00:00
}
results . SecretShares = shares
}
if len ( c . recoveryRekeyConfig . PGPKeys ) > 0 {
hexEncodedShares := make ( [ ] [ ] byte , len ( results . SecretShares ) )
for i , _ := range results . SecretShares {
hexEncodedShares [ i ] = [ ] byte ( hex . EncodeToString ( results . SecretShares [ i ] ) )
}
results . PGPFingerprints , results . SecretShares , err = pgpkeys . EncryptShares ( hexEncodedShares , c . recoveryRekeyConfig . PGPKeys )
if err != nil {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to encrypt shares: {{err}}" , err ) . Error ( ) )
2016-04-04 14:44:22 +00:00
}
if c . recoveryRekeyConfig . Backup {
backupInfo := map [ string ] [ ] string { }
for i := 0 ; i < len ( results . PGPFingerprints ) ; i ++ {
encShare := bytes . NewBuffer ( results . SecretShares [ i ] )
if backupInfo [ results . PGPFingerprints [ i ] ] == nil {
backupInfo [ results . PGPFingerprints [ i ] ] = [ ] string { hex . EncodeToString ( encShare . Bytes ( ) ) }
} else {
backupInfo [ results . PGPFingerprints [ i ] ] = append ( backupInfo [ results . PGPFingerprints [ i ] ] , hex . EncodeToString ( encShare . Bytes ( ) ) )
}
}
backupVals := & RekeyBackup {
Nonce : c . recoveryRekeyConfig . Nonce ,
Keys : backupInfo ,
}
buf , err := json . Marshal ( backupVals )
if err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "failed to marshal recovery key backup" , "error" , err )
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to marshal recovery key backup: {{err}}" , err ) . Error ( ) )
2016-04-04 14:44:22 +00:00
}
pe := & physical . Entry {
Key : coreRecoveryUnsealKeysBackupPath ,
Value : buf ,
}
2018-01-19 06:44:44 +00:00
if err = c . physical . Put ( ctx , pe ) ; err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "failed to save unseal key backup" , "error" , err )
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to save unseal key backup: {{err}}" , err ) . Error ( ) )
2016-04-04 14:44:22 +00:00
}
}
}
2018-05-18 01:17:52 +00:00
// If we are requiring validation, return now; otherwise save the recovery
// key
if c . recoveryRekeyConfig . VerificationRequired {
nonce , err := uuid . GenerateUUID ( )
if err != nil {
c . recoveryRekeyConfig = nil
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to generate verification nonce: {{err}}" , err ) . Error ( ) )
2018-05-18 01:17:52 +00:00
}
c . recoveryRekeyConfig . VerificationNonce = nonce
c . recoveryRekeyConfig . VerificationKey = newMasterKey
results . VerificationRequired = true
results . VerificationNonce = nonce
return results , nil
}
if err := c . performRecoveryRekey ( ctx , newMasterKey ) ; err != nil {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to perform recovery rekey: {{err}}" , err ) . Error ( ) )
2018-05-18 01:17:52 +00:00
}
c . recoveryRekeyConfig = nil
return results , nil
}
2018-05-20 03:43:48 +00:00
func ( c * Core ) performRecoveryRekey ( ctx context . Context , newMasterKey [ ] byte ) logical . HTTPCodedError {
2018-01-19 06:44:44 +00:00
if err := c . seal . SetRecoveryKey ( ctx , newMasterKey ) ; err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "failed to set recovery key" , "error" , err )
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to set recovery key: {{err}}" , err ) . Error ( ) )
2016-04-04 14:44:22 +00:00
}
2018-05-18 01:17:52 +00:00
c . recoveryRekeyConfig . VerificationKey = nil
2018-01-19 06:44:44 +00:00
if err := c . seal . SetRecoveryConfig ( ctx , c . recoveryRekeyConfig ) ; err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "error saving rekey seal configuration" , "error" , err )
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to save rekey seal configuration: {{err}}" , err ) . Error ( ) )
2016-01-14 22:01:04 +00:00
}
2017-02-24 15:45:29 +00:00
// Write to the canary path, which will force a synchronous truing during
// replication
2019-01-31 14:25:18 +00:00
if err := c . barrier . Put ( ctx , & logical . StorageEntry {
2017-02-24 15:45:29 +00:00
Key : coreKeyringCanaryPath ,
Value : [ ] byte ( c . recoveryRekeyConfig . Nonce ) ,
} ) ; err != nil {
2018-04-03 00:46:59 +00:00
c . logger . Error ( "error saving keyring canary" , "error" , err )
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to save keyring canary: {{err}}" , err ) . Error ( ) )
2017-02-24 15:45:29 +00:00
}
2018-05-29 17:13:47 +00:00
c . recoveryRekeyConfig . RekeyProgress = nil
2018-05-18 01:17:52 +00:00
return nil
}
2018-05-21 21:46:32 +00:00
func ( c * Core ) RekeyVerify ( ctx context . Context , key [ ] byte , nonce string , recovery bool ) ( ret * RekeyVerifyResult , retErr logical . HTTPCodedError ) {
2018-05-18 01:17:52 +00:00
// Ensure we are already unsealed
c . stateLock . RLock ( )
defer c . stateLock . RUnlock ( )
2018-07-24 20:57:25 +00:00
if c . Sealed ( ) {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusServiceUnavailable , consts . ErrSealed . Error ( ) )
2018-05-18 01:17:52 +00:00
}
if c . standby {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , consts . ErrStandby . Error ( ) )
2018-05-18 01:17:52 +00:00
}
// Verify the key length
min , max := c . barrier . KeyLength ( )
max += shamir . ShareOverhead
if len ( key ) < min {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , fmt . Sprintf ( "key is shorter than minimum %d bytes" , min ) )
2018-05-18 01:17:52 +00:00
}
if len ( key ) > max {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , fmt . Sprintf ( "key is longer than maximum %d bytes" , max ) )
2018-05-18 01:17:52 +00:00
}
c . rekeyLock . Lock ( )
defer c . rekeyLock . Unlock ( )
2018-05-21 21:46:32 +00:00
config := c . barrierRekeyConfig
if recovery {
config = c . recoveryRekeyConfig
}
2018-05-18 01:17:52 +00:00
// Ensure a rekey is in progress
2018-05-21 21:46:32 +00:00
if config == nil {
return nil , logical . CodedError ( http . StatusBadRequest , "no rekey in progress" )
2018-05-18 01:17:52 +00:00
}
2018-05-29 17:13:47 +00:00
if len ( config . VerificationKey ) == 0 {
2018-05-28 04:39:53 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , "no rekey verification in progress" )
}
2018-05-21 21:46:32 +00:00
if nonce != config . VerificationNonce {
return nil , logical . CodedError ( http . StatusBadRequest , fmt . Sprintf ( "incorrect nonce supplied; nonce for this verify operation is %q" , config . VerificationNonce ) )
2018-05-20 06:42:15 +00:00
}
2018-05-18 01:17:52 +00:00
// Check if we already have this piece
2018-05-21 21:46:32 +00:00
for _ , existing := range config . VerificationProgress {
2018-05-18 01:30:39 +00:00
if subtle . ConstantTimeCompare ( existing , key ) == 1 {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , "given key has already been provided during this verify operation" )
2018-05-18 01:17:52 +00:00
}
}
// Store this key
2018-05-21 21:46:32 +00:00
config . VerificationProgress = append ( config . VerificationProgress , key )
2018-05-18 01:17:52 +00:00
// Check if we don't have enough keys to unlock
2018-05-21 21:46:32 +00:00
if len ( config . VerificationProgress ) < config . SecretThreshold {
2018-05-18 01:17:52 +00:00
if c . logger . IsDebug ( ) {
2018-05-21 21:46:32 +00:00
c . logger . Debug ( "cannot verify yet, not enough keys" , "keys" , len ( config . VerificationProgress ) , "threshold" , config . SecretThreshold )
2018-05-18 01:17:52 +00:00
}
return nil , nil
}
// Schedule the progress for forgetting and rotate the nonce if possible
defer func ( ) {
2018-05-21 21:46:32 +00:00
config . VerificationProgress = nil
2018-05-22 00:54:20 +00:00
if ret != nil && ret . Complete {
return
}
// Not complete, so rotate nonce
2018-05-21 21:46:32 +00:00
nonce , err := uuid . GenerateUUID ( )
2018-05-21 22:25:58 +00:00
if err == nil {
config . VerificationNonce = nonce
if ret != nil {
ret . Nonce = nonce
2018-05-18 01:17:52 +00:00
}
}
} ( )
// Recover the master key or recovery key
var recoveredKey [ ] byte
2018-05-21 21:46:32 +00:00
if config . SecretThreshold == 1 {
recoveredKey = config . VerificationProgress [ 0 ]
2018-05-18 01:17:52 +00:00
} else {
2018-05-21 18:47:00 +00:00
var err error
2018-05-21 21:46:32 +00:00
recoveredKey , err = shamir . Combine ( config . VerificationProgress )
2018-05-18 01:17:52 +00:00
if err != nil {
2018-05-21 21:46:32 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to compute key for verification: {{err}}" , err ) . Error ( ) )
2018-05-18 01:17:52 +00:00
}
}
2018-05-21 21:46:32 +00:00
if subtle . ConstantTimeCompare ( recoveredKey , config . VerificationKey ) != 1 {
2018-05-18 01:17:52 +00:00
c . logger . Error ( "rekey verification failed" )
2018-05-22 01:06:38 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , "rekey verification failed; incorrect key shares supplied" )
2018-05-18 01:30:39 +00:00
}
2018-05-21 21:46:32 +00:00
switch recovery {
case false :
if err := c . performBarrierRekey ( ctx , recoveredKey ) ; err != nil {
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to perform rekey: {{err}}" , err ) . Error ( ) )
2018-05-18 01:30:39 +00:00
}
2018-05-21 21:46:32 +00:00
c . barrierRekeyConfig = nil
default :
if err := c . performRecoveryRekey ( ctx , recoveredKey ) ; err != nil {
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "failed to perform recovery key rekey: {{err}}" , err ) . Error ( ) )
2018-05-18 01:30:39 +00:00
}
2018-05-21 21:46:32 +00:00
c . recoveryRekeyConfig = nil
2018-05-18 01:30:39 +00:00
}
res := & RekeyVerifyResult {
2018-05-22 00:54:20 +00:00
Nonce : config . VerificationNonce ,
Complete : true ,
2018-05-18 01:30:39 +00:00
}
return res , nil
}
// RekeyCancel is used to cancel an in-progress rekey
2018-05-20 03:43:48 +00:00
func ( c * Core ) RekeyCancel ( recovery bool ) logical . HTTPCodedError {
2016-01-14 22:01:04 +00:00
c . stateLock . RLock ( )
defer c . stateLock . RUnlock ( )
2018-07-24 20:57:25 +00:00
if c . Sealed ( ) {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusServiceUnavailable , consts . ErrSealed . Error ( ) )
2016-01-14 22:01:04 +00:00
}
if c . standby {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusBadRequest , consts . ErrStandby . Error ( ) )
2016-01-14 22:01:04 +00:00
}
2016-04-04 14:44:22 +00:00
c . rekeyLock . Lock ( )
defer c . rekeyLock . Unlock ( )
2016-01-14 22:01:04 +00:00
// Clear any progress or config
2016-04-04 14:44:22 +00:00
if recovery {
c . recoveryRekeyConfig = nil
} else {
c . barrierRekeyConfig = nil
}
2016-01-14 22:01:04 +00:00
return nil
}
2018-05-28 04:39:53 +00:00
// RekeyVerifyRestart is used to start the verification process over
2018-05-20 03:43:48 +00:00
func ( c * Core ) RekeyVerifyRestart ( recovery bool ) logical . HTTPCodedError {
2018-05-18 01:17:52 +00:00
c . stateLock . RLock ( )
defer c . stateLock . RUnlock ( )
2018-07-24 20:57:25 +00:00
if c . Sealed ( ) {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusServiceUnavailable , consts . ErrSealed . Error ( ) )
2018-05-18 01:17:52 +00:00
}
if c . standby {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusBadRequest , consts . ErrStandby . Error ( ) )
2018-05-18 01:17:52 +00:00
}
c . rekeyLock . Lock ( )
defer c . rekeyLock . Unlock ( )
// Attempt to generate a new nonce, but don't bail if it doesn't succeed
// (which is extraordinarily unlikely)
nonce , nonceErr := uuid . GenerateUUID ( )
// Clear any progress or config
if recovery {
2018-05-21 21:46:32 +00:00
c . recoveryRekeyConfig . VerificationProgress = nil
2018-05-18 01:17:52 +00:00
if nonceErr == nil {
c . recoveryRekeyConfig . VerificationNonce = nonce
}
} else {
2018-05-21 21:46:32 +00:00
c . barrierRekeyConfig . VerificationProgress = nil
2018-05-18 01:17:52 +00:00
if nonceErr == nil {
c . barrierRekeyConfig . VerificationNonce = nonce
}
}
return nil
}
2016-01-14 22:01:04 +00:00
// RekeyRetrieveBackup is used to retrieve any backed-up PGP-encrypted unseal
// keys
2018-05-20 03:43:48 +00:00
func ( c * Core ) RekeyRetrieveBackup ( ctx context . Context , recovery bool ) ( * RekeyBackup , logical . HTTPCodedError ) {
2018-07-24 20:57:25 +00:00
if c . Sealed ( ) {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusServiceUnavailable , consts . ErrSealed . Error ( ) )
2016-01-14 22:01:04 +00:00
}
if c . standby {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusBadRequest , consts . ErrStandby . Error ( ) )
2016-01-14 22:01:04 +00:00
}
2016-04-04 14:44:22 +00:00
c . rekeyLock . RLock ( )
defer c . rekeyLock . RUnlock ( )
var entry * physical . Entry
var err error
if recovery {
2018-01-19 06:44:44 +00:00
entry , err = c . physical . Get ( ctx , coreRecoveryUnsealKeysBackupPath )
2016-04-04 14:44:22 +00:00
} else {
2018-01-19 06:44:44 +00:00
entry , err = c . physical . Get ( ctx , coreBarrierUnsealKeysBackupPath )
2016-04-04 14:44:22 +00:00
}
2016-01-14 22:01:04 +00:00
if err != nil {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "error getting keys from backup: {{err}}" , err ) . Error ( ) )
2016-01-14 22:01:04 +00:00
}
if entry == nil {
return nil , nil
}
ret := & RekeyBackup { }
2016-07-06 16:25:40 +00:00
err = jsonutil . DecodeJSON ( entry . Value , ret )
2016-01-14 22:01:04 +00:00
if err != nil {
2018-05-20 03:43:48 +00:00
return nil , logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "error decoding backup keys: {{err}}" , err ) . Error ( ) )
2016-01-14 22:01:04 +00:00
}
return ret , nil
}
// RekeyDeleteBackup is used to delete any backed-up PGP-encrypted unseal keys
2018-05-20 03:43:48 +00:00
func ( c * Core ) RekeyDeleteBackup ( ctx context . Context , recovery bool ) logical . HTTPCodedError {
2018-07-24 20:57:25 +00:00
if c . Sealed ( ) {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusServiceUnavailable , consts . ErrSealed . Error ( ) )
2016-01-14 22:01:04 +00:00
}
if c . standby {
2018-05-20 03:43:48 +00:00
return logical . CodedError ( http . StatusBadRequest , consts . ErrStandby . Error ( ) )
2016-01-14 22:01:04 +00:00
}
2016-04-04 14:44:22 +00:00
c . rekeyLock . Lock ( )
defer c . rekeyLock . Unlock ( )
if recovery {
2018-05-20 03:43:48 +00:00
err := c . physical . Delete ( ctx , coreRecoveryUnsealKeysBackupPath )
if err != nil {
return logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "error deleting backup keys: {{err}}" , err ) . Error ( ) )
}
return nil
}
err := c . physical . Delete ( ctx , coreBarrierUnsealKeysBackupPath )
if err != nil {
return logical . CodedError ( http . StatusInternalServerError , errwrap . Wrapf ( "error deleting backup keys: {{err}}" , err ) . Error ( ) )
2016-04-04 14:44:22 +00:00
}
2018-05-20 03:43:48 +00:00
return nil
2016-01-14 22:01:04 +00:00
}