1
0
mirror of https://github.com/getsops/sops.git synced 2026-02-05 12:45:21 +01:00

Fix KMS encryption context handling (#435)

* Fix KMS encryption context handling

The code copying encryption context value strings to a map
containing string pointers was incorrectly getting a pointer to a
string variable which is being re-used by the for loop, causing
all keys to point to the same value string.

* Extract helper method for KmsKey to KMS MasterKey conversion

* Add test for kmsKeyToMasterKey helper function
This commit is contained in:
jpsrn
2019-03-21 19:08:37 +02:00
committed by AJ Bahnken
parent 51503b5177
commit f2e48b1a2c
2 changed files with 97 additions and 20 deletions

View File

@@ -29,16 +29,7 @@ func (ks *Server) encryptWithPgp(key *PgpKey, plaintext []byte) ([]byte, error)
}
func (ks *Server) encryptWithKms(key *KmsKey, plaintext []byte) ([]byte, error) {
ctx := make(map[string]*string)
for k, v := range key.Context {
ctx[k] = &v
}
kmsKey := kms.MasterKey{
Arn: key.Arn,
Role: key.Role,
EncryptionContext: ctx,
AwsProfile: key.AwsProfile,
}
kmsKey := kmsKeyToMasterKey(key)
err := kmsKey.Encrypt(plaintext)
if err != nil {
return nil, err
@@ -78,16 +69,7 @@ func (ks *Server) decryptWithPgp(key *PgpKey, ciphertext []byte) ([]byte, error)
}
func (ks *Server) decryptWithKms(key *KmsKey, ciphertext []byte) ([]byte, error) {
ctx := make(map[string]*string)
for k, v := range key.Context {
ctx[k] = &v
}
kmsKey := kms.MasterKey{
Arn: key.Arn,
Role: key.Role,
EncryptionContext: ctx,
AwsProfile: key.AwsProfile,
}
kmsKey := kmsKeyToMasterKey(key)
kmsKey.EncryptedKey = string(ciphertext)
plaintext, err := kmsKey.Decrypt()
return []byte(plaintext), err
@@ -249,3 +231,17 @@ func (ks Server) Decrypt(ctx context.Context,
}
return response, nil
}
func kmsKeyToMasterKey(key *KmsKey) kms.MasterKey {
ctx := make(map[string]*string)
for k, v := range key.Context {
value := v // Allocate a new string to prevent the pointer below from referring to only the last iteration value
ctx[k] = &value
}
return kms.MasterKey{
Arn: key.Arn,
Role: key.Role,
EncryptionContext: ctx,
AwsProfile: key.AwsProfile,
}
}

81
keyservice/server_test.go Normal file
View File

@@ -0,0 +1,81 @@
package keyservice
import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
)
func TestKmsKeyToMasterKey(t *testing.T) {
cases := []struct {
description string
expectedArn string
expectedRole string
expectedCtx map[string]string
expectedAwsProfile string
}{
{
description: "empty context",
expectedArn: "arn:aws:kms:eu-west-1:123456789012:key/d5c90a06-f824-4628-922b-12424571ed4d",
expectedRole: "ExampleRole",
expectedCtx: map[string]string{},
expectedAwsProfile: "",
},
{
description: "context with one key-value pair",
expectedArn: "arn:aws:kms:eu-west-1:123456789012:key/d5c90a06-f824-4628-922b-12424571ed4d",
expectedRole: "",
expectedCtx: map[string]string{
"firstKey": "first value",
},
expectedAwsProfile: "ExampleProfile",
},
{
description: "context with three key-value pairs",
expectedArn: "arn:aws:kms:eu-west-1:123456789012:key/d5c90a06-f824-4628-922b-12424571ed4d",
expectedRole: "",
expectedCtx: map[string]string{
"firstKey": "first value",
"secondKey": "second value",
"thirdKey": "third value",
},
expectedAwsProfile: "",
},
}
for _, c := range cases {
t.Run(c.description, func(t *testing.T) {
inputCtx := make(map[string]string)
for k, v := range c.expectedCtx {
inputCtx[k] = v
}
key := &KmsKey{
Arn: c.expectedArn,
Role: c.expectedRole,
Context: inputCtx,
AwsProfile: c.expectedAwsProfile,
}
masterKey := kmsKeyToMasterKey(key)
foundCtx := masterKey.EncryptionContext
for k, _ := range c.expectedCtx {
require.Containsf(t, foundCtx, k, "Context does not contain expected key '%s'", k)
}
for k, _ := range foundCtx {
require.Containsf(t, c.expectedCtx, k, "Context contains an unexpected key '%s' which cannot be found from expected map", k)
}
for k, expected := range c.expectedCtx {
foundVal := *foundCtx[k]
assert.Equalf(t, expected, foundVal, "Context key '%s' value '%s' does not match expected value '%s'", k, foundVal, expected)
}
assert.Equalf(t, c.expectedArn, masterKey.Arn, "Expected ARN to be '%s', but found '%s'", c.expectedArn, masterKey.Arn)
assert.Equalf(t, c.expectedRole, masterKey.Role, "Expected Role to be '%s', but found '%s'", c.expectedRole, masterKey.Role)
assert.Equalf(t, c.expectedAwsProfile, masterKey.AwsProfile, "Expected AWS profile to be '%s', but found '%s'", c.expectedAwsProfile, masterKey.AwsProfile)
})
}
}