Skip to content

Commit

Permalink
Reintroduce PrimitiveFromKeyData in Config
Browse files Browse the repository at this point in the history
Removing this API was premature; having a "legacy" way to create primitive using key manager vs the "new" way using constructor functions makes the logic to get `Primitives()` cleaner. The goal is to have `PrimitiveFromKey` always return "full" primitives, that is, primitives that are also aware of the output prefix, and `PrimitiveFromKeyData` to return legacy primitives that do not add any prefix to the output.

PiperOrigin-RevId: 689779144
Change-Id: I8cab76eafa1fb3ecac920f749c3c9c90c3a24fca
  • Loading branch information
morambro authored and copybara-github committed Oct 25, 2024
1 parent 6156308 commit 1ed7ed9
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 70 deletions.
34 changes: 33 additions & 1 deletion internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import (
"fmt"
"reflect"

"github.com/tink-crypto/tink-go/v2/core/registry"
"github.com/tink-crypto/tink-go/v2/internal/internalapi"
"github.com/tink-crypto/tink-go/v2/key"
tinkpb "github.com/tink-crypto/tink-go/v2/proto/tink_go_proto"
)

// Config keeps a collection of functions that create a primitive from
Expand All @@ -29,10 +31,24 @@ import (
// This is an internal API.
type Config struct {
primitiveConstructors map[reflect.Type]primitiveConstructor
keysetManagers map[string]registry.KeyManager
}

type primitiveConstructor func(key key.Key) (any, error)

// PrimitiveFromKeyData creates a primitive from the given [tinkpb.KeyData].
// Returns an error if there is no key manager registered for the given key
// type URL.
//
// This is an internal API.
func (c *Config) PrimitiveFromKeyData(kd *tinkpb.KeyData, _ internalapi.Token) (any, error) {
km, ok := c.keysetManagers[kd.GetTypeUrl()]
if !ok {
return nil, fmt.Errorf("PrimitiveFromKeyData: no key manager for key URL %v", kd.GetTypeUrl())
}
return km.Primitive(kd.GetValue())
}

// PrimitiveFromKey creates a primitive from the given [key.Key]. Returns an
// error if there is no primitiveConstructor registered for the given key.
//
Expand Down Expand Up @@ -63,7 +79,23 @@ func (c *Config) RegisterPrimitiveConstructor(keyType reflect.Type, constructor
return nil
}

// RegisterKeyManger registers a key manager for a key type URL.
//
// Not thread-safe.
//
// This is an internal API.
func (c *Config) RegisterKeyManger(keyTypeURL string, km registry.KeyManager, _ internalapi.Token) error {
if _, ok := c.keysetManagers[keyTypeURL]; ok {
return fmt.Errorf("RegisterKeyManger: attempt to register a different key manager for %v", keyTypeURL)
}
c.keysetManagers[keyTypeURL] = km
return nil
}

// New creates an empty Config.
func New() (*Config, error) {
return &Config{map[reflect.Type]primitiveConstructor{}}, nil
return &Config{
primitiveConstructors: map[reflect.Type]primitiveConstructor{},
keysetManagers: map[string]registry.KeyManager{},
}, nil
}
118 changes: 117 additions & 1 deletion internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ import (
"reflect"
"testing"

"google.golang.org/protobuf/proto"
"github.com/tink-crypto/tink-go/v2/internal/config"
"github.com/tink-crypto/tink-go/v2/internal/internalapi"
"github.com/tink-crypto/tink-go/v2/key"
tinkpb "github.com/tink-crypto/tink-go/v2/proto/tink_go_proto"
)

type testParameters0 struct{}
Expand Down Expand Up @@ -59,7 +61,7 @@ func (tk testKeyUnregistered) Parameters() key.Parameters { retur
func (tk testKeyUnregistered) IDRequirement() (id uint32, required bool) { return 0, false }
func (tk testKeyUnregistered) Equals(other key.Key) bool { return false }

func TestConfigWorks(t *testing.T) {
func TestConfigPrimitiveFromKeyWorks(t *testing.T) {
testConfig, err := config.New()
if err != nil {
t.Fatalf("Config.New() err = %v, want nil", err)
Expand All @@ -80,6 +82,54 @@ func TestConfigWorks(t *testing.T) {
}
}

const (
typeURL0 = "type_url_0"
typeURL1 = "type_url_1"
)

type stubKeyManager0 struct{}

func (km *stubKeyManager0) Primitive(_ []byte) (any, error) { return &testPrimitive0{}, nil }
func (km *stubKeyManager0) NewKeyData(_ []byte) (*tinkpb.KeyData, error) { return nil, nil }
func (km *stubKeyManager0) DoesSupport(t string) bool { return t == typeURL0 }
func (km *stubKeyManager0) TypeURL() string { return typeURL0 }
func (km *stubKeyManager0) NewKey(serializedKeyFormat []byte) (proto.Message, error) {
return nil, nil
}

type stubKeyManager1 struct{}

func (km *stubKeyManager1) Primitive(_ []byte) (any, error) { return &testPrimitive1{}, nil }
func (km *stubKeyManager1) NewKeyData(_ []byte) (*tinkpb.KeyData, error) { return nil, nil }
func (km *stubKeyManager1) DoesSupport(t string) bool { return t == typeURL1 }
func (km *stubKeyManager1) TypeURL() string { return typeURL1 }
func (km *stubKeyManager1) NewKey(serializedKeyFormat []byte) (proto.Message, error) { return nil, nil }

func TestConfigPrimitiveFromKeDataWorks(t *testing.T) {
testConfig, err := config.New()
if err != nil {
t.Fatalf("Config.New() err = %v, want nil", err)
}
token := internalapi.Token{}

err = testConfig.RegisterKeyManger(typeURL0, &stubKeyManager0{}, token)
if err != nil {
t.Fatalf("testConfig.RegisterKeyManger() err = %v, want nil", err)
}

keyData := &tinkpb.KeyData{
TypeUrl: typeURL0,
Value: []byte("key"),
}
p0, err := testConfig.PrimitiveFromKeyData(keyData, token)
if err != nil {
t.Fatalf("testConfig.PrimitiveFromKeyData() err = %v, want nil", err)
}
if p0.(*testPrimitive0) == nil {
t.Errorf("Wrong primitive returned: got %T, want testPrimitive0", p0)
}
}

func TestMultiplePrimitiveConstructors(t *testing.T) {
testConfig, err := config.New()
if err != nil {
Expand Down Expand Up @@ -112,6 +162,38 @@ func TestMultiplePrimitiveConstructors(t *testing.T) {
}
}

func TestMultipleKeyManagers(t *testing.T) {
testConfig, err := config.New()
if err != nil {
t.Fatalf("config.New() err = %v, want nil", err)
}
token := internalapi.Token{}

err = testConfig.RegisterKeyManger(typeURL0, &stubKeyManager0{}, token)
if err != nil {
t.Fatalf("testConfig.RegisterKeyManger() err = %v, want nil", err)
}
err = testConfig.RegisterKeyManger(typeURL1, &stubKeyManager1{}, token)
if err != nil {
t.Fatalf("testConfig.RegisterKeyManger() err = %v, want nil", err)
}

p0, err := testConfig.PrimitiveFromKeyData(&tinkpb.KeyData{TypeUrl: typeURL0, Value: []byte("key")}, token)
if err != nil {
t.Fatalf("testConfig.RegisterPrimitiveConstructor() err = %v, want nil", err)
}
if p0.(*testPrimitive0) == nil {
t.Errorf("Wrong primitive returned: got %T, want testPrimitive0", p0)
}
p1, err := testConfig.PrimitiveFromKeyData(&tinkpb.KeyData{TypeUrl: typeURL1, Value: []byte("key")}, token)
if err != nil {
t.Fatalf("testConfig.RegisterPrimitiveConstructor() err = %v, want nil", err)
}
if p1.(*testPrimitive1) == nil {
t.Errorf("Wrong primitive returned: got %T, want testPrimitive0", p1)
}
}

func TestRegisterDifferentPrimitiveConstructor(t *testing.T) {
testConfig, err := config.New()
if err != nil {
Expand All @@ -131,6 +213,24 @@ func TestRegisterDifferentPrimitiveConstructor(t *testing.T) {
}
}

func TestRegisterDifferentKeyManagers(t *testing.T) {
testConfig, err := config.New()
if err != nil {
t.Fatalf("config.New() err = %v, want nil", err)
}
token := internalapi.Token{}

err = testConfig.RegisterKeyManger(typeURL0, &stubKeyManager0{}, token)
if err != nil {
t.Fatalf("testConfig.RegisterKeyManger() err = %v, want nil", err)
}

// Register another primitiveCreator for the same key type fails.
if err = testConfig.RegisterKeyManger(typeURL0, &stubKeyManager1{}, token); err == nil {
t.Errorf("testConfig.RegisterKeyManger() err = nil, want error")
}
}

func TestUnregisteredPrimitive(t *testing.T) {
testConfig, err := config.New()
if err != nil {
Expand All @@ -151,3 +251,19 @@ func TestUnregisteredPrimitive(t *testing.T) {
t.Errorf("testConfig.PrimitiveFromKey() err = nil, want error")
}
}

func TestUnregisteredKeyManager(t *testing.T) {
testConfig, err := config.New()
if err != nil {
t.Fatalf("config.New() err = %v, want nil", err)
}
token := internalapi.Token{}

if err = testConfig.RegisterKeyManger(typeURL0, &stubKeyManager0{}, token); err != nil {
t.Fatalf("testConfig.RegisterKeyManger() err = %v, want nil", err)
}

if _, err := testConfig.PrimitiveFromKeyData(&tinkpb.KeyData{TypeUrl: typeURL1, Value: []byte("key")}, token); err == nil {
t.Errorf("testConfig.PrimitiveFromKey() err = nil, want error")
}
}
14 changes: 7 additions & 7 deletions internal/registryconfig/registry_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import (

"github.com/tink-crypto/tink-go/v2/core/registry"
"github.com/tink-crypto/tink-go/v2/internal/internalapi"
"github.com/tink-crypto/tink-go/v2/internal/protoserialization"
"github.com/tink-crypto/tink-go/v2/key"
tinkpb "github.com/tink-crypto/tink-go/v2/proto/tink_go_proto"
)

var (
Expand All @@ -39,19 +39,19 @@ type primitiveConstructor func(key key.Key) (any, error)
// old global Registry through the new Configuration interface.
type RegistryConfig struct{}

// PrimitiveFromKeyData constructs a primitive from a [key.Key] using the registry.
func (c *RegistryConfig) PrimitiveFromKeyData(keyData *tinkpb.KeyData, _ internalapi.Token) (any, error) {
return registry.PrimitiveFromKeyData(keyData)
}

// PrimitiveFromKey constructs a primitive from a [key.Key] using the registry.
func (c *RegistryConfig) PrimitiveFromKey(key key.Key, _ internalapi.Token) (any, error) {
if key == nil {
return nil, fmt.Errorf("key is nil")
}
constructor, found := primitiveConstructors[reflect.TypeOf(key)]
if !found {
// Fallback to using the key manager.
keySerialization, err := protoserialization.SerializeKey(key)
if err != nil {
return nil, err
}
return registry.PrimitiveFromKeyData(keySerialization.KeyData())
return nil, fmt.Errorf("no constructor found for key %T", key)
}
return constructor(key)
}
Expand Down
Loading

0 comments on commit 1ed7ed9

Please sign in to comment.