Skip to content

Commit

Permalink
Merge pull request getsops#966 from cedi/fix/sops-multi-recipient
Browse files Browse the repository at this point in the history
[Fix] sops multi recipient for age encryption
  • Loading branch information
ajvb committed Mar 22, 2022
2 parents e682723 + 1dc90ad commit 66090e7
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 27 deletions.
3 changes: 3 additions & 0 deletions age/keys.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# created: 2020-07-18T03:16:47-07:00
# public key: age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw
AGE-SECRET-KEY-1NJT5YCS2LWU4V4QAJQ6R4JNU7LXPDX602DZ9NUFANVU5GDTGUWCQ5T59M6
# created: 2021-12-12T01:39:30+01:00
# public key: age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep
AGE-SECRET-KEY-1T0Z66WSXS6RMNCPSL7P2E8N4Q7SUD8VMG9ND27S08JL7Y2XAU9EQECHDS7
6 changes: 3 additions & 3 deletions age/keysource.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func MasterKeysFromRecipients(commaSeparatedRecipients string) ([]*MasterKey, er
var keys []*MasterKey

for _, recipient := range recipients {
key, err := MasterKeyFromRecipient(recipient)
key, err := masterKeyFromRecipient(recipient)

if err != nil {
return nil, err
Expand All @@ -196,8 +196,8 @@ func MasterKeysFromRecipients(commaSeparatedRecipients string) ([]*MasterKey, er
return keys, nil
}

// MasterKeyFromRecipient takes a Bech32-encoded public key and returns a new MasterKey.
func MasterKeyFromRecipient(recipient string) (*MasterKey, error) {
// masterKeyFromRecipient takes a Bech32-encoded public key and returns a new MasterKey.
func masterKeyFromRecipient(recipient string) (*MasterKey, error) {
recipient = strings.TrimSpace(recipient)
parsedRecipient, err := parseRecipient(recipient)

Expand Down
95 changes: 75 additions & 20 deletions age/keysource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,76 +21,131 @@ func TestMasterKeysFromRecipientsEmpty(t *testing.T) {
assert.Equal(recipients, make([]*MasterKey, 0))
}

func TestMasterKeyFromRecipientWithLeadingAndTrailingSpaces(t *testing.T) {
func TestMasterKeyFromRecipientWithLeadingAndTrailingSpacesSingle(t *testing.T) {
assert := assert.New(t)

key, err := MasterKeyFromRecipient(" age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw ")
commaSeparatedRecipients := " age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw "
keys, err := MasterKeysFromRecipients(commaSeparatedRecipients)

assert.NoError(err)

assert.Equal(key.Recipient, "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw")
assert.Equal(len(keys), 1)
assert.Equal(keys[0].Recipient, "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw")
}

func TestAge(t *testing.T) {
func TestMasterKeyFromRecipientWithLeadingAndTrailingSpacesMultiple(t *testing.T) {
assert := assert.New(t)

key, err := MasterKeyFromRecipient("age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw")
commaSeparatedRecipients := " age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw , age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep "
keys, err := MasterKeysFromRecipients(commaSeparatedRecipients)

assert.NoError(err)
assert.Equal("age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw", key.ToString())

dataKey := []byte("abcdefghijklmnopqrstuvwxyz123456")
assert.Equal(len(keys), 2)
assert.Equal(keys[0].Recipient, "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw")
assert.Equal(keys[1].Recipient, "age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep")
}

func TestMasterKeysFromRecipientsWithSingle(t *testing.T) {
assert := assert.New(t)

commaSeparatedRecipients := "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw"
keys, err := MasterKeysFromRecipients(commaSeparatedRecipients)

err = key.Encrypt(dataKey)
assert.NoError(err)

_, filename, _, _ := runtime.Caller(0)
err = os.Setenv(SopsAgeKeyFileEnv, path.Join(path.Dir(filename), "keys.txt"))
assert.Equal(len(keys), 1)
assert.Equal(keys[0].Recipient, "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw")
}

func TestMasterKeysFromRecipientsWithMultiple(t *testing.T) {
assert := assert.New(t)

commaSeparatedRecipients := "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw,age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep"
keys, err := MasterKeysFromRecipients(commaSeparatedRecipients)

assert.NoError(err)

decryptedKey, err := key.Decrypt()
assert.Equal(len(keys), 2)
assert.Equal(keys[0].Recipient, "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw")
assert.Equal(keys[1].Recipient, "age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep")
}

func TestAge(t *testing.T) {
assert := assert.New(t)

commaSeparatedRecipients := "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw,age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep"
keys, err := MasterKeysFromRecipients(commaSeparatedRecipients)

assert.NoError(err)
assert.Equal(dataKey, decryptedKey)

assert.Equal(len(keys), 2)
assert.Equal(keys[0].Recipient, "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw")
assert.Equal(keys[1].Recipient, "age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep")

dataKey := []byte("abcdefghijklmnopqrstuvwxyz123456")

for _, key := range keys {
err = key.Encrypt(dataKey)
assert.NoError(err)

_, filename, _, _ := runtime.Caller(0)
err = os.Setenv("SOPS_AGE_KEY_FILE", path.Join(path.Dir(filename), "keys.txt"))
assert.NoError(err)

decryptedKey, err := key.Decrypt()
assert.NoError(err)
assert.Equal(dataKey, decryptedKey)
}

}

func TestAgeDotEnv(t *testing.T) {
assert := assert.New(t)

key, err := MasterKeyFromRecipient("age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw")
commaSeparatedRecipients := "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw,age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep"
keys, err := MasterKeysFromRecipients(commaSeparatedRecipients)

assert.NoError(err)
assert.Equal("age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw", key.ToString())

assert.Equal(len(keys), 2)
assert.Equal(keys[0].Recipient, "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw")
assert.Equal(keys[1].Recipient, "age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep")

dotenv := `IMAGE_PREFIX=repo/service-
APPLICATION_KEY=K6pfAWuUVND9Fz5SC7jmA6pfAWuUVND9Fz5SC7jmA
KEY_ID=003683d721f2ae683d721f2a1
DOMAIN=files.127.0.0.1.nip.io`
dataKey := []byte(dotenv)

err = key.Encrypt(dataKey)
err = keys[0].Encrypt(dataKey)
assert.NoError(err)

_, filename, _, _ := runtime.Caller(0)
err = os.Setenv(SopsAgeKeyFileEnv, path.Join(path.Dir(filename), "keys.txt"))
defer os.Unsetenv(SopsAgeKeyFileEnv)
assert.NoError(err)

decryptedKey, err := key.Decrypt()
decryptedKey, err := keys[0].Decrypt()
assert.NoError(err)
assert.Equal(dataKey, decryptedKey)
}

func TestAgeEnv(t *testing.T) {
assert := assert.New(t)

key, err := MasterKeyFromRecipient("age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw")
commaSeparatedRecipients := "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw,age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep"
keys, err := MasterKeysFromRecipients(commaSeparatedRecipients)

assert.NoError(err)
assert.Equal("age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw", key.ToString())

assert.Equal(len(keys), 2)
assert.Equal(keys[0].Recipient, "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw")
assert.Equal(keys[1].Recipient, "age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep")

dataKey := []byte("abcdefghijklmnopqrstuvwxyz123456")

err = key.Encrypt(dataKey)
err = keys[0].Encrypt(dataKey)
assert.NoError(err)

_, filename, _, _ := runtime.Caller(0)
Expand All @@ -100,7 +155,7 @@ func TestAgeEnv(t *testing.T) {
defer os.Unsetenv(SopsAgeKeyEnv)
assert.NoError(err)

decryptedKey, err := key.Decrypt()
decryptedKey, err := keys[0].Decrypt()
assert.NoError(err)
assert.Equal(dataKey, decryptedKey)
}
6 changes: 4 additions & 2 deletions cmd/sops/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,12 +442,14 @@ func main() {
group = append(group, k)
}
for _, recipient := range ageRecipients {
k, err := age.MasterKeyFromRecipient(recipient)
keys, err := age.MasterKeysFromRecipients(recipient)
if err != nil {
log.WithError(err).Error("Failed to add key")
continue
}
group = append(group, k)
for _, key := range keys {
group = append(group, key)
}
}
return groups.Add(groups.AddOpts{
InputPath: c.String("file"),
Expand Down
6 changes: 4 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,13 @@ func getKeyGroupsFromCreationRule(cRule *creationRule, kmsEncryptionContext map[
for _, group := range cRule.KeyGroups {
var keyGroup sops.KeyGroup
for _, k := range group.Age {
key, err := age.MasterKeyFromRecipient(k)
keys, err := age.MasterKeysFromRecipients(k)
if err != nil {
return nil, err
}
keyGroup = append(keyGroup, key)
for _, key := range keys {
keyGroup = append(keyGroup, key)
}
}
for _, k := range group.PGP {
keyGroup = append(keyGroup, pgp.NewMasterKeyFromFingerprint(k))
Expand Down

0 comments on commit 66090e7

Please sign in to comment.