diff --git a/scion-pki/conf/trc.go b/scion-pki/conf/trc.go index dd059f2550..647d234f17 100644 --- a/scion-pki/conf/trc.go +++ b/scion-pki/conf/trc.go @@ -17,6 +17,7 @@ package conf import ( "crypto/x509" "path/filepath" + "strconv" "strings" "github.com/scionproto/scion/pkg/addr" @@ -59,12 +60,29 @@ func LoadTRC(file string) (TRC, error) { } // Certificates returns the specified certificates. -func (cfg *TRC) Certificates() ([]*x509.Certificate, error) { +func (cfg *TRC) Certificates(pred *cppki.TRC) ([]*x509.Certificate, error) { if len(cfg.CertificateFiles) == 0 { return nil, serrors.New("no cert_files specified") } + certs := make([]*x509.Certificate, 0, len(cfg.CertificateFiles)) for _, certFile := range cfg.CertificateFiles { + + if raw, ok := strings.CutPrefix(certFile, "predecessor:"); ok { + if pred == nil { + return nil, serrors.New("predecessor certificate requested on base TRC") + } + idx, err := strconv.Atoi(raw) + if err != nil { + return nil, serrors.Wrap("parsing predecessor index", err, "input", raw) + } + if idx < 0 || idx >= len(pred.Certificates) { + return nil, serrors.New("predecessor index out of bounds", "index", idx) + } + certs = append(certs, pred.Certificates[idx]) + continue + } + if !strings.HasPrefix(certFile, "/") { certFile = filepath.Join(cfg.relPath, certFile) } diff --git a/scion-pki/conf/trc_test.go b/scion-pki/conf/trc_test.go index 6af098ee08..1055239b08 100644 --- a/scion-pki/conf/trc_test.go +++ b/scion-pki/conf/trc_test.go @@ -114,11 +114,21 @@ func TestTRCCertificates(t *testing.T) { prepareCfg func(*conf.TRC) errMsg string expectedCrts []*x509.Certificate + pred *cppki.TRC }{ "valid": { prepareCfg: func(_ *conf.TRC) {}, expectedCrts: []*x509.Certificate{rVoting, sVoting}, }, + "load from predecessor": { + prepareCfg: func(cfg *conf.TRC) { + cfg.CertificateFiles[0] = "predecessor:4" + }, + expectedCrts: []*x509.Certificate{rVoting, sVoting}, + pred: &cppki.TRC{ + Certificates: []*x509.Certificate{4: rVoting}, + }, + }, "file not found": { prepareCfg: func(cfg *conf.TRC) { cfg.CertificateFiles = []string{"notfound"} }, errMsg: "no such file or directory", @@ -128,7 +138,7 @@ func TestTRCCertificates(t *testing.T) { t.Run(name, func(t *testing.T) { cfg := createTRC(t) tc.prepareCfg(cfg) - crts, err := cfg.Certificates() + crts, err := cfg.Certificates(tc.pred) if tc.errMsg != "" { assert.Error(t, err) assert.Contains(t, err.Error(), tc.errMsg) diff --git a/scion-pki/testcrypto/testcrypto.go b/scion-pki/testcrypto/testcrypto.go index 0a819333fe..a641ee813a 100644 --- a/scion-pki/testcrypto/testcrypto.go +++ b/scion-pki/testcrypto/testcrypto.go @@ -321,7 +321,7 @@ func createTRCs(cfg config) error { CertificateFiles: certFiles[isd], } sort.Strings(trcConf.CertificateFiles) - trc, err := trcs.CreatePayload(trcConf) + trc, err := trcs.CreatePayload(trcConf, nil) if err != nil { return serrors.Wrap("creating TRC payload", err, "isd", isd) } diff --git a/scion-pki/trcs/payload.go b/scion-pki/trcs/payload.go index 0fa2d7bc9d..056bcec422 100644 --- a/scion-pki/trcs/payload.go +++ b/scion-pki/trcs/payload.go @@ -70,7 +70,7 @@ To inspect the created asn.1 file you can use the openssl tool:: return err } prepareCfg(&cfg, pred) - trc, err := CreatePayload(cfg) + trc, err := CreatePayload(cfg, pred) if err != nil { return serrors.Wrap("failed to marshal TRC", err) } diff --git a/scion-pki/trcs/toasn.go b/scion-pki/trcs/toasn.go index d563f4ee59..3051e14515 100644 --- a/scion-pki/trcs/toasn.go +++ b/scion-pki/trcs/toasn.go @@ -23,8 +23,8 @@ import ( // CreatePayload creates the ASN.1 payload for the TRC from the given // configuration. -func CreatePayload(cfg conf.TRC) (*cppki.TRC, error) { - certs, err := cfg.Certificates() +func CreatePayload(cfg conf.TRC, pred *cppki.TRC) (*cppki.TRC, error) { + certs, err := cfg.Certificates(pred) if err != nil { return nil, err } diff --git a/scion-pki/trcs/toasn_test.go b/scion-pki/trcs/toasn_test.go index c12be71597..b245d4844a 100644 --- a/scion-pki/trcs/toasn_test.go +++ b/scion-pki/trcs/toasn_test.go @@ -27,7 +27,7 @@ import ( func TestMarshalPayload(t *testing.T) { cfg, err := conf.LoadTRC("testdata/admin/ISD1-B1-S1.toml") require.NoError(t, err) - trc, err := CreatePayload(cfg) + trc, err := CreatePayload(cfg, nil) require.NoError(t, err) raw, err := trc.Encode() require.NoError(t, err)