func (c *Core) generateShares(sc *SealConfig) ([]byte, [][]byte, error) { // Generate a master key masterKey, err := c.barrier.GenerateKey() if err != nil { return nil, nil, fmt.Errorf("key generation failed: %v", err) } // Return the master key if only a single key part is used var unsealKeys [][]byte if sc.SecretShares == 1 { unsealKeys = append(unsealKeys, masterKey) } else { // Split the master key using the Shamir algorithm shares, err := shamir.Split(masterKey, sc.SecretShares, sc.SecretThreshold) if err != nil { return nil, nil, fmt.Errorf("failed to generate shares: %v", err) } unsealKeys = shares } // If we have PGP keys, perform the encryption if len(sc.PGPKeys) > 0 { hexEncodedShares := make([][]byte, len(unsealKeys)) for i, _ := range unsealKeys { hexEncodedShares[i] = []byte(hex.EncodeToString(unsealKeys[i])) } _, encryptedShares, err := pgpkeys.EncryptShares(hexEncodedShares, sc.PGPKeys) if err != nil { return nil, nil, err } unsealKeys = encryptedShares } return masterKey, unsealKeys, nil }
// Initialize is used to initialize the Vault with the given // configurations. func (c *Core) Initialize(config *SealConfig) (*InitResult, error) { // Check if the seal configuraiton is valid if err := config.Validate(); err != nil { c.logger.Printf("[ERR] core: invalid seal configuration: %v", err) return nil, fmt.Errorf("invalid seal configuration: %v", err) } // Avoid an initialization race c.stateLock.Lock() defer c.stateLock.Unlock() // Check if we are initialized init, err := c.Initialized() if err != nil { return nil, err } if init { return nil, ErrAlreadyInit } // Encode the seal configuration buf, err := json.Marshal(config) if err != nil { return nil, fmt.Errorf("failed to encode seal configuration: %v", err) } // 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 write seal configuration: %v", err) return nil, fmt.Errorf("failed to write seal configuration: %v", err) } // Generate a master key masterKey, 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(InitResult) if config.SecretShares == 1 { results.SecretShares = append(results.SecretShares, masterKey) } else { // Split the master key using the Shamir algorithm shares, err := shamir.Split(masterKey, config.SecretShares, config.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(config.PGPKeys) > 0 { encryptedShares, err := pgpkeys.EncryptShares(results.SecretShares, config.PGPKeys) if err != nil { return nil, err } results.SecretShares = encryptedShares } // Initialize the barrier if err := c.barrier.Initialize(masterKey); err != nil { c.logger.Printf("[ERR] core: failed to initialize barrier: %v", err) return nil, fmt.Errorf("failed to initialize barrier: %v", err) } c.logger.Printf("[INFO] core: security barrier initialized (shares: %d, threshold %d)", config.SecretShares, config.SecretThreshold) // Unseal the barrier if err := c.barrier.Unseal(masterKey); err != nil { c.logger.Printf("[ERR] core: failed to unseal barrier: %v", err) return nil, fmt.Errorf("failed to unseal barrier: %v", err) } // Ensure the barrier is re-sealed defer func() { if err := c.barrier.Seal(); err != nil { c.logger.Printf("[ERR] core: failed to seal barrier: %v", err) } }() // Perform initial setup if err := c.postUnseal(); err != nil { c.logger.Printf("[ERR] core: post-unseal setup failed: %v", err) return nil, err } // Generate a new root token rootToken, err := c.tokenStore.RootToken() if err != nil { c.logger.Printf("[ERR] core: root token generation failed: %v", err) return nil, err } results.RootToken = rootToken.ID c.logger.Printf("[INFO] core: root token generated") // Prepare to re-seal if err := c.preSeal(); err != nil { c.logger.Printf("[ERR] core: pre-seal teardown failed: %v", err) return nil, err } return results, 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 }