diff --git a/acceptance/cert_renewal_acceptance/test b/acceptance/cert_renewal_acceptance_disabled/test similarity index 100% rename from acceptance/cert_renewal_acceptance/test rename to acceptance/cert_renewal_acceptance_disabled/test diff --git a/go/beacon_srv/BUILD.bazel b/go/beacon_srv/BUILD.bazel index 76d17bc558..56831967ff 100644 --- a/go/beacon_srv/BUILD.bazel +++ b/go/beacon_srv/BUILD.bazel @@ -25,8 +25,7 @@ go_library( "//go/lib/infra/messenger:go_default_library", "//go/lib/infra/modules/idiscovery:go_default_library", "//go/lib/infra/modules/itopo:go_default_library", - "//go/lib/infra/modules/trust:go_default_library", - "//go/lib/infra/modules/trust/trustdb:go_default_library", + "//go/lib/infra/modules/trust/v2:go_default_library", "//go/lib/keyconf:go_default_library", "//go/lib/log:go_default_library", "//go/lib/periodic:go_default_library", diff --git a/go/beacon_srv/main.go b/go/beacon_srv/main.go index d0b401da08..182f7edc60 100644 --- a/go/beacon_srv/main.go +++ b/go/beacon_srv/main.go @@ -49,8 +49,7 @@ import ( "github.com/scionproto/scion/go/lib/infra/messenger" "github.com/scionproto/scion/go/lib/infra/modules/idiscovery" "github.com/scionproto/scion/go/lib/infra/modules/itopo" - "github.com/scionproto/scion/go/lib/infra/modules/trust" - "github.com/scionproto/scion/go/lib/infra/modules/trust/trustdb" + "github.com/scionproto/scion/go/lib/infra/modules/trust/v2" "github.com/scionproto/scion/go/lib/keyconf" "github.com/scionproto/scion/go/lib/log" "github.com/scionproto/scion/go/lib/periodic" @@ -101,25 +100,8 @@ func realMain() int { log.Crit("Setup failed", "err", err) return 1 } - trustDB, err := cfg.TrustDB.New() - if err != nil { - log.Crit("Unable to initialize trustDB", "err", err) - return 1 - } - trustDB = trustdb.WithMetrics(string(cfg.TrustDB.Backend()), trustDB) - defer trustDB.Close() + topo := itopo.Get() - trustConf := trust.Config{ - MustHaveLocalChain: true, - ServiceType: proto.ServiceType_bs, - TopoProvider: itopo.Provider(), - } - trustStore := trust.NewStore(trustDB, topo.IA(), trustConf, log.Root()) - err = trustStore.LoadAuthoritativeCrypto(filepath.Join(cfg.General.ConfigDir, "certs")) - if err != nil { - log.Crit("Unable to load local crypto", "err", err) - return 1 - } if !topo.Exists(addr.SvcBS, cfg.General.ID) { log.Crit("Unable to find topo address") return 1 @@ -143,7 +125,6 @@ func realMain() int { KeyFile: cfg.QUIC.KeyFile, }, SVCResolutionFraction: cfg.QUIC.ResolutionFraction, - TrustStore: trustStore, SVCRouter: messenger.NewSVCRouter(itopo.Provider()), } msgr, err := nc.Messenger() @@ -152,6 +133,40 @@ func realMain() int { return 1 } defer msgr.CloseServer() + + trustDB, err := cfg.TrustDB.New() + if err != nil { + log.Crit("Error initializing trust database", "err", err) + return 1 + } + defer trustDB.Close() + inserter := trust.ForwardingInserter{ + BaseInserter: trust.BaseInserter{DB: trustDB}, + Router: trust.LocalRouter{IA: topo.IA()}, + RPC: trust.DefaultRPC{Msgr: msgr}, + } + provider := trust.Provider{ + DB: trustDB, + Recurser: trust.LocalOnlyRecurser{}, + Resolver: trust.DefaultResolver{ + DB: trustDB, + Inserter: inserter, + RPC: trust.DefaultRPC{Msgr: msgr}, + }, + Router: trust.LocalRouter{IA: topo.IA()}, + } + trustStore := trust.Store{ + Inspector: trust.DefaultInspector{Provider: provider}, + CryptoProvider: provider, + Inserter: inserter, + DB: trustDB, + } + certsDir := filepath.Join(cfg.General.ConfigDir, "certs") + if err = trustStore.LoadCryptoMaterial(context.Background(), certsDir); err != nil { + log.Crit("Error loading crypto material", "err", err) + return 1 + } + store, err := loadStore(topo.Core(), topo.IA(), cfg) if err != nil { log.Crit("Unable to open beacon store", "err", err) @@ -160,13 +175,13 @@ func realMain() int { defer store.Close() intfs = ifstate.NewInterfaces(topo.IFInfoMap(), ifstate.Config{}) prometheus.MustRegister(ifstate.NewCollector(intfs)) - msgr.AddHandler(infra.ChainRequest, trustStore.NewChainReqHandler(false)) - msgr.AddHandler(infra.TRCRequest, trustStore.NewTRCReqHandler(false)) + msgr.AddHandler(infra.ChainRequest, trustStore.NewChainReqHandler()) + msgr.AddHandler(infra.TRCRequest, trustStore.NewTRCReqHandler()) msgr.AddHandler(infra.IfStateReq, ifstate.NewHandler(intfs)) msgr.AddHandler(infra.SignedRev, revocation.NewHandler(store, - trustStore.NewVerifier(), 5*time.Second)) + trust.NewVerifier(trustStore), 5*time.Second)) msgr.AddHandler(infra.Seg, beaconing.NewHandler(topo.IA(), intfs, store, - trustStore.NewVerifier())) + trust.NewVerifier(trustStore))) msgr.AddHandler(infra.IfId, keepalive.NewHandler(topo.IA(), intfs, keepalive.StateChangeTasks{ RevDropper: store, @@ -205,7 +220,7 @@ func realMain() int { tasks = &periodicTasks{ intfs: intfs, conn: conn.(*snet.SCIONPacketConn), - trustDB: trustDB, + trustStore: trustStore, store: store, msgr: msgr, topoProvider: itopo.Provider(), @@ -266,7 +281,7 @@ type periodicTasks struct { intfs *ifstate.Interfaces conn *snet.SCIONPacketConn genMac func() hash.Hash - trustDB trustdb.TrustDB + trustStore trust.Store store beaconstorage.Store msgr infra.Messenger topoProvider topology.Provider @@ -485,22 +500,17 @@ func (t *periodicTasks) startRegistrar(topo topology.Topology, segType proto.Pat } func (t *periodicTasks) createSigner(ia addr.IA) (infra.Signer, error) { - dir := filepath.Join(cfg.General.ConfigDir, "keys") - cfg, err := keyconf.Load(dir, false, false, false, false) - if err != nil { - return nil, common.NewBasicError("unable to load key config", err) - } ctx, cancelF := context.WithTimeout(context.Background(), time.Second) defer cancelF() - meta, err := trust.CreateSignMeta(ctx, ia, t.trustDB) - if err != nil { - return nil, common.NewBasicError("unable to create sign meta", err) - } - signer, err := trust.NewBasicSigner(cfg.SignKey, meta) - if err != nil { - return nil, common.NewBasicError("unable to create signer", err) + gen := trust.SignerGen{ + IA: itopo.Get().IA(), + Provider: t.trustStore, + KeyRing: keyconf.LoadingRing{ + Dir: filepath.Join(cfg.General.ConfigDir, "keys"), + IA: ia, + }, } - return signer, nil + return gen.Signer(ctx) } func (t *periodicTasks) Kill() { diff --git a/go/cert_srv/BUILD.bazel b/go/cert_srv/BUILD.bazel index 4f6ce379af..3df37bdd21 100644 --- a/go/cert_srv/BUILD.bazel +++ b/go/cert_srv/BUILD.bazel @@ -8,7 +8,6 @@ go_library( visibility = ["//visibility:private"], deps = [ "//go/cert_srv/internal/config:go_default_library", - "//go/cert_srv/internal/reiss:go_default_library", "//go/lib/addr:go_default_library", "//go/lib/common:go_default_library", "//go/lib/discovery:go_default_library", @@ -19,8 +18,8 @@ go_library( "//go/lib/infra/messenger:go_default_library", "//go/lib/infra/modules/idiscovery:go_default_library", "//go/lib/infra/modules/itopo:go_default_library", - "//go/lib/infra/modules/trust:go_default_library", - "//go/lib/infra/modules/trust/trustdb:go_default_library", + "//go/lib/infra/modules/trust/v2:go_default_library", + "//go/lib/keyconf:go_default_library", "//go/lib/log:go_default_library", "//go/lib/periodic:go_default_library", "//go/lib/prom:go_default_library", diff --git a/go/cert_srv/internal/config/BUILD.bazel b/go/cert_srv/internal/config/BUILD.bazel index 50805c5676..3818ff97e7 100644 --- a/go/cert_srv/internal/config/BUILD.bazel +++ b/go/cert_srv/internal/config/BUILD.bazel @@ -5,7 +5,6 @@ go_library( srcs = [ "config.go", "sample.go", - "state.go", ], importpath = "github.com/scionproto/scion/go/cert_srv/internal/config", visibility = ["//go/cert_srv:__subpackages__"], @@ -13,11 +12,7 @@ go_library( "//go/lib/common:go_default_library", "//go/lib/config:go_default_library", "//go/lib/env:go_default_library", - "//go/lib/infra:go_default_library", "//go/lib/infra/modules/idiscovery:go_default_library", - "//go/lib/infra/modules/trust:go_default_library", - "//go/lib/infra/modules/trust/trustdb:go_default_library", - "//go/lib/keyconf:go_default_library", "//go/lib/scrypto/cert:go_default_library", "//go/lib/serrors:go_default_library", "//go/lib/truststorage:go_default_library", @@ -27,20 +22,14 @@ go_library( go_test( name = "go_default_test", - srcs = [ - "config_test.go", - "state_test.go", - ], + srcs = ["config_test.go"], data = glob(["testdata/**"]), embed = [":go_default_library"], deps = [ "//go/lib/env/envtest:go_default_library", "//go/lib/infra/modules/idiscovery/idiscoverytest:go_default_library", - "//go/lib/keyconf:go_default_library", - "//go/lib/scrypto:go_default_library", "//go/lib/truststorage/truststoragetest:go_default_library", "@com_github_burntsushi_toml//:go_default_library", - "@com_github_smartystreets_goconvey//convey:go_default_library", "@com_github_stretchr_testify//assert:go_default_library", ], ) diff --git a/go/cert_srv/internal/config/state.go b/go/cert_srv/internal/config/state.go deleted file mode 100644 index 765cecce22..0000000000 --- a/go/cert_srv/internal/config/state.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2018 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 config - -import ( - "path/filepath" - "sync" - - "github.com/scionproto/scion/go/lib/common" - "github.com/scionproto/scion/go/lib/infra" - "github.com/scionproto/scion/go/lib/infra/modules/trust" - "github.com/scionproto/scion/go/lib/infra/modules/trust/trustdb" - "github.com/scionproto/scion/go/lib/keyconf" -) - -type State struct { - // Store is the trust store. - Store *trust.Store - // TrustDB is the trust DB. - TrustDB trustdb.TrustDB - // keyConf contains the AS level keys. - keyConf *keyconf.Conf - // keyConfLock guards KeyConf. - keyConfLock sync.RWMutex - // signer is used to sign ctrl payloads. - signer infra.Signer - // signerLock guards signer. - signerLock sync.RWMutex - // verifier is used to verify ctrl payloads. - verifier infra.Verifier - // verifierLock guards verifier. - verifierLock sync.RWMutex -} - -func LoadState(confDir string, isCore bool, trustDB trustdb.TrustDB, - trustStore *trust.Store) (*State, error) { - - s := &State{ - Store: trustStore, - TrustDB: trustDB, - } - if err := s.loadKeyConf(confDir, isCore); err != nil { - return nil, err - } - return s, nil -} - -// loadKeyConf loads the key configuration. -func (s *State) loadKeyConf(confDir string, isCore bool) error { - var err error - s.keyConf, err = keyconf.Load(filepath.Join(confDir, "keys"), isCore, isCore, false, true) - if err != nil { - return common.NewBasicError(ErrKeyConf, err) - } - return nil -} - -// GetSigningKey returns the signing key of the current key configuration. -func (s *State) GetSigningKey() common.RawBytes { - s.keyConfLock.RLock() - defer s.keyConfLock.RUnlock() - return s.keyConf.SignKey -} - -// GetIssSigningKey returns the issuer signing key of the current key configuration. -func (s *State) GetIssSigningKey() common.RawBytes { - s.keyConfLock.RLock() - defer s.keyConfLock.RUnlock() - return s.keyConf.IssSigKey -} - -// GetDecryptKey returns the decryption key of the current key configuration. -func (s *State) GetDecryptKey() common.RawBytes { - s.keyConfLock.RLock() - defer s.keyConfLock.RUnlock() - return s.keyConf.DecryptKey -} - -// GetOnRootKey returns the online root key of the current key configuration. -func (s *State) GetOnRootKey() common.RawBytes { - s.keyConfLock.RLock() - defer s.keyConfLock.RUnlock() - return s.keyConf.OnRootKey -} - -// GetSigner returns the signer of the current configuration. -func (s *State) GetSigner() infra.Signer { - s.signerLock.RLock() - defer s.signerLock.RUnlock() - return s.signer -} - -// SetSigner sets the signer of the current configuration. -func (s *State) SetSigner(signer infra.Signer) { - s.signerLock.Lock() - defer s.signerLock.Unlock() - s.signer = signer -} - -// GetVerifier returns the verifier of the current configuration. -func (s *State) GetVerifier() infra.Verifier { - s.verifierLock.RLock() - defer s.verifierLock.RUnlock() - return s.verifier -} - -// SetVerifier sets the verifier of the current configuration. -func (s *State) SetVerifier(verifier infra.Verifier) { - s.verifierLock.Lock() - defer s.verifierLock.Unlock() - s.verifier = verifier -} diff --git a/go/cert_srv/internal/config/state_test.go b/go/cert_srv/internal/config/state_test.go deleted file mode 100644 index ac9864fd0c..0000000000 --- a/go/cert_srv/internal/config/state_test.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2018 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 config - -import ( - "testing" - - . "github.com/smartystreets/goconvey/convey" - - "github.com/scionproto/scion/go/lib/keyconf" - "github.com/scionproto/scion/go/lib/scrypto" -) - -func TestLoadState(t *testing.T) { - mstr0, _ := keyconf.LoadKey("testdata/keys/master0.key", keyconf.RawKey) - mstr1, _ := keyconf.LoadKey("testdata/keys/master1.key", keyconf.RawKey) - dcrpt, _ := keyconf.LoadKey("testdata/keys/as-decrypt.key", - scrypto.Curve25519xSalsa20Poly1305) - asSig, _ := keyconf.LoadKey("testdata/keys/as-sig.seed", scrypto.Ed25519) - issSig, _ := keyconf.LoadKey("testdata/keys/core-sig.seed", scrypto.Ed25519) - online, _ := keyconf.LoadKey("testdata/keys/online-root.seed", scrypto.Ed25519) - Convey("Load core state", t, func() { - state, err := LoadState("testdata", true, nil, nil) - SoMsg("err", err, ShouldBeNil) - SoMsg("Master0", state.keyConf.Master.Key0, ShouldResemble, mstr0) - SoMsg("Master1", state.keyConf.Master.Key1, ShouldResemble, mstr1) - SoMsg("Decrypt", state.keyConf.DecryptKey, ShouldResemble, dcrpt) - SoMsg("AS-Sign", state.keyConf.SignKey, ShouldResemble, asSig) - SoMsg("Issuer-Sign", state.keyConf.IssSigKey, ShouldResemble, issSig) - SoMsg("Online", state.keyConf.OnRootKey, ShouldResemble, online) - SoMsg("Offline", state.keyConf.OffRootKey, ShouldBeZeroValue) - }) - - Convey("Load non-core state", t, func() { - state, err := LoadState("testdata", false, nil, nil) - SoMsg("err", err, ShouldBeNil) - SoMsg("Master0", state.keyConf.Master.Key0, ShouldResemble, mstr0) - SoMsg("Master1", state.keyConf.Master.Key1, ShouldResemble, mstr1) - SoMsg("Decrypt", state.keyConf.DecryptKey, ShouldResemble, dcrpt) - SoMsg("AS-Sign", state.keyConf.SignKey, ShouldResemble, asSig) - SoMsg("Issuer-Sign", state.keyConf.IssSigKey, ShouldBeZeroValue) - SoMsg("Online", state.keyConf.OnRootKey, ShouldBeZeroValue) - SoMsg("Offline", state.keyConf.OffRootKey, ShouldBeZeroValue) - }) -} diff --git a/go/cert_srv/internal/reiss/BUILD.bazel b/go/cert_srv/internal/reiss/BUILD.bazel deleted file mode 100644 index e67e41301a..0000000000 --- a/go/cert_srv/internal/reiss/BUILD.bazel +++ /dev/null @@ -1,53 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") - -go_library( - name = "go_default_library", - srcs = [ - "corepush.go", - "handler.go", - "requester.go", - "self.go", - ], - importpath = "github.com/scionproto/scion/go/cert_srv/internal/reiss", - visibility = ["//go/cert_srv:__subpackages__"], - deps = [ - "//go/cert_srv/internal/config:go_default_library", - "//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/trust:go_default_library", - "//go/lib/infra/modules/trust/trustdb:go_default_library", - "//go/lib/log:go_default_library", - "//go/lib/periodic:go_default_library", - "//go/lib/scrypto:go_default_library", - "//go/lib/scrypto/cert:go_default_library", - "//go/lib/scrypto/trc:go_default_library", - "//go/lib/serrors:go_default_library", - "//go/lib/snet:go_default_library", - "//go/lib/util:go_default_library", - "@org_golang_x_crypto//ed25519:go_default_library", - ], -) - -go_test( - name = "go_default_test", - srcs = ["corepush_test.go"], - data = glob(["testdata/**"]), - embed = [":go_default_library"], - deps = [ - "//go/lib/common:go_default_library", - "//go/lib/ctrl/cert_mgmt:go_default_library", - "//go/lib/infra/mock_infra:go_default_library", - "//go/lib/infra/modules/trust/trustdb/mock_trustdb:go_default_library", - "//go/lib/periodic:go_default_library", - "//go/lib/scrypto/cert:go_default_library", - "//go/lib/scrypto/trc:go_default_library", - "//go/lib/serrors:go_default_library", - "//go/lib/xtest:go_default_library", - "//go/lib/xtest/matchers:go_default_library", - "@com_github_golang_mock//gomock:go_default_library", - ], -) diff --git a/go/cert_srv/internal/reiss/corepush.go b/go/cert_srv/internal/reiss/corepush.go deleted file mode 100644 index 0f74221761..0000000000 --- a/go/cert_srv/internal/reiss/corepush.go +++ /dev/null @@ -1,206 +0,0 @@ -// 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 reiss - -import ( - "context" - "sync" - "time" - - "github.com/scionproto/scion/go/lib/addr" - "github.com/scionproto/scion/go/lib/common" - "github.com/scionproto/scion/go/lib/ctrl/cert_mgmt" - "github.com/scionproto/scion/go/lib/infra" - "github.com/scionproto/scion/go/lib/infra/messenger" - "github.com/scionproto/scion/go/lib/infra/modules/trust/trustdb" - "github.com/scionproto/scion/go/lib/log" - "github.com/scionproto/scion/go/lib/periodic" - "github.com/scionproto/scion/go/lib/scrypto/cert" - "github.com/scionproto/scion/go/lib/snet" -) - -var ( - // SleepAfterFailure is the base time to sleep after a failed attempt to push the chain. - // The actual sleep time is: attempts * SleepAfterFailure. - SleepAfterFailure = time.Second - // DefaultTryTimeout is the default timeout for one sync try if the context - // has no deadline set. - DefaultTryTimeout = 20 * time.Second -) - -var _ periodic.Task = (*CorePusher)(nil) - -// CorePusher is a periodic.Task that pushes the local chain to all core CSes in the ISD. -// The interval this task is run in is expected to be rather large (e.g. 1h). -type CorePusher struct { - LocalIA addr.IA - TrustDB trustdb.TrustDB - Msger infra.Messenger -} - -// Name returns the tasks name. -func (p *CorePusher) Name() string { - return "cs_reiss_corepusher" -} - -// Run makes sure all core CS have the chain of the local AS. -func (p *CorePusher) Run(ctx context.Context) { - logger := log.FromCtx(ctx) - chain, err := p.TrustDB.GetChainMaxVersion(ctx, p.LocalIA) - if err != nil { - logger.Error("[reiss.CorePusher] Failed to get local chain from DB", "err", err) - return - } - cores, err := p.coreASes(ctx) - if err != nil { - logger.Error("[reiss.CorePusher] Failed to determine core ASes", "err", err) - return - } - numCores := len(cores.ias) - tryTimeout := DefaultTryTimeout - if deadline, ok := ctx.Deadline(); ok { - tryTimeout = deadline.Sub(time.Now()) / 3 - } - for syncTries := 0; syncTries < 3 && ctx.Err() == nil; syncTries++ { - tryCtx, cancelF := context.WithTimeout(ctx, tryTimeout) - err = p.syncCores(tryCtx, chain, cores) - cancelF() - if err == nil { - logger.Info("[reiss.CorePusher] Successfully pushed chain to cores", "cores", numCores) - return - } - logger.Error("[reiss.CorePusher] Failed to sync all cores", "err", err) - select { - case <-time.After(time.Duration(syncTries+1) * SleepAfterFailure): - case <-ctx.Done(): - } - } -} - -func (p *CorePusher) coreASes(ctx context.Context) (*iaMap, error) { - trc, err := p.TrustDB.GetTRCMaxVersion(ctx, p.LocalIA.I) - if err != nil { - return nil, common.NewBasicError("Unable to get TRC for local ISD", err) - } - cores := make(map[addr.IA]struct{}) - for _, ia := range trc.CoreASes.ASList() { - if !p.LocalIA.Equal(ia) { - cores[ia] = struct{}{} - } - } - return &iaMap{ias: cores}, nil -} - -// syncCores tries to sync to the given cores and returns the cores for which the syncing failed. -func (p *CorePusher) syncCores(ctx context.Context, chain *cert.Chain, cores *iaMap) error { - - wg := &sync.WaitGroup{} - wg.Add(len(cores.ias)) - checkErrs := &iaList{} - for coreIA := range cores.ias { - p.asyncPush(ctx, chain, cores, coreIA, checkErrs, wg) - } - wg.Wait() - if len(checkErrs.ias) > 0 || len(cores.ias) > 0 { - return common.NewBasicError("Sync error", nil, "checkErrors", checkErrs.ias, - "remainingCores", cores.list()) - } - return nil -} - -// asyncPush pushes the certificate chain to the core if it does not have it already. -func (p *CorePusher) asyncPush(ctx context.Context, chain *cert.Chain, cores *iaMap, - core addr.IA, checkErrs *iaList, wg *sync.WaitGroup) { - - go func() { - defer log.LogPanicAndExit() - defer wg.Done() - hasChain, err := p.hasChain(ctx, core, chain) - if err != nil { - checkErrs.append(core) - // fall-through explicitly, we just assume the core doesn't have it and send it. - } - var sendErr error - if !hasChain { - sendErr = p.sendChain(ctx, core, chain) - } - if sendErr == nil { - cores.delete(core) - } - }() -} - -func (p *CorePusher) hasChain(ctx context.Context, coreAS addr.IA, - expectedChain *cert.Chain) (bool, error) { - - chainIA, ver := expectedChain.IAVer() - req := &cert_mgmt.ChainReq{ - RawIA: chainIA.IAInt(), - Version: ver, - CacheOnly: true, - } - a := snet.NewSVCAddr(coreAS, nil, nil, addr.SvcCS) - reply, err := p.Msger.GetCertChain(ctx, req, a, messenger.NextId()) - if err != nil { - return false, common.NewBasicError("Error during fetch", err) - } - chain, err := reply.Chain() - return chain != nil, err -} - -func (p *CorePusher) sendChain(ctx context.Context, coreAS addr.IA, chain *cert.Chain) error { - rawChain, err := chain.Compress() - if err != nil { - return common.NewBasicError("Failed to compress chain", err) - } - msg := &cert_mgmt.Chain{ - RawChain: rawChain, - } - a := snet.NewSVCAddr(coreAS, nil, nil, addr.SvcCS) - // TODO(lukedirtwalker): Expect Acks. - return p.Msger.SendCertChain(ctx, msg, a, messenger.NextId()) -} - -type iaList struct { - mu sync.Mutex - ias []addr.IA -} - -func (l *iaList) append(ia addr.IA) { - l.mu.Lock() - l.ias = append(l.ias, ia) - l.mu.Unlock() -} - -type iaMap struct { - mu sync.Mutex - ias map[addr.IA]struct{} -} - -func (m *iaMap) delete(ia addr.IA) { - m.mu.Lock() - delete(m.ias, ia) - m.mu.Unlock() -} - -func (m *iaMap) list() []addr.IA { - m.mu.Lock() - l := make([]addr.IA, 0, len(m.ias)) - for ia := range m.ias { - l = append(l, ia) - } - m.mu.Unlock() - return l -} diff --git a/go/cert_srv/internal/reiss/corepush_test.go b/go/cert_srv/internal/reiss/corepush_test.go deleted file mode 100644 index e03c773889..0000000000 --- a/go/cert_srv/internal/reiss/corepush_test.go +++ /dev/null @@ -1,189 +0,0 @@ -// 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 reiss - -import ( - "bytes" - "context" - "fmt" - "testing" - "time" - - "github.com/golang/mock/gomock" - - "github.com/scionproto/scion/go/lib/common" - "github.com/scionproto/scion/go/lib/ctrl/cert_mgmt" - "github.com/scionproto/scion/go/lib/infra/mock_infra" - "github.com/scionproto/scion/go/lib/infra/modules/trust/trustdb/mock_trustdb" - "github.com/scionproto/scion/go/lib/periodic" - "github.com/scionproto/scion/go/lib/scrypto/cert" - "github.com/scionproto/scion/go/lib/scrypto/trc" - "github.com/scionproto/scion/go/lib/serrors" - "github.com/scionproto/scion/go/lib/xtest" - "github.com/scionproto/scion/go/lib/xtest/matchers" -) - -var ( - localIA = xtest.MustParseIA("1-ff00:0:311") - localISD = localIA.I - - core1_110 = xtest.MustParseIA("1-ff00:0:110") - core1_130 = xtest.MustParseIA("1-ff00:0:130") - core1_120 = xtest.MustParseIA("1-ff00:0:120") - - trcISD1 = &trc.TRC{ - CoreASes: trc.CoreASMap{ - core1_110: nil, - core1_120: nil, - core1_130: nil, - }, - } - - chain *cert.Chain - rawChain common.RawBytes - chainMsg *cert_mgmt.Chain - - emptyChainMsg = &cert_mgmt.Chain{RawChain: nil} -) - -func setup(t *testing.T) (*gomock.Controller, *mock_infra.MockMessenger, periodic.Task) { - ctrl := gomock.NewController(t) - trustDB := mock_trustdb.NewMockTrustDB(ctrl) - msger := mock_infra.NewMockMessenger(ctrl) - pusher := &CorePusher{ - LocalIA: localIA, - TrustDB: trustDB, - Msger: msger, - } - var err error - chain, err = cert.ChainFromFile("testdata/ISD1-ASff00_0_311-V1.crt", false) - xtest.FailOnErr(t, err) - rawChain, err = chain.Compress() - xtest.FailOnErr(t, err) - chainMsg = &cert_mgmt.Chain{RawChain: rawChain} - SleepAfterFailure = 0 - - trustDB.EXPECT().GetTRCMaxVersion(gomock.Any(), gomock.Eq(localISD)).Return(trcISD1, nil) - trustDB.EXPECT().GetChainMaxVersion(gomock.Any(), gomock.Eq(localIA)).Return(chain, nil) - - return ctrl, msger, pusher -} - -func TestNonExistingChainsArePushed(t *testing.T) { - ctx, cancelF := context.WithTimeout(context.Background(), time.Second) - defer cancelF() - ctrl, msger, pusher := setup(t) - defer ctrl.Finish() - - msger.EXPECT().GetCertChain( - gomock.Any(), gomock.Any(), matchers.IsSnetAddrWithIA(core1_110), gomock.Any()).Return( - emptyChainMsg, nil, - ) - msger.EXPECT().GetCertChain( - gomock.Any(), gomock.Any(), matchers.IsSnetAddrWithIA(core1_120), gomock.Any()).Return( - emptyChainMsg, nil, - ) - msger.EXPECT().GetCertChain( - gomock.Any(), gomock.Any(), matchers.IsSnetAddrWithIA(core1_130), gomock.Any()).Return( - emptyChainMsg, nil, - ) - msger.EXPECT().SendCertChain( - gomock.Any(), matchesChain(rawChain), matchers.IsSnetAddrWithIA(core1_110), gomock.Any()) - msger.EXPECT().SendCertChain( - gomock.Any(), matchesChain(rawChain), matchers.IsSnetAddrWithIA(core1_120), gomock.Any()) - msger.EXPECT().SendCertChain( - gomock.Any(), matchesChain(rawChain), matchers.IsSnetAddrWithIA(core1_130), gomock.Any()) - pusher.Run(ctx) -} - -func TestExistingChainsAreNotPushed(t *testing.T) { - ctx, cancelF := context.WithTimeout(context.Background(), time.Second) - defer cancelF() - ctrl, msger, pusher := setup(t) - defer ctrl.Finish() - - msger.EXPECT().GetCertChain( - gomock.Any(), gomock.Any(), matchers.IsSnetAddrWithIA(core1_110), gomock.Any()).Return( - chainMsg, nil, - ) - msger.EXPECT().GetCertChain( - gomock.Any(), gomock.Any(), matchers.IsSnetAddrWithIA(core1_120), gomock.Any()).Return( - chainMsg, nil, - ) - msger.EXPECT().GetCertChain( - gomock.Any(), gomock.Any(), matchers.IsSnetAddrWithIA(core1_130), gomock.Any()).Return( - emptyChainMsg, nil, - ) - msger.EXPECT().SendCertChain( - gomock.Any(), matchesChain(rawChain), matchers.IsSnetAddrWithIA(core1_130), gomock.Any()) - pusher.Run(ctx) -} - -func TestErrDuringSendIsRetried(t *testing.T) { - ctx, cancelF := context.WithTimeout(context.Background(), time.Second) - defer cancelF() - ctrl, msger, pusher := setup(t) - defer ctrl.Finish() - - msger.EXPECT().GetCertChain( - gomock.Any(), gomock.Any(), matchers.IsSnetAddrWithIA(core1_110), gomock.Any()).Return( - chainMsg, nil, - ) - msger.EXPECT().GetCertChain( - gomock.Any(), gomock.Any(), matchers.IsSnetAddrWithIA(core1_120), gomock.Any()).Return( - chainMsg, nil, - ) - msger.EXPECT().GetCertChain( - gomock.Any(), gomock.Any(), matchers.IsSnetAddrWithIA(core1_130), gomock.Any()).Return( - emptyChainMsg, nil, - ) - gomock.InOrder( - msger.EXPECT().SendCertChain( - gomock.Any(), matchesChain(rawChain), matchers.IsSnetAddrWithIA(core1_130), - gomock.Any()).Return(serrors.New("test error")), - msger.EXPECT().GetCertChain( - gomock.Any(), gomock.Any(), matchers.IsSnetAddrWithIA(core1_130), gomock.Any()).Return( - emptyChainMsg, nil, - ), - msger.EXPECT().SendCertChain( - gomock.Any(), matchesChain(rawChain), - matchers.IsSnetAddrWithIA(core1_130), gomock.Any()), - ) - pusher.Run(ctx) -} - -var _ gomock.Matcher = (*chainMsgMatcher)(nil) - -type chainMsgMatcher struct { - rawChain common.RawBytes -} - -func matchesChain(rawChain common.RawBytes) *chainMsgMatcher { - return &chainMsgMatcher{ - rawChain: rawChain, - } -} - -func (m *chainMsgMatcher) Matches(x interface{}) bool { - msg, ok := x.(*cert_mgmt.Chain) - if !ok { - return false - } - return bytes.Equal(m.rawChain, msg.RawChain) -} - -func (m *chainMsgMatcher) String() string { - return fmt.Sprintf("Chain msg with raw: %s", m.rawChain) -} diff --git a/go/cert_srv/internal/reiss/handler.go b/go/cert_srv/internal/reiss/handler.go deleted file mode 100644 index be3e5fef7f..0000000000 --- a/go/cert_srv/internal/reiss/handler.go +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright 2018 ETH Zurich, 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 reiss - -import ( - "bytes" - "context" - "net" - "time" - - "github.com/scionproto/scion/go/cert_srv/internal/config" - "github.com/scionproto/scion/go/lib/addr" - "github.com/scionproto/scion/go/lib/common" - "github.com/scionproto/scion/go/lib/ctrl" - "github.com/scionproto/scion/go/lib/ctrl/cert_mgmt" - "github.com/scionproto/scion/go/lib/infra" - "github.com/scionproto/scion/go/lib/infra/modules/trust/trustdb" - "github.com/scionproto/scion/go/lib/log" - "github.com/scionproto/scion/go/lib/scrypto" - "github.com/scionproto/scion/go/lib/scrypto/cert" - "github.com/scionproto/scion/go/lib/serrors" - "github.com/scionproto/scion/go/lib/snet" - "github.com/scionproto/scion/go/lib/util" -) - -const ( - HandlerTimeout = 5 * time.Second -) - -// Errors -const ( - ErrKeyChanged common.ErrMsg = "Verifying key has changed in the meantime" - ErrNotACustomer common.ErrMsg = "ISD-AS not in customer mapping" -) - -// Handler handles certificate chain reissue requests. -// -// Reissue requests are sent by non-issuer ASes to issuer ASes. The request -// needs to be signed with the private key associated with the newest verifying -// key in the customer mapping. Certificate chains are issued automatically by -// the issuer ASes. -type Handler struct { - State *config.State - IA addr.IA -} - -func (h *Handler) Handle(r *infra.Request) *infra.HandlerResult { - var addr *snet.Addr - switch peer := r.Peer.(type) { - case *snet.Addr: - addr = peer - case *snet.UDPAddr: - addr = peer.ToAddr() - case *snet.SVCAddr: - addr = peer.ToAddr() - } - - req := r.Message.(*cert_mgmt.ChainIssReq) - if err := h.handle(r, addr, req); err != nil { - log.Error("[reiss.Handler] Dropping certificate reissue request", - "addr", addr, "req", req, "err", err) - } - // TODO(lukedirtwalker): reflect error in metrics. - return infra.MetricsResultOk -} - -// handle handles certificate chain reissue requests. If the requested -// certificate chain is already present, the existing certificate chain is -// resent. Otherwise, a new certificate chain is issued. -func (h *Handler) handle(r *infra.Request, addr *snet.Addr, req *cert_mgmt.ChainIssReq) error { - ctx, cancelF := context.WithTimeout(r.Context(), HandlerTimeout) - defer cancelF() - logger := log.FromCtx(ctx) - signed := r.FullMessage.(*ctrl.SignedPld) - logger.Trace("[reiss.Handler] Received certificate reissue request", "addr", addr, "req", req) - // Validate the request was correctly signed by the requester - verChain, err := h.validateSign(ctx, addr, signed) - if err != nil { - return common.NewBasicError("Unable to validate chain", err) - } - // Parse the requested certificate - crt, err := req.Cert() - if err != nil { - return common.NewBasicError("Unable to parse requested certificate", err) - } - // Respond with max chain for outdated requests. - opts := infra.ChainOpts{TrustStoreOpts: infra.TrustStoreOpts{LocalOnly: true}} - maxChain, err := h.State.Store.GetChain(ctx, verChain.Leaf.Subject, scrypto.LatestVer, opts) - if err != nil { - return common.NewBasicError("Unable to fetch max chain", err) - } - if maxChain != nil && crt.Version <= maxChain.Leaf.Version { - logger.Info("[reiss.Handler] Resending certificate chain", "addr", addr, "req", req) - return h.sendRep(ctx, addr, maxChain) - } - // Get the verifying key from the customer mapping - verKey, verVersion, err := h.getVerifyingKey(ctx, addr.IA) - if err != nil { - return common.NewBasicError("Unable to get verifying key", err) - } - // Verify request and check the verifying key matches - if err = h.validateReq(crt, verKey, verChain, maxChain); err != nil { - return common.NewBasicError("Unable to verify request", err) - } - // Issue certificate chain - newChain, err := h.issueChain(ctx, crt, verKey, verVersion) - if err != nil { - return common.NewBasicError("Unable to reissue certificate chain", err) - } - // Send issued certificate chain - if err := h.sendRep(ctx, addr, newChain); err != nil { - return common.NewBasicError("Unable to send reissued certificate chain", err) - } - return nil -} - -// validateSign validates that the signer matches the requester and returns the -// certificate chain used when verifying the signature. -func (h *Handler) validateSign(ctx context.Context, addr *snet.Addr, - signed *ctrl.SignedPld) (*cert.Chain, error) { - - if signed.Sign == nil { - return nil, serrors.New("Sign is nil") - } - src, err := ctrl.NewSignSrcDefFromRaw(signed.Sign.Src) - if err != nil { - return nil, err - } - opts := infra.ChainOpts{TrustStoreOpts: infra.TrustStoreOpts{LocalOnly: true}} - verChain, err := h.State.Store.GetChain(ctx, src.IA, scrypto.Version(src.ChainVer), opts) - if err != nil { - return nil, err - } - if signed.Sign.Type.String() != verChain.Leaf.SignAlgorithm { - return nil, common.NewBasicError("Invalid sign type", nil, - "expected", verChain.Leaf.SignAlgorithm, "actual", signed.Sign.Type) - } - // Verify that the requester matches the signer - if !verChain.Leaf.Subject.Equal(addr.IA) { - return nil, common.NewBasicError("Origin AS does not match signer", nil, - "signer", verChain.Leaf.Subject, "origin", addr.IA) - } - return verChain, nil -} - -// validateReq validates the requested certificate. Additionally, it validates that -// the request was verified with the same verifying key as in the customer mapping. -func (h *Handler) validateReq(c *cert.Certificate, vKey common.RawBytes, - vChain, maxChain *cert.Chain) error { - - if !c.Subject.Equal(vChain.Leaf.Subject) { - return common.NewBasicError("Requester does not match subject", nil, "ia", - vChain.Leaf.Subject, "sub", c.Subject) - } - if maxChain.Leaf.Version+1 != c.Version { - return common.NewBasicError("Invalid version", nil, "expected", maxChain.Leaf.Version+1, - "actual", c.Version) - } - if !c.Issuer.Equal(h.IA) { - return common.NewBasicError("Requested Issuer is not this AS", nil, "iss", - c.Issuer, "expected", h.IA) - } - if c.CanIssue { - return serrors.New("CanIssue not allowed to be true") - } - if !bytes.Equal(vKey, vChain.Leaf.SubjectSignKey) { - return serrors.New("Request signed with wrong signing key") - } - return nil -} - -// issueChain creates a certificate chain for the certificate and adds it to the -// trust store. -func (h *Handler) issueChain(ctx context.Context, c *cert.Certificate, - vKey common.RawBytes, verVersion scrypto.Version) (*cert.Chain, error) { - - issCert, err := h.getIssuerCert(ctx) - if err != nil { - return nil, err - } - chain := &cert.Chain{Leaf: c.Copy(), Issuer: issCert} - chain.Leaf.CanIssue = false - chain.Leaf.TRCVersion = chain.Issuer.TRCVersion - chain.Leaf.IssuingTime = util.TimeToSecs(time.Now()) - chain.Leaf.ExpirationTime = chain.Leaf.IssuingTime + cert.DefaultLeafCertValidity - // Leaf certificate must expire before issuer certificate - if chain.Issuer.ExpirationTime < chain.Leaf.ExpirationTime { - chain.Leaf.ExpirationTime = chain.Issuer.ExpirationTime - } - if err = chain.Leaf.Sign(h.State.GetIssSigningKey(), chain.Issuer.SignAlgorithm); err != nil { - return nil, err - } - err = chain.Leaf.Verify(c.Subject, issCert.SubjectSignKey, issCert.SignAlgorithm) - if err != nil { - return nil, err - } - tx, err := h.State.TrustDB.BeginTransaction(ctx, nil) - if err != nil { - return nil, common.NewBasicError("Failed to create transaction", err) - } - // Set verifying key. - newCustKey := &trustdb.CustKey{IA: c.Subject, Key: c.SubjectSignKey, Version: c.Version} - err = tx.InsertCustKey(ctx, newCustKey, verVersion) - if err != nil { - tx.Rollback() - return nil, err - } - var n int64 - if n, err = tx.InsertChain(ctx, chain); err != nil { - tx.Rollback() - log.FromCtx(ctx).Error("[reiss.Handler] Unable to write reissued certificate chain to disk", - "err", err) - return nil, err - } - if n == 0 { - tx.Rollback() - return nil, common.NewBasicError("Chain already in DB", nil, "chain", chain) - } - if err = tx.Commit(); err != nil { - return nil, common.NewBasicError("Failed to commit transaction", err) - } - return chain, nil -} - -func (h *Handler) sendRep(ctx context.Context, addr net.Addr, chain *cert.Chain) error { - - raw, err := chain.Compress() - if err != nil { - return err - } - rw, ok := infra.ResponseWriterFromContext(ctx) - if !ok { - return serrors.New("Unable to send reply, no response writer found") - } - log.Trace("[reiss.Handler] Sending reissued certificate chain", "chain", chain, - "addr", addr) - return rw.SendChainIssueReply(ctx, &cert_mgmt.ChainIssRep{RawChain: raw}) -} - -func (h *Handler) getIssuerCert(ctx context.Context) (*cert.Certificate, error) { - issCrt, err := h.State.TrustDB.GetIssCertMaxVersion(ctx, h.IA) - if err != nil { - return nil, err - } - if issCrt == nil { - return nil, common.NewBasicError("Issuer certificate not found", nil, "ia", h.IA) - } - return issCrt, nil -} - -// getVerifyingKey returns the verifying key from the requested AS and nil if it is in the mapping. -// Otherwise, nil and an error. -func (h *Handler) getVerifyingKey(ctx context.Context, - ia addr.IA) (common.RawBytes, scrypto.Version, error) { - - k, err := h.State.TrustDB.GetCustKey(ctx, ia) - if err != nil { - return nil, 0, err - } - if k == nil { - return nil, 0, common.NewBasicError(ErrNotACustomer, nil, "ISD-AS", ia) - } - return k.Key, k.Version, nil -} diff --git a/go/cert_srv/internal/reiss/requester.go b/go/cert_srv/internal/reiss/requester.go deleted file mode 100644 index e4f553a693..0000000000 --- a/go/cert_srv/internal/reiss/requester.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2018 ETH Zurich, 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 reiss - -import ( - "bytes" - "context" - "fmt" - "time" - - "golang.org/x/crypto/ed25519" - - "github.com/scionproto/scion/go/cert_srv/internal/config" - "github.com/scionproto/scion/go/lib/addr" - "github.com/scionproto/scion/go/lib/common" - "github.com/scionproto/scion/go/lib/ctrl/cert_mgmt" - "github.com/scionproto/scion/go/lib/infra" - "github.com/scionproto/scion/go/lib/infra/messenger" - "github.com/scionproto/scion/go/lib/infra/modules/trust" - "github.com/scionproto/scion/go/lib/log" - "github.com/scionproto/scion/go/lib/periodic" - "github.com/scionproto/scion/go/lib/scrypto" - "github.com/scionproto/scion/go/lib/scrypto/cert" - "github.com/scionproto/scion/go/lib/snet" - "github.com/scionproto/scion/go/lib/util" -) - -var _ periodic.Task = (*Requester)(nil) - -// Requester requests reissued certificate chains before -// expiration of the currently active certificate chain. -type Requester struct { - Msgr infra.Messenger - State *config.State - IA addr.IA - LeafTime time.Duration - CorePusher *periodic.Runner - Caller string -} - -// Name returns the tasks name. -func (r *Requester) Name() string { - return fmt.Sprintf("%s_reiss_requester", r.Caller) -} - -// Run requests reissued certificate chains from the issuer AS. -func (r *Requester) Run(ctx context.Context) { - logger := log.FromCtx(ctx) - crit, err := r.run(ctx) - switch { - case crit && err != nil: - logger.Crit("[reiss.Requester] Unable to get reissued certificate chain", "err", err) - case err != nil: - logger.Error("[reiss.Requester] Unable to get reissued certificate chain", "err", err) - } -} - -func (r *Requester) run(ctx context.Context) (bool, error) { - opts := infra.ChainOpts{TrustStoreOpts: infra.TrustStoreOpts{LocalOnly: true}} - chain, err := r.State.Store.GetChain(ctx, r.IA, scrypto.LatestVer, opts) - if err != nil { - return true, common.NewBasicError("Unable to get local certificate chain", err) - } - exp := util.SecsToTime(chain.Leaf.ExpirationTime) - now := time.Now() - if now.After(exp) { - return true, common.NewBasicError("Certificate expired without being reissued", nil, - "chain", chain, "expTime", util.TimeToCompact(exp), "now", util.TimeToString(now)) - } - if now.Add(r.LeafTime).Before(exp) { - return false, nil - } - return r.sendReq(ctx, chain) -} - -// sendReq creates and sends a certificate chain reissue request based on the newest -// currently active certificate chain. -func (r *Requester) sendReq(ctx context.Context, chain *cert.Chain) (bool, error) { - logger := log.FromCtx(ctx) - c := chain.Leaf.Copy() - c.IssuingTime = util.TimeToSecs(time.Now()) - c.ExpirationTime = c.IssuingTime + (chain.Leaf.ExpirationTime - chain.Leaf.IssuingTime) - c.Version++ - if err := c.Sign(r.State.GetSigningKey(), chain.Leaf.SignAlgorithm); err != nil { - return true, common.NewBasicError("Unable to sign certificate", err) - } - raw, err := c.JSON(false) - if err != nil { - return false, common.NewBasicError("Unable to pack certificate", err) - } - req := &cert_mgmt.ChainIssReq{RawCert: raw} - a := snet.NewSVCAddr(c.Issuer, nil, nil, addr.SvcCS) - rep, err := r.Msgr.RequestChainIssue(ctx, req, a, messenger.NextId()) - if err != nil { - return false, common.NewBasicError("Unable to request reissued certificate chain", err) - } - logger.Trace("[reiss.Requester] Received certificate reissue reply", "addr", a, "rep", rep) - if crit, err := r.handleRep(ctx, rep); err != nil { - return crit, common.NewBasicError("Unable to handle reply", err, "addr", a, "rep", rep) - } - return false, nil -} - -func (r *Requester) handleRep(ctx context.Context, rep *cert_mgmt.ChainIssRep) (bool, error) { - logger := log.FromCtx(ctx) - chain, err := rep.Chain() - if err != nil { - return false, common.NewBasicError("Unable to parse chain", err) - } - if err = r.validateRep(ctx, chain); err != nil { - return true, common.NewBasicError("Unable to validate chain", err, "chain", chain) - } - if _, err = r.State.TrustDB.InsertChain(ctx, chain); err != nil { - return true, common.NewBasicError("Unable to insert reissued certificate chain in TrustDB", - err, "chain", chain) - } - meta, err := trust.CreateSignMeta(ctx, r.IA, r.State.TrustDB) - if err != nil { - return true, common.NewBasicError("Unable create sign meta", err) - } - signer, err := trust.NewBasicSigner(r.State.GetSigningKey(), meta) - if err != nil { - return true, common.NewBasicError("Unable to create new signer", err) - } - r.State.SetSigner(signer) - r.Msgr.UpdateSigner(signer, []infra.MessageType{infra.ChainIssueRequest}) - logger.Info("[reiss.Requester] Updated certificate chain", "chain", chain) - if r.CorePusher != nil { - r.CorePusher.TriggerRun() - } - return false, nil -} - -// validateRep validates that the received certificate chain can be added to the trust store. -func (r *Requester) validateRep(ctx context.Context, chain *cert.Chain) error { - verKey := common.RawBytes(ed25519.PrivateKey( - r.State.GetSigningKey()).Public().(ed25519.PublicKey)) - if !bytes.Equal(chain.Leaf.SubjectSignKey, verKey) { - return common.NewBasicError("Invalid SubjectSignKey", nil, "expected", - verKey, "actual", chain.Leaf.SubjectSignKey) - } - // FIXME(roosd): validate SubjectEncKey - opts := infra.ChainOpts{TrustStoreOpts: infra.TrustStoreOpts{LocalOnly: true}} - chain, err := r.State.Store.GetChain(ctx, r.IA, scrypto.LatestVer, opts) - if err != nil { - return err - } - issuer := chain.Leaf.Issuer - if !chain.Leaf.Issuer.Equal(issuer) { - return common.NewBasicError("Invalid Issuer", nil, "expected", - issuer, "actual", chain.Leaf.Issuer) - } - return trust.VerifyChain(ctx, r.IA, chain, r.State.Store) -} diff --git a/go/cert_srv/internal/reiss/self.go b/go/cert_srv/internal/reiss/self.go deleted file mode 100644 index ad68989a92..0000000000 --- a/go/cert_srv/internal/reiss/self.go +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2018 ETH Zurich, 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 reiss - -import ( - "context" - "fmt" - "time" - - "github.com/scionproto/scion/go/cert_srv/internal/config" - "github.com/scionproto/scion/go/lib/addr" - "github.com/scionproto/scion/go/lib/common" - "github.com/scionproto/scion/go/lib/infra" - "github.com/scionproto/scion/go/lib/infra/modules/trust" - "github.com/scionproto/scion/go/lib/log" - "github.com/scionproto/scion/go/lib/periodic" - "github.com/scionproto/scion/go/lib/scrypto" - "github.com/scionproto/scion/go/lib/scrypto/cert" - "github.com/scionproto/scion/go/lib/scrypto/trc" - "github.com/scionproto/scion/go/lib/util" -) - -var _ periodic.Task = (*Self)(nil) - -// Self periodically issues self-signed certificate chains -// on an issuer AS before the old one expires. -type Self struct { - // Msgr is used to propagate key updates to the messenger, and not for network traffic - Msgr infra.Messenger - State *config.State - IA addr.IA - IssTime time.Duration - LeafTime time.Duration - CorePusher *periodic.Runner - Caller string -} - -// Name returns the tasks name. -func (s *Self) Name() string { - return fmt.Sprintf("%s_reiss_self", s.Caller) -} - -// Run issues certificate chains for the local AS. -func (s *Self) Run(ctx context.Context) { - if err := s.run(ctx); err != nil { - log.FromCtx(ctx).Crit("[reiss.Self] Unable to self issue", "err", err) - } -} - -func (s *Self) run(ctx context.Context) error { - issCrt, err := s.getIssuerCert(ctx) - if err != nil { - return common.NewBasicError("Unable to get issuer certificate", err) - } - opts := infra.ChainOpts{TrustStoreOpts: infra.TrustStoreOpts{LocalOnly: true}} - chain, err := s.State.Store.GetChain(ctx, s.IA, scrypto.LatestVer, opts) - if err != nil { - return common.NewBasicError("Unable to get certificate chain", err) - } - now := time.Now() - iSleep := time.Unix(int64(issCrt.ExpirationTime), 0).Sub(now) - s.IssTime - lSleep := time.Unix(int64(chain.Leaf.ExpirationTime), 0).Sub(now) - s.LeafTime - if lSleep > 0 && iSleep > 0 { - return nil - } - if iSleep <= 0 { - // The issuer certificated needs to be updated. - if err = s.createIssuerCert(ctx, issCrt); err != nil { - return common.NewBasicError("Unable to create issuer certificate", err) - } - } - if lSleep <= 0 { - if err = s.createLeafCert(ctx, chain.Leaf); err != nil { - return common.NewBasicError("Unable to issue certificate chain", err) - } - } - if s.CorePusher != nil { - s.CorePusher.TriggerRun() - } - return nil -} - -// createLeafCert creates a leaf certificate. -func (s *Self) createLeafCert(ctx context.Context, leaf *cert.Certificate) error { - issCrt, err := s.getIssuerCert(ctx) - if err != nil { - return common.NewBasicError("Unable to get issuer certificate", err) - } - chain := &cert.Chain{Leaf: leaf.Copy(), Issuer: issCrt} - chain.Leaf.Version++ - chain.Leaf.IssuingTime = util.TimeToSecs(time.Now()) - chain.Leaf.CanIssue = false - chain.Leaf.ExpirationTime = chain.Leaf.IssuingTime + cert.DefaultLeafCertValidity - if chain.Issuer.ExpirationTime < chain.Leaf.ExpirationTime { - chain.Leaf.ExpirationTime = chain.Issuer.ExpirationTime - } - if err := chain.Leaf.Sign(s.State.GetIssSigningKey(), issCrt.SignAlgorithm); err != nil { - return common.NewBasicError("Unable to sign leaf certificate", err, "chain", chain) - } - if err := trust.VerifyChain(ctx, s.IA, chain, s.State.Store); err != nil { - return common.NewBasicError("Unable to verify chain", err, "chain", chain) - } - if _, err := s.State.TrustDB.InsertChain(ctx, chain); err != nil { - return common.NewBasicError("Unable to write certificate chain", err, "chain", chain) - } - log.FromCtx(ctx).Info("[reiss.Self] Created certificate chain", "chain", chain) - meta, err := trust.CreateSignMeta(ctx, s.IA, s.State.TrustDB) - if err != nil { - return common.NewBasicError("Unable to create sign meta", err) - } - signer, err := trust.NewBasicSigner(s.State.GetSigningKey(), meta) - if err != nil { - return common.NewBasicError("Unable to create new signer", err) - } - s.State.SetSigner(signer) - s.Msgr.UpdateSigner(signer, []infra.MessageType{infra.ChainIssueReply}) - return nil -} - -func (s *Self) getIssuerCert(ctx context.Context) (*cert.Certificate, error) { - issCrt, err := s.State.TrustDB.GetIssCertMaxVersion(ctx, s.IA) - if err != nil { - return nil, err - } - if issCrt == nil { - return nil, common.NewBasicError("Issuer certificate not found", nil, "ia", s.IA) - } - return issCrt, nil -} - -// createIssuerCert creates an issuer certificate. -func (s *Self) createIssuerCert(ctx context.Context, crt *cert.Certificate) error { - crt = crt.Copy() - crt.Version += 1 - crt.IssuingTime = util.TimeToSecs(time.Now()) - crt.CanIssue = true - crt.ExpirationTime = crt.IssuingTime + cert.DefaultIssuerCertValidity - coreAS, err := s.getCoreASEntry(ctx) - if err != nil { - return common.NewBasicError("Unable to get core AS entry", err, "cert", crt) - } - if err = crt.Sign(s.State.GetOnRootKey(), coreAS.OnlineKeyAlg); err != nil { - return common.NewBasicError("Unable to sign issuer certificate", err, "cert", crt) - } - if err = crt.Verify(crt.Issuer, coreAS.OnlineKey, coreAS.OnlineKeyAlg); err != nil { - return common.NewBasicError("Invalid issuer certificate signature", err, "cert", crt) - } - if err = s.setIssuerCert(ctx, crt); err != nil { - return common.NewBasicError("Unable to store issuer certificate", err, "cert", crt) - } - log.FromCtx(ctx).Info("[reiss.Self] Created issuer certificate", "cert", crt) - return nil -} - -func (s *Self) getCoreASEntry(ctx context.Context) (*trc.CoreAS, error) { - opts := infra.TRCOpts{TrustStoreOpts: infra.TrustStoreOpts{LocalOnly: true}} - maxTrc, err := s.State.Store.GetTRC(ctx, s.IA.I, scrypto.LatestVer, opts) - if err != nil { - return nil, common.NewBasicError("Unable to find local TRC", err) - } - coreAS := maxTrc.CoreASes[s.IA] - if coreAS == nil { - return nil, common.NewBasicError("Local AS is not a core AS in the max TRC", - nil, "maxTrc", maxTrc) - } - return coreAS, nil -} - -func (s *Self) setIssuerCert(ctx context.Context, crt *cert.Certificate) error { - affected, err := s.State.TrustDB.InsertIssCert(ctx, crt) - if err != nil { - return err - } - if affected == 0 { - return common.NewBasicError("Issuer certificate already exists", nil, "cert", crt) - } - return nil -} diff --git a/go/cert_srv/internal/reiss/testdata/ISD1-ASff00_0_311-V1.crt b/go/cert_srv/internal/reiss/testdata/ISD1-ASff00_0_311-V1.crt deleted file mode 100644 index b982d9ed3d..0000000000 --- a/go/cert_srv/internal/reiss/testdata/ISD1-ASff00_0_311-V1.crt +++ /dev/null @@ -1,32 +0,0 @@ -{ - "0": { - "SignAlgorithm": "ed25519", - "SubjectSignKey": "5YYo/Djor8KoUPbcG89m0sOXbhaxU/wserVf7X4w0W4=", - "Version": 1, - "EncAlgorithm": "curve25519xsalsa20poly1305", - "SubjectEncKey": "nP1HkZwkW8ujqeEO82Rb9cN6AVqFPO1UIiypdZU+dHI=", - "TRCVersion": 2, - "ExpirationTime": 1539868933, - "Signature": "36dhobVsPBt6UlMCZtmYHoKJbuS3MbZNvu24nA+kt780bf4ZenIreuvnxphIxuI327cBoeDsB+Tg1EvSPnwEBg==", - "Issuer": "1-ff00:0:110", - "CanIssue": false, - "Subject": "1-ff00:0:311", - "IssuingTime": 1508332933, - "Comment": "AS Certificate\u2602\u2602\u2602\u2602" - }, - "1": { - "SignAlgorithm": "ed25519", - "SubjectSignKey": "kqh9WJfVH10/apH278var5ec3AYIU5LjdS1n7SP5+p8=", - "Version": 1, - "EncAlgorithm": "curve25519xsalsa20poly1305", - "SubjectEncKey": "MxxFIP+KlhIyqxsv6B0Um72D+NPoLKGuBPNt8b14/RI=", - "TRCVersion": 2, - "ExpirationTime": 1539868933, - "Signature": "CbjEsqIe4LW7kjMsyMBim4RdRn0YwM4kCjED+1Lbja4o3lwQVHqxVzQ8Rx0CsmHdsm4mwPoNg++KKUlUxrRmCg==", - "Issuer": "1-ff00:0:110", - "CanIssue": true, - "Subject": "1-ff00:0:110", - "IssuingTime": 1508332933, - "Comment": "Core AS Certificate" - } -} diff --git a/go/cert_srv/main.go b/go/cert_srv/main.go index 5a0ddda637..a87dd5e8c2 100644 --- a/go/cert_srv/main.go +++ b/go/cert_srv/main.go @@ -23,13 +23,11 @@ import ( "os" "path/filepath" "sync" - "time" "github.com/BurntSushi/toml" "github.com/opentracing/opentracing-go" "github.com/scionproto/scion/go/cert_srv/internal/config" - "github.com/scionproto/scion/go/cert_srv/internal/reiss" "github.com/scionproto/scion/go/lib/addr" "github.com/scionproto/scion/go/lib/common" "github.com/scionproto/scion/go/lib/discovery" @@ -40,8 +38,8 @@ import ( "github.com/scionproto/scion/go/lib/infra/messenger" "github.com/scionproto/scion/go/lib/infra/modules/idiscovery" "github.com/scionproto/scion/go/lib/infra/modules/itopo" - "github.com/scionproto/scion/go/lib/infra/modules/trust" - "github.com/scionproto/scion/go/lib/infra/modules/trust/trustdb" + "github.com/scionproto/scion/go/lib/infra/modules/trust/v2" + "github.com/scionproto/scion/go/lib/keyconf" "github.com/scionproto/scion/go/lib/log" "github.com/scionproto/scion/go/lib/periodic" "github.com/scionproto/scion/go/lib/prom" @@ -84,12 +82,12 @@ func realMain() int { log.Crit("Setup failed", "err", err) return 1 } + topo := itopo.Get() if !topo.Exists(addr.SvcCS, cfg.General.ID) { log.Crit("Unable to find topo address") return 1 } - tracer, trCloser, err := cfg.Tracing.NewTracer(cfg.General.ID) if err != nil { log.Crit("Unable to create tracer", "err", err) @@ -103,31 +101,6 @@ func realMain() int { log.Crit("Unable to initialize path router", "err", err) return 1 } - trustDB, err := cfg.TrustDB.New() - if err != nil { - log.Crit("Unable to initialize trustDB", "err", err) - return 1 - } - trustDB = trustdb.WithMetrics(string(cfg.TrustDB.Backend()), trustDB) - defer trustDB.Close() - trustConf := trust.Config{ - MustHaveLocalChain: true, - ServiceType: proto.ServiceType_cs, - Router: router, - TopoProvider: itopo.Provider(), - } - trustStore := trust.NewStore(trustDB, topo.IA(), trustConf, log.Root()) - err = trustStore.LoadAuthoritativeCrypto(filepath.Join(cfg.General.ConfigDir, "certs")) - if err != nil { - log.Crit("Unable to load local crypto", "err", err) - return 1 - } - - state, err := newState(topo, trustDB, trustStore) - if err != nil { - log.Crit("Unable to load state", "err", err) - return 1 - } nc := infraenv.NetworkConfig{ IA: topo.IA(), @@ -140,7 +113,6 @@ func realMain() int { KeyFile: cfg.QUIC.KeyFile, }, SVCResolutionFraction: cfg.QUIC.ResolutionFraction, - TrustStore: trustStore, Router: router, SVCRouter: messenger.NewSVCRouter(itopo.Provider()), } @@ -151,25 +123,66 @@ func realMain() int { } defer msgr.CloseServer() - msgr.AddHandler(infra.ChainRequest, trustStore.NewChainReqHandler(true)) - msgr.AddHandler(infra.TRCRequest, trustStore.NewTRCReqHandler(true)) + trustDB, err := cfg.TrustDB.New() + if err != nil { + log.Crit("Error initializing trust database", "err", err) + return 1 + } + defer trustDB.Close() + inserter := trust.DefaultInserter{ + BaseInserter: trust.BaseInserter{DB: trustDB}, + } + provider := trust.Provider{ + DB: trustDB, + Recurser: trust.ASLocalRecurser{IA: topo.IA()}, + Resolver: trust.DefaultResolver{ + DB: trustDB, + Inserter: inserter, + RPC: trust.DefaultRPC{Msgr: msgr}, + }, + Router: trust.AuthRouter{ + ISD: topo.IA().I, + Router: router, + DB: trustDB, + }, + } + trustStore := trust.Store{ + Inspector: trust.DefaultInspector{Provider: provider}, + CryptoProvider: provider, + Inserter: inserter, + DB: trustDB, + } + certsDir := filepath.Join(cfg.General.ConfigDir, "certs") + if err = trustStore.LoadCryptoMaterial(context.Background(), certsDir); err != nil { + log.Crit("Error loading crypto material", "err", err) + return 1 + } + gen := trust.SignerGen{ + IA: topo.IA(), + KeyRing: keyconf.LoadingRing{ + Dir: filepath.Join(cfg.General.ConfigDir, "keys"), + IA: topo.IA(), + }, + Provider: trustStore, + } + signer, err := gen.Signer(context.Background()) + if err != nil { + log.Crit("Error initializing signer", "err", err) + return 1 + } + + msgr.AddHandler(infra.ChainRequest, trustStore.NewChainReqHandler()) + msgr.AddHandler(infra.TRCRequest, trustStore.NewTRCReqHandler()) msgr.AddHandler(infra.Chain, trustStore.NewChainPushHandler()) msgr.AddHandler(infra.TRC, trustStore.NewTRCPushHandler()) - msgr.UpdateSigner(state.GetSigner(), []infra.MessageType{infra.ChainIssueRequest}) - msgr.UpdateVerifier(trust.NewBasicVerifier(trustStore)) - // Only core CS handles certificate reissuance requests. - if topo.Core() { - msgr.AddHandler(infra.ChainIssueRequest, &reiss.Handler{ - State: state, - IA: topo.IA(), - }) - } + msgr.UpdateSigner(signer, []infra.MessageType{infra.ChainIssueRequest}) + msgr.UpdateVerifier(trust.NewVerifier(trustStore)) + // Start the messenger. go func() { defer log.LogPanicAndExit() msgr.ListenAndServe() }() - cfg.Metrics.StartPrometheus() discoRunners, err := idiscovery.StartRunners(cfg.Discovery, discovery.Full, idiscovery.TopoHandlers{}, nil, "cs") @@ -183,7 +196,6 @@ func realMain() int { TopoProvider: itopo.Provider(), Msgr: msgr, TrustDB: trustDB, - State: state, } if err := tasks.Start(); err != nil { log.Crit("Unable to start periodic tasks", "err", err) @@ -202,8 +214,7 @@ func realMain() int { type periodicTasks struct { TopoProvider topology.Provider Msgr infra.Messenger - TrustDB trustdb.TrustDB - State *config.State + TrustDB trust.DB corePusher *periodic.Runner reissuance *periodic.Runner @@ -220,64 +231,12 @@ func (t *periodicTasks) Start() error { return nil } t.running = true - t.corePusher = t.startCorePusher() - t.reissuance = t.startReissuance(t.corePusher) + // t.corePusher = t.startCorePusher() + // t.reissuance = t.startReissuance(t.corePusher) log.Info("Started periodic tasks") return nil } -func (t *periodicTasks) startCorePusher() *periodic.Runner { - if cfg.CS.DisableCorePush { - return nil - } - p := periodic.Start( - &reiss.CorePusher{ - LocalIA: t.TopoProvider.Get().IA(), - TrustDB: t.TrustDB, - Msger: t.Msgr, - }, - time.Hour, - time.Minute, - ) - p.TriggerRun() - return p -} - -func (t *periodicTasks) startReissuance(corePusher *periodic.Runner) *periodic.Runner { - if !cfg.CS.AutomaticRenewal { - log.Info("Certificate reissuance disabled, not starting periodic task.") - return nil - } - if t.TopoProvider.Get().Core() { - log.Info("Starting periodic self-issuing reissuance task.") - return periodic.Start( - &reiss.Self{ - Msgr: t.Msgr, - State: t.State, - IA: t.TopoProvider.Get().IA(), - IssTime: cfg.CS.IssuerReissueLeadTime.Duration, - LeafTime: cfg.CS.LeafReissueLeadTime.Duration, - CorePusher: corePusher, - Caller: "cs", - }, - cfg.CS.ReissueRate.Duration, - cfg.CS.ReissueTimeout.Duration, - ) - } - log.Info("Starting periodic reissuance requester task.") - return periodic.Start( - &reiss.Requester{ - Msgr: t.Msgr, - State: t.State, - IA: t.TopoProvider.Get().IA(), - LeafTime: cfg.CS.LeafReissueLeadTime.Duration, - CorePusher: corePusher, - }, - cfg.CS.ReissueRate.Duration, - cfg.CS.ReissueTimeout.Duration, - ) -} - func (t *periodicTasks) Kill() { t.mtx.Lock() defer t.mtx.Unlock() @@ -330,26 +289,3 @@ func setup() error { infraenv.InitInfraEnvironment(cfg.General.Topology) return nil } - -// TODO(roosd): Remove with trust store v2 -func newState(topo topology.Topology, db trustdb.TrustDB, - store *trust.Store) (*config.State, error) { - - state, err := config.LoadState(cfg.General.ConfigDir, topo.Core(), db, store) - if err != nil { - return nil, serrors.WrapStr("unable to load CS state", err) - } - ctx, cancelF := context.WithTimeout(context.Background(), 2*time.Second) - defer cancelF() - meta, err := trust.CreateSignMeta(ctx, topo.IA(), db) - if err != nil { - return nil, err - } - signer, err := trust.NewBasicSigner(state.GetSigningKey(), meta) - if err != nil { - return nil, err - } - state.SetSigner(signer) - state.SetVerifier(state.Store.NewVerifier()) - return state, nil -} diff --git a/go/integration/cert_req/BUILD.bazel b/go/integration/cert_req/BUILD.bazel index 2eb0f99e6d..a05068e436 100644 --- a/go/integration/cert_req/BUILD.bazel +++ b/go/integration/cert_req/BUILD.bazel @@ -17,8 +17,8 @@ go_library( "//go/lib/log:go_default_library", "//go/lib/sciond:go_default_library", "//go/lib/scrypto:go_default_library", - "//go/lib/scrypto/cert:go_default_library", - "//go/lib/serrors:go_default_library", + "//go/lib/scrypto/cert/v2:go_default_library", + "//go/lib/scrypto/trc/v2:go_default_library", "//go/lib/snet:go_default_library", ], ) diff --git a/go/integration/cert_req/main.go b/go/integration/cert_req/main.go index e5d14e6753..11ffc608b9 100644 --- a/go/integration/cert_req/main.go +++ b/go/integration/cert_req/main.go @@ -31,8 +31,8 @@ import ( "github.com/scionproto/scion/go/lib/log" "github.com/scionproto/scion/go/lib/sciond" "github.com/scionproto/scion/go/lib/scrypto" - "github.com/scionproto/scion/go/lib/scrypto/cert" - "github.com/scionproto/scion/go/lib/serrors" + "github.com/scionproto/scion/go/lib/scrypto/cert/v2" + "github.com/scionproto/scion/go/lib/scrypto/trc/v2" "github.com/scionproto/scion/go/lib/snet" ) @@ -109,9 +109,8 @@ func (c client) attemptRequest(n int) bool { func (c client) requestCert() (*cert.Chain, error) { req := &cert_mgmt.ChainReq{ - CacheOnly: false, - RawIA: remoteIA.IAInt(), - Version: scrypto.LatestVer, + RawIA: remoteIA.IAInt(), + Version: scrypto.LatestVer, } log.Info("Request to SVC: Chain request", "req", req, "svc", svc) ctx, cancelF := context.WithTimeout(context.Background(), integration.DefaultIOTimeout) @@ -120,26 +119,26 @@ func (c client) requestCert() (*cert.Chain, error) { if err != nil { return nil, common.NewBasicError("Unable to get chain", err) } - chain, err := rawChain.Chain() + chain, err := cert.ParseChain(rawChain.RawChain) if err != nil { return nil, common.NewBasicError("Unable to parse chain", err) } - if chain == nil { - return nil, serrors.New("Empty reply") + as, err := chain.AS.Encoded.Decode() + if err != nil { + return nil, common.NewBasicError("Unable to parse AS certificate", err) } - if !chain.Leaf.Subject.Equal(remoteIA) { + if !as.Subject.Equal(remoteIA) { return nil, common.NewBasicError("Invalid subject", nil, - "expected", remoteIA, "actual", chain.Leaf.Subject) + "expected", remoteIA, "actual", as.Subject) } log.Info("Response from SVC: Correct chain", "chain", chain) - return chain, nil + return &chain, nil } func (c client) requestTRC(chain *cert.Chain) error { req := &cert_mgmt.TRCReq{ - CacheOnly: false, - ISD: remoteIA.I, - Version: scrypto.LatestVer, + ISD: remoteIA.I, + Version: scrypto.LatestVer, } log.Info("Request to SVC: TRC request", "req", req, "svc", svc) ctx, cancelF := context.WithTimeout(context.Background(), integration.DefaultIOTimeout) @@ -148,24 +147,59 @@ func (c client) requestTRC(chain *cert.Chain) error { if err != nil { return common.NewBasicError("Unable to get trc", err) } - trc, err := rawTrc.TRC() + signed, err := trc.ParseSigned(rawTrc.RawTRC) if err != nil { - return common.NewBasicError("Unable to parse trc", err) + return common.NewBasicError("Unable to parse signed trc", err) } - if trc == nil { - return serrors.New("Empty reply") + trc, err := signed.EncodedTRC.Decode() + if err != nil { + return common.NewBasicError("Unable to parse trc payload", err) } if trc.ISD != remoteIA.I { return common.NewBasicError("Invalid ISD", nil, "expected", remoteIA.I, "actual", trc.ISD) } - if err := chain.Verify(remoteIA, trc); err != nil { - return common.NewBasicError("Certificate verification failed", err) + if err := c.verifyChain(chain, trc); err != nil { + return common.NewBasicError("unable to verify chain", err) } log.Info("Response from SVC: Correct TRC", "TRC", trc) return nil } +func (c client) verifyChain(chain *cert.Chain, t *trc.TRC) error { + as, err := chain.AS.Encoded.Decode() + if err != nil { + return common.NewBasicError("unable to parse AS certificate", err) + } + if err := as.Validate(); err != nil { + return common.NewBasicError("unable to validate AS certificate", err) + } + iss, err := chain.Issuer.Encoded.Decode() + if err != nil { + return common.NewBasicError("unable to parse issuer certificate", err) + } + if err := iss.Validate(); err != nil { + return common.NewBasicError("unable to validate issuer certificate", err) + } + issVerifier := cert.IssuerVerifier{ + Issuer: iss, + SignedIssuer: &chain.Issuer, + TRC: t, + } + if err := issVerifier.Verify(); err != nil { + return common.NewBasicError("unable to verify issuer certificate", err) + } + asVerifier := cert.ASVerifier{ + Issuer: iss, + SignedAS: &chain.AS, + AS: as, + } + if err := asVerifier.Verify(); err != nil { + return common.NewBasicError("unable to verify issuer certificate", err) + } + return nil +} + func getRemote() error { // Fetch address of service var svcHost *net.UDPAddr diff --git a/go/lib/ctrl/cert_mgmt/BUILD.bazel b/go/lib/ctrl/cert_mgmt/BUILD.bazel index e36648b361..53e955c9c7 100644 --- a/go/lib/ctrl/cert_mgmt/BUILD.bazel +++ b/go/lib/ctrl/cert_mgmt/BUILD.bazel @@ -18,7 +18,9 @@ go_library( "//go/lib/common:go_default_library", "//go/lib/scrypto:go_default_library", "//go/lib/scrypto/cert:go_default_library", + "//go/lib/scrypto/cert/v2:go_default_library", "//go/lib/scrypto/trc:go_default_library", + "//go/lib/scrypto/trc/v2:go_default_library", "//go/proto:go_default_library", ], ) diff --git a/go/lib/ctrl/cert_mgmt/chain.go b/go/lib/ctrl/cert_mgmt/chain.go index dbd7e8fde5..56811abdd1 100644 --- a/go/lib/ctrl/cert_mgmt/chain.go +++ b/go/lib/ctrl/cert_mgmt/chain.go @@ -19,7 +19,8 @@ import ( "fmt" "github.com/scionproto/scion/go/lib/common" - "github.com/scionproto/scion/go/lib/scrypto/cert" + legacy "github.com/scionproto/scion/go/lib/scrypto/cert" + "github.com/scionproto/scion/go/lib/scrypto/cert/v2" "github.com/scionproto/scion/go/proto" ) @@ -29,11 +30,11 @@ type Chain struct { RawChain common.RawBytes `capnp:"chain"` } -func (c *Chain) Chain() (*cert.Chain, error) { +func (c *Chain) Chain() (*legacy.Chain, error) { if c.RawChain == nil { return nil, nil } - return cert.ChainFromRaw(c.RawChain, true) + return legacy.ChainFromRaw(c.RawChain, true) } func (c *Chain) ProtoId() proto.ProtoIdType { @@ -41,9 +42,13 @@ func (c *Chain) ProtoId() proto.ProtoIdType { } func (c *Chain) String() string { - chain, err := c.Chain() + raw, err := cert.ParseChain(c.RawChain) if err != nil { return fmt.Sprintf("Invalid CertificateChain: %v", err) } - return chain.String() + as, err := raw.AS.Encoded.Decode() + if err != nil { + return fmt.Sprintf("Invalid AS certificate: %v", err) + } + return fmt.Sprintf("ISD%d-AS%s-V%d", as.Subject.I, as.Subject.A, as.Version) } diff --git a/go/lib/ctrl/cert_mgmt/trc.go b/go/lib/ctrl/cert_mgmt/trc.go index 2cadb3bcba..c992e25ac1 100644 --- a/go/lib/ctrl/cert_mgmt/trc.go +++ b/go/lib/ctrl/cert_mgmt/trc.go @@ -19,7 +19,8 @@ import ( "fmt" "github.com/scionproto/scion/go/lib/common" - "github.com/scionproto/scion/go/lib/scrypto/trc" + legacy "github.com/scionproto/scion/go/lib/scrypto/trc" + "github.com/scionproto/scion/go/lib/scrypto/trc/v2" "github.com/scionproto/scion/go/proto" ) @@ -29,11 +30,11 @@ type TRC struct { RawTRC common.RawBytes `capnp:"trc"` } -func (t *TRC) TRC() (*trc.TRC, error) { +func (t *TRC) TRC() (*legacy.TRC, error) { if t.RawTRC == nil { return nil, nil } - return trc.TRCFromRaw(t.RawTRC, true) + return legacy.TRCFromRaw(t.RawTRC, true) } func (t *TRC) ProtoId() proto.ProtoIdType { @@ -41,9 +42,13 @@ func (t *TRC) ProtoId() proto.ProtoIdType { } func (t *TRC) String() string { - u, err := t.TRC() + signed, err := trc.ParseSigned(t.RawTRC) if err != nil { - return fmt.Sprintf("Invalid TRC: %v", err) + return fmt.Sprintf("Invalid signed TRC: %v", err) } - return u.String() + pld, err := signed.EncodedTRC.Decode() + if err != nil { + return fmt.Sprintf("Invalid TRC payload: %v", err) + } + return fmt.Sprintf("ISD%d-V%d", pld.ISD, pld.Version) } diff --git a/go/lib/infra/infraenv/BUILD.bazel b/go/lib/infra/infraenv/BUILD.bazel index bc3d8738c3..2f48562286 100644 --- a/go/lib/infra/infraenv/BUILD.bazel +++ b/go/lib/infra/infraenv/BUILD.bazel @@ -12,7 +12,6 @@ go_library( "//go/lib/infra:go_default_library", "//go/lib/infra/disp:go_default_library", "//go/lib/infra/messenger:go_default_library", - "//go/lib/infra/modules/trust:go_default_library", "//go/lib/log:go_default_library", "//go/lib/sciond:go_default_library", "//go/lib/snet:go_default_library", diff --git a/go/lib/infra/infraenv/infraenv.go b/go/lib/infra/infraenv/infraenv.go index fcb6689124..581f0e6145 100644 --- a/go/lib/infra/infraenv/infraenv.go +++ b/go/lib/infra/infraenv/infraenv.go @@ -30,7 +30,6 @@ import ( "github.com/scionproto/scion/go/lib/infra" "github.com/scionproto/scion/go/lib/infra/disp" "github.com/scionproto/scion/go/lib/infra/messenger" - "github.com/scionproto/scion/go/lib/infra/modules/trust" "github.com/scionproto/scion/go/lib/log" "github.com/scionproto/scion/go/lib/sciond" "github.com/scionproto/scion/go/lib/snet" @@ -66,8 +65,6 @@ type NetworkConfig struct { // SVC registers this server to receive packets with the specified SVC // destination address. SVC addr.HostSVC - // TrustStore is the crypto backend for control-plane verification. - TrustStore *trust.Store // ReconnectToDispatcher sets up sockets that automatically reconnect if // the dispatcher closes the connection (e.g., if the dispatcher goes // down). @@ -123,7 +120,6 @@ func (nc *NetworkConfig) Messenger() (infra.Messenger, error) { } } msger := messenger.New(msgerCfg) - nc.TrustStore.SetMessenger(msger) return msger, nil } diff --git a/go/lib/infra/modules/trust/v2/BUILD.bazel b/go/lib/infra/modules/trust/v2/BUILD.bazel index 440edbc8b4..7efada00fc 100644 --- a/go/lib/infra/modules/trust/v2/BUILD.bazel +++ b/go/lib/infra/modules/trust/v2/BUILD.bazel @@ -13,6 +13,7 @@ go_library( "router.go", "rpc.go", "signer.go", + "store.go", "verifier.go", ], importpath = "github.com/scionproto/scion/go/lib/infra/modules/trust/v2", @@ -41,7 +42,6 @@ go_library( go_test( name = "go_default_test", srcs = [ - "export_test.go", "handlers_test.go", "inserter_test.go", "inspector_test.go", @@ -51,6 +51,7 @@ go_test( "resolver_test.go", "router_test.go", "signer_test.go", + "store_test.go", "verifier_export_test.go", "verifier_test.go", ], @@ -67,6 +68,7 @@ go_test( "//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/infra/modules/trust/v2/trustdbsqlite:go_default_library", "//go/lib/keyconf:go_default_library", "//go/lib/log:go_default_library", "//go/lib/scrypto:go_default_library", diff --git a/go/lib/infra/modules/trust/v2/export_test.go b/go/lib/infra/modules/trust/v2/export_test.go deleted file mode 100644 index ed24577f73..0000000000 --- a/go/lib/infra/modules/trust/v2/export_test.go +++ /dev/null @@ -1,70 +0,0 @@ -// 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 "github.com/scionproto/scion/go/lib/infra" - -var ( - // NewChainPushHandler allows instantiating the private chain push handler for black-box - // testing. - NewChainPushHandler = newTestChainPushHandler - // NewTRCPushHandler allows instantiating the private TRC push handler for black-box - // testing. - NewTRCPushHandler = newTestTRCPushHandler - // NewChainReqHandler allows instantiating the private certificate chain - // request handler for black-box testing. - NewChainReqHandler = newTestChainReqHandler - // NewTRCReqHandler allows instantiating the private trc request handler for - // black-box testing. - NewTRCReqHandler = newTestTRCReqResolver -) - -// newTestChainReqHandler returns a new resolver for testing. -func newTestChainReqHandler(request *infra.Request, provider CryptoProvider) *chainReqHandler { - return &chainReqHandler{ - request: request, - provider: provider, - } -} - -// newTestResolver returns a new resolver for testing. -func newTestTRCReqResolver(request *infra.Request, provider CryptoProvider) *trcReqHandler { - return &trcReqHandler{ - request: request, - provider: provider, - } -} - -// newChainPushHandler returns a new chain push handler for testing. -func newTestChainPushHandler(request *infra.Request, provider CryptoProvider, - inserter Inserter) *chainPushHandler { - - return &chainPushHandler{ - request: request, - provider: provider, - inserter: inserter, - } -} - -// newTRCPushHandler returns a new TRC push handler for testing. -func newTestTRCPushHandler(request *infra.Request, provider CryptoProvider, - inserter Inserter) *trcPushHandler { - - return &trcPushHandler{ - request: request, - provider: provider, - inserter: inserter, - } -} diff --git a/go/lib/infra/modules/trust/v2/handlers_test.go b/go/lib/infra/modules/trust/v2/handlers_test.go index 99fee4e751..c94f280763 100644 --- a/go/lib/infra/modules/trust/v2/handlers_test.go +++ b/go/lib/infra/modules/trust/v2/handlers_test.go @@ -150,11 +150,10 @@ func TestChainReqHandler(t *testing.T) { t.Parallel() ctrl := gomock.NewController(t) defer ctrl.Finish() - handler := trust.NewChainReqHandler( - test.Request(ctrl), - test.Provider(ctrl), - ) - result := handler.Handle() + store := trust.Store{ + CryptoProvider: test.Provider(ctrl), + } + result := store.NewChainReqHandler().Handle(test.Request(ctrl)) assert.Equal(t, test.ExpectedResult, result) }) } @@ -277,11 +276,10 @@ func TestTRCReqHandler(t *testing.T) { t.Parallel() ctrl := gomock.NewController(t) defer ctrl.Finish() - handler := trust.NewTRCReqHandler( - test.Request(ctrl), - test.Provider(ctrl), - ) - result := handler.Handle() + store := trust.Store{ + CryptoProvider: test.Provider(ctrl), + } + result := store.NewTRCReqHandler().Handle(test.Request(ctrl)) assert.Equal(t, test.ExpectedResult, result) }) } @@ -451,20 +449,18 @@ func TestChainPushHandler(t *testing.T) { }, } - for _, test := range testCases { - tc := test - t.Run(tc.Name, func(t *testing.T) { + for _, tc := range testCases { + test := tc + t.Run(test.Name, func(t *testing.T) { t.Parallel() ctrl := gomock.NewController(t) defer ctrl.Finish() - chainPushHandler := trust.NewChainPushHandler( - tc.Request(ctrl), - nil, - tc.Inserter(ctrl), - ) - result := chainPushHandler.Handle() - assert.Equal(t, tc.ExpectedResult, result) + store := trust.Store{ + Inserter: test.Inserter(ctrl), + } + result := store.NewChainPushHandler().Handle(test.Request(ctrl)) + assert.Equal(t, test.ExpectedResult, result) }) } } @@ -633,20 +629,18 @@ func TestTRCPushHandler(t *testing.T) { }, } - for _, test := range testCases { - tc := test - t.Run(tc.Name, func(t *testing.T) { + for _, tc := range testCases { + test := tc + t.Run(test.Name, func(t *testing.T) { t.Parallel() ctrl := gomock.NewController(t) defer ctrl.Finish() - trcPushHandler := trust.NewTRCPushHandler( - tc.Request(ctrl), - nil, - tc.Inserter(ctrl), - ) - result := trcPushHandler.Handle() - assert.Equal(t, tc.ExpectedResult, result) + store := trust.Store{ + Inserter: test.Inserter(ctrl), + } + result := store.NewTRCPushHandler().Handle(test.Request(ctrl)) + assert.Equal(t, test.ExpectedResult, result) }) } } diff --git a/go/lib/infra/modules/trust/v2/recurser.go b/go/lib/infra/modules/trust/v2/recurser.go index f7eaaa6cc0..e07c4c16bf 100644 --- a/go/lib/infra/modules/trust/v2/recurser.go +++ b/go/lib/infra/modules/trust/v2/recurser.go @@ -18,6 +18,7 @@ import ( "net" "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/common" "github.com/scionproto/scion/go/lib/serrors" "github.com/scionproto/scion/go/lib/snet" ) @@ -48,10 +49,15 @@ func (r ASLocalRecurser) AllowRecursion(peer net.Addr) error { return nil } + // TODO(roosd): Remove when snet.Addr is removed. + if a, ok := peer.(*snet.Addr); ok { + peer = a.ToXAddr() + } + a, ok := peer.(*snet.UDPAddr) if !ok { return serrors.WrapStr("unable to determine AS of peer", ErrRecursionNotAllowed, - "addr", peer) + "addr", peer, "type", common.TypeOf(peer)) } if !r.IA.Equal(a.IA) { return serrors.WrapStr("client outside local AS", ErrRecursionNotAllowed, diff --git a/go/lib/infra/modules/trust/v2/store.go b/go/lib/infra/modules/trust/v2/store.go new file mode 100644 index 0000000000..de7cf0a1f5 --- /dev/null +++ b/go/lib/infra/modules/trust/v2/store.go @@ -0,0 +1,179 @@ +// 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 ( + "context" + "fmt" + "io/ioutil" + "path/filepath" + "sort" + + "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/serrors" +) + +// Store keeps track of the control-plane PKI crypto material. +type Store struct { + Inspector + CryptoProvider + Inserter Inserter + DB DB +} + +// NewTRCReqHandler returns an infra.Handler for TRC requests coming from a +// peer, backed by the trust store. The configured recurser defines whether the +// trust store is allowed to issue new TRC requests over the network. This +// method should only be used when servicing requests coming from remote nodes. +func (s Store) NewTRCReqHandler() infra.Handler { + f := func(r *infra.Request) *infra.HandlerResult { + handler := &trcReqHandler{ + request: r, + provider: s.CryptoProvider, + } + return handler.Handle() + } + return infra.HandlerFunc(f) +} + +// NewChainReqHandler returns an infra.Handler for Certificate Chain requests +// coming from a peer, backed by the trust store. The configured recurser +// defines whether the trust store is allowed to issue new TRC and certificate +// chain requests over the network. This method should only be used when +// servicing requests coming from remote nodes. +func (s Store) NewChainReqHandler() infra.Handler { + f := func(r *infra.Request) *infra.HandlerResult { + handler := chainReqHandler{ + request: r, + provider: s.CryptoProvider, + } + return handler.Handle() + } + return infra.HandlerFunc(f) +} + +// NewTRCPushHandler returns an infra.Handler for TRC pushes coming from a peer, +// backed by the trust store. TRCs are pushed by local BSes and PSes. Pushes are +// allowed from all local AS sources. +func (s Store) NewTRCPushHandler() infra.Handler { + f := func(r *infra.Request) *infra.HandlerResult { + handler := trcPushHandler{ + request: r, + provider: s.CryptoProvider, + inserter: s.Inserter, + } + return handler.Handle() + } + return infra.HandlerFunc(f) +} + +// NewChainPushHandler returns an infra.Handler for Certificate Chain pushes +// coming from a peer, backed by the trust store. Certificate chains are pushed +// by other ASes during core registration, or the local BSes and PSes. Pushes +// are allowed from all local ISD sources. +func (s Store) NewChainPushHandler() infra.Handler { + f := func(r *infra.Request) *infra.HandlerResult { + handler := chainPushHandler{ + request: r, + provider: s.CryptoProvider, + inserter: s.Inserter, + } + return handler.Handle() + } + return infra.HandlerFunc(f) +} + +// LoadCryptoMaterial loads the crypto material from the file system and +// populates the trust database. +func (s Store) LoadCryptoMaterial(ctx context.Context, dir string) error { + if err := s.LoadTRCs(ctx, dir); err != nil { + return err + } + if err := s.LoadChains(ctx, dir); err != nil { + return err + } + return nil +} + +// LoadTRCs loads the TRCs from the file system. This call ensures that the +// hashes match for TRCs that are already in the database. Before insertion, +// TRCs are verified. +func (s Store) LoadTRCs(ctx context.Context, dir string) error { + files, err := filepath.Glob(fmt.Sprintf("%s/ISD*-V*.trc", dir)) + if err != nil { + panic(err) + } + sort.Strings(files) + for _, file := range files { + if err := s.loadTRC(ctx, file); err != nil { + return serrors.WrapStr("unable to load TRC", err, "file", file) + } + } + return nil +} + +func (s Store) loadTRC(ctx context.Context, file string) error { + raw, err := ioutil.ReadFile(file) + if err != nil { + return err + } + dec, err := decoded.DecodeTRC(raw) + if err != nil { + return err + } + unsafeInserter := DefaultInserter{ + BaseInserter: BaseInserter{ + DB: s.DB, + Unsafe: true, + }, + } + return unsafeInserter.InsertTRC(ctx, dec, s.DB.GetTRC) +} + +// LoadChains loads the certificate chains from the file system. This call +// ensures that the hashes match for the chains that are already in the +// database. Before insertion, certificate chains are verified. +func (s Store) LoadChains(ctx context.Context, dir string) error { + files, err := filepath.Glob(fmt.Sprintf("%s/ISD*-AS*-V*.crt", dir)) + if err != nil { + panic(err) + } + sort.Strings(files) + for _, file := range files { + if err := s.loadChain(ctx, file); err != nil { + return serrors.WithCtx(err, "file", file) + } + } + return nil +} + +func (s Store) loadChain(ctx context.Context, file string) error { + raw, err := ioutil.ReadFile(file) + if err != nil { + return err + } + dec, err := decoded.DecodeChain(raw) + if err != nil { + return err + } + unsafeInserter := DefaultInserter{ + BaseInserter: BaseInserter{ + DB: s.DB, + Unsafe: true, + }, + } + return unsafeInserter.InsertChain(ctx, dec, s.DB.GetTRC) +} diff --git a/go/lib/infra/modules/trust/v2/store_test.go b/go/lib/infra/modules/trust/v2/store_test.go new file mode 100644 index 0000000000..e3f7c890c0 --- /dev/null +++ b/go/lib/infra/modules/trust/v2/store_test.go @@ -0,0 +1,145 @@ +// 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" + "io/ioutil" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/scionproto/scion/go/lib/addr" + "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/trustdbsqlite" + "github.com/scionproto/scion/go/lib/scrypto" + "github.com/scionproto/scion/go/lib/xtest" +) + +func TestStoreLoadCryptoMaterial(t *testing.T) { + tests := map[string]struct { + Prepare func(t *testing.T, scratch string) + ErrAssertion assert.ErrorAssertionFunc + }{ + "valid": { + Prepare: func(t *testing.T, scratch string) { + collectTRCs(t, tmpDir, scratch) + collectChains(t, tmpDir, scratch) + }, + ErrAssertion: assert.NoError, + }, + "unreadable TRC": { + Prepare: func(t *testing.T, scratch string) { + collectChains(t, tmpDir, scratch) + err := ioutil.WriteFile(filepath.Join(scratch, "ISD1-V1.trc"), []byte("no"), 0x000) + require.NoError(t, err) + }, + ErrAssertion: assert.Error, + }, + "garbage TRC": { + Prepare: func(t *testing.T, scratch string) { + collectChains(t, tmpDir, scratch) + err := ioutil.WriteFile(filepath.Join(scratch, "ISD1-V1.trc"), []byte("no"), 0x777) + require.NoError(t, err) + }, + ErrAssertion: assert.Error, + }, + "unreadable chain": { + Prepare: func(t *testing.T, scratch string) { + collectTRCs(t, tmpDir, scratch) + err := ioutil.WriteFile(filepath.Join(scratch, "ISD1-AS1-V1.crt"), + []byte("no"), 0x000) + require.NoError(t, err) + }, + ErrAssertion: assert.Error, + }, + "garbage chain": { + Prepare: func(t *testing.T, scratch string) { + collectTRCs(t, tmpDir, scratch) + err := ioutil.WriteFile(filepath.Join(scratch, "ISD1-AS1-V1.crt"), + []byte("no"), 0x777) + require.NoError(t, err) + }, + ErrAssertion: assert.Error, + }, + } + for n, tc := range tests { + name, test := n, tc + t.Run(name, func(t *testing.T) { + t.Parallel() + scratch, clean := xtest.MustTempDir("", "trust-load-crypto") + defer clean() + db, err := trustdbsqlite.New(":memory:") + require.NoError(t, err) + store := trust.Store{ + DB: db, + CryptoProvider: trust.Provider{ + DB: db, + }, + } + test.Prepare(t, scratch) + err = store.LoadCryptoMaterial(context.Background(), scratch) + test.ErrAssertion(t, err) + if err != nil { + return + } + trcOpts := infra.TRCOpts{AllowInactive: true} + for v := scrypto.Version(1); v < 5; v++ { + id := trust.TRCID{ISD: 1, Version: v} + raw, err := store.GetRawTRC(context.Background(), id, trcOpts) + assert.NoError(t, err) + assert.Equal(t, loadTRC(t, TRCDesc{ISD: 1, Version: v}).Raw, raw) + } + chainOpts := infra.ChainOpts{AllowInactive: true} + for _, ia := range []addr.IA{ia110, ia120, ia122, ia130, ia210} { + id := trust.ChainID{IA: ia, Version: 1} + raw, err := store.GetRawChain(context.Background(), id, chainOpts) + assert.NoError(t, err) + assert.Equal(t, loadChain(t, ChainDesc{IA: ia, Version: 1}).Raw, raw) + } + }) + } +} + +func collectTRCs(t *testing.T, origDir, outDir string) { + t.Helper() + trcs, err := filepath.Glob(filepath.Join(origDir, "ISD*/trcs/*.trc")) + require.NoError(t, err, help) + require.Greater(t, len(trcs), 0) + for _, trc := range trcs { + raw, err := ioutil.ReadFile(trc) + require.NoError(t, err) + _, file := filepath.Split(trc) + err = ioutil.WriteFile(filepath.Join(outDir, file), raw, 0x777) + require.NoError(t, err) + } +} + +func collectChains(t *testing.T, origDir, outDir string) { + t.Helper() + chains, err := filepath.Glob(filepath.Join(origDir, "ISD*/AS*/certs/*.crt")) + require.NoError(t, err, help) + require.Greater(t, len(chains), 0) + for _, chain := range chains { + raw, err := ioutil.ReadFile(chain) + require.NoError(t, err) + _, file := filepath.Split(chain) + err = ioutil.WriteFile(filepath.Join(outDir, file), raw, 0x777) + require.NoError(t, err) + } +} diff --git a/go/lib/truststorage/BUILD.bazel b/go/lib/truststorage/BUILD.bazel index 788a653478..0cc743ae03 100644 --- a/go/lib/truststorage/BUILD.bazel +++ b/go/lib/truststorage/BUILD.bazel @@ -12,8 +12,8 @@ go_library( "//go/lib/common:go_default_library", "//go/lib/config:go_default_library", "//go/lib/infra/modules/db:go_default_library", - "//go/lib/infra/modules/trust/trustdb:go_default_library", - "//go/lib/infra/modules/trust/trustdb/trustdbsqlite:go_default_library", + "//go/lib/infra/modules/trust/v2:go_default_library", + "//go/lib/infra/modules/trust/v2/trustdbsqlite:go_default_library", "//go/lib/log:go_default_library", "//go/lib/serrors:go_default_library", "//go/lib/util:go_default_library", diff --git a/go/lib/truststorage/truststorage.go b/go/lib/truststorage/truststorage.go index d5732031cf..5d5660650f 100644 --- a/go/lib/truststorage/truststorage.go +++ b/go/lib/truststorage/truststorage.go @@ -24,8 +24,8 @@ import ( "github.com/scionproto/scion/go/lib/common" "github.com/scionproto/scion/go/lib/config" "github.com/scionproto/scion/go/lib/infra/modules/db" - "github.com/scionproto/scion/go/lib/infra/modules/trust/trustdb" - "github.com/scionproto/scion/go/lib/infra/modules/trust/trustdb/trustdbsqlite" + "github.com/scionproto/scion/go/lib/infra/modules/trust/v2" + "github.com/scionproto/scion/go/lib/infra/modules/trust/v2/trustdbsqlite" "github.com/scionproto/scion/go/lib/log" "github.com/scionproto/scion/go/lib/serrors" "github.com/scionproto/scion/go/lib/util" @@ -104,11 +104,11 @@ func (cfg *TrustDBConf) validateBackend() error { return common.NewBasicError("Unsupported backend", nil, "backend", cfg.Backend()) } -// New creates a TrustDB from the config. -func (cfg *TrustDBConf) New() (trustdb.TrustDB, error) { +// New creates a trust database from the config. +func (cfg *TrustDBConf) New() (trust.DB, error) { log.Info("Connecting TrustDB", "backend", cfg.Backend(), "connection", cfg.Connection()) var err error - var tdb trustdb.TrustDB + var tdb trust.DB switch cfg.Backend() { case BackendSqlite: diff --git a/go/path_srv/BUILD.bazel b/go/path_srv/BUILD.bazel index 8139e94568..fc0e7adb10 100644 --- a/go/path_srv/BUILD.bazel +++ b/go/path_srv/BUILD.bazel @@ -17,17 +17,16 @@ go_library( "//go/lib/infra/messenger:go_default_library", "//go/lib/infra/modules/idiscovery:go_default_library", "//go/lib/infra/modules/itopo:go_default_library", - "//go/lib/infra/modules/trust:go_default_library", - "//go/lib/infra/modules/trust/trustdb:go_default_library", + "//go/lib/infra/modules/trust/v2:go_default_library", "//go/lib/log:go_default_library", "//go/lib/pathdb:go_default_library", "//go/lib/pathstorage:go_default_library", "//go/lib/periodic:go_default_library", "//go/lib/prom:go_default_library", "//go/lib/revcache:go_default_library", + "//go/lib/serrors:go_default_library", "//go/lib/topology:go_default_library", "//go/path_srv/internal/config:go_default_library", - "//go/path_srv/internal/cryptosyncer:go_default_library", "//go/path_srv/internal/handlers:go_default_library", "//go/path_srv/internal/segreq:go_default_library", "//go/path_srv/internal/segsyncer:go_default_library", diff --git a/go/path_srv/main.go b/go/path_srv/main.go index 2017882260..8be8034774 100644 --- a/go/path_srv/main.go +++ b/go/path_srv/main.go @@ -15,6 +15,7 @@ package main import ( + "context" "flag" "fmt" _ "net/http/pprof" @@ -36,17 +37,16 @@ import ( "github.com/scionproto/scion/go/lib/infra/messenger" "github.com/scionproto/scion/go/lib/infra/modules/idiscovery" "github.com/scionproto/scion/go/lib/infra/modules/itopo" - "github.com/scionproto/scion/go/lib/infra/modules/trust" - "github.com/scionproto/scion/go/lib/infra/modules/trust/trustdb" + "github.com/scionproto/scion/go/lib/infra/modules/trust/v2" "github.com/scionproto/scion/go/lib/log" "github.com/scionproto/scion/go/lib/pathdb" "github.com/scionproto/scion/go/lib/pathstorage" "github.com/scionproto/scion/go/lib/periodic" "github.com/scionproto/scion/go/lib/prom" "github.com/scionproto/scion/go/lib/revcache" + "github.com/scionproto/scion/go/lib/serrors" "github.com/scionproto/scion/go/lib/topology" "github.com/scionproto/scion/go/path_srv/internal/config" - "github.com/scionproto/scion/go/path_srv/internal/cryptosyncer" "github.com/scionproto/scion/go/path_srv/internal/handlers" "github.com/scionproto/scion/go/path_srv/internal/segreq" "github.com/scionproto/scion/go/path_srv/internal/segsyncer" @@ -93,25 +93,8 @@ func realMain() int { defer revCache.Close() pathDB = pathdb.WithMetrics("std", pathDB) defer pathDB.Close() - trustDB, err := cfg.TrustDB.New() - if err != nil { - log.Crit("Unable to initialize trustDB", "err", err) - return 1 - } - trustDB = trustdb.WithMetrics(string(cfg.TrustDB.Backend()), trustDB) - defer trustDB.Close() + topo := itopo.Get() - trustConf := trust.Config{ - MustHaveLocalChain: true, - ServiceType: proto.ServiceType_ps, - TopoProvider: itopo.Provider(), - } - trustStore := trust.NewStore(trustDB, topo.IA(), trustConf, log.Root()) - err = trustStore.LoadAuthoritativeCrypto(filepath.Join(cfg.General.ConfigDir, "certs")) - if err != nil { - log.Crit("Unable to load local crypto", "err", err) - return 1 - } if !topo.Exists(addr.SvcPS, cfg.General.ID) { log.Crit("Unable to find topo address") return 1 @@ -135,7 +118,6 @@ func realMain() int { KeyFile: cfg.QUIC.KeyFile, }, SVCResolutionFraction: cfg.QUIC.ResolutionFraction, - TrustStore: trustStore, SVCRouter: messenger.NewSVCRouter(itopo.Provider()), } msger, err := nc.Messenger() @@ -144,15 +126,49 @@ func realMain() int { return 1 } defer msger.CloseServer() - msger.AddHandler(infra.ChainRequest, trustStore.NewChainReqHandler(false)) + + trustDB, err := cfg.TrustDB.New() + if err != nil { + log.Crit("Error initializing trust database", "err", err) + return 1 + } + defer trustDB.Close() + inserter := trust.ForwardingInserter{ + BaseInserter: trust.BaseInserter{DB: trustDB}, + Router: trust.LocalRouter{IA: topo.IA()}, + RPC: trust.DefaultRPC{Msgr: msger}, + } + provider := trust.Provider{ + DB: trustDB, + Recurser: trust.LocalOnlyRecurser{}, + Resolver: trust.DefaultResolver{ + DB: trustDB, + Inserter: inserter, + RPC: trust.DefaultRPC{Msgr: msger}, + }, + Router: trust.LocalRouter{IA: topo.IA()}, + } + trustStore := trust.Store{ + Inspector: trust.DefaultInspector{Provider: provider}, + CryptoProvider: provider, + Inserter: inserter, + DB: trustDB, + } + certsDir := filepath.Join(cfg.General.ConfigDir, "certs") + if err = trustStore.LoadCryptoMaterial(context.Background(), certsDir); err != nil { + log.Crit("Error loading crypto material", "err", err) + return 1 + } + + msger.AddHandler(infra.ChainRequest, trustStore.NewChainReqHandler()) // TODO(lukedirtwalker): with the new CP-PKI design the PS should no longer need to handle TRC // and cert requests. - msger.AddHandler(infra.TRCRequest, trustStore.NewTRCReqHandler(false)) + msger.AddHandler(infra.TRCRequest, trustStore.NewTRCReqHandler()) args := handlers.HandlerArgs{ PathDB: pathDB, RevCache: revCache, ASInspector: trustStore, - VerifierFactory: trustStore, + VerifierFactory: verificationFactory{Provider: trustStore}, QueryInterval: cfg.PS.QueryInterval.Duration, IA: topo.IA(), TopoProvider: itopo.Provider(), @@ -200,7 +216,7 @@ func realMain() int { type periodicTasks struct { args handlers.HandlerArgs msger infra.Messenger - trustDB trustdb.TrustDB + trustDB trust.DB mtx sync.Mutex running bool segSyncers []*periodic.Runner @@ -226,11 +242,12 @@ func (t *periodicTasks) Start() error { } t.pathDBCleaner = periodic.Start(pathdb.NewCleaner(t.args.PathDB, "ps_segments"), 300*time.Second, 295*time.Second) - t.cryptosyncer = periodic.Start(&cryptosyncer.Syncer{ - DB: t.trustDB, - Msger: t.msger, - IA: t.args.IA, - }, cfg.PS.CryptoSyncInterval.Duration, cfg.PS.CryptoSyncInterval.Duration) + // TODO(roosd): Re-enable + // t.cryptosyncer = periodic.Start(&cryptosyncer.Syncer{ + // DB: t.trustDB, + // Msger: t.msger, + // IA: t.args.IA, + // }, cfg.PS.CryptoSyncInterval.Duration, cfg.PS.CryptoSyncInterval.Duration) t.rcCleaner = periodic.Start(revcache.NewCleaner(t.args.RevCache, "ps_revocation"), 10*time.Second, 10*time.Second) return nil @@ -253,6 +270,18 @@ func (t *periodicTasks) Kill() { t.running = false } +type verificationFactory struct { + Provider trust.CryptoProvider +} + +func (v verificationFactory) NewSigner(common.RawBytes, infra.SignerMeta) (infra.Signer, error) { + return nil, serrors.New("signer generation not supported") +} + +func (v verificationFactory) NewVerifier() infra.Verifier { + return trust.NewVerifier(v.Provider) +} + func setupBasic() error { if _, err := toml.DecodeFile(env.ConfigFile(), &cfg); err != nil { return err diff --git a/go/sciond/BUILD.bazel b/go/sciond/BUILD.bazel index 81a59859f4..8a1c674875 100644 --- a/go/sciond/BUILD.bazel +++ b/go/sciond/BUILD.bazel @@ -12,18 +12,20 @@ go_library( "//go/lib/discovery:go_default_library", "//go/lib/env:go_default_library", "//go/lib/fatal:go_default_library", + "//go/lib/infra:go_default_library", "//go/lib/infra/infraenv:go_default_library", "//go/lib/infra/messenger:go_default_library", "//go/lib/infra/modules/idiscovery:go_default_library", "//go/lib/infra/modules/itopo:go_default_library", "//go/lib/infra/modules/segfetcher:go_default_library", - "//go/lib/infra/modules/trust:go_default_library", + "//go/lib/infra/modules/trust/v2:go_default_library", "//go/lib/log:go_default_library", "//go/lib/pathdb:go_default_library", "//go/lib/pathstorage:go_default_library", "//go/lib/periodic:go_default_library", "//go/lib/prom:go_default_library", "//go/lib/revcache:go_default_library", + "//go/lib/serrors:go_default_library", "//go/lib/topology:go_default_library", "//go/proto:go_default_library", "//go/sciond/internal/config:go_default_library", diff --git a/go/sciond/internal/fetcher/fetcher.go b/go/sciond/internal/fetcher/fetcher.go index 9dfe608c60..137400c47e 100644 --- a/go/sciond/internal/fetcher/fetcher.go +++ b/go/sciond/internal/fetcher/fetcher.go @@ -59,8 +59,9 @@ type Fetcher struct { segfetcher *segfetcher.Fetcher } -func NewFetcher(messenger infra.Messenger, pathDB pathdb.PathDB, trustStore TrustStore, - revCache revcache.RevCache, cfg config.SDConfig, topoProvider topology.Provider) *Fetcher { +func NewFetcher(messenger infra.Messenger, pathDB pathdb.PathDB, inspector infra.ASInspector, + verificationFactory infra.VerificationFactory, revCache revcache.RevCache, cfg config.SDConfig, + topoProvider topology.Provider) *Fetcher { localIA := topoProvider.Get().IA() return &Fetcher{ @@ -71,13 +72,13 @@ func NewFetcher(messenger infra.Messenger, pathDB pathdb.PathDB, trustStore Trus segfetcher: segfetcher.FetcherConfig{ QueryInterval: cfg.QueryInterval.Duration, LocalIA: localIA, - ASInspector: trustStore, - VerificationFactory: trustStore, + ASInspector: inspector, + VerificationFactory: verificationFactory, PathDB: pathDB, RevCache: revCache, RequestAPI: messenger, DstProvider: &dstProvider{IA: localIA}, - Splitter: NewRequestSplitter(localIA, trustStore), + Splitter: NewRequestSplitter(localIA, inspector), SciondMode: true, MetricsNamespace: metrics.Namespace, LocalInfo: neverLocal{}, diff --git a/go/sciond/main.go b/go/sciond/main.go index e0f00db610..47665973c7 100644 --- a/go/sciond/main.go +++ b/go/sciond/main.go @@ -32,18 +32,20 @@ import ( "github.com/scionproto/scion/go/lib/discovery" "github.com/scionproto/scion/go/lib/env" "github.com/scionproto/scion/go/lib/fatal" + "github.com/scionproto/scion/go/lib/infra" "github.com/scionproto/scion/go/lib/infra/infraenv" "github.com/scionproto/scion/go/lib/infra/messenger" "github.com/scionproto/scion/go/lib/infra/modules/idiscovery" "github.com/scionproto/scion/go/lib/infra/modules/itopo" "github.com/scionproto/scion/go/lib/infra/modules/segfetcher" - "github.com/scionproto/scion/go/lib/infra/modules/trust" + "github.com/scionproto/scion/go/lib/infra/modules/trust/v2" "github.com/scionproto/scion/go/lib/log" "github.com/scionproto/scion/go/lib/pathdb" "github.com/scionproto/scion/go/lib/pathstorage" "github.com/scionproto/scion/go/lib/periodic" "github.com/scionproto/scion/go/lib/prom" "github.com/scionproto/scion/go/lib/revcache" + "github.com/scionproto/scion/go/lib/serrors" "github.com/scionproto/scion/go/lib/topology" "github.com/scionproto/scion/go/proto" "github.com/scionproto/scion/go/sciond/internal/config" @@ -97,19 +99,6 @@ func realMain() int { } defer pathDB.Close() defer revCache.Close() - trustDB, err := cfg.TrustDB.New() - if err != nil { - log.Crit("Unable to initialize trustDB", "err", err) - return 1 - } - defer trustDB.Close() - trustConf := trust.Config{TopoProvider: itopo.Provider()} - trustStore := trust.NewStore(trustDB, itopo.Get().IA(), trustConf, log.Root()) - err = trustStore.LoadAuthoritativeTRC(filepath.Join(cfg.General.ConfigDir, "certs")) - if err != nil { - log.Crit("Unable to load local TRC", "err", err) - return 1 - } tracer, trCloser, err := cfg.Tracing.NewTracer(cfg.General.ID) if err != nil { log.Crit("Unable to create tracer", "err", err) @@ -135,7 +124,6 @@ func realMain() int { KeyFile: cfg.QUIC.KeyFile, }, SVCResolutionFraction: cfg.QUIC.ResolutionFraction, - TrustStore: trustStore, SVCRouter: messenger.NewSVCRouter(itopo.Provider()), } msger, err := nc.Messenger() @@ -143,6 +131,40 @@ func realMain() int { log.Crit(infraenv.ErrAppUnableToInitMessenger.Error(), "err", err) return 1 } + defer msger.CloseServer() + + trustDB, err := cfg.TrustDB.New() + if err != nil { + log.Crit("Error initializing trust database", "err", err) + return 1 + } + defer trustDB.Close() + inserter := trust.DefaultInserter{ + BaseInserter: trust.BaseInserter{DB: trustDB}, + } + provider := trust.Provider{ + DB: trustDB, + Recurser: trust.LocalOnlyRecurser{}, + Resolver: trust.DefaultResolver{ + DB: trustDB, + Inserter: inserter, + RPC: trust.DefaultRPC{Msgr: msger}, + }, + Router: trust.LocalRouter{IA: itopo.Get().IA()}, + } + trustStore := trust.Store{ + Inspector: trust.DefaultInspector{Provider: provider}, + CryptoProvider: provider, + Inserter: inserter, + DB: trustDB, + } + certsDir := filepath.Join(cfg.General.ConfigDir, "certs") + err = trustStore.LoadCryptoMaterial(context.Background(), certsDir) + if err != nil { + log.Crit("Error loading crypto material", "err", err) + return 1 + } + // Route messages to their correct handlers handlers := servers.HandlerMap{ proto.SCIONDMsg_Which_pathReq: &servers.PathRequestHandler{ @@ -150,6 +172,7 @@ func realMain() int { msger, pathDB, trustStore, + verificationFactory{Provider: trustStore}, revCache, cfg.SD, itopo.Provider(), @@ -162,7 +185,7 @@ func realMain() int { proto.SCIONDMsg_Which_serviceInfoRequest: &servers.SVCInfoRequestHandler{}, proto.SCIONDMsg_Which_revNotification: &servers.RevNotificationHandler{ RevCache: revCache, - VerifierFactory: trustStore, + VerifierFactory: verificationFactory{Provider: trustStore}, NextQueryCleaner: segfetcher.NextQueryCleaner{PathDB: pathDB}, }, } @@ -190,6 +213,18 @@ func realMain() int { } } +type verificationFactory struct { + Provider trust.CryptoProvider +} + +func (v verificationFactory) NewSigner(common.RawBytes, infra.SignerMeta) (infra.Signer, error) { + return nil, serrors.New("signer generation not supported") +} + +func (v verificationFactory) NewVerifier() infra.Verifier { + return trust.NewVerifier(v.Provider) +} + func setupBasic() error { if _, err := toml.DecodeFile(env.ConfigFile(), &cfg); err != nil { return err diff --git a/go/tools/scion-custpk-load/BUILD.bazel b/go/tools/scion-custpk-load/BUILD.bazel index b9d202021d..4a97a3057c 100644 --- a/go/tools/scion-custpk-load/BUILD.bazel +++ b/go/tools/scion-custpk-load/BUILD.bazel @@ -17,6 +17,7 @@ go_library( "//go/lib/infra/modules/trust/trustdb:go_default_library", "//go/lib/keyconf:go_default_library", "//go/lib/scrypto:go_default_library", + "//go/lib/serrors:go_default_library", "//go/lib/truststorage:go_default_library", "@com_github_burntsushi_toml//:go_default_library", ], diff --git a/go/tools/scion-custpk-load/main.go b/go/tools/scion-custpk-load/main.go index 7c892f8417..68b55b338a 100644 --- a/go/tools/scion-custpk-load/main.go +++ b/go/tools/scion-custpk-load/main.go @@ -26,6 +26,7 @@ import ( "github.com/scionproto/scion/go/lib/config" "github.com/scionproto/scion/go/lib/env" "github.com/scionproto/scion/go/lib/infra/modules/trust/trustdb" + "github.com/scionproto/scion/go/lib/serrors" "github.com/scionproto/scion/go/lib/truststorage" ) @@ -106,10 +107,11 @@ func loadConfig() error { if err != nil { return common.NewBasicError("Unable to validate config", err) } - if trustDB, err = cfg.TrustDB.New(); err != nil { - return common.NewBasicError("Failed to init the database", err) - } - return nil + // TODO(roosd): uncomment + // if trustDB, err = cfg.TrustDB.New(); err != nil { + // return common.NewBasicError("Failed to init the database", err) + // } + return serrors.New("not implemented") } func printSummary(files []string, loadedCusts []*CustKeyMeta) { diff --git a/python/topology/cert.py b/python/topology/cert.py index c6b389a331..4dfeeffbc3 100755 --- a/python/topology/cert.py +++ b/python/topology/cert.py @@ -16,6 +16,8 @@ :mod:`cert` --- SCION topology certificate generator ============================================= """ +import base64 +import os from collections import defaultdict from plumbum import local @@ -38,13 +40,23 @@ def __init__(self, args): self.core_count = defaultdict(int) def generate(self, topo_dicts): - self.pki('tmpl', 'topo', self.args.topo_config, '-d', self.args.output_dir) - self.pki('keys', 'gen', '*', '-d', self.args.output_dir) - self.pki('trc', 'gen', '*', '-d', self.args.output_dir) - self.pki('certs', 'gen', '*', '-d', self.args.output_dir) - self.pki('certs', 'customers', '*', '-d', self.args.output_dir) + self.pki('v2', 'tmpl', 'topo', self.args.topo_config, '-d', self.args.output_dir) + self.pki('v2', 'keys', 'private', '*', '-d', self.args.output_dir) + self.pki('v2', 'keys', 'master', '*', '-d', self.args.output_dir) + self.pki('v2', 'trcs', 'gen', '*', '-d', self.args.output_dir) + self.pki('v2', 'certs', 'issuer', '*', '-d', self.args.output_dir) + self.pki('v2', 'certs', 'chain', '*', '-d', self.args.output_dir) + self._master_keys(topo_dicts) self._copy_files(topo_dicts) + def _master_keys(self, topo_dicts): + for topo_id, as_topo in topo_dicts.items(): + base = topo_id.base_dir(self.args.output_dir) + with open(os.path.join(base, 'keys', 'master0.key'), 'w') as f: + f.write(base64.b64encode(os.urandom(16)).decode()) + with open(os.path.join(base, 'keys', 'master1.key'), 'w') as f: + f.write(base64.b64encode(os.urandom(16)).decode()) + def _copy_files(self, topo_dicts): cp = local['cp'] # Copy the certs and key dir for all elements. @@ -54,7 +66,7 @@ def _copy_files(self, topo_dicts): as_dir = elem_dir.dirname cp('-r', as_dir / 'certs', elem_dir / 'certs') cp('-r', as_dir / 'keys', elem_dir / 'keys') - cp(as_dir.dirname / 'trcs' // '*.trc', elem_dir / 'certs') + cp(as_dir.dirname.dirname // '*/trcs/*.trc', elem_dir / 'certs') # Copy the customers dir for all certificate servers. for topo_id, as_topo in topo_dicts.items(): as_dir = local.path(topo_id.base_dir(self.args.output_dir))