From bfa28b132c0b66e844cef8073a9f4f1dd3484480 Mon Sep 17 00:00:00 2001 From: roos Date: Fri, 13 Dec 2019 11:07:32 +0100 Subject: [PATCH 1/2] TrustStore: Add signer Add Signer that implements infra.Signer. Additionally, add a signer generator that selects the correct key based on the latest certificate chain. fixes #3118 --- go/lib/infra/modules/trust/v2/BUILD.bazel | 6 + go/lib/infra/modules/trust/v2/main_test.go | 10 + .../modules/trust/v2/mock_v2/BUILD.bazel | 1 + go/lib/infra/modules/trust/v2/mock_v2/v2.go | 41 +- go/lib/infra/modules/trust/v2/signer.go | 166 +++++++++ go/lib/infra/modules/trust/v2/signer_test.go | 349 ++++++++++++++++++ tools/gomocks | 2 +- 7 files changed, 573 insertions(+), 2 deletions(-) create mode 100644 go/lib/infra/modules/trust/v2/signer.go create mode 100644 go/lib/infra/modules/trust/v2/signer_test.go diff --git a/go/lib/infra/modules/trust/v2/BUILD.bazel b/go/lib/infra/modules/trust/v2/BUILD.bazel index 3a1f52c2c7..a173aeeebb 100644 --- a/go/lib/infra/modules/trust/v2/BUILD.bazel +++ b/go/lib/infra/modules/trust/v2/BUILD.bazel @@ -12,17 +12,20 @@ go_library( "resolver.go", "router.go", "rpc.go", + "signer.go", ], importpath = "github.com/scionproto/scion/go/lib/infra/modules/trust/v2", visibility = ["//visibility:public"], deps = [ "//go/lib/addr:go_default_library", "//go/lib/common:go_default_library", + "//go/lib/ctrl:go_default_library", "//go/lib/ctrl/cert_mgmt:go_default_library", "//go/lib/infra:go_default_library", "//go/lib/infra/messenger:go_default_library", "//go/lib/infra/modules/db:go_default_library", "//go/lib/infra/modules/trust/v2/internal/decoded:go_default_library", + "//go/lib/keyconf:go_default_library", "//go/lib/log:go_default_library", "//go/lib/scrypto:go_default_library", "//go/lib/scrypto/cert/v2:go_default_library", @@ -46,6 +49,7 @@ go_test( "recurser_test.go", "resolver_test.go", "router_test.go", + "signer_test.go", ], data = [ "//go/lib/infra/modules/trust/v2/testdata:crypto_tar", @@ -54,11 +58,13 @@ go_test( deps = [ "//go/lib/addr:go_default_library", "//go/lib/common:go_default_library", + "//go/lib/ctrl:go_default_library", "//go/lib/ctrl/cert_mgmt:go_default_library", "//go/lib/infra:go_default_library", "//go/lib/infra/mock_infra:go_default_library", "//go/lib/infra/modules/trust/v2/internal/decoded:go_default_library", "//go/lib/infra/modules/trust/v2/mock_v2:go_default_library", + "//go/lib/keyconf:go_default_library", "//go/lib/log:go_default_library", "//go/lib/scrypto:go_default_library", "//go/lib/scrypto/cert/v2:go_default_library", diff --git a/go/lib/infra/modules/trust/v2/main_test.go b/go/lib/infra/modules/trust/v2/main_test.go index cd7e2e9f75..0790c7da03 100644 --- a/go/lib/infra/modules/trust/v2/main_test.go +++ b/go/lib/infra/modules/trust/v2/main_test.go @@ -26,6 +26,7 @@ import ( "github.com/scionproto/scion/go/lib/addr" "github.com/scionproto/scion/go/lib/infra/modules/trust/v2/internal/decoded" + "github.com/scionproto/scion/go/lib/keyconf" "github.com/scionproto/scion/go/lib/log" "github.com/scionproto/scion/go/lib/scrypto" "github.com/scionproto/scion/go/lib/scrypto/cert/v2" @@ -138,3 +139,12 @@ func loadChain(t *testing.T, desc ChainDesc) decoded.Chain { require.NoError(t, err, help) return chain } + +func loadPrivateKey(t *testing.T, id keyconf.ID) keyconf.Key { + t.Helper() + file := filepath.Join(tmpDir, fmt.Sprintf("ISD%d/AS%s/keys", id.IA.I, id.IA.A.FileFmt()), + keyconf.PrivateKeyFile(id.Usage, id.Version)) + key, err := keyconf.LoadKeyFromFile(file, keyconf.PrivateKey, id) + require.NoError(t, err, help) + return key +} diff --git a/go/lib/infra/modules/trust/v2/mock_v2/BUILD.bazel b/go/lib/infra/modules/trust/v2/mock_v2/BUILD.bazel index 1b6d5df1d7..5b96031141 100644 --- a/go/lib/infra/modules/trust/v2/mock_v2/BUILD.bazel +++ b/go/lib/infra/modules/trust/v2/mock_v2/BUILD.bazel @@ -10,6 +10,7 @@ go_library( "//go/lib/infra:go_default_library", "//go/lib/infra/modules/trust/v2:go_default_library", "//go/lib/infra/modules/trust/v2/internal/decoded:go_default_library", + "//go/lib/keyconf:go_default_library", "//go/lib/scrypto:go_default_library", "//go/lib/scrypto/trc/v2:go_default_library", "@com_github_golang_mock//gomock:go_default_library", diff --git a/go/lib/infra/modules/trust/v2/mock_v2/v2.go b/go/lib/infra/modules/trust/v2/mock_v2/v2.go index 66dfb74375..4f83eb7e7e 100644 --- a/go/lib/infra/modules/trust/v2/mock_v2/v2.go +++ b/go/lib/infra/modules/trust/v2/mock_v2/v2.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/scionproto/scion/go/lib/infra/modules/trust/v2 (interfaces: CryptoProvider,DB,Inserter,Recurser,Resolver,Router,RPC) +// Source: github.com/scionproto/scion/go/lib/infra/modules/trust/v2 (interfaces: CryptoProvider,DB,KeyRing,Inserter,Recurser,Resolver,Router,RPC) // Package mock_v2 is a generated GoMock package. package mock_v2 @@ -12,6 +12,7 @@ import ( infra "github.com/scionproto/scion/go/lib/infra" v2 "github.com/scionproto/scion/go/lib/infra/modules/trust/v2" decoded "github.com/scionproto/scion/go/lib/infra/modules/trust/v2/internal/decoded" + keyconf "github.com/scionproto/scion/go/lib/keyconf" scrypto "github.com/scionproto/scion/go/lib/scrypto" v20 "github.com/scionproto/scion/go/lib/scrypto/trc/v2" net "net" @@ -298,6 +299,44 @@ func (mr *MockDBMockRecorder) TRCExists(arg0, arg1 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TRCExists", reflect.TypeOf((*MockDB)(nil).TRCExists), arg0, arg1) } +// MockKeyRing is a mock of KeyRing interface +type MockKeyRing struct { + ctrl *gomock.Controller + recorder *MockKeyRingMockRecorder +} + +// MockKeyRingMockRecorder is the mock recorder for MockKeyRing +type MockKeyRingMockRecorder struct { + mock *MockKeyRing +} + +// NewMockKeyRing creates a new mock instance +func NewMockKeyRing(ctrl *gomock.Controller) *MockKeyRing { + mock := &MockKeyRing{ctrl: ctrl} + mock.recorder = &MockKeyRingMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockKeyRing) EXPECT() *MockKeyRingMockRecorder { + return m.recorder +} + +// PrivateKey mocks base method +func (m *MockKeyRing) PrivateKey(arg0 keyconf.Usage, arg1 scrypto.KeyVersion) (keyconf.Key, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PrivateKey", arg0, arg1) + ret0, _ := ret[0].(keyconf.Key) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PrivateKey indicates an expected call of PrivateKey +func (mr *MockKeyRingMockRecorder) PrivateKey(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrivateKey", reflect.TypeOf((*MockKeyRing)(nil).PrivateKey), arg0, arg1) +} + // MockInserter is a mock of Inserter interface type MockInserter struct { ctrl *gomock.Controller diff --git a/go/lib/infra/modules/trust/v2/signer.go b/go/lib/infra/modules/trust/v2/signer.go new file mode 100644 index 0000000000..b786d56cbf --- /dev/null +++ b/go/lib/infra/modules/trust/v2/signer.go @@ -0,0 +1,166 @@ +// Copyright 2019 Anapaya Systems +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trust + +import ( + "bytes" + "context" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/ctrl" + "github.com/scionproto/scion/go/lib/infra" + "github.com/scionproto/scion/go/lib/infra/modules/trust/v2/internal/decoded" + "github.com/scionproto/scion/go/lib/keyconf" + "github.com/scionproto/scion/go/lib/scrypto" + "github.com/scionproto/scion/go/lib/scrypto/cert/v2" + "github.com/scionproto/scion/go/lib/serrors" + "github.com/scionproto/scion/go/proto" +) + +// KeyRing provides different private keys. +type KeyRing interface { + // PrivateKey returns the private key for the given usage and version. If it + // is not in the key ring, an error is returned. + PrivateKey(usage keyconf.Usage, version scrypto.KeyVersion) (keyconf.Key, error) +} + +// SignerConf holds the configuration of a signer. +type SignerConf struct { + ChainVer scrypto.Version + TRCVer scrypto.Version + Validity scrypto.Validity + Key keyconf.Key +} + +// Validate validates that the signer config is valid. +func (cfg SignerConf) Validate() error { + switch { + case cfg.ChainVer.IsLatest(): + return serrors.New("chain version is latest") + case cfg.TRCVer.IsLatest(): + return serrors.New("TRC version is latest") + case cfg.Key.IA.IsWildcard(): + return serrors.New("wildcard IA") + case cfg.Key.Type != keyconf.PrivateKey: + return serrors.New("wrong key type", "type", cfg.Key.Type) + } + if _, err := signTypeFromAlgo(cfg.Key.Algorithm); err != nil { + return err + } + return nil +} + +// Signer is used to sign control plane data authenticated by certificate chains. +type Signer struct { + cfg SignerConf + signType proto.SignType + src []byte +} + +// NewSigner constructs a new signer. +func NewSigner(cfg SignerConf) (*Signer, error) { + if err := cfg.Validate(); err != nil { + return nil, err + } + signType, _ := signTypeFromAlgo(cfg.Key.Algorithm) + src := ctrl.SignSrcDef{ + IA: cfg.Key.IA, + ChainVer: cfg.ChainVer, + TRCVer: cfg.TRCVer, + } + s := &Signer{ + signType: signType, + src: src.Pack(), + cfg: cfg, + } + return s, nil +} + +// Sign signs the message. +func (s *Signer) Sign(msg []byte) (*proto.SignS, error) { + var err error + sign := proto.NewSignS(s.signType, append(s.src[:0:0], s.src...)) + sign.Signature, err = scrypto.Sign(sign.SigInput(msg, true), + s.cfg.Key.Bytes, s.cfg.Key.Algorithm) + if err != nil { + return nil, err + } + return sign, nil +} + +// Meta returns the meta data the signer uses when signing. +func (s *Signer) Meta() infra.SignerMeta { + return infra.SignerMeta{ + Src: ctrl.SignSrcDef{ + IA: s.cfg.Key.IA, + ChainVer: s.cfg.ChainVer, + TRCVer: s.cfg.TRCVer, + }, + ExpTime: s.cfg.Validity.NotAfter.Time, + Algo: s.cfg.Key.Algorithm, + } +} + +// SignerGen generates signers based on the certificate chains and keys that are +// available. +type SignerGen struct { + IA addr.IA + KeyRing KeyRing + Provider CryptoProvider +} + +// Signer returns the active signer. +func (g *SignerGen) Signer(ctx context.Context) (*Signer, error) { + raw, err := g.Provider.GetRawChain(ctx, g.IA, scrypto.LatestVer, infra.ChainOpts{}, nil) + if err != nil { + return nil, serrors.WrapStr("error fetching latest chain", err) + } + dec, err := decoded.DecodeChain(raw) + if err != nil { + return nil, err + } + priv, err := g.KeyRing.PrivateKey(keyconf.ASSigningKey, dec.AS.Keys[cert.SigningKey].KeyVersion) + if err != nil { + return nil, serrors.WrapStr("private key not found", err, + "key_version", dec.AS.Keys[cert.SigningKey].KeyVersion) + } + pub, err := scrypto.GetPubKey(priv.Bytes, priv.Algorithm) + if err != nil { + return nil, serrors.WrapStr("unable to compute public key", err) + } + if !bytes.Equal(dec.AS.Keys[cert.SigningKey].Key, pub) { + return nil, serrors.WrapStr("public key does not match", err, + "chain_version", dec.AS.Version) + } + trc, err := g.Provider.GetTRC(ctx, g.IA.I, scrypto.LatestVer, infra.TRCOpts{}) + if err != nil { + return nil, serrors.WrapStr("unable to get latest TRC", err) + } + return NewSigner(SignerConf{ + ChainVer: dec.AS.Version, + TRCVer: trc.Version, + Validity: *dec.AS.Validity, + Key: priv, + }) +} + +func signTypeFromAlgo(algo string) (proto.SignType, error) { + switch algo { + case scrypto.Ed25519: + return proto.SignType_ed25519, nil + default: + return proto.SignType_none, serrors.New("unsupported signing algorithm", "algo", algo) + } +} diff --git a/go/lib/infra/modules/trust/v2/signer_test.go b/go/lib/infra/modules/trust/v2/signer_test.go new file mode 100644 index 0000000000..5cb13e89a2 --- /dev/null +++ b/go/lib/infra/modules/trust/v2/signer_test.go @@ -0,0 +1,349 @@ +// Copyright 2019 Anapaya Systems +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trust_test + +import ( + "context" + "crypto/ed25519" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/ctrl" + "github.com/scionproto/scion/go/lib/infra" + "github.com/scionproto/scion/go/lib/infra/modules/trust/v2" + "github.com/scionproto/scion/go/lib/infra/modules/trust/v2/mock_v2" + "github.com/scionproto/scion/go/lib/keyconf" + "github.com/scionproto/scion/go/lib/scrypto" + "github.com/scionproto/scion/go/lib/scrypto/cert/v2" + "github.com/scionproto/scion/go/lib/serrors" + "github.com/scionproto/scion/go/lib/util" +) + +func TestNewSigner(t *testing.T) { + orig := trust.SignerConf{ + ChainVer: 1, + TRCVer: 1, + Validity: scrypto.Validity{ + NotBefore: util.UnixTime{Time: time.Now()}, + NotAfter: util.UnixTime{Time: time.Now().Add(time.Hour)}, + }, + Key: keyconf.Key{ + ID: keyconf.ID{ + Usage: keyconf.ASSigningKey, + IA: ia110, + Version: 2, + }, + Type: keyconf.PrivateKey, + Algorithm: scrypto.Ed25519, + Bytes: make([]byte, ed25519.PrivateKeySize), + }, + } + + tests := map[string]struct { + Modify func(orig trust.SignerConf) trust.SignerConf + ErrAssertion assert.ErrorAssertionFunc + }{ + "chain version is latest": { + Modify: func(orig trust.SignerConf) trust.SignerConf { + orig.ChainVer = scrypto.LatestVer + return orig + }, + ErrAssertion: assert.Error, + }, + "trc version is latest": { + Modify: func(orig trust.SignerConf) trust.SignerConf { + orig.TRCVer = scrypto.LatestVer + return orig + }, + ErrAssertion: assert.Error, + }, + "wildcard IA": { + Modify: func(orig trust.SignerConf) trust.SignerConf { + orig.Key.IA.A = 0 + return orig + }, + ErrAssertion: assert.Error, + }, + "public key": { + Modify: func(orig trust.SignerConf) trust.SignerConf { + orig.Key.Type = keyconf.PublicKey + return orig + }, + ErrAssertion: assert.Error, + }, + "unknown algorithm": { + Modify: func(orig trust.SignerConf) trust.SignerConf { + orig.Key.Algorithm = "unknown" + return orig + }, + ErrAssertion: assert.Error, + }, + "valid": { + Modify: func(orig trust.SignerConf) trust.SignerConf { return orig }, + ErrAssertion: assert.NoError, + }, + } + for n, tc := range tests { + name, test := n, tc + t.Run(name, func(t *testing.T) { + t.Parallel() + _, err := trust.NewSigner(test.Modify(orig)) + test.ErrAssertion(t, err) + }) + } + +} + +func TestSignerSign(t *testing.T) { + pub, priv, err := scrypto.GenKeyPair(scrypto.Ed25519) + require.NoError(t, err) + cfg := trust.SignerConf{ + ChainVer: 1, + TRCVer: 1, + Validity: scrypto.Validity{ + NotBefore: util.UnixTime{Time: time.Now()}, + NotAfter: util.UnixTime{Time: time.Now().Add(time.Hour)}, + }, + Key: keyconf.Key{ + ID: keyconf.ID{ + Usage: keyconf.ASSigningKey, + IA: ia110, + Version: 2, + }, + Type: keyconf.PrivateKey, + Algorithm: scrypto.Ed25519, + Bytes: priv, + }, + } + t.Run("valid", func(t *testing.T) { + signer, err := trust.NewSigner(cfg) + require.NoError(t, err) + sign, err := signer.Sign([]byte("wasn't me")) + require.NoError(t, err) + + input := sign.SigInput([]byte("wasn't me"), false) + scrypto.Verify(input, sign.Signature, pub, scrypto.Ed25519) + }) + t.Run("fail", func(t *testing.T) { + mcfg := cfg + mcfg.Key.Bytes = []byte("garbage key") + signer, err := trust.NewSigner(mcfg) + require.NoError(t, err) + _, err = signer.Sign(nil) + assert.Error(t, err) + }) + +} + +func TestSignerMeta(t *testing.T) { + cfg := trust.SignerConf{ + ChainVer: 1, + TRCVer: 2, + Validity: scrypto.Validity{ + NotBefore: util.UnixTime{Time: time.Now()}, + NotAfter: util.UnixTime{Time: time.Now().Add(time.Hour)}, + }, + Key: keyconf.Key{ + ID: keyconf.ID{ + Usage: keyconf.ASSigningKey, + IA: ia110, + Version: 2, + }, + Type: keyconf.PrivateKey, + Algorithm: scrypto.Ed25519, + Bytes: []byte("some key"), + }, + } + signer, err := trust.NewSigner(cfg) + require.NoError(t, err) + meta := signer.Meta() + exp := infra.SignerMeta{ + Src: ctrl.SignSrcDef{ + IA: ia110, + ChainVer: 1, + TRCVer: 2, + }, + ExpTime: cfg.Validity.NotAfter.Time, + Algo: scrypto.Ed25519, + } + assert.Equal(t, exp, meta) +} + +func TestSignerGenSigner(t *testing.T) { + internal := serrors.New("internal") + tests := map[string]struct { + Provider func(t *testing.T, ctrl *gomock.Controller) trust.CryptoProvider + KeyRing func(t *testing.T, ctrl *gomock.Controller) trust.KeyRing + ErrAssertion assert.ErrorAssertionFunc + }{ + "chain lookup fails": { + Provider: func(t *testing.T, ctrl *gomock.Controller) trust.CryptoProvider { + p := mock_v2.NewMockCryptoProvider(ctrl) + p.EXPECT().GetRawChain(gomock.Any(), ia110, scrypto.LatestVer, + infra.ChainOpts{}, nil).Return(nil, internal) + return p + }, + KeyRing: func(t *testing.T, ctrl *gomock.Controller) trust.KeyRing { + return mock_v2.NewMockKeyRing(ctrl) + }, + ErrAssertion: assert.Error, + }, + "garbage chain": { + Provider: func(t *testing.T, ctrl *gomock.Controller) trust.CryptoProvider { + p := mock_v2.NewMockCryptoProvider(ctrl) + p.EXPECT().GetRawChain(gomock.Any(), ia110, scrypto.LatestVer, + infra.ChainOpts{}, nil).Return([]byte("garbage"), nil) + return p + }, + KeyRing: func(t *testing.T, ctrl *gomock.Controller) trust.KeyRing { + return mock_v2.NewMockKeyRing(ctrl) + }, + ErrAssertion: assert.Error, + }, + "key not found": { + Provider: func(t *testing.T, ctrl *gomock.Controller) trust.CryptoProvider { + p := mock_v2.NewMockCryptoProvider(ctrl) + p.EXPECT().GetRawChain(gomock.Any(), ia110, scrypto.LatestVer, + infra.ChainOpts{}, nil).Return(loadChain(t, chain110v1).Raw, nil) + return p + }, + KeyRing: func(t *testing.T, ctrl *gomock.Controller) trust.KeyRing { + r := mock_v2.NewMockKeyRing(ctrl) + r.EXPECT().PrivateKey(gomock.Any(), gomock.Any()).Return(keyconf.Key{}, internal) + return r + }, + ErrAssertion: assert.Error, + }, + "garbage private key": { + Provider: func(t *testing.T, ctrl *gomock.Controller) trust.CryptoProvider { + p := mock_v2.NewMockCryptoProvider(ctrl) + p.EXPECT().GetRawChain(gomock.Any(), ia110, scrypto.LatestVer, + infra.ChainOpts{}, nil).Return(loadChain(t, chain110v1).Raw, nil) + return p + }, + KeyRing: func(t *testing.T, ctrl *gomock.Controller) trust.KeyRing { + r := mock_v2.NewMockKeyRing(ctrl) + id := keyconf.ID{IA: ia110, Usage: keyconf.ASSigningKey, Version: 1} + key := loadPrivateKey(t, id) + key.Bytes = []byte("garbage key") + r.EXPECT().PrivateKey(gomock.Any(), gomock.Any()).Return(key, nil) + return r + }, + ErrAssertion: assert.Error, + }, + "differing key": { + Provider: func(t *testing.T, ctrl *gomock.Controller) trust.CryptoProvider { + p := mock_v2.NewMockCryptoProvider(ctrl) + p.EXPECT().GetRawChain(gomock.Any(), ia110, scrypto.LatestVer, + infra.ChainOpts{}, nil).Return(loadChain(t, chain110v1).Raw, nil) + return p + }, + KeyRing: func(t *testing.T, ctrl *gomock.Controller) trust.KeyRing { + r := mock_v2.NewMockKeyRing(ctrl) + id := keyconf.ID{IA: ia110, Usage: keyconf.ASSigningKey, Version: 1} + key := loadPrivateKey(t, id) + key.Bytes[0] ^= 0xFF + r.EXPECT().PrivateKey(gomock.Any(), gomock.Any()).Return(key, nil) + return r + }, + ErrAssertion: assert.Error, + }, + "getting TRC fails": { + Provider: func(t *testing.T, ctrl *gomock.Controller) trust.CryptoProvider { + p := mock_v2.NewMockCryptoProvider(ctrl) + p.EXPECT().GetRawChain(gomock.Any(), ia110, scrypto.LatestVer, + infra.ChainOpts{}, nil).Return(loadChain(t, chain110v1).Raw, nil) + p.EXPECT().GetTRC(gomock.Any(), ia110.I, scrypto.LatestVer, gomock.Any()).Return( + nil, internal, + ) + return p + }, + KeyRing: func(t *testing.T, ctrl *gomock.Controller) trust.KeyRing { + r := mock_v2.NewMockKeyRing(ctrl) + id := keyconf.ID{IA: ia110, Usage: keyconf.ASSigningKey, Version: 1} + r.EXPECT().PrivateKey(gomock.Any(), gomock.Any()).Return(loadPrivateKey(t, id), nil) + return r + }, + ErrAssertion: assert.Error, + }, + "invalid IA": { + Provider: func(t *testing.T, ctrl *gomock.Controller) trust.CryptoProvider { + p := mock_v2.NewMockCryptoProvider(ctrl) + p.EXPECT().GetRawChain(gomock.Any(), ia110, scrypto.LatestVer, + infra.ChainOpts{}, nil).Return(loadChain(t, chain110v1).Raw, nil) + p.EXPECT().GetTRC(gomock.Any(), ia110.I, scrypto.LatestVer, gomock.Any()).Return( + loadTRC(t, trc1v1).TRC, nil, + ) + return p + }, + KeyRing: func(t *testing.T, ctrl *gomock.Controller) trust.KeyRing { + r := mock_v2.NewMockKeyRing(ctrl) + id := keyconf.ID{IA: ia110, Usage: keyconf.ASSigningKey, Version: 1} + key := loadPrivateKey(t, id) + key.IA = addr.IA{} + r.EXPECT().PrivateKey(gomock.Any(), gomock.Any()).Return(key, nil) + return r + }, + ErrAssertion: assert.Error, + }, + "valid": { + Provider: func(t *testing.T, ctrl *gomock.Controller) trust.CryptoProvider { + p := mock_v2.NewMockCryptoProvider(ctrl) + p.EXPECT().GetRawChain(gomock.Any(), ia110, scrypto.LatestVer, + infra.ChainOpts{}, nil).Return(loadChain(t, chain110v1).Raw, nil) + p.EXPECT().GetTRC(gomock.Any(), ia110.I, scrypto.LatestVer, gomock.Any()).Return( + loadTRC(t, trc1v1).TRC, nil, + ) + return p + }, + KeyRing: func(t *testing.T, ctrl *gomock.Controller) trust.KeyRing { + r := mock_v2.NewMockKeyRing(ctrl) + id := keyconf.ID{IA: ia110, Usage: keyconf.ASSigningKey, Version: 1} + r.EXPECT().PrivateKey(gomock.Any(), gomock.Any()).Return(loadPrivateKey(t, id), nil) + return r + }, + ErrAssertion: assert.NoError, + }, + } + + for n, tc := range tests { + name, test := n, tc + t.Run(name, func(t *testing.T) { + t.Parallel() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + g := trust.SignerGen{ + IA: ia110, + KeyRing: test.KeyRing(t, ctrl), + Provider: test.Provider(t, ctrl), + } + signer, err := g.Signer(context.Background()) + test.ErrAssertion(t, err) + if signer != nil { + sign, err := signer.Sign([]byte("wasn't me")) + require.NoError(t, err) + + meta := loadChain(t, chain110v1).AS.Keys[cert.SigningKey] + input := sign.SigInput([]byte("wasn't me"), false) + scrypto.Verify(input, sign.Signature, meta.Key, meta.Algorithm) + } + }) + } +} diff --git a/tools/gomocks b/tools/gomocks index 22d50978e3..9cfd14ac39 100755 --- a/tools/gomocks +++ b/tools/gomocks @@ -49,7 +49,7 @@ MOCK_TARGETS = [ (SCION_PACKAGE_PREFIX + "/go/lib/infra/modules/seghandler", "Storage,Verifier"), (SCION_PACKAGE_PREFIX + "/go/lib/infra/modules/trust/trustdb", "TrustDB"), (SCION_PACKAGE_PREFIX + "/go/lib/infra/modules/trust/v2", - "CryptoProvider,DB,Inserter,Recurser,Resolver,Router,RPC"), + "CryptoProvider,DB,KeyRing,Inserter,Recurser,Resolver,Router,RPC"), (SCION_PACKAGE_PREFIX + "/go/lib/l4", "L4Header"), (SCION_PACKAGE_PREFIX + "/go/lib/log", "Handler,Logger"), (SCION_PACKAGE_PREFIX + "/go/lib/overlay/conn", "Conn"), From 542a0f1ddc77783c91849552a341a40845166061 Mon Sep 17 00:00:00 2001 From: roos Date: Fri, 13 Dec 2019 14:37:49 +0100 Subject: [PATCH 2/2] feedback --- go/lib/infra/modules/trust/v2/signer_test.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/go/lib/infra/modules/trust/v2/signer_test.go b/go/lib/infra/modules/trust/v2/signer_test.go index 5cb13e89a2..e99c8af493 100644 --- a/go/lib/infra/modules/trust/v2/signer_test.go +++ b/go/lib/infra/modules/trust/v2/signer_test.go @@ -139,7 +139,7 @@ func TestSignerSign(t *testing.T) { require.NoError(t, err) input := sign.SigInput([]byte("wasn't me"), false) - scrypto.Verify(input, sign.Signature, pub, scrypto.Ed25519) + assert.NoError(t, scrypto.Verify(input, sign.Signature, pub, scrypto.Ed25519)) }) t.Run("fail", func(t *testing.T) { mcfg := cfg @@ -336,14 +336,16 @@ func TestSignerGenSigner(t *testing.T) { } signer, err := g.Signer(context.Background()) test.ErrAssertion(t, err) - if signer != nil { - sign, err := signer.Sign([]byte("wasn't me")) - require.NoError(t, err) - - meta := loadChain(t, chain110v1).AS.Keys[cert.SigningKey] - input := sign.SigInput([]byte("wasn't me"), false) - scrypto.Verify(input, sign.Signature, meta.Key, meta.Algorithm) + if signer == nil { + return } + sign, err := signer.Sign([]byte("wasn't me")) + require.NoError(t, err) + + meta := loadChain(t, chain110v1).AS.Keys[cert.SigningKey] + input := sign.SigInput([]byte("wasn't me"), false) + assert.NoError(t, scrypto.Verify(input, sign.Signature, meta.Key, meta.Algorithm)) + }) } }