diff --git a/keyservice/keyservice.go b/keyservice/keyservice.go index 04125f7510..bd893a02df 100644 --- a/keyservice/keyservice.go +++ b/keyservice/keyservice.go @@ -5,6 +5,7 @@ master keys. package keyservice import ( + "errors" "fmt" "github.com/getsops/sops/v3/age" @@ -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{ @@ -27,7 +39,7 @@ func KeyFromMasterKey(mk keys.MasterKey) Key { Fingerprint: mk.Fingerprint, }, }, - } + }, nil case *gcpkms.MasterKey: return Key{ KeyType: &Key_GcpKmsKey{ @@ -35,7 +47,7 @@ func KeyFromMasterKey(mk keys.MasterKey) Key { ResourceId: mk.ResourceID, }, }, - } + }, nil case *hcvault.MasterKey: return Key{ KeyType: &Key_VaultKey{ @@ -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 { @@ -60,7 +72,7 @@ func KeyFromMasterKey(mk keys.MasterKey) Key { AwsProfile: mk.AwsProfile, }, }, - } + }, nil case *azkv.MasterKey: return Key{ KeyType: &Key_AzureKeyvaultKey{ @@ -70,7 +82,7 @@ func KeyFromMasterKey(mk keys.MasterKey) Key { Version: mk.Version, }, }, - } + }, nil case *age.MasterKey: return Key{ KeyType: &Key_AgeKey{ @@ -78,7 +90,7 @@ func KeyFromMasterKey(mk keys.MasterKey) Key { Recipient: mk.Recipient, }, }, - } + }, nil case *hckms.MasterKey: return Key{ KeyType: &Key_HckmsKey{ @@ -86,8 +98,8 @@ func KeyFromMasterKey(mk keys.MasterKey) Key { 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) } } diff --git a/keyservice/keyservice_test.go b/keyservice/keyservice_test.go new file mode 100644 index 0000000000..9657079642 --- /dev/null +++ b/keyservice/keyservice_test.go @@ -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{}) +} diff --git a/sops.go b/sops.go index 797ba08d80..c2acd6c627 100644 --- a/sops.go +++ b/sops.go @@ -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 { @@ -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(),