Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions keyservice/keyservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ master keys.
package keyservice

import (
"errors"
"fmt"

"github.com/getsops/sops/v3/age"
Expand All @@ -17,8 +18,19 @@ import (
"github.com/getsops/sops/v3/pgp"
)

// ErrUnsupportedMasterKeyType indicates that the provided master key type cannot be converted
// into a keyservice RPC key.
var ErrUnsupportedMasterKeyType = errors.New("unsupported master key type")

// KeyFromMasterKey converts a SOPS internal MasterKey to an RPC Key that can be serialized with Protocol Buffers
func KeyFromMasterKey(mk keys.MasterKey) Key {
k, _ := KeyFromMasterKeyOrError(mk)
return k
}

// KeyFromMasterKeyOrError converts a SOPS internal MasterKey to an RPC Key and
// returns an error for unsupported key types.
func KeyFromMasterKeyOrError(mk keys.MasterKey) (Key, error) {
switch mk := mk.(type) {
case *pgp.MasterKey:
return Key{
Expand All @@ -27,15 +39,15 @@ func KeyFromMasterKey(mk keys.MasterKey) Key {
Fingerprint: mk.Fingerprint,
},
},
}
}, nil
case *gcpkms.MasterKey:
return Key{
KeyType: &Key_GcpKmsKey{
GcpKmsKey: &GcpKmsKey{
ResourceId: mk.ResourceID,
},
},
}
}, nil
case *hcvault.MasterKey:
return Key{
KeyType: &Key_VaultKey{
Expand All @@ -45,7 +57,7 @@ func KeyFromMasterKey(mk keys.MasterKey) Key {
KeyName: mk.KeyName,
},
},
}
}, nil
case *kms.MasterKey:
ctx := make(map[string]string)
for k, v := range mk.EncryptionContext {
Expand All @@ -60,7 +72,7 @@ func KeyFromMasterKey(mk keys.MasterKey) Key {
AwsProfile: mk.AwsProfile,
},
},
}
}, nil
case *azkv.MasterKey:
return Key{
KeyType: &Key_AzureKeyvaultKey{
Expand All @@ -70,24 +82,24 @@ func KeyFromMasterKey(mk keys.MasterKey) Key {
Version: mk.Version,
},
},
}
}, nil
case *age.MasterKey:
return Key{
KeyType: &Key_AgeKey{
AgeKey: &AgeKey{
Recipient: mk.Recipient,
},
},
}
}, nil
case *hckms.MasterKey:
return Key{
KeyType: &Key_HckmsKey{
HckmsKey: &HckmsKey{
KeyId: mk.KeyID,
},
},
}
}, nil
default:
panic(fmt.Sprintf("Tried to convert unknown MasterKey type %T to keyservice.Key", mk))
return Key{}, fmt.Errorf("%w: %T", ErrUnsupportedMasterKeyType, mk)
}
}
38 changes: 38 additions & 0 deletions keyservice/keyservice_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package keyservice

import (
"errors"
"testing"
)

type unsupportedMasterKey struct{}

func (k *unsupportedMasterKey) Encrypt([]byte) error { return nil }
func (k *unsupportedMasterKey) EncryptIfNeeded([]byte) error { return nil }
func (k *unsupportedMasterKey) EncryptedDataKey() []byte { return nil }
func (k *unsupportedMasterKey) SetEncryptedDataKey([]byte) {}
func (k *unsupportedMasterKey) Decrypt() ([]byte, error) { return nil, nil }
func (k *unsupportedMasterKey) NeedsRotation() bool { return false }
func (k *unsupportedMasterKey) ToString() string { return "unsupported" }
func (k *unsupportedMasterKey) ToMap() map[string]interface{} { return nil }
func (k *unsupportedMasterKey) TypeToIdentifier() string { return "unsupported" }

func TestKeyFromMasterKeyOrErrorUnsupportedType(t *testing.T) {
_, err := KeyFromMasterKeyOrError(&unsupportedMasterKey{})
if err == nil {
t.Fatal("expected error for unsupported key type")
}
if !errors.Is(err, ErrUnsupportedMasterKeyType) {
t.Fatalf("expected ErrUnsupportedMasterKeyType, got: %v", err)
}
}

func TestKeyFromMasterKeyDoesNotPanicOnUnsupportedType(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Fatalf("expected no panic, got panic: %v", r)
}
}()

_ = KeyFromMasterKey(&unsupportedMasterKey{})
}
14 changes: 12 additions & 2 deletions sops.go
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,11 @@ func (m *Metadata) UpdateMasterKeysWithKeyServices(dataKey []byte, svcs []keyser
}
}
for _, key := range group {
svcKey := keyservice.KeyFromMasterKey(key)
svcKey, err := keyservice.KeyFromMasterKeyOrError(key)
if err != nil {
errs = append(errs, fmt.Errorf("failed to convert master key %q for key service: %w", key.ToString(), err))
continue
}
var keyErrs []error
encrypted := false
for _, svc := range svcs {
Expand Down Expand Up @@ -928,7 +932,13 @@ func sortKeyGroupIndices(group KeyGroup, decryptionOrder []string) []int {
// decryptKey tries to decrypt the contents of the provided MasterKey with any
// of the key services, returning as soon as one key service succeeds.
func decryptKey(key keys.MasterKey, svcs []keyservice.KeyServiceClient) ([]byte, error) {
svcKey := keyservice.KeyFromMasterKey(key)
svcKey, err := keyservice.KeyFromMasterKeyOrError(key)
if err != nil {
return nil, &decryptKeyError{
keyName: key.ToString(),
errs: []error{err},
}
}
var part []byte
decryptErr := decryptKeyError{
keyName: key.ToString(),
Expand Down