Fix GetValue methods to return LockedBuffer internally

- Changed Secret.GetValue and Version.GetValue to return *memguard.LockedBuffer
- Updated all internal callers to handle LockedBuffer properly
- For backward compatibility, vault.GetSecret still returns []byte but makes a copy
- This ensures secret values are protected in memory during decryption
- Updated tests to handle LockedBuffer returns
- Fixed CLI getSecretValue to use LockedBuffer throughout
This commit is contained in:
2025-07-15 08:59:23 +02:00
parent 819902f385
commit 8ec3fc877d
6 changed files with 32 additions and 39 deletions

View File

@@ -96,21 +96,13 @@ func (cli *Instance) Encrypt(secretName, inputFile, outputFile string) error {
}
} else {
// Secret exists, get the age secret key from it
secretValue, err := cli.getSecretValue(vlt, secretObj)
secretBuffer, err := cli.getSecretValue(vlt, secretObj)
if err != nil {
return fmt.Errorf("failed to get secret value: %w", err)
}
defer secretBuffer.Destroy()
// Create secure buffer for the secret value
secureBuffer := memguard.NewBufferFromBytes(secretValue)
defer secureBuffer.Destroy()
// Clear the original secret value
for i := range secretValue {
secretValue[i] = 0
}
ageSecretKey = secureBuffer.String()
ageSecretKey = secretBuffer.String()
// Validate that it's a valid age secret key
if !isValidAgeSecretKey(ageSecretKey) {
@@ -189,36 +181,28 @@ func (cli *Instance) Decrypt(secretName, inputFile, outputFile string) error {
}
// Get the age secret key from the secret
var secretValue []byte
var secretBuffer *memguard.LockedBuffer
if os.Getenv(secret.EnvMnemonic) != "" {
secretValue, err = secretObj.GetValue(nil)
secretBuffer, err = secretObj.GetValue(nil)
} else {
unlocker, unlockErr := vlt.GetCurrentUnlocker()
if unlockErr != nil {
return fmt.Errorf("failed to get current unlocker: %w", unlockErr)
}
secretValue, err = secretObj.GetValue(unlocker)
secretBuffer, err = secretObj.GetValue(unlocker)
}
if err != nil {
return fmt.Errorf("failed to get secret value: %w", err)
}
// Create secure buffer for the secret value
secureBuffer := memguard.NewBufferFromBytes(secretValue)
defer secureBuffer.Destroy()
// Clear the original secret value
for i := range secretValue {
secretValue[i] = 0
}
defer secretBuffer.Destroy()
// Validate that it's a valid age secret key
if !isValidAgeSecretKey(secureBuffer.String()) {
if !isValidAgeSecretKey(secretBuffer.String()) {
return fmt.Errorf("secret '%s' does not contain a valid age secret key", secretName)
}
// Parse the age secret key to get the identity
identity, err := age.ParseX25519Identity(secureBuffer.String())
identity, err := age.ParseX25519Identity(secretBuffer.String())
if err != nil {
return fmt.Errorf("failed to parse age secret key: %w", err)
}
@@ -266,7 +250,7 @@ func isValidAgeSecretKey(key string) bool {
}
// getSecretValue retrieves the value of a secret using the appropriate unlocker
func (cli *Instance) getSecretValue(vlt *vault.Vault, secretObj *secret.Secret) ([]byte, error) {
func (cli *Instance) getSecretValue(vlt *vault.Vault, secretObj *secret.Secret) (*memguard.LockedBuffer, error) {
if os.Getenv(secret.EnvMnemonic) != "" {
return secretObj.GetValue(nil)
}