// Unseal is used to provide one of the key parts to unseal the Vault. // // They key given as a parameter will automatically be zerod after // this method is done with it. If you want to keep the key around, a copy // should be made. func (c *Core) Unseal(key []byte) (bool, error) { defer metrics.MeasureSince([]string{"core", "unseal"}, time.Now()) // Verify the key length min, max := c.barrier.KeyLength() max += shamir.ShareOverhead if len(key) < min { return false, &ErrInvalidKey{fmt.Sprintf("key is shorter than minimum %d bytes", min)} } if len(key) > max { return false, &ErrInvalidKey{fmt.Sprintf("key is longer than maximum %d bytes", max)} } // Get the seal configuration config, err := c.SealConfig() if err != nil { return false, err } // Ensure the barrier is initialized if config == nil { return false, ErrNotInit } c.stateLock.Lock() defer c.stateLock.Unlock() // Check if already unsealed if !c.sealed { return true, nil } // Check if we already have this piece for _, existing := range c.unlockParts { if bytes.Equal(existing, key) { return false, nil } } // Store this key c.unlockParts = append(c.unlockParts, key) // Check if we don't have enough keys to unlock if len(c.unlockParts) < config.SecretThreshold { c.logger.Printf("[DEBUG] core: cannot unseal, have %d of %d keys", len(c.unlockParts), config.SecretThreshold) return false, nil } // Recover the master key var masterKey []byte if config.SecretThreshold == 1 { masterKey = c.unlockParts[0] c.unlockParts = nil } else { masterKey, err = shamir.Combine(c.unlockParts) c.unlockParts = nil if err != nil { return false, fmt.Errorf("failed to compute master key: %v", err) } } defer memzero(masterKey) // Attempt to unlock if err := c.barrier.Unseal(masterKey); err != nil { return false, err } c.logger.Printf("[INFO] core: vault is unsealed") // Do post-unseal setup if HA is not enabled if c.ha == nil { c.standby = false if err := c.postUnseal(); err != nil { c.logger.Printf("[ERR] core: post-unseal setup failed: %v", err) c.barrier.Seal() c.logger.Printf("[WARN] core: vault is sealed") return false, err } } else { // Go to standby mode, wait until we are active to unseal c.standbyDoneCh = make(chan struct{}) c.standbyStopCh = make(chan struct{}) go c.runStandby(c.standbyDoneCh, c.standbyStopCh) } // Success! c.sealed = false return true, nil }
// RekeyUpdate is used to provide a new key part func (c *Core) RekeyUpdate(key []byte) (*RekeyResult, error) { // Verify the key length min, max := c.barrier.KeyLength() max += shamir.ShareOverhead if len(key) < min { return nil, &ErrInvalidKey{fmt.Sprintf("key is shorter than minimum %d bytes", min)} } if len(key) > max { return nil, &ErrInvalidKey{fmt.Sprintf("key is longer than maximum %d bytes", max)} } // Get the seal configuration config, err := c.SealConfig() if err != nil { return nil, err } // Ensure the barrier is initialized if config == nil { return nil, ErrNotInit } // Ensure we are already unsealed c.stateLock.RLock() defer c.stateLock.RUnlock() if c.sealed { return nil, ErrSealed } if c.standby { return nil, ErrStandby } c.rekeyLock.Lock() defer c.rekeyLock.Unlock() // Ensure a rekey is in progress if c.rekeyConfig == nil { return nil, fmt.Errorf("no rekey in progress") } // Check if we already have this piece for _, existing := range c.rekeyProgress { if bytes.Equal(existing, key) { return nil, nil } } // Store this key c.rekeyProgress = append(c.rekeyProgress, key) // Check if we don't have enough keys to unlock if len(c.rekeyProgress) < config.SecretThreshold { c.logger.Printf("[DEBUG] core: cannot rekey, have %d of %d keys", len(c.rekeyProgress), config.SecretThreshold) return nil, nil } // Recover the master key var masterKey []byte if config.SecretThreshold == 1 { masterKey = c.rekeyProgress[0] c.rekeyProgress = nil } else { masterKey, err = shamir.Combine(c.rekeyProgress) c.rekeyProgress = nil if err != nil { return nil, fmt.Errorf("failed to compute master key: %v", err) } } // Verify the master key if err := c.barrier.VerifyMaster(masterKey); err != nil { c.logger.Printf("[ERR] core: rekey aborted, master key verification failed: %v", err) return nil, err } // Generate a new master key newMasterKey, err := c.barrier.GenerateKey() if err != nil { c.logger.Printf("[ERR] core: failed to generate master key: %v", err) return nil, fmt.Errorf("master key generation failed: %v", err) } // Return the master key if only a single key part is used results := new(RekeyResult) if c.rekeyConfig.SecretShares == 1 { results.SecretShares = append(results.SecretShares, newMasterKey) } else { // Split the master key using the Shamir algorithm shares, err := shamir.Split(newMasterKey, c.rekeyConfig.SecretShares, c.rekeyConfig.SecretThreshold) if err != nil { c.logger.Printf("[ERR] core: failed to generate shares: %v", err) return nil, fmt.Errorf("failed to generate shares: %v", err) } results.SecretShares = shares } if len(c.rekeyConfig.PGPKeys) > 0 { encryptedShares, err := pgpkeys.EncryptShares(results.SecretShares, c.rekeyConfig.PGPKeys) if err != nil { return nil, err } results.SecretShares = encryptedShares } // Encode the seal configuration buf, err := json.Marshal(c.rekeyConfig) if err != nil { return nil, fmt.Errorf("failed to encode seal configuration: %v", err) } // Rekey the barrier if err := c.barrier.Rekey(newMasterKey); err != nil { c.logger.Printf("[ERR] core: failed to rekey barrier: %v", err) return nil, fmt.Errorf("failed to rekey barrier: %v", err) } c.logger.Printf("[INFO] core: security barrier rekeyed (shares: %d, threshold: %d)", c.rekeyConfig.SecretShares, c.rekeyConfig.SecretThreshold) // Store the seal configuration pe := &physical.Entry{ Key: coreSealConfigPath, Value: buf, } if err := c.physical.Put(pe); err != nil { c.logger.Printf("[ERR] core: failed to update seal configuration: %v", err) return nil, fmt.Errorf("failed to update seal configuration: %v", err) } // Done! c.rekeyProgress = nil c.rekeyConfig = nil return results, nil }
// RecoveryRekeyUpdate is used to provide a new key part func (c *Core) RecoveryRekeyUpdate(key []byte, nonce string) (*RekeyResult, error) { // Ensure we are already unsealed c.stateLock.RLock() defer c.stateLock.RUnlock() if c.sealed { return nil, ErrSealed } if c.standby { return nil, ErrStandby } // Verify the key length min, max := c.barrier.KeyLength() max += shamir.ShareOverhead if len(key) < min { return nil, &ErrInvalidKey{fmt.Sprintf("key is shorter than minimum %d bytes", min)} } if len(key) > max { return nil, &ErrInvalidKey{fmt.Sprintf("key is longer than maximum %d bytes", max)} } c.rekeyLock.Lock() defer c.rekeyLock.Unlock() // Get the seal configuration barrierConfig, err := c.seal.BarrierConfig() if err != nil { return nil, err } // Ensure the barrier is initialized if barrierConfig == nil { return nil, ErrNotInit } existingConfig, err := c.seal.RecoveryConfig() if err != nil { return nil, err } // Ensure a rekey is in progress if c.recoveryRekeyConfig == nil { return nil, fmt.Errorf("no rekey in progress") } if nonce != c.recoveryRekeyConfig.Nonce { return nil, fmt.Errorf("incorrect nonce supplied; nonce for this rekey operation is %s", c.recoveryRekeyConfig.Nonce) } // Check if we already have this piece for _, existing := range c.recoveryRekeyProgress { if bytes.Equal(existing, key) { return nil, nil } } // Store this key c.recoveryRekeyProgress = append(c.recoveryRekeyProgress, key) // Check if we don't have enough keys to unlock if len(c.recoveryRekeyProgress) < existingConfig.SecretThreshold { c.logger.Printf("[DEBUG] core: cannot rekey, have %d of %d keys", len(c.recoveryRekeyProgress), existingConfig.SecretThreshold) return nil, nil } // Recover the master key var masterKey []byte if existingConfig.SecretThreshold == 1 { masterKey = c.recoveryRekeyProgress[0] c.recoveryRekeyProgress = nil } else { masterKey, err = shamir.Combine(c.recoveryRekeyProgress) c.recoveryRekeyProgress = nil if err != nil { return nil, fmt.Errorf("failed to compute recovery key: %v", err) } } // Verify the recovery key if err := c.seal.VerifyRecoveryKey(masterKey); err != nil { c.logger.Printf("[ERR] core: rekey aborted, recovery key verification failed: %v", err) return nil, err } // Generate a new master key newMasterKey, err := c.barrier.GenerateKey() if err != nil { c.logger.Printf("[ERR] core: failed to generate recovery key: %v", err) return nil, fmt.Errorf("recovery key generation failed: %v", err) } // 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 { c.logger.Printf("[ERR] core: failed to generate shares: %v", err) return nil, fmt.Errorf("failed to generate shares: %v", err) } 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 { return nil, err } 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 { c.logger.Printf("[ERR] core: failed to marshal recovery key backup: %v", err) return nil, fmt.Errorf("failed to marshal recovery key backup: %v", err) } pe := &physical.Entry{ Key: coreRecoveryUnsealKeysBackupPath, Value: buf, } if err = c.physical.Put(pe); err != nil { c.logger.Printf("[ERR] core: failed to save unseal key backup: %v", err) return nil, fmt.Errorf("failed to save unseal key backup: %v", err) } } } if err := c.seal.SetRecoveryKey(newMasterKey); err != nil { c.logger.Printf("[ERR] core: failed to set recovery key: %v", err) return nil, fmt.Errorf("failed to set recovery key: %v", err) } if err := c.seal.SetRecoveryConfig(c.recoveryRekeyConfig); err != nil { c.logger.Printf("[ERR] core: error saving rekey seal configuration: %v", err) return nil, fmt.Errorf("failed to save rekey seal configuration: %v", err) } // Done! c.recoveryRekeyProgress = nil c.recoveryRekeyConfig = nil return results, nil }
// GenerateRootUpdate is used to provide a new key part func (c *Core) GenerateRootUpdate(key []byte, nonce string) (*GenerateRootResult, error) { // Verify the key length min, max := c.barrier.KeyLength() max += shamir.ShareOverhead if len(key) < min { return nil, &ErrInvalidKey{fmt.Sprintf("key is shorter than minimum %d bytes", min)} } if len(key) > max { return nil, &ErrInvalidKey{fmt.Sprintf("key is longer than maximum %d bytes", max)} } // Get the seal configuration config, err := c.SealConfig() if err != nil { return nil, err } // Ensure the barrier is initialized if config == nil { return nil, ErrNotInit } // Ensure we are already unsealed c.stateLock.RLock() defer c.stateLock.RUnlock() if c.sealed { return nil, ErrSealed } if c.standby { return nil, ErrStandby } c.generateRootLock.Lock() defer c.generateRootLock.Unlock() // Ensure a generateRoot is in progress if c.generateRootConfig == nil { return nil, fmt.Errorf("no root generation in progress") } if nonce != c.generateRootConfig.Nonce { return nil, fmt.Errorf("incorrect nonce supplied; nonce for this root generation operation is %s", c.generateRootConfig.Nonce) } // Check if we already have this piece for _, existing := range c.generateRootProgress { if bytes.Equal(existing, key) { return nil, nil } } // Store this key c.generateRootProgress = append(c.generateRootProgress, key) progress := len(c.generateRootProgress) // Check if we don't have enough keys to unlock if len(c.generateRootProgress) < config.SecretThreshold { c.logger.Printf("[DEBUG] core: cannot generate root, have %d of %d keys", progress, config.SecretThreshold) return &GenerateRootResult{ Progress: progress, Required: config.SecretThreshold, PGPFingerprint: c.generateRootConfig.PGPFingerprint, }, nil } // Recover the master key var masterKey []byte if config.SecretThreshold == 1 { masterKey = c.generateRootProgress[0] c.generateRootProgress = nil } else { masterKey, err = shamir.Combine(c.generateRootProgress) c.generateRootProgress = nil if err != nil { return nil, fmt.Errorf("failed to compute master key: %v", err) } } // Verify the master key if err := c.barrier.VerifyMaster(masterKey); err != nil { c.logger.Printf("[ERR] core: root generation aborted, master key verification failed: %v", err) return nil, err } te, err := c.tokenStore.rootToken() if err != nil { c.logger.Printf("[ERR] core: root token generation failed: %v", err) return nil, err } if te == nil { c.logger.Printf("[ERR] core: got nil token entry back from root generation") return nil, fmt.Errorf("got nil token entry back from root generation") } uuidBytes, err := uuid.ParseUUID(te.ID) if err != nil { c.tokenStore.Revoke(te.ID) c.logger.Printf("[ERR] core: error getting generated token bytes: %v", err) return nil, err } if uuidBytes == nil { c.tokenStore.Revoke(te.ID) c.logger.Printf("[ERR] core: got nil parsed UUID bytes") return nil, fmt.Errorf("got nil parsed UUID bytes") } var tokenBytes []byte // Get the encoded value first so that if there is an error we don't create // the root token. switch { case len(c.generateRootConfig.OTP) > 0: // This function performs decoding checks so rather than decode the OTP, // just encode the value we're passing in. tokenBytes, err = xor.XORBase64(c.generateRootConfig.OTP, base64.StdEncoding.EncodeToString(uuidBytes)) if err != nil { c.tokenStore.Revoke(te.ID) c.logger.Printf("[ERR] core: xor of root token failed: %v", err) return nil, err } case len(c.generateRootConfig.PGPKey) > 0: _, tokenBytesArr, err := pgpkeys.EncryptShares([][]byte{[]byte(te.ID)}, []string{c.generateRootConfig.PGPKey}) if err != nil { c.tokenStore.Revoke(te.ID) c.logger.Printf("[ERR] core: error encrypting new root token: %v", err) return nil, err } tokenBytes = tokenBytesArr[0] default: c.tokenStore.Revoke(te.ID) return nil, fmt.Errorf("unreachable condition") } results := &GenerateRootResult{ Progress: progress, Required: config.SecretThreshold, EncodedRootToken: base64.StdEncoding.EncodeToString(tokenBytes), PGPFingerprint: c.generateRootConfig.PGPFingerprint, } c.logger.Printf("[INFO] core: root generation finished (nonce: %s)", c.generateRootConfig.Nonce) c.generateRootProgress = nil c.generateRootConfig = nil return results, nil }
// Unseal is used to provide one of the key parts to unseal the Vault. // // They key given as a parameter will automatically be zerod after // this method is done with it. If you want to keep the key around, a copy // should be made. func (c *Core) Unseal(key []byte) (bool, error) { defer metrics.MeasureSince([]string{"core", "unseal"}, time.Now()) // Verify the key length min, max := c.barrier.KeyLength() max += shamir.ShareOverhead if len(key) < min { return false, &ErrInvalidKey{fmt.Sprintf("key is shorter than minimum %d bytes", min)} } if len(key) > max { return false, &ErrInvalidKey{fmt.Sprintf("key is longer than maximum %d bytes", max)} } // Get the seal configuration config, err := c.seal.BarrierConfig() if err != nil { return false, err } // Ensure the barrier is initialized if config == nil { return false, ErrNotInit } c.stateLock.Lock() defer c.stateLock.Unlock() // Check if already unsealed if !c.sealed { return true, nil } // Check if we already have this piece for _, existing := range c.unlockParts { if bytes.Equal(existing, key) { return false, nil } } // Store this key c.unlockParts = append(c.unlockParts, key) // Check if we don't have enough keys to unlock if len(c.unlockParts) < config.SecretThreshold { if c.logger.IsDebug() { c.logger.Debug("core: cannot unseal, not enough keys", "keys", len(c.unlockParts), "threshold", config.SecretThreshold) } return false, nil } // Recover the master key var masterKey []byte if config.SecretThreshold == 1 { masterKey = c.unlockParts[0] c.unlockParts = nil } else { masterKey, err = shamir.Combine(c.unlockParts) c.unlockParts = nil if err != nil { return false, fmt.Errorf("failed to compute master key: %v", err) } } defer memzero(masterKey) // Attempt to unlock if err := c.barrier.Unseal(masterKey); err != nil { return false, err } if c.logger.IsInfo() { c.logger.Info("core: vault is unsealed") } // Do post-unseal setup if HA is not enabled if c.ha == nil { // We still need to set up cluster info even if it's not part of a // cluster right now if err := c.setupCluster(); err != nil { c.logger.Error("core: cluster setup failed", "error", err) c.barrier.Seal() c.logger.Warn("core: vault is sealed") return false, err } if err := c.postUnseal(); err != nil { c.logger.Error("core: post-unseal setup failed", "error", err) c.barrier.Seal() c.logger.Warn("core: vault is sealed") return false, err } c.standby = false } else { // Go to standby mode, wait until we are active to unseal c.standbyDoneCh = make(chan struct{}) c.standbyStopCh = make(chan struct{}) c.manualStepDownCh = make(chan struct{}) go c.runStandby(c.standbyDoneCh, c.standbyStopCh, c.manualStepDownCh) } // Success! c.sealed = false if c.ha != nil { sd, ok := c.ha.(physical.ServiceDiscovery) if ok { if err := sd.NotifySealedStateChange(); err != nil { if c.logger.IsWarn() { c.logger.Warn("core: failed to notify unsealed status", "error", err) } } } } return true, nil }