From e5719e3cd5ed8512445ddbbabf710f2cbd8dff82 Mon Sep 17 00:00:00 2001 From: Matthias Frei Date: Tue, 28 Sep 2021 11:02:59 +0200 Subject: [PATCH] DRKey ported from previous SCIONLab branch Squashed changes for DRKey, ported to latest upstream master branch. This includes the following main commits: * 707a5e6ca DRKey ported from the old SCIONLab (#77) This is itself a squashed commit containing the bulk of the newly added DRKey implementation. * 5a623a29f Allow a second call to initQUICSockets. (#79) * df3a25891 unify personal annotations to JordiSubira (#80) * 9380c7671 fix Level 1 key Exchange (#81) Add sanity check in the drkey_fetcher which validates that the response srcIA matches the intended server IA. * a90f354e2 Remove redundant fields from Lvl1Req/Resp (#83) * 64f4c2308 cs/drkey: handle situations where no path to a peer AS can be found (#90) This condition is now handled analog to a similar condition in github.com/scionproto/scion/go/pkg/trust.AuthRouter.ChooseServer The main change applied to make this compatible with the master branch was to resolve the renaming / moving of what was previously pkg/sciond to now pkg/daemon. Co-authored-by: JordiSubira Co-authored-by: Juan A. Garcia Pardo --- go/cs/BUILD.bazel | 7 + go/cs/config/BUILD.bazel | 11 +- go/cs/config/config.go | 4 + go/cs/config/drkey.go | 161 +++++ go/cs/config/drkey_test.go | 144 +++++ go/cs/config/sample.go | 9 + go/cs/main.go | 88 +++ go/daemon/BUILD.bazel | 3 + go/daemon/main.go | 23 + go/lib/ctrl/drkey/BUILD.bazel | 35 ++ go/lib/ctrl/drkey/lvl1_req.go | 124 ++++ go/lib/ctrl/drkey/lvl2_req.go | 192 ++++++ go/lib/ctrl/drkey/protobuf_test.go | 217 +++++++ go/lib/daemon/BUILD.bazel | 2 + go/lib/daemon/daemon.go | 5 + go/lib/daemon/fake/BUILD.bazel | 1 + go/lib/daemon/fake/fake.go | 6 + go/lib/daemon/grpc.go | 40 ++ go/lib/daemon/mock_daemon/BUILD.bazel | 1 + go/lib/daemon/mock_daemon/mock.go | 17 + go/lib/drkey/BUILD.bazel | 31 + go/lib/drkey/db.go | 47 ++ go/lib/drkey/drkey.go | 29 + go/lib/drkey/drkeydbsqlite/BUILD.bazel | 33 + go/lib/drkey/drkeydbsqlite/base_db.go | 85 +++ go/lib/drkey/drkeydbsqlite/db_test.go | 236 +++++++ go/lib/drkey/drkeydbsqlite/lvl1db.go | 208 +++++++ go/lib/drkey/drkeydbsqlite/lvl2db.go | 151 +++++ go/lib/drkey/epoch.go | 48 ++ go/lib/drkey/exchange/BUILD.bazel | 15 + go/lib/drkey/exchange/grpc.go | 38 ++ go/lib/drkey/level1.go | 44 ++ go/lib/drkey/level2.go | 69 ++ go/lib/drkey/protocol/BUILD.bazel | 33 + go/lib/drkey/protocol/delegated.go | 99 +++ go/lib/drkey/protocol/piskes.go | 45 ++ go/lib/drkey/protocol/protocol.go | 51 ++ go/lib/drkey/protocol/protocol_test.go | 192 ++++++ go/lib/drkey/protocol/scmp.go | 39 ++ go/lib/drkey/protocol/standard.go | 87 +++ go/lib/drkey/secret_value.go | 63 ++ go/lib/drkey/secret_value_test.go | 38 ++ go/lib/drkeystorage/BUILD.bazel | 13 + .../mock_drkeystorage/BUILD.bazel | 13 + .../drkeystorage/mock_drkeystorage/store.go | 226 +++++++ go/lib/drkeystorage/store.go | 59 ++ go/lib/infra/infraenv/infraenv.go | 40 +- go/lib/infra/messenger/addr.go | 30 +- go/lib/infra/messenger/export_test.go | 4 +- go/lib/svc/messages.go | 3 +- go/pkg/cs/BUILD.bazel | 2 + go/pkg/cs/drkey/BUILD.bazel | 43 ++ go/pkg/cs/drkey/export_test.go | 36 ++ go/pkg/cs/drkey/grpc/BUILD.bazel | 61 ++ go/pkg/cs/drkey/grpc/drkey_fetcher.go | 102 +++ go/pkg/cs/drkey/grpc/drkey_fetcher_test.go | 79 +++ go/pkg/cs/drkey/grpc/drkey_service.go | 232 +++++++ go/pkg/cs/drkey/grpc/drkey_service_test.go | 36 ++ go/pkg/cs/drkey/grpc/export_test.go | 19 + go/pkg/cs/drkey/grpc/lvl1_exchange_test.go | 199 ++++++ go/pkg/cs/drkey/grpc/mock_grpc/BUILD.bazel | 22 + go/pkg/cs/drkey/grpc/mock_grpc/mock.go | 52 ++ go/pkg/cs/drkey/grpc/testdata/ISD1-B1-S1.trc | Bin 0 -> 8935 bytes .../crypto/as/ISD1-ASff00_0_110.pem | 27 + .../ISD1/ASff00_0_110/crypto/as/cp-as.key | 5 + .../ISD1/ASff00_0_110/crypto/as/cp-as.tmpl | 4 + .../crypto/ca/ISD1-ASff00_0_110.ca.crt | 13 + .../crypto/ca/ISD1-ASff00_0_110.root.crt | 13 + .../ISD1/ASff00_0_110/crypto/ca/cp-ca.key | 5 + .../ISD1/ASff00_0_110/crypto/ca/cp-ca.tmpl | 4 + .../ISD1/ASff00_0_110/crypto/ca/cp-root.key | 5 + .../ISD1/ASff00_0_110/crypto/ca/cp-root.tmpl | 4 + .../voting/ISD1-ASff00_0_110.regular.crt | 13 + .../voting/ISD1-ASff00_0_110.sensitive.crt | 13 + .../crypto/voting/regular-voting.key | 5 + .../ASff00_0_110/crypto/voting/regular.tmpl | 4 + .../crypto/voting/sensitive-voting.key | 5 + .../ASff00_0_110/crypto/voting/sensitive.tmpl | 4 + .../crypto/as/ISD1-ASff00_0_111.pem | 27 + .../ISD1/ASff00_0_111/crypto/as/cp-as.key | 5 + .../ISD1/ASff00_0_111/crypto/as/cp-as.tmpl | 4 + .../crypto/as/ISD1-ASff00_0_112.pem | 27 + .../ISD1/ASff00_0_112/crypto/as/cp-as.key | 5 + .../ISD1/ASff00_0_112/crypto/as/cp-as.tmpl | 4 + .../testdata/common/ISD1/TRC-B1-S1.pld.der | Bin 0 -> 1636 bytes .../common/ISD1/trcs/ISD1-B1-S1.pem.trc | 53 ++ .../testdata/common/ISD1/trcs/ISD1-B1-S1.trc | Bin 0 -> 2412 bytes .../common/certs/ISD1-ASff00_0_110.ca.crt | 13 + .../common/certs/ISD1-ASff00_0_110.pem | 27 + .../certs/ISD1-ASff00_0_110.regular.crt | 13 + .../certs/ISD1-ASff00_0_110.regular.s2.crt | 13 + .../common/certs/ISD1-ASff00_0_110.root.crt | 13 + .../certs/ISD1-ASff00_0_110.root.s2.crt | 13 + .../certs/ISD1-ASff00_0_110.sensitive.crt | 13 + .../common/certs/ISD1-ASff00_0_111.pem | 27 + .../common/certs/ISD1-ASff00_0_112.pem | 27 + .../grpc/testdata/common/certs/dummy.pem | 0 .../grpc/testdata/common/trcs/ISD1-B1-S1.trc | Bin 0 -> 2412 bytes .../grpc/testdata/common/trcs/ISD1-B1-S2.trc | Bin 0 -> 2664 bytes go/pkg/cs/drkey/grpc/testdata/golden.topo | 11 + .../cs/drkey/grpc/testdata/keys/invalid.key | 5 + .../cs/drkey/grpc/testdata/keys/non-key.key | 5 + go/pkg/cs/drkey/grpc/testdata/keys/valid.key | 5 + .../grpc/testdata/store/invalid-trc/dummy.trc | 1 + go/pkg/cs/drkey/mock_drkey/BUILD.bazel | 13 + go/pkg/cs/drkey/mock_drkey/fetcher.go | 52 ++ go/pkg/cs/drkey/prefetcher.go | 80 +++ go/pkg/cs/drkey/secret_value_store.go | 142 +++++ go/pkg/cs/drkey/secret_value_store_test.go | 128 ++++ go/pkg/cs/drkey/service_store.go | 112 ++++ go/pkg/cs/drkey/service_store_test.go | 111 ++++ go/pkg/cs/drkey/test/BUILD.bazel | 17 + go/pkg/cs/drkey/test/testcommons.go | 82 +++ go/pkg/cs/tasks.go | 52 +- go/pkg/daemon/BUILD.bazel | 1 + go/pkg/daemon/config/config.go | 9 + go/pkg/daemon/daemon.go | 3 + go/pkg/daemon/drkey/BUILD.bazel | 16 + go/pkg/daemon/drkey/client_store.go | 86 +++ go/pkg/daemon/drkey/grpc/BUILD.bazel | 37 ++ go/pkg/daemon/drkey/grpc/lvl2_fetcher.go | 81 +++ .../daemon/drkey/grpc/lvl2_fetching_test.go | 109 ++++ go/pkg/daemon/internal/servers/BUILD.bazel | 3 + go/pkg/daemon/internal/servers/grpc.go | 45 ++ go/pkg/grpc/dialer.go | 9 +- go/pkg/grpc/mock_grpc/BUILD.bazel | 12 + go/pkg/grpc/mock_grpc/dialer.go | 51 ++ go/pkg/proto/control_plane/BUILD.bazel | 1 + go/pkg/proto/control_plane/drkey.pb.go | 399 ++++++++++++ .../mock_control_plane/BUILD.bazel | 3 + .../control_plane/mock_control_plane/mock.go | 79 ++- go/pkg/proto/daemon/BUILD.bazel | 3 + go/pkg/proto/daemon/daemon.pb.go | 311 +++++++-- go/pkg/proto/daemon/mock_daemon/BUILD.bazel | 12 + go/pkg/proto/daemon/mock_daemon/daemon.go | 125 ++++ go/pkg/proto/drkey/BUILD.bazel | 21 + go/pkg/proto/drkey/mgmt.pb.go | 589 ++++++++++++++++++ go/pkg/storage/BUILD.bazel | 2 + go/pkg/storage/storage.go | 26 + go/pkg/trust/BUILD.bazel | 2 + go/pkg/trust/tls_handshake.go | 15 + go/pkg/trust/transport_credentials.go | 117 ++++ proto/control_plane/v1/BUILD.bazel | 2 + proto/control_plane/v1/drkey.proto | 41 ++ proto/daemon/v1/BUILD.bazel | 1 + proto/daemon/v1/daemon.proto | 13 + proto/drkey/mgmt/v1/BUILD.bazel | 10 + proto/drkey/mgmt/v1/mgmt.proto | 82 +++ 148 files changed, 7493 insertions(+), 89 deletions(-) create mode 100644 go/cs/config/drkey.go create mode 100644 go/cs/config/drkey_test.go create mode 100644 go/lib/ctrl/drkey/BUILD.bazel create mode 100644 go/lib/ctrl/drkey/lvl1_req.go create mode 100644 go/lib/ctrl/drkey/lvl2_req.go create mode 100644 go/lib/ctrl/drkey/protobuf_test.go create mode 100644 go/lib/drkey/BUILD.bazel create mode 100644 go/lib/drkey/db.go create mode 100644 go/lib/drkey/drkey.go create mode 100644 go/lib/drkey/drkeydbsqlite/BUILD.bazel create mode 100644 go/lib/drkey/drkeydbsqlite/base_db.go create mode 100644 go/lib/drkey/drkeydbsqlite/db_test.go create mode 100644 go/lib/drkey/drkeydbsqlite/lvl1db.go create mode 100644 go/lib/drkey/drkeydbsqlite/lvl2db.go create mode 100644 go/lib/drkey/epoch.go create mode 100644 go/lib/drkey/exchange/BUILD.bazel create mode 100644 go/lib/drkey/exchange/grpc.go create mode 100644 go/lib/drkey/level1.go create mode 100644 go/lib/drkey/level2.go create mode 100644 go/lib/drkey/protocol/BUILD.bazel create mode 100644 go/lib/drkey/protocol/delegated.go create mode 100644 go/lib/drkey/protocol/piskes.go create mode 100644 go/lib/drkey/protocol/protocol.go create mode 100644 go/lib/drkey/protocol/protocol_test.go create mode 100644 go/lib/drkey/protocol/scmp.go create mode 100644 go/lib/drkey/protocol/standard.go create mode 100644 go/lib/drkey/secret_value.go create mode 100644 go/lib/drkey/secret_value_test.go create mode 100644 go/lib/drkeystorage/BUILD.bazel create mode 100644 go/lib/drkeystorage/mock_drkeystorage/BUILD.bazel create mode 100644 go/lib/drkeystorage/mock_drkeystorage/store.go create mode 100644 go/lib/drkeystorage/store.go create mode 100644 go/pkg/cs/drkey/BUILD.bazel create mode 100644 go/pkg/cs/drkey/export_test.go create mode 100644 go/pkg/cs/drkey/grpc/BUILD.bazel create mode 100644 go/pkg/cs/drkey/grpc/drkey_fetcher.go create mode 100644 go/pkg/cs/drkey/grpc/drkey_fetcher_test.go create mode 100644 go/pkg/cs/drkey/grpc/drkey_service.go create mode 100644 go/pkg/cs/drkey/grpc/drkey_service_test.go create mode 100644 go/pkg/cs/drkey/grpc/export_test.go create mode 100644 go/pkg/cs/drkey/grpc/lvl1_exchange_test.go create mode 100644 go/pkg/cs/drkey/grpc/mock_grpc/BUILD.bazel create mode 100644 go/pkg/cs/drkey/grpc/mock_grpc/mock.go create mode 100644 go/pkg/cs/drkey/grpc/testdata/ISD1-B1-S1.trc create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_110/crypto/as/ISD1-ASff00_0_110.pem create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_110/crypto/as/cp-as.key create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_110/crypto/as/cp-as.tmpl create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_110/crypto/ca/ISD1-ASff00_0_110.ca.crt create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_110/crypto/ca/ISD1-ASff00_0_110.root.crt create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_110/crypto/ca/cp-ca.key create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_110/crypto/ca/cp-ca.tmpl create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_110/crypto/ca/cp-root.key create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_110/crypto/ca/cp-root.tmpl create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_110/crypto/voting/ISD1-ASff00_0_110.regular.crt create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_110/crypto/voting/ISD1-ASff00_0_110.sensitive.crt create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_110/crypto/voting/regular-voting.key create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_110/crypto/voting/regular.tmpl create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_110/crypto/voting/sensitive-voting.key create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_110/crypto/voting/sensitive.tmpl create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_111/crypto/as/ISD1-ASff00_0_111.pem create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_111/crypto/as/cp-as.key create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_111/crypto/as/cp-as.tmpl create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_112/crypto/as/ISD1-ASff00_0_112.pem create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_112/crypto/as/cp-as.key create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/ASff00_0_112/crypto/as/cp-as.tmpl create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/TRC-B1-S1.pld.der create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/trcs/ISD1-B1-S1.pem.trc create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/ISD1/trcs/ISD1-B1-S1.trc create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.ca.crt create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.pem create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.regular.crt create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.regular.s2.crt create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.root.crt create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.root.s2.crt create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.sensitive.crt create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_111.pem create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_112.pem create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/certs/dummy.pem create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/trcs/ISD1-B1-S1.trc create mode 100644 go/pkg/cs/drkey/grpc/testdata/common/trcs/ISD1-B1-S2.trc create mode 100644 go/pkg/cs/drkey/grpc/testdata/golden.topo create mode 100644 go/pkg/cs/drkey/grpc/testdata/keys/invalid.key create mode 100644 go/pkg/cs/drkey/grpc/testdata/keys/non-key.key create mode 100644 go/pkg/cs/drkey/grpc/testdata/keys/valid.key create mode 100644 go/pkg/cs/drkey/grpc/testdata/store/invalid-trc/dummy.trc create mode 100644 go/pkg/cs/drkey/mock_drkey/BUILD.bazel create mode 100644 go/pkg/cs/drkey/mock_drkey/fetcher.go create mode 100644 go/pkg/cs/drkey/prefetcher.go create mode 100644 go/pkg/cs/drkey/secret_value_store.go create mode 100644 go/pkg/cs/drkey/secret_value_store_test.go create mode 100644 go/pkg/cs/drkey/service_store.go create mode 100644 go/pkg/cs/drkey/service_store_test.go create mode 100644 go/pkg/cs/drkey/test/BUILD.bazel create mode 100644 go/pkg/cs/drkey/test/testcommons.go create mode 100644 go/pkg/daemon/drkey/BUILD.bazel create mode 100644 go/pkg/daemon/drkey/client_store.go create mode 100644 go/pkg/daemon/drkey/grpc/BUILD.bazel create mode 100644 go/pkg/daemon/drkey/grpc/lvl2_fetcher.go create mode 100644 go/pkg/daemon/drkey/grpc/lvl2_fetching_test.go create mode 100644 go/pkg/grpc/mock_grpc/BUILD.bazel create mode 100644 go/pkg/grpc/mock_grpc/dialer.go create mode 100644 go/pkg/proto/control_plane/drkey.pb.go create mode 100644 go/pkg/proto/daemon/mock_daemon/BUILD.bazel create mode 100644 go/pkg/proto/daemon/mock_daemon/daemon.go create mode 100644 go/pkg/proto/drkey/BUILD.bazel create mode 100644 go/pkg/proto/drkey/mgmt.pb.go create mode 100644 go/pkg/trust/transport_credentials.go create mode 100644 proto/control_plane/v1/drkey.proto create mode 100644 proto/drkey/mgmt/v1/BUILD.bazel create mode 100644 proto/drkey/mgmt/v1/mgmt.proto diff --git a/go/cs/BUILD.bazel b/go/cs/BUILD.bazel index 4c955e1d6e..a8b787585c 100644 --- a/go/cs/BUILD.bazel +++ b/go/cs/BUILD.bazel @@ -20,12 +20,14 @@ go_library( "//go/cs/segreq:go_default_library", "//go/cs/segreq/grpc:go_default_library", "//go/lib/addr:go_default_library", + "//go/lib/drkeystorage:go_default_library", "//go/lib/fatal:go_default_library", "//go/lib/infra/infraenv:go_default_library", "//go/lib/infra/messenger:go_default_library", "//go/lib/infra/modules/itopo:go_default_library", "//go/lib/infra/modules/segfetcher/grpc:go_default_library", "//go/lib/infra/modules/seghandler:go_default_library", + "//go/lib/keyconf:go_default_library", "//go/lib/log:go_default_library", "//go/lib/metrics:go_default_library", "//go/lib/periodic:go_default_library", @@ -44,6 +46,8 @@ go_library( "//go/pkg/command:go_default_library", "//go/pkg/cs:go_default_library", "//go/pkg/cs/api:go_default_library", + "//go/pkg/cs/drkey:go_default_library", + "//go/pkg/cs/drkey/grpc:go_default_library", "//go/pkg/cs/trust/grpc:go_default_library", "//go/pkg/cs/trust/metrics:go_default_library", "//go/pkg/discovery:go_default_library", @@ -63,9 +67,12 @@ go_library( "@com_github_go_chi_chi_v5//:go_default_library", "@com_github_go_chi_cors//:go_default_library", "@com_github_grpc_ecosystem_go_grpc_prometheus//:go_default_library", + "@com_github_grpc_ecosystem_grpc_opentracing//go/otgrpc:go_default_library", + "@com_github_opentracing_opentracing_go//:go_default_library", "@com_github_spf13_cobra//:go_default_library", "@in_gopkg_yaml_v2//:go_default_library", "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//credentials:go_default_library", "@org_golang_google_grpc//health:go_default_library", "@org_golang_google_grpc//health/grpc_health_v1:go_default_library", ], diff --git a/go/cs/config/BUILD.bazel b/go/cs/config/BUILD.bazel index 5d9f937842..79ee88e6fe 100644 --- a/go/cs/config/BUILD.bazel +++ b/go/cs/config/BUILD.bazel @@ -5,12 +5,15 @@ go_library( srcs = [ "bs_sample.go", "config.go", + "drkey.go", "sample.go", ], importpath = "github.com/scionproto/scion/go/cs/config", visibility = ["//visibility:public"], deps = [ + "//go/lib/addr:go_default_library", "//go/lib/config:go_default_library", + "//go/lib/drkey/protocol:go_default_library", "//go/lib/env:go_default_library", "//go/lib/log:go_default_library", "//go/lib/serrors:go_default_library", @@ -24,15 +27,21 @@ go_library( go_test( name = "go_default_test", - srcs = ["config_test.go"], + srcs = [ + "config_test.go", + "drkey_test.go", + ], embed = [":go_default_library"], deps = [ "//go/lib/env/envtest:go_default_library", "//go/lib/log/logtest:go_default_library", "//go/pkg/api/apitest:go_default_library", "//go/pkg/api/jwtauth:go_default_library", + "//go/pkg/storage:go_default_library", "//go/pkg/storage/test:go_default_library", + "@com_github_burntsushi_toml//:go_default_library", "@com_github_pelletier_go_toml//:go_default_library", "@com_github_stretchr_testify//assert:go_default_library", + "@com_github_stretchr_testify//require:go_default_library", ], ) diff --git a/go/cs/config/config.go b/go/cs/config/config.go index 5e27461eca..6158efbb75 100644 --- a/go/cs/config/config.go +++ b/go/cs/config/config.go @@ -64,6 +64,7 @@ type Config struct { PS PSConfig `toml:"path,omitempty"` CA CA `toml:"ca,omitempty"` TrustEngine trustengine.Config `toml:"trustengine,omitempty"` + DRKey DRKeyConfig `toml:"drkey,omitempty"` } // InitDefaults initializes the default values for all parts of the config. @@ -82,6 +83,7 @@ func (cfg *Config) InitDefaults() { &cfg.PS, &cfg.CA, &cfg.TrustEngine, + &cfg.DRKey, ) } @@ -100,6 +102,7 @@ func (cfg *Config) Validate() error { &cfg.PS, &cfg.CA, &cfg.TrustEngine, + &cfg.DRKey, ) } @@ -138,6 +141,7 @@ func (cfg *Config) Sample(dst io.Writer, path config.Path, _ config.CtxMap) { &cfg.PS, &cfg.CA, &cfg.TrustEngine, + &cfg.DRKey, ) } diff --git a/go/cs/config/drkey.go b/go/cs/config/drkey.go new file mode 100644 index 0000000000..ad2a6702a2 --- /dev/null +++ b/go/cs/config/drkey.go @@ -0,0 +1,161 @@ +// Copyright 2019 ETH Zurich +// +// 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 ( + "io" + "time" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/config" + "github.com/scionproto/scion/go/lib/drkey/protocol" + "github.com/scionproto/scion/go/lib/serrors" + "github.com/scionproto/scion/go/lib/util" + "github.com/scionproto/scion/go/pkg/storage" +) + +const ( + // DefaultEpochDuration is the default duration for the drkey SV and derived keys + DefaultEpochDuration = 24 * time.Hour +) + +var _ (config.Config) = (*DRKeyConfig)(nil) + +// DRKeyConfig is the configuration for the connection to the trust database. +type DRKeyConfig struct { + // enabled is set to true if we find all the required fields in the configuration. + enabled bool + // DRKeyDB contains the DRKey DB configuration. + DRKeyDB storage.DBConfig `toml:"drkey_db,omitempty"` + // EpochDuration is the duration of the keys in this CS. + EpochDuration util.DurWrap `toml:"epoch_duration,omitempty"` + // AuthorizedDelegations is the DelegationList for this CS. + Delegation DelegationList `toml:"delegation,omitempty"` + + //TLS config + CertFile string `toml:"cert_file,omitempty"` + KeyFile string `toml:"key_file,omitempty"` +} + +// NewDRKeyConfig returns a pointer to a valid, empty configuration. +func NewDRKeyConfig() *DRKeyConfig { + c := DRKeyConfig{ + DRKeyDB: storage.DBConfig{}, + Delegation: DelegationList{}, + } + return &c +} + +// InitDefaults initializes values of unset keys and determines if the configuration enables DRKey. +func (cfg *DRKeyConfig) InitDefaults() { + cfg.enabled = true + if cfg.EpochDuration.Duration == 0 { + cfg.EpochDuration.Duration = DefaultEpochDuration + } + config.InitAll(&cfg.Delegation) +} + +// Enabled returns true if DRKey is configured. False otherwise. +func (cfg *DRKeyConfig) Enabled() bool { + if cfg.DRKeyDB.Connection == "" { + return false + } + return true +} + +// Validate validates that all values are parsable. +func (cfg *DRKeyConfig) Validate() error { + return config.ValidateAll(&cfg.DRKeyDB, &cfg.Delegation) +} + +// Sample writes a config sample to the writer. +func (cfg *DRKeyConfig) Sample(dst io.Writer, path config.Path, ctx config.CtxMap) { + config.WriteString(dst, drkeySample) + config.WriteSample(dst, path, + config.CtxMap{config.ID: idSample}, + config.OverrideName( + config.FormatData( + &cfg.DRKeyDB, + storage.SetID(storage.SampleDRKeyDB, idSample).Connection, + ), + "drkey_db", + ), + &cfg.Delegation, + ) +} + +// ConfigName is the key in the toml file. +func (cfg *DRKeyConfig) ConfigName() string { + return "drkey" +} + +// DelegationList configures which endhosts can get delegation secrets, per protocol. +type DelegationList map[string][]string + +var _ (config.Config) = (*DelegationList)(nil) + +// InitDefaults will not add or modify any entry in the config. +func (cfg *DelegationList) InitDefaults() { + if *cfg == nil { + *cfg = make(DelegationList) + } +} + +// Validate validates that the protocols exist, and their addresses are parsable. +func (cfg *DelegationList) Validate() error { + for proto, list := range *cfg { + if _, found := protocol.KnownDerivations[proto]; !found { + return serrors.New("Configured protocol not found", "protocol", proto) + } + for _, ip := range list { + if h := addr.HostFromIPStr(ip); h == nil { + return serrors.New("Syntax error: not a valid address", "ip", ip) + } + } + } + return nil +} + +// Sample writes a config sample to the writer. +func (cfg *DelegationList) Sample(dst io.Writer, path config.Path, ctx config.CtxMap) { + config.WriteString(dst, drkeyDelegationListSample) +} + +// ConfigName is the key in the toml file. +func (cfg *DelegationList) ConfigName() string { + return "delegation" +} + +// ToMapPerHost will return map where there is a set of supported protocols per host. +func (cfg *DelegationList) ToMapPerHost() map[[16]byte]map[string]struct{} { + m := make(map[[16]byte]map[string]struct{}) + for proto, ipList := range *cfg { + for _, ip := range ipList { + host := addr.HostFromIPStr(ip) + if host == nil { + continue + } + var rawHost [16]byte + copy(rawHost[:], host.IP().To16()) + protoSet := m[rawHost] + if protoSet == nil { + protoSet = make(map[string]struct{}) + } + protoSet[proto] = struct{}{} + m[rawHost] = protoSet + } + } + return m +} diff --git a/go/cs/config/drkey_test.go b/go/cs/config/drkey_test.go new file mode 100644 index 0000000000..1024f09263 --- /dev/null +++ b/go/cs/config/drkey_test.go @@ -0,0 +1,144 @@ +// Copyright 2019 ETH Zurich +// +// 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 ( + "bytes" + "io/ioutil" + "net" + "os" + "testing" + "time" + + "github.com/BurntSushi/toml" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/scionproto/scion/go/pkg/storage" +) + +func TestInitDefaults(t *testing.T) { + var cfg DRKeyConfig + cfg.InitDefaults() + assert.EqualValues(t, 24*time.Hour, cfg.EpochDuration.Duration) +} + +func TestDRKeyConfigSample(t *testing.T) { + var sample bytes.Buffer + var cfg DRKeyConfig + cfg.Sample(&sample, nil, nil) + meta, err := toml.Decode(sample.String(), &cfg) + require.NoError(t, err) + require.Empty(t, meta.Undecoded()) + err = cfg.Validate() + require.NoError(t, err) + assert.Equal(t, DefaultEpochDuration, cfg.EpochDuration.Duration) +} + +func TestDisable(t *testing.T) { + var cfg = NewDRKeyConfig() + require.False(t, cfg.Enabled()) + var err error + err = cfg.Validate() + require.NoError(t, err) + cfg.EpochDuration.Duration = 10 * time.Hour + require.False(t, cfg.Enabled()) + cfg.DRKeyDB.Connection = "a" + cfg.InitDefaults() + require.True(t, cfg.Enabled()) + err = cfg.Validate() + require.NoError(t, err) + assert.EqualValues(t, 10*time.Hour, cfg.EpochDuration.Duration) +} + +func TestValidate(t *testing.T) { + var err error + var cfg = NewDRKeyConfig() + err = cfg.Validate() + require.NoError(t, err) + cfg.EpochDuration.Duration = 10 * time.Hour + sample1 := `piskes = ["not an address"]` + toml.Decode(sample1, &cfg.Delegation) + require.Error(t, cfg.Validate()) + sample2 := `piskes = ["1.1.1.1"]` + toml.Decode(sample2, &cfg.Delegation) + require.NoError(t, cfg.Validate()) + cfg.DRKeyDB.Connection = "a" + require.NoError(t, cfg.Validate()) +} + +func TestDelegationListDefaults(t *testing.T) { + var cfg DelegationList + cfg.InitDefaults() + require.NotNil(t, cfg) + require.Empty(t, cfg) +} + +func TestDelegationListSyntax(t *testing.T) { + var cfg DelegationList + sample1 := `piskes = ["1.1.1.1"]` + meta, err := toml.Decode(sample1, &cfg) + require.NoError(t, err) + require.Empty(t, meta.Undecoded()) + require.NoError(t, cfg.Validate()) + + sample2 := `piskes = ["not an address"]` + meta, err = toml.Decode(sample2, &cfg) + require.NoError(t, err) + require.Empty(t, meta.Undecoded()) + require.Error(t, cfg.Validate()) +} + +func TestToMapPerHost(t *testing.T) { + var cfg DelegationList + sample := `piskes = ["1.1.1.1", "2.2.2.2"] + scmp = ["1.1.1.1"]` + toml.Decode(sample, &cfg) + require.NoError(t, cfg.Validate()) + m := cfg.ToMapPerHost() + require.Len(t, m, 2) + + var rawIP [16]byte + copy(rawIP[:], net.ParseIP("1.1.1.1").To16()) + require.Len(t, m[rawIP], 2) + require.Contains(t, m[rawIP], "piskes") + require.Contains(t, m[rawIP], "scmp") + + copy(rawIP[:], net.ParseIP("2.2.2.2").To16()) + require.Len(t, m[rawIP], 1) + require.Contains(t, m[rawIP], "piskes") +} + +func TestNewLvl1DB(t *testing.T) { + cfg := DRKeyConfig{} + cfg.InitDefaults() + cfg.DRKeyDB.Connection = tempFile(t) + db, err := storage.NewDRKeyLvl1Storage(cfg.DRKeyDB) + defer func() { + db.Close() + os.Remove(cfg.DRKeyDB.Connection) + }() + require.NoError(t, err) + require.NotNil(t, db) +} + +func tempFile(t *testing.T) string { + file, err := ioutil.TempFile("", "db-test-") + require.NoError(t, err) + name := file.Name() + err = file.Close() + require.NoError(t, err) + return name +} diff --git a/go/cs/config/sample.go b/go/cs/config/sample.go index 75975c7a8b..7a472194b1 100644 --- a/go/cs/config/sample.go +++ b/go/cs/config/sample.go @@ -50,6 +50,15 @@ max_as_validity = "3d" mode = "in-process" ` +const drkeySample = ` +# EpochDuration of the DRKey secret value and of all derived keys. (default "24h") +epoch_duration = "24h" +` +const drkeyDelegationListSample = ` +# The list of hosts authorized to get a DS per protocol. +piskes = [ "127.0.0.1", "127.0.0.2"] +` + const serviceSample = ` # The path to the PEM-encoded shared secret that is used to create JWT tokens. shared_secret = "" diff --git a/go/cs/main.go b/go/cs/main.go index b79c357f72..b6c9bffc59 100644 --- a/go/cs/main.go +++ b/go/cs/main.go @@ -16,6 +16,7 @@ package main import ( "context" + "crypto/tls" "errors" "net" "net/http" @@ -26,8 +27,11 @@ import ( "github.com/go-chi/chi/v5" "github.com/go-chi/cors" promgrpc "github.com/grpc-ecosystem/go-grpc-prometheus" + "github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc" + "github.com/opentracing/opentracing-go" "github.com/spf13/cobra" "google.golang.org/grpc" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/health" healthpb "google.golang.org/grpc/health/grpc_health_v1" @@ -41,12 +45,14 @@ import ( "github.com/scionproto/scion/go/cs/segreq" segreqgrpc "github.com/scionproto/scion/go/cs/segreq/grpc" "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/drkeystorage" "github.com/scionproto/scion/go/lib/fatal" "github.com/scionproto/scion/go/lib/infra/infraenv" "github.com/scionproto/scion/go/lib/infra/messenger" "github.com/scionproto/scion/go/lib/infra/modules/itopo" segfetchergrpc "github.com/scionproto/scion/go/lib/infra/modules/segfetcher/grpc" "github.com/scionproto/scion/go/lib/infra/modules/seghandler" + "github.com/scionproto/scion/go/lib/keyconf" "github.com/scionproto/scion/go/lib/log" libmetrics "github.com/scionproto/scion/go/lib/metrics" "github.com/scionproto/scion/go/lib/periodic" @@ -65,6 +71,8 @@ import ( "github.com/scionproto/scion/go/pkg/command" "github.com/scionproto/scion/go/pkg/cs" "github.com/scionproto/scion/go/pkg/cs/api" + "github.com/scionproto/scion/go/pkg/cs/drkey" + drkeygrpc "github.com/scionproto/scion/go/pkg/cs/drkey/grpc" cstrustgrpc "github.com/scionproto/scion/go/pkg/cs/trust/grpc" cstrustmetrics "github.com/scionproto/scion/go/pkg/cs/trust/metrics" "github.com/scionproto/scion/go/pkg/discovery" @@ -472,6 +480,66 @@ func realMain(ctx context.Context) error { } dpb.RegisterDiscoveryServiceServer(quicServer, ds) + //DRKey feature + var drkeyServStore drkeystorage.ServiceStore + var quicTLSServer *grpc.Server + if globalCfg.DRKey.Enabled() { + masterKey, err := loadMasterSecret(globalCfg.General.ConfigDir) + if err != nil { + return serrors.WrapStr("loading master secret in DRKey", err) + } + svFactory := drkey.NewSecretValueFactory( + masterKey.Key0, globalCfg.DRKey.EpochDuration.Duration) + drkeyDB, err := storage.NewDRKeyLvl1Storage(globalCfg.DRKey.DRKeyDB) + if err != nil { + return serrors.WrapStr("initializing DRKey DB", err) + } + loader := trust.FileLoader{ + CertFile: globalCfg.DRKey.CertFile, + KeyFile: globalCfg.DRKey.KeyFile, + } + tlsMgr := trust.NewTLSCryptoManager(loader, trustDB) + drkeyFetcher := drkeygrpc.DRKeyFetcher{ + Getter: drkeygrpc.Lvl1KeyFetcher{ + Dialer: &libgrpc.TLSQUICDialer{ + Rewriter: nc.AddressRewriter(nil), + Dialer: quicStack.TLSDialer, + Credentials: trust.GetTansportCredentials(tlsMgr), + }, + Router: segreq.NewRouter(fetcherCfg), + }, + } + drkeyServStore = &drkey.ServiceStore{ + LocalIA: topo.IA(), + DB: drkeyDB, + SecretValues: svFactory, + Fetcher: drkeyFetcher, + } + drkeyService := &drkeygrpc.DRKeyServer{ + LocalIA: topo.IA(), + Store: drkeyServStore, + AllowedDSs: globalCfg.DRKey.Delegation.ToMapPerHost(), + } + srvConfig := &tls.Config{ + InsecureSkipVerify: true, + GetCertificate: tlsMgr.GetCertificate, + VerifyPeerCertificate: tlsMgr.VerifyPeerCertificate, + ClientAuth: tls.RequireAnyClientCert, + } + quicTLSServer = grpc.NewServer( + grpc.Creds(credentials.NewTLS(srvConfig)), + grpc.ChainUnaryInterceptor( + otgrpc.OpenTracingServerInterceptor(opentracing.GlobalTracer()), + libgrpc.LogIDServerInterceptor(), + ), + ) + cppb.RegisterDRKeyLvl1ServiceServer(quicTLSServer, drkeyService) + cppb.RegisterDRKeyLvl2ServiceServer(tcpServer, drkeyService) + log.Info("DRKey is enabled") + } else { + log.Info("DRKey is DISABLED by configuration") + } + dsHealth := health.NewServer() dsHealth.SetServingStatus("discovery", healthpb.HealthCheckResponse_SERVING) healthpb.RegisterHealthServer(tcpServer, dsHealth) @@ -505,6 +573,16 @@ func realMain(ctx context.Context) error { fatal.Fatal(err) } }() + + if globalCfg.DRKey.Enabled() { + go func() { + defer log.HandlePanic() + if err := quicTLSServer.Serve(quicStack.TLSListener); err != nil { + fatal.Fatal(err) + } + }() + } + if globalCfg.API.Addr != "" { r := chi.NewRouter() r.Use(cors.Handler(cors.Options{ @@ -577,6 +655,7 @@ func realMain(ctx context.Context) error { Signer: signer, Inspector: inspector, Metrics: metrics, + DRKeyStore: drkeyServStore, MACGen: macGen, TopoProvider: itopo.Provider(), StaticInfo: func() *beaconing.StaticInfoCfg { return staticInfo }, @@ -584,6 +663,7 @@ func realMain(ctx context.Context) error { OriginationInterval: globalCfg.BS.OriginationInterval.Duration, PropagationInterval: globalCfg.BS.PropagationInterval.Duration, RegistrationInterval: globalCfg.BS.RegistrationInterval.Duration, + DRKeyEpochInterval: globalCfg.DRKey.EpochDuration.Duration, HiddenPathRegistrationCfg: hpWriterCfg, AllowIsdLoop: isdLoopAllowed, }) @@ -651,6 +731,14 @@ func createBeaconStore( return store, &policies, *policies.Prop.Filter.AllowIsdLoop, err } +func loadMasterSecret(dir string) (keyconf.Master, error) { + masterKey, err := keyconf.LoadMaster(filepath.Join(dir, "keys")) + if err != nil { + return keyconf.Master{}, serrors.WrapStr("error getting master secret", err) + } + return masterKey, nil +} + type topoInformation struct{} func (topoInformation) Gateways() ([]topology.GatewayInfo, error) { diff --git a/go/daemon/BUILD.bazel b/go/daemon/BUILD.bazel index fca527cbc0..e70ce89f31 100644 --- a/go/daemon/BUILD.bazel +++ b/go/daemon/BUILD.bazel @@ -14,6 +14,7 @@ go_library( visibility = ["//visibility:private"], deps = [ "//go/lib/addr:go_default_library", + "//go/lib/drkeystorage:go_default_library", "//go/lib/fatal:go_default_library", "//go/lib/infra:go_default_library", "//go/lib/infra/infraenv:go_default_library", @@ -32,6 +33,8 @@ go_library( "//go/pkg/app/launcher:go_default_library", "//go/pkg/daemon:go_default_library", "//go/pkg/daemon/config:go_default_library", + "//go/pkg/daemon/drkey:go_default_library", + "//go/pkg/daemon/drkey/grpc:go_default_library", "//go/pkg/daemon/fetcher:go_default_library", "//go/pkg/grpc:go_default_library", "//go/pkg/hiddenpath:go_default_library", diff --git a/go/daemon/main.go b/go/daemon/main.go index 911a4b08c7..9aa31e7ab9 100644 --- a/go/daemon/main.go +++ b/go/daemon/main.go @@ -27,6 +27,7 @@ import ( "google.golang.org/grpc/resolver" "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/drkeystorage" "github.com/scionproto/scion/go/lib/fatal" "github.com/scionproto/scion/go/lib/infra" "github.com/scionproto/scion/go/lib/infra/infraenv" @@ -45,6 +46,8 @@ import ( "github.com/scionproto/scion/go/pkg/app/launcher" "github.com/scionproto/scion/go/pkg/daemon" "github.com/scionproto/scion/go/pkg/daemon/config" + "github.com/scionproto/scion/go/pkg/daemon/drkey" + dk_grpc "github.com/scionproto/scion/go/pkg/daemon/drkey/grpc" "github.com/scionproto/scion/go/pkg/daemon/fetcher" libgrpc "github.com/scionproto/scion/go/pkg/grpc" "github.com/scionproto/scion/go/pkg/hiddenpath" @@ -139,6 +142,25 @@ func realMain(ctx context.Context) error { MaxCacheExpiration: globalCfg.TrustEngine.Cache.Expiration, } + var drkeyStore drkeystorage.ClientStore + if globalCfg.DRKeyDB.Connection != "" { + ia := itopo.Get().IA() + drkeyDB, err := storage.NewDRKeyLvl2Storage(globalCfg.DRKeyDB) + if err != nil { + log.Error("Creating Lvl2 DRKey DB", "err", err) + } + defer drkeyDB.Close() + + drkeyFetcher := dk_grpc.DRKeyFetcher{ + Dialer: dialer, + } + drkeyStore = drkey.NewClientStore(ia, drkeyDB, drkeyFetcher) + + drkeyCleaner := periodic.Start(drkeystorage.NewStoreCleaner(drkeyStore), + time.Hour, 10*time.Minute) + defer drkeyCleaner.Stop() + } + listen := daemon.APIAddress(globalCfg.SD.Address) listener, err := net.Listen("tcp", listen) if err != nil { @@ -189,6 +211,7 @@ func realMain(ctx context.Context) error { Engine: engine, RevCache: revCache, TopoProvider: itopo.Provider(), + DRKeyStore: drkeyStore, })) promgrpc.Register(server) diff --git a/go/lib/ctrl/drkey/BUILD.bazel b/go/lib/ctrl/drkey/BUILD.bazel new file mode 100644 index 0000000000..cc9fda4327 --- /dev/null +++ b/go/lib/ctrl/drkey/BUILD.bazel @@ -0,0 +1,35 @@ +load("//lint:go.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "lvl1_req.go", + "lvl2_req.go", + ], + importpath = "github.com/scionproto/scion/go/lib/ctrl/drkey", + visibility = ["//visibility:public"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/scrypto/cppki:go_default_library", + "//go/lib/serrors:go_default_library", + "//go/pkg/proto/drkey:go_default_library", + "@com_github_golang_protobuf//ptypes:go_default_library_gen", + ], +) + +go_test( + name = "go_default_test", + srcs = ["protobuf_test.go"], + deps = [ + ":go_default_library", + "//go/lib/addr:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/util:go_default_library", + "//go/lib/xtest:go_default_library", + "//go/pkg/proto/drkey:go_default_library", + "@com_github_golang_protobuf//ptypes:go_default_library_gen", + "@com_github_stretchr_testify//assert:go_default_library", + "@com_github_stretchr_testify//require:go_default_library", + ], +) diff --git a/go/lib/ctrl/drkey/lvl1_req.go b/go/lib/ctrl/drkey/lvl1_req.go new file mode 100644 index 0000000000..fb627774c3 --- /dev/null +++ b/go/lib/ctrl/drkey/lvl1_req.go @@ -0,0 +1,124 @@ +// Copyright 2020 ETH Zurich +// +// 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 drkey + +import ( + "time" + + "github.com/golang/protobuf/ptypes" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/scrypto/cppki" + "github.com/scionproto/scion/go/lib/serrors" + dkpb "github.com/scionproto/scion/go/pkg/proto/drkey" +) + +// Lvl1Req represents a level 1 request between CS. +type Lvl1Req struct { + ValTime time.Time + Timestamp time.Time +} + +// NewLvl1Req returns a fresh Lvl1Req +func NewLvl1Req(valTime time.Time) Lvl1Req { + return Lvl1Req{ + ValTime: valTime, + Timestamp: time.Now(), + } +} + +// Lvl1reqToProtoRequest parses the Lvl1Req to a protobuf Lvl1Request. +func Lvl1reqToProtoRequest(req Lvl1Req) (*dkpb.DRKeyLvl1Request, error) { + valTime, err := ptypes.TimestampProto(req.ValTime) + if err != nil { + return nil, serrors.WrapStr("invalid valTime from request", err) + } + timestamp, err := ptypes.TimestampProto(req.Timestamp) + if err != nil { + return nil, serrors.WrapStr("invalid timeStamp from request", err) + } + return &dkpb.DRKeyLvl1Request{ + ValTime: valTime, + Timestamp: timestamp, + }, nil +} + +// GetLvl1KeyFromReply extracts the level 1 drkey from the reply. +func GetLvl1KeyFromReply(srcIA, dstIA addr.IA, rep *dkpb.DRKeyLvl1Response) (drkey.Lvl1Key, error) { + + epochBegin, err := ptypes.Timestamp(rep.EpochBegin) + if err != nil { + return drkey.Lvl1Key{}, serrors.WrapStr("invalid EpochBegin from response", err) + } + epochEnd, err := ptypes.Timestamp(rep.EpochEnd) + if err != nil { + return drkey.Lvl1Key{}, serrors.WrapStr("invalid EpochEnd from response", err) + } + epoch := drkey.Epoch{ + Validity: cppki.Validity{ + NotBefore: epochBegin, + NotAfter: epochEnd, + }, + } + return drkey.Lvl1Key{ + Lvl1Meta: drkey.Lvl1Meta{ + SrcIA: srcIA, + DstIA: dstIA, + Epoch: epoch, + }, + Key: drkey.DRKey(rep.Drkey), + }, nil +} + +// KeyToLvl1Resp builds a Lvl1Resp provided a given Lvl1Key. +func KeyToLvl1Resp(drkey drkey.Lvl1Key) (*dkpb.DRKeyLvl1Response, error) { + epochBegin, err := ptypes.TimestampProto(drkey.Epoch.NotBefore) + if err != nil { + return nil, serrors.WrapStr("invalid EpochBegin from key", err) + } + epochEnd, err := ptypes.TimestampProto(drkey.Epoch.NotAfter) + if err != nil { + return nil, serrors.WrapStr("invalid EpochEnd from key", err) + } + now, err := ptypes.TimestampProto(time.Now()) + if err != nil { + return nil, serrors.WrapStr("invalid conversion to timestamp", err) + } + + return &dkpb.DRKeyLvl1Response{ + EpochBegin: epochBegin, + EpochEnd: epochEnd, + Drkey: []byte(drkey.Key), + Timestamp: now, + }, nil +} + +// RequestToLvl1Req parses the protobuf Lvl1Request to a Lvl1Req. +func RequestToLvl1Req(req *dkpb.DRKeyLvl1Request) (Lvl1Req, error) { + valTime, err := ptypes.Timestamp(req.ValTime) + if err != nil { + return Lvl1Req{}, serrors.WrapStr("invalid valTime from pb req", err) + } + timestamp, err := ptypes.Timestamp(req.Timestamp) + if err != nil { + return Lvl1Req{}, serrors.WrapStr("invalid timeStamp from pb req", err) + } + + return Lvl1Req{ + ValTime: valTime, + Timestamp: timestamp, + }, nil +} diff --git a/go/lib/ctrl/drkey/lvl2_req.go b/go/lib/ctrl/drkey/lvl2_req.go new file mode 100644 index 0000000000..95f5a7041e --- /dev/null +++ b/go/lib/ctrl/drkey/lvl2_req.go @@ -0,0 +1,192 @@ +// Copyright 2020 ETH Zurich +// +// 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 drkey + +import ( + "time" + + "github.com/golang/protobuf/ptypes" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/scrypto/cppki" + "github.com/scionproto/scion/go/lib/serrors" + dkpb "github.com/scionproto/scion/go/pkg/proto/drkey" +) + +// Host represents a host part of a level 2 drkey. +type Host struct { + Type addr.HostAddrType // uint8 + Host []byte +} + +// NewHost returns a new Host from an addr.HostAddr. +func NewHost(host addr.HostAddr) Host { + if host == nil { + host = addr.HostNone{} + } + return Host{ + Type: host.Type(), + Host: host.Pack(), + } +} + +// ToHostAddr returns the host as a addr.HostAddr. +func (h *Host) ToHostAddr() addr.HostAddr { + host, err := addr.HostFromRaw(h.Host, h.Type) + if err != nil { + panic("Could not convert addr.HostAddr to drkey.Host") + } + return host +} + +// Lvl2Req represents a level 2 key request from an endhost to a CS. +type Lvl2Req struct { + Protocol string + ReqType uint32 + ValTime time.Time + SrcIA addr.IA + DstIA addr.IA + SrcHost Host + DstHost Host + Misc []byte +} + +// NewLvl2ReqFromMeta constructs a level 2 request from a standard level 2 meta info. +func NewLvl2ReqFromMeta(meta drkey.Lvl2Meta, valTime time.Time) Lvl2Req { + return Lvl2Req{ + ReqType: uint32(meta.KeyType), + Protocol: meta.Protocol, + ValTime: valTime, + SrcIA: meta.SrcIA, + DstIA: meta.DstIA, + SrcHost: NewHost(meta.SrcHost), + DstHost: NewHost(meta.DstHost), + } +} + +// ToMeta returns metadata of the requested Lvl2 DRKey. +func (c Lvl2Req) ToMeta() drkey.Lvl2Meta { + return drkey.Lvl2Meta{ + KeyType: drkey.Lvl2KeyType(c.ReqType), + Protocol: c.Protocol, + SrcIA: c.SrcIA, + DstIA: c.DstIA, + SrcHost: c.SrcHost.ToHostAddr(), + DstHost: c.DstHost.ToHostAddr(), + } +} + +// RequestToLvl2Req parses the protobuf Lvl2Request to a Lvl2Req. +func RequestToLvl2Req(req *dkpb.DRKeyLvl2Request) (Lvl2Req, error) { + valTime, err := ptypes.Timestamp(req.ValTime) + if err != nil { + return Lvl2Req{}, serrors.WrapStr("invalid valTime from pb request", err) + } + + return Lvl2Req{ + Protocol: req.Protocol, + ReqType: req.ReqType, + ValTime: valTime, + SrcIA: addr.IAInt(req.SrcIa).IA(), + DstIA: addr.IAInt(req.DstIa).IA(), + SrcHost: Host{ + Type: addr.HostAddrType(req.SrcHost.Type), + Host: req.SrcHost.Host, + }, + DstHost: Host{ + Type: addr.HostAddrType(req.DstHost.Type), + Host: req.DstHost.Host, + }, + Misc: req.Misc, + }, nil +} + +// KeyToLvl2Resp builds a Lvl2Resp provided a given Lvl2Key. +func KeyToLvl2Resp(drkey drkey.Lvl2Key) (*dkpb.DRKeyLvl2Response, error) { + epochBegin, err := ptypes.TimestampProto(drkey.Epoch.NotBefore) + if err != nil { + return nil, serrors.WrapStr("invalid EpochBegin from key", err) + } + epochEnd, err := ptypes.TimestampProto(drkey.Epoch.NotAfter) + if err != nil { + return nil, serrors.WrapStr("invalid EpochEnd from key", err) + } + now, err := ptypes.TimestampProto(time.Now()) + if err != nil { + return nil, serrors.WrapStr("invalid conversion to timestamp", err) + } + + return &dkpb.DRKeyLvl2Response{ + EpochBegin: epochBegin, + EpochEnd: epochEnd, + Drkey: []byte(drkey.Key), + Timestamp: now, + }, nil +} + +// Lvl2reqToProtoRequest parses the Lvl2Req to a protobuf Lvl2Request. +func Lvl2reqToProtoRequest(req Lvl2Req) (*dkpb.DRKeyLvl2Request, error) { + valTime, err := ptypes.TimestampProto(req.ValTime) + if err != nil { + return nil, serrors.WrapStr("invalid valTime from request", err) + } + return &dkpb.DRKeyLvl2Request{ + Protocol: req.Protocol, + ReqType: req.ReqType, + DstIa: uint64(req.DstIA.IAInt()), + SrcIa: uint64(req.SrcIA.IAInt()), + ValTime: valTime, + SrcHost: &dkpb.DRKeyLvl2Request_DRKeyHost{ + Type: uint32(req.SrcHost.Type), + Host: req.SrcHost.Host, + }, + DstHost: &dkpb.DRKeyLvl2Request_DRKeyHost{ + Type: uint32(req.DstHost.Type), + Host: req.DstHost.Host, + }, + }, nil +} + +// GetLvl2KeyFromReply extracts the level 2 drkey from the reply. +func GetLvl2KeyFromReply(rep *dkpb.DRKeyLvl2Response, meta drkey.Lvl2Meta) (drkey.Lvl2Key, error) { + + epochBegin, err := ptypes.Timestamp(rep.EpochBegin) + if err != nil { + return drkey.Lvl2Key{}, serrors.WrapStr("invalid EpochBegin from response", err) + } + epochEnd, err := ptypes.Timestamp(rep.EpochEnd) + if err != nil { + return drkey.Lvl2Key{}, serrors.WrapStr("invalid EpochEnd from response", err) + } + epoch := drkey.Epoch{ + Validity: cppki.Validity{ + NotBefore: epochBegin, + NotAfter: epochEnd, + }, + } + return drkey.Lvl2Key{ + Lvl2Meta: drkey.Lvl2Meta{ + KeyType: meta.KeyType, + Protocol: meta.Protocol, + SrcIA: meta.SrcIA, + DstIA: meta.DstIA, + SrcHost: meta.SrcHost, + DstHost: meta.DstHost, + Epoch: epoch, + }, + Key: drkey.DRKey(rep.Drkey), + }, nil +} diff --git a/go/lib/ctrl/drkey/protobuf_test.go b/go/lib/ctrl/drkey/protobuf_test.go new file mode 100644 index 0000000000..98a55ca7d0 --- /dev/null +++ b/go/lib/ctrl/drkey/protobuf_test.go @@ -0,0 +1,217 @@ +// Copyright 2020 ETH Zurich +// +// 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 drkey_test + +import ( + "testing" + "time" + + "github.com/golang/protobuf/ptypes" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/scionproto/scion/go/lib/addr" + ctrl "github.com/scionproto/scion/go/lib/ctrl/drkey" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/util" + "github.com/scionproto/scion/go/lib/xtest" + dkpb "github.com/scionproto/scion/go/pkg/proto/drkey" +) + +func TestLvl1reqToProtoRequest(t *testing.T) { + now := time.Now().UTC() + + valTime, err := ptypes.TimestampProto(now) + require.NoError(t, err) + timestamp, err := ptypes.TimestampProto(now) + require.NoError(t, err) + + pbReq := &dkpb.DRKeyLvl1Request{ + ValTime: valTime, + Timestamp: timestamp, + } + + lvl1Req := ctrl.Lvl1Req{ + ValTime: now, + Timestamp: now, + } + + req, err := ctrl.Lvl1reqToProtoRequest(lvl1Req) + require.NoError(t, err) + assert.Equal(t, pbReq, req) +} + +func TestRequestToLvl1Req(t *testing.T) { + now := time.Now().UTC() + + valTime, err := ptypes.TimestampProto(now) + require.NoError(t, err) + timestamp, err := ptypes.TimestampProto(now) + require.NoError(t, err) + + req := &dkpb.DRKeyLvl1Request{ + ValTime: valTime, + Timestamp: timestamp, + } + + lvl1Req, err := ctrl.RequestToLvl1Req(req) + require.NoError(t, err) + assert.Equal(t, now, lvl1Req.ValTime) + assert.Equal(t, now, lvl1Req.Timestamp) +} + +func TestKeyToLvl1Resp(t *testing.T) { + epochBegin, err := ptypes.TimestampProto(util.SecsToTime(0)) + require.NoError(t, err) + epochEnd, err := ptypes.TimestampProto(util.SecsToTime(1)) + require.NoError(t, err) + dstIA := xtest.MustParseIA("1-ff00:0:110") + srcIA := xtest.MustParseIA("1-ff00:0:111") + k := xtest.MustParseHexString("c584cad32613547c64823c756651b6f5") // just a level 1 key + + lvl1Key := drkey.Lvl1Key{ + Lvl1Meta: drkey.Lvl1Meta{ + Epoch: drkey.NewEpoch(0, 1), + SrcIA: srcIA, + DstIA: dstIA, + }, + Key: k, + } + + targetResp := &dkpb.DRKeyLvl1Response{ + EpochBegin: epochBegin, + EpochEnd: epochEnd, + Drkey: k, + } + + pbResp, err := ctrl.KeyToLvl1Resp(lvl1Key) + targetResp.Timestamp = pbResp.Timestamp + require.NoError(t, err) + assert.Equal(t, targetResp, pbResp) + +} + +func TestGetLvl1KeyFromReply(t *testing.T) { + epochBegin, err := ptypes.TimestampProto(util.SecsToTime(0)) + require.NoError(t, err) + epochEnd, err := ptypes.TimestampProto(util.SecsToTime(1)) + require.NoError(t, err) + dstIA := xtest.MustParseIA("1-ff00:0:110") + srcIA := xtest.MustParseIA("1-ff00:0:111") + k := xtest.MustParseHexString("c584cad32613547c64823c756651b6f5") // just a level 1 key + + resp := &dkpb.DRKeyLvl1Response{ + EpochBegin: epochBegin, + EpochEnd: epochEnd, + Drkey: k, + } + + targetLvl1Key := drkey.Lvl1Key{ + Lvl1Meta: drkey.Lvl1Meta{ + Epoch: drkey.NewEpoch(0, 1), + SrcIA: srcIA, + DstIA: dstIA, + }, + Key: k, + } + + lvl1Key, err := ctrl.GetLvl1KeyFromReply(srcIA, dstIA, resp) + require.NoError(t, err) + assert.Equal(t, targetLvl1Key, lvl1Key) + +} + +func TestRequestToLvl2Req(t *testing.T) { + now := time.Now().UTC() + valTime, err := ptypes.TimestampProto(now) + require.NoError(t, err) + dstIA := xtest.MustParseIA("1-ff00:0:110") + srcIA := xtest.MustParseIA("1-ff00:0:111") + reqType := drkey.Host2Host + hostType := addr.HostTypeSVC + hostAddr := addr.SvcCS + + req := &dkpb.DRKeyLvl2Request{ + Protocol: "piskes", + ReqType: uint32(reqType), + DstIa: uint64(dstIA.IAInt()), + SrcIa: uint64(srcIA.IAInt()), + ValTime: valTime, + SrcHost: &dkpb.DRKeyLvl2Request_DRKeyHost{ + Type: uint32(hostType), + Host: hostAddr.Pack(), + }, + DstHost: &dkpb.DRKeyLvl2Request_DRKeyHost{ + Type: uint32(hostType), + Host: hostAddr.Pack(), + }, + } + + targetLvl2Req := ctrl.Lvl2Req{ + Protocol: "piskes", + ReqType: uint32(reqType), + ValTime: now, + SrcIA: srcIA, + DstIA: dstIA, + SrcHost: ctrl.Host{ + Type: hostType, + Host: hostAddr.Pack(), + }, + DstHost: ctrl.Host{ + Type: hostType, + Host: hostAddr.Pack(), + }, + } + + lvl2Req, err := ctrl.RequestToLvl2Req(req) + require.NoError(t, err) + assert.Equal(t, targetLvl2Req, lvl2Req) + +} + +func TestKeyToLvl2Resp(t *testing.T) { + srcIA := xtest.MustParseIA("1-ff00:0:1") + dstIA := xtest.MustParseIA("1-ff00:0:2") + key := xtest.MustParseHexString("47bfbb7d94706dc9e79825e5a837b006") + meta := drkey.Lvl2Meta{ + KeyType: drkey.AS2AS, + Protocol: "scmp", + Epoch: drkey.NewEpoch(0, 1), + SrcIA: srcIA, + DstIA: dstIA, + SrcHost: addr.HostNone{}, + DstHost: addr.HostNone{}, + } + lvl2Key := drkey.Lvl2Key{ + Lvl2Meta: meta, + Key: key, + } + + epochBegin, err := ptypes.TimestampProto(lvl2Key.Epoch.NotBefore) + require.NoError(t, err) + epochEnd, err := ptypes.TimestampProto(lvl2Key.Epoch.NotAfter) + require.NoError(t, err) + + targetResp := &dkpb.DRKeyLvl2Response{ + EpochBegin: epochBegin, + EpochEnd: epochEnd, + Drkey: []byte(lvl2Key.Key), + } + + resp, err := ctrl.KeyToLvl2Resp(lvl2Key) + require.NoError(t, err) + targetResp.Timestamp = resp.Timestamp + assert.Equal(t, targetResp, resp) +} diff --git a/go/lib/daemon/BUILD.bazel b/go/lib/daemon/BUILD.bazel index 432282f19c..05d06474c6 100644 --- a/go/lib/daemon/BUILD.bazel +++ b/go/lib/daemon/BUILD.bazel @@ -13,8 +13,10 @@ go_library( deps = [ "//go/lib/addr:go_default_library", "//go/lib/common:go_default_library", + "//go/lib/ctrl/drkey:go_default_library", "//go/lib/ctrl/path_mgmt:go_default_library", "//go/lib/daemon/internal/metrics:go_default_library", + "//go/lib/drkey:go_default_library", "//go/lib/log:go_default_library", "//go/lib/metrics:go_default_library", "//go/lib/prom:go_default_library", diff --git a/go/lib/daemon/daemon.go b/go/lib/daemon/daemon.go index 086e341f1a..0e440f54f4 100644 --- a/go/lib/daemon/daemon.go +++ b/go/lib/daemon/daemon.go @@ -19,11 +19,13 @@ package daemon import ( "context" "net" + "time" "github.com/scionproto/scion/go/lib/addr" "github.com/scionproto/scion/go/lib/common" "github.com/scionproto/scion/go/lib/ctrl/path_mgmt" "github.com/scionproto/scion/go/lib/daemon/internal/metrics" + "github.com/scionproto/scion/go/lib/drkey" libmetrics "github.com/scionproto/scion/go/lib/metrics" "github.com/scionproto/scion/go/lib/serrors" "github.com/scionproto/scion/go/lib/snet" @@ -80,6 +82,9 @@ type Connector interface { SVCInfo(ctx context.Context, svcTypes []addr.HostSVC) (map[addr.HostSVC]string, error) // RevNotification sends a RevocationInfo message to the daemon. RevNotification(ctx context.Context, revInfo *path_mgmt.RevInfo) error + // DRKeyGetLvl2Key sends a DRKey Lvl2Key request to SCIOND + DRKeyGetLvl2Key(ctx context.Context, meta drkey.Lvl2Meta, + valTime time.Time) (drkey.Lvl2Key, error) // Close shuts down the connection to the daemon. Close(ctx context.Context) error } diff --git a/go/lib/daemon/fake/BUILD.bazel b/go/lib/daemon/fake/BUILD.bazel index aaa9b72c86..1a26fb35f2 100644 --- a/go/lib/daemon/fake/BUILD.bazel +++ b/go/lib/daemon/fake/BUILD.bazel @@ -10,6 +10,7 @@ go_library( "//go/lib/common:go_default_library", "//go/lib/ctrl/path_mgmt:go_default_library", "//go/lib/daemon:go_default_library", + "//go/lib/drkey:go_default_library", "//go/lib/serrors:go_default_library", "//go/lib/snet:go_default_library", "//go/lib/snet/path:go_default_library", diff --git a/go/lib/daemon/fake/fake.go b/go/lib/daemon/fake/fake.go index ee4f98b6ff..d766a8e4b2 100644 --- a/go/lib/daemon/fake/fake.go +++ b/go/lib/daemon/fake/fake.go @@ -25,6 +25,7 @@ import ( "github.com/scionproto/scion/go/lib/common" "github.com/scionproto/scion/go/lib/ctrl/path_mgmt" "github.com/scionproto/scion/go/lib/daemon" + "github.com/scionproto/scion/go/lib/drkey" "github.com/scionproto/scion/go/lib/serrors" "github.com/scionproto/scion/go/lib/snet" snetpath "github.com/scionproto/scion/go/lib/snet/path" @@ -185,6 +186,11 @@ func (c connector) RevNotification(ctx context.Context, panic("not implemented") } +func (c connector) DRKeyGetLvl2Key(ctx context.Context, meta drkey.Lvl2Meta, + valTime time.Time) (drkey.Lvl2Key, error) { + panic("not implemented") +} + func (c connector) Close(ctx context.Context) error { return nil } diff --git a/go/lib/daemon/grpc.go b/go/lib/daemon/grpc.go index 561fa8f94e..f400e5f847 100644 --- a/go/lib/daemon/grpc.go +++ b/go/lib/daemon/grpc.go @@ -23,7 +23,9 @@ import ( "github.com/scionproto/scion/go/lib/addr" "github.com/scionproto/scion/go/lib/common" + dkctrl "github.com/scionproto/scion/go/lib/ctrl/drkey" "github.com/scionproto/scion/go/lib/ctrl/path_mgmt" + "github.com/scionproto/scion/go/lib/drkey" "github.com/scionproto/scion/go/lib/serrors" "github.com/scionproto/scion/go/lib/slayers/path/scion" "github.com/scionproto/scion/go/lib/snet" @@ -157,6 +159,29 @@ func (c grpcConn) RevNotification(ctx context.Context, revInfo *path_mgmt.RevInf } +func (c grpcConn) DRKeyGetLvl2Key(ctx context.Context, meta drkey.Lvl2Meta, + valTime time.Time) (drkey.Lvl2Key, error) { + + client := sdpb.NewDaemonServiceClient(c.conn) + + lvl2Req := dkctrl.NewLvl2ReqFromMeta(meta, valTime) + pbLvl2Req, err := lvl2reqToProtoRequest(lvl2Req) + if err != nil { + return drkey.Lvl2Key{}, err + } + + reply, err := client.DRKeyLvl2(ctx, pbLvl2Req) + if err != nil { + return drkey.Lvl2Key{}, err + } + + lvl2Key, err := getLvl2KeyFromReply(reply, meta) + if err != nil { + return drkey.Lvl2Key{}, err + } + return lvl2Key, nil +} + func (c grpcConn) Close(_ context.Context) error { return c.conn.Close() } @@ -253,3 +278,18 @@ func topoServiceTypeToSVCAddr(st topology.ServiceType) addr.HostSVC { return addr.SvcNone } } + +func lvl2reqToProtoRequest(req dkctrl.Lvl2Req) (*sdpb.DRKeyLvl2Request, error) { + baseReq, err := dkctrl.Lvl2reqToProtoRequest(req) + if err != nil { + return nil, err + } + return &sdpb.DRKeyLvl2Request{ + BaseReq: baseReq, + }, nil +} + +// getLvl2KeyFromReply decrypts and extracts the level 1 drkey from the reply. +func getLvl2KeyFromReply(rep *sdpb.DRKeyLvl2Response, meta drkey.Lvl2Meta) (drkey.Lvl2Key, error) { + return dkctrl.GetLvl2KeyFromReply(rep.BaseRep, meta) +} diff --git a/go/lib/daemon/mock_daemon/BUILD.bazel b/go/lib/daemon/mock_daemon/BUILD.bazel index d36ac119dd..5cdfcad21c 100644 --- a/go/lib/daemon/mock_daemon/BUILD.bazel +++ b/go/lib/daemon/mock_daemon/BUILD.bazel @@ -19,6 +19,7 @@ go_library( "//go/lib/common:go_default_library", "//go/lib/ctrl/path_mgmt:go_default_library", "//go/lib/daemon:go_default_library", + "//go/lib/drkey:go_default_library", "//go/lib/snet:go_default_library", "@com_github_golang_mock//gomock:go_default_library", ], diff --git a/go/lib/daemon/mock_daemon/mock.go b/go/lib/daemon/mock_daemon/mock.go index 6b4a7a711a..27954169ab 100644 --- a/go/lib/daemon/mock_daemon/mock.go +++ b/go/lib/daemon/mock_daemon/mock.go @@ -8,12 +8,14 @@ import ( context "context" net "net" reflect "reflect" + time "time" gomock "github.com/golang/mock/gomock" addr "github.com/scionproto/scion/go/lib/addr" common "github.com/scionproto/scion/go/lib/common" path_mgmt "github.com/scionproto/scion/go/lib/ctrl/path_mgmt" daemon "github.com/scionproto/scion/go/lib/daemon" + drkey "github.com/scionproto/scion/go/lib/drkey" snet "github.com/scionproto/scion/go/lib/snet" ) @@ -69,6 +71,21 @@ func (mr *MockConnectorMockRecorder) Close(arg0 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockConnector)(nil).Close), arg0) } +// DRKeyGetLvl2Key mocks base method. +func (m *MockConnector) DRKeyGetLvl2Key(arg0 context.Context, arg1 drkey.Lvl2Meta, arg2 time.Time) (drkey.Lvl2Key, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DRKeyGetLvl2Key", arg0, arg1, arg2) + ret0, _ := ret[0].(drkey.Lvl2Key) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DRKeyGetLvl2Key indicates an expected call of DRKeyGetLvl2Key. +func (mr *MockConnectorMockRecorder) DRKeyGetLvl2Key(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DRKeyGetLvl2Key", reflect.TypeOf((*MockConnector)(nil).DRKeyGetLvl2Key), arg0, arg1, arg2) +} + // IFInfo mocks base method. func (m *MockConnector) IFInfo(arg0 context.Context, arg1 []common.IFIDType) (map[common.IFIDType]*net.UDPAddr, error) { m.ctrl.T.Helper() diff --git a/go/lib/drkey/BUILD.bazel b/go/lib/drkey/BUILD.bazel new file mode 100644 index 0000000000..7b691c61a5 --- /dev/null +++ b/go/lib/drkey/BUILD.bazel @@ -0,0 +1,31 @@ +load("//lint:go.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "db.go", + "drkey.go", + "epoch.go", + "level1.go", + "level2.go", + "secret_value.go", + ], + importpath = "github.com/scionproto/scion/go/lib/drkey", + visibility = ["//visibility:public"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/infra/modules/db:go_default_library", + "//go/lib/scrypto/cppki:go_default_library", + "//go/lib/util:go_default_library", + "@org_golang_x_crypto//pbkdf2:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["secret_value_test.go"], + embed = [":go_default_library"], + deps = [ + "//go/lib/xtest:go_default_library", + ], +) diff --git a/go/lib/drkey/db.go b/go/lib/drkey/db.go new file mode 100644 index 0000000000..ecb17e477c --- /dev/null +++ b/go/lib/drkey/db.go @@ -0,0 +1,47 @@ +// Copyright 2019 ETH Zurich +// +// 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 drkey + +import ( + "context" + "io" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/infra/modules/db" +) + +// BaseDB defines basic interface +type BaseDB interface { + io.Closer + db.LimitSetter +} + +// Lvl1DB is the drkey database interface for level 1. +type Lvl1DB interface { + BaseDB + GetLvl1Key(ctx context.Context, key Lvl1Meta, valTime uint32) (Lvl1Key, error) + InsertLvl1Key(ctx context.Context, key Lvl1Key) error + RemoveOutdatedLvl1Keys(ctx context.Context, cutoff uint32) (int64, error) + GetLvl1SrcASes(ctx context.Context) ([]addr.IA, error) + GetValidLvl1SrcASes(ctx context.Context, valTime uint32) ([]addr.IA, error) +} + +// Lvl2DB is the drkey database interface for level 2. +type Lvl2DB interface { + BaseDB + GetLvl2Key(ctx context.Context, key Lvl2Meta, valTime uint32) (Lvl2Key, error) + InsertLvl2Key(ctx context.Context, key Lvl2Key) error + RemoveOutdatedLvl2Keys(ctx context.Context, cutoff uint32) (int64, error) +} diff --git a/go/lib/drkey/drkey.go b/go/lib/drkey/drkey.go new file mode 100644 index 0000000000..b74cc44d98 --- /dev/null +++ b/go/lib/drkey/drkey.go @@ -0,0 +1,29 @@ +// Copyright 2019 ETH Zurich +// +// 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 drkey + +import "bytes" + +// DRKey represents a raw binary key +type DRKey []byte + +func (k DRKey) String() string { + return "[redacted key]" +} + +// Equal returns true if both DRKeys are identical +func (k DRKey) Equal(other DRKey) bool { + return bytes.Equal(k, other) +} diff --git a/go/lib/drkey/drkeydbsqlite/BUILD.bazel b/go/lib/drkey/drkeydbsqlite/BUILD.bazel new file mode 100644 index 0000000000..d4343ad534 --- /dev/null +++ b/go/lib/drkey/drkeydbsqlite/BUILD.bazel @@ -0,0 +1,33 @@ +load("//lint:go.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "base_db.go", + "lvl1db.go", + "lvl2db.go", + ], + importpath = "github.com/scionproto/scion/go/lib/drkey/drkeydbsqlite", + visibility = ["//visibility:public"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/infra/modules/db:go_default_library", + "//go/lib/serrors:go_default_library", + "@com_github_mattn_go_sqlite3//:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["db_test.go"], + embed = [":go_default_library"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/drkey/protocol:go_default_library", + "//go/lib/scrypto/cppki:go_default_library", + "//go/lib/util:go_default_library", + "@com_github_stretchr_testify//require:go_default_library", + ], +) diff --git a/go/lib/drkey/drkeydbsqlite/base_db.go b/go/lib/drkey/drkeydbsqlite/base_db.go new file mode 100644 index 0000000000..fc391569a6 --- /dev/null +++ b/go/lib/drkey/drkeydbsqlite/base_db.go @@ -0,0 +1,85 @@ +// Copyright 2019 ETH Zurich +// +// 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 drkeydbsqlite + +import ( + "database/sql" + + _ "github.com/mattn/go-sqlite3" + + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/infra/modules/db" + "github.com/scionproto/scion/go/lib/serrors" +) + +const ( + unableToPrepareStmt = "Unable to prepare stmt" + unableToExecuteStmt = "Unable to execute stmt" +) + +var _ drkey.BaseDB = (*dbBaseBackend)(nil) + +// dbBaseBackend is the common part of all level backends. +type dbBaseBackend struct { + db *sql.DB +} + +// newBaseBackend builds the base backend common for all level backends. +func newBaseBackend(path, schema string, version int) (*dbBaseBackend, error) { + db, err := db.NewSqlite(path, schema, version) + if err != nil { + return nil, err + } + return &dbBaseBackend{ + db: db, + }, nil +} + +type preparedStmts map[string]**sql.Stmt + +// prepareAll will create the prepared statements or return an error as soon as one fails. +func (b *dbBaseBackend) prepareAll(stmts preparedStmts) error { + var err error + // On future errors, close the sql database before exiting + defer func() { + if err != nil { + b.Close() + } + }() + for str, stmt := range stmts { + // FIXME(matzf): the sqlclosecheck linter does not like this pattern. + // Perhapse this should be refactored to just avoid the prepared statements; + // this does not appear to be goroutine safe anyway. + if *stmt, err = b.db.Prepare(str); err != nil { // nolint:sqlclosecheck + return serrors.WrapStr(unableToPrepareStmt, err) + } + } + return nil +} + +// Close closes the database connection. +func (b *dbBaseBackend) Close() error { + return b.db.Close() +} + +// SetMaxOpenConns sets the maximum number of open connections. +func (b *dbBaseBackend) SetMaxOpenConns(maxOpenConns int) { + b.db.SetMaxOpenConns(maxOpenConns) +} + +// SetMaxIdleConns sets the maximum number of idle connections. +func (b *dbBaseBackend) SetMaxIdleConns(maxIdleConns int) { + b.db.SetMaxIdleConns(maxIdleConns) +} diff --git a/go/lib/drkey/drkeydbsqlite/db_test.go b/go/lib/drkey/drkeydbsqlite/db_test.go new file mode 100644 index 0000000000..eab15e8260 --- /dev/null +++ b/go/lib/drkey/drkeydbsqlite/db_test.go @@ -0,0 +1,236 @@ +// Copyright 2019 ETH Zurich +// +// 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 drkeydbsqlite + +import ( + "context" + "io/ioutil" + "net" + "os" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/drkey/protocol" + "github.com/scionproto/scion/go/lib/scrypto/cppki" + "github.com/scionproto/scion/go/lib/util" +) + +const ( + timeOffset = 10 * 60 // 10 minutes +) + +var ( + asMasterPassword = []byte("0123456789012345") + rawSrcIA = []byte{0xF0, 0x11, 0xF2, 0x33, 0x44, 0x55, 0x66, 0x77} + rawDstIA = []byte{0xF0, 0x11, 0xF2, 0x33, 0x44, 0x55, 0x66, 0x88} + SrcHostIP = net.IPv4(192, 168, 1, 37) + DstHostIP = net.IPv4(192, 168, 1, 38) +) + +func TestDRKeyLvl1(t *testing.T) { + ctx, cancelF := context.WithTimeout(context.Background(), time.Second) + defer cancelF() + db, cleanF := newLvl1Database(t) + defer cleanF() + + epoch := drkey.Epoch{ + Validity: cppki.Validity{ + NotBefore: time.Now(), + NotAfter: time.Now().Add(timeOffset * time.Second), + }, + } + sv, err := drkey.DeriveSV(drkey.SVMeta{Epoch: epoch}, asMasterPassword) + require.NoError(t, err) + + drkeyLvl1, err := protocol.DeriveLvl1(drkey.Lvl1Meta{ + Epoch: epoch, + SrcIA: addr.IAFromRaw(rawSrcIA), + DstIA: addr.IAFromRaw(rawDstIA)}, sv) + require.NoError(t, err) + + err = db.InsertLvl1Key(ctx, drkeyLvl1) + require.NoError(t, err) + // same key again. It should be okay. + err = db.InsertLvl1Key(ctx, drkeyLvl1) + require.NoError(t, err) + + newKey, err := db.GetLvl1Key(ctx, drkeyLvl1.Lvl1Meta, util.TimeToSecs(time.Now())) + require.NoError(t, err) + require.Equal(t, drkeyLvl1.Key, newKey.Key) + + rows, err := db.RemoveOutdatedLvl1Keys(ctx, + util.TimeToSecs(time.Now().Add(-timeOffset*time.Second))) + require.NoError(t, err) + require.EqualValues(t, 0, rows) + + rows, err = db.RemoveOutdatedLvl1Keys(ctx, + util.TimeToSecs(time.Now().Add(2*timeOffset*time.Second))) + require.NoError(t, err) + require.EqualValues(t, 1, rows) + +} + +func TestDRKeyLvl2(t *testing.T) { + ctx, cancelF := context.WithTimeout(context.Background(), time.Second) + defer cancelF() + + db, cleanF := newLvl2Database(t) + defer cleanF() + + srcIA := addr.IAFromRaw(rawSrcIA) + dstIA := addr.IAFromRaw(rawDstIA) + epoch := drkey.Epoch{ + Validity: cppki.Validity{ + NotBefore: time.Now(), + NotAfter: time.Now().Add(timeOffset * time.Second), + }, + } + sv, err := drkey.DeriveSV(drkey.SVMeta{Epoch: epoch}, asMasterPassword) + require.NoError(t, err) + drkeyLvl1, err := protocol.DeriveLvl1(drkey.Lvl1Meta{ + Epoch: epoch, + SrcIA: srcIA, + DstIA: dstIA, + }, sv) + require.NoError(t, err) + + standardImpl := protocol.Standard{} + drkeyLvl2, err := standardImpl.DeriveLvl2(drkey.Lvl2Meta{ + KeyType: drkey.Host2Host, + Protocol: "test", + Epoch: epoch, + SrcIA: srcIA, + DstIA: dstIA, + SrcHost: addr.HostFromIP(SrcHostIP), + DstHost: addr.HostFromIP(DstHostIP), + }, drkeyLvl1) + require.NoError(t, err) + + err = db.InsertLvl2Key(ctx, drkeyLvl2) + require.NoError(t, err) + err = db.InsertLvl2Key(ctx, drkeyLvl2) + require.NoError(t, err) + + newKey, err := db.GetLvl2Key(ctx, drkeyLvl2.Lvl2Meta, util.TimeToSecs(time.Now())) + require.NoError(t, err) + require.Equal(t, drkeyLvl2.Key, newKey.Key) + + rows, err := db.RemoveOutdatedLvl2Keys(ctx, + util.TimeToSecs(time.Now().Add(-timeOffset*time.Second))) + require.NoError(t, err) + require.EqualValues(t, 0, rows) + + rows, err = db.RemoveOutdatedLvl2Keys(ctx, + util.TimeToSecs(time.Now().Add(2*timeOffset*time.Second))) + require.NoError(t, err) + require.EqualValues(t, 1, rows) +} + +func TestGetMentionedASes(t *testing.T) { + ctx, cancelF := context.WithTimeout(context.Background(), time.Second) + defer cancelF() + + db, cleanF := newLvl1Database(t) + defer cleanF() + + pairsL1 := [][]interface{}{ + {"1-ff00:0:111", "1-ff00:0:112", 1}, + {"1-ff00:0:111", "1-ff00:0:110", 10}, + {"2-ff00:0:211", "1-ff00:0:113", 1}, + } + for _, p := range pairsL1 { + srcIA, _ := addr.IAFromString(p[0].(string)) + dstIA, _ := addr.IAFromString(p[1].(string)) + begin := time.Unix(0, 0) + epoch := drkey.Epoch{ + Validity: cppki.Validity{ + NotBefore: begin, + NotAfter: begin.Add(time.Duration(p[2].(int)) * time.Second), + }, + } + sv, err := drkey.DeriveSV(drkey.SVMeta{Epoch: epoch}, asMasterPassword) + require.NoError(t, err) + + key, err := protocol.DeriveLvl1(drkey.Lvl1Meta{ + Epoch: epoch, + SrcIA: srcIA, + DstIA: dstIA, + }, sv) + require.NoError(t, err) + + err = db.InsertLvl1Key(ctx, key) + require.NoError(t, err) + } + + list, err := db.GetLvl1SrcASes(ctx) + require.NoError(t, err) + + expected := []addr.IA{ + ia("1-ff00:0:111"), + ia("2-ff00:0:211"), + } + + require.Equal(t, expected, list) + + list, err = db.GetValidLvl1SrcASes(ctx, 3) + require.NoError(t, err) + + expected = []addr.IA{ + ia("1-ff00:0:111"), + } + require.Equal(t, expected, list) +} + +func ia(iaStr string) addr.IA { + ia, err := addr.IAFromString(iaStr) + if err != nil { + panic("Invalid value") + } + return ia +} + +func newLvl1Database(t *testing.T) (*Lvl1Backend, func()) { + file, err := ioutil.TempFile("", "db-test-") + require.NoError(t, err) + name := file.Name() + err = file.Close() + require.NoError(t, err) + db, err := NewLvl1Backend(name) + require.NoError(t, err) + + return db, func() { + db.Close() + os.Remove(name) + } +} + +func newLvl2Database(t *testing.T) (*Lvl2Backend, func()) { + file, err := ioutil.TempFile("", "db-test-") + require.NoError(t, err) + name := file.Name() + err = file.Close() + require.NoError(t, err) + db, err := NewLvl2Backend(name) + require.NoError(t, err) + + return db, func() { + db.Close() + os.Remove(name) + } +} diff --git a/go/lib/drkey/drkeydbsqlite/lvl1db.go b/go/lib/drkey/drkeydbsqlite/lvl1db.go new file mode 100644 index 0000000000..3f96dfcfd1 --- /dev/null +++ b/go/lib/drkey/drkeydbsqlite/lvl1db.go @@ -0,0 +1,208 @@ +// Copyright 2019 ETH Zurich +// +// 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 drkeydbsqlite + +import ( + "context" + "database/sql" + + _ "github.com/mattn/go-sqlite3" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/serrors" +) + +const ( + // Lvl1SchemaVersion is the version of the SQLite schema understood by this backend. + // Whenever changes to the schema are made, this version number should be increased + // to prevent data corruption between incompatible database schemas. + Lvl1SchemaVersion = 1 + // Lvl1Schema is the SQLite database layout. + Lvl1Schema = ` + CREATE TABLE DRKeyLvl1 ( + SrcIsdID INTEGER NOT NULL, + SrcAsID INTEGER NOT NULL, + DstIsdID INTEGER NOT NULL, + DstAsID INTEGER NOT NULL, + EpochBegin INTEGER NOT NULL, + EpochEnd INTEGER NOT NULL, + Key TEXT NOT NULL, + PRIMARY KEY (SrcIsdID, SrcAsID, DstIsdID, DstAsID, EpochBegin) + );` +) + +var _ drkey.Lvl1DB = (*Lvl1Backend)(nil) + +// Lvl1Backend implements a level 1 drkey DB with sqlite. +type Lvl1Backend struct { + dbBaseBackend + getLvl1SrcASesStmt *sql.Stmt + getValidLvl1SrcASesStmt *sql.Stmt + getLvl1KeyStmt *sql.Stmt + insertLvl1KeyStmt *sql.Stmt + removeOutdatedLvl1KeysStmt *sql.Stmt +} + +// NewLvl1Backend creates a database and prepares all statements. +func NewLvl1Backend(path string) (*Lvl1Backend, error) { + base, err := newBaseBackend(path, Lvl1Schema, Lvl1SchemaVersion) + if err != nil { + return nil, err + } + b := &Lvl1Backend{ + dbBaseBackend: *base, + } + stmts := preparedStmts{ + getLvl1SrcASes: &b.getLvl1SrcASesStmt, + getValidLvl1SrcASes: &b.getValidLvl1SrcASesStmt, + getLvl1Key: &b.getLvl1KeyStmt, + insertLvl1Key: &b.insertLvl1KeyStmt, + removeOutdatedLvl1Keys: &b.removeOutdatedLvl1KeysStmt, + } + if err := base.prepareAll(stmts); err != nil { + return nil, err + } + return b, nil +} + +const getLvl1SrcASes = ` +SELECT SrcIsdID as I, SrcASID as A FROM DRKeyLvl1 +GROUP BY I, A +` + +// GetLvl1SrcASes returns a list of distinct ASes seen in the SRC of a level 1 key +func (b *Lvl1Backend) GetLvl1SrcASes(ctx context.Context) ([]addr.IA, error) { + rows, err := b.getLvl1SrcASesStmt.QueryContext(ctx) + if err != nil { + if err != sql.ErrNoRows { + err = serrors.WrapStr(unableToExecuteStmt, err) + } + return nil, err + } + defer rows.Close() + ases := []addr.IA{} + for rows.Next() { + var I, A int + if err := rows.Scan(&I, &A); err != nil { + return nil, serrors.WrapStr("Cannot copy from SQL to memory", err) + } + ia := addr.IA{ + I: addr.ISD(I), + A: addr.AS(A), + } + ases = append(ases, ia) + } + if err := rows.Err(); err != nil { + return nil, err + } + return ases, nil +} + +const getValidLvl1SrcASes = ` +SELECT SrcIsdID as I, SrcASID as A FROM DRKeyLvl1 +WHERE EpochBegin <= ? AND ? < EpochEnd +GROUP BY I, A +` + +// GetValidLvl1SrcASes returns a list of distinct IAs that have a still valid level 1 key +// If the level 1 key is still valid according to valTime, its src IA will be in the list +func (b *Lvl1Backend) GetValidLvl1SrcASes(ctx context.Context, valTime uint32) ([]addr.IA, error) { + rows, err := b.getValidLvl1SrcASesStmt.QueryContext(ctx, valTime, valTime) + if err != nil { + if err != sql.ErrNoRows { + err = serrors.WrapStr(unableToExecuteStmt, err) + } + return nil, err + } + defer rows.Close() + ases := []addr.IA{} + for rows.Next() { + var I, A int + if err := rows.Scan(&I, &A); err != nil { + return nil, serrors.WrapStr("Cannot copy from SQL to memory", err) + } + ia := addr.IA{ + I: addr.ISD(I), + A: addr.AS(A), + } + ases = append(ases, ia) + } + if err := rows.Err(); err != nil { + return nil, err + } + return ases, nil +} + +const getLvl1Key = ` +SELECT EpochBegin, EpochEnd, Key FROM DRKeyLvl1 +WHERE SrcIsdID=? AND SrcAsID=? AND DstIsdID=? AND DstAsID=? +AND EpochBegin<=? AND ?= EpochEnd +` + +// RemoveOutdatedLvl1Keys removes all expired first level DRKeys. I.e. all the keys +// which expiration time is strictly smaller than the cutoff +func (b *Lvl1Backend) RemoveOutdatedLvl1Keys(ctx context.Context, cutoff uint32) (int64, error) { + res, err := b.removeOutdatedLvl1KeysStmt.ExecContext(ctx, cutoff) + if err != nil { + return 0, err + } + return res.RowsAffected() +} diff --git a/go/lib/drkey/drkeydbsqlite/lvl2db.go b/go/lib/drkey/drkeydbsqlite/lvl2db.go new file mode 100644 index 0000000000..0f755b01fc --- /dev/null +++ b/go/lib/drkey/drkeydbsqlite/lvl2db.go @@ -0,0 +1,151 @@ +// Copyright 2019 ETH Zurich +// +// 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 drkeydbsqlite + +import ( + "context" + "database/sql" + + _ "github.com/mattn/go-sqlite3" + + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/serrors" +) + +const ( + // Lvl2SchemaVersion is the version of the SQLite schema understood by this backend. + // Whenever changes to the schema are made, this version number should be increased + // to prevent data corruption between incompatible database schemas. + Lvl2SchemaVersion = 1 + // Lvl2Schema is the SQLite database layout. + Lvl2Schema = ` + CREATE TABLE DRKeyLvl2 ( + Protocol TEXT NOT NULL, + Type INTEGER NOT NULL, + SrcIsdID INTEGER NOT NULL, + SrcAsID INTEGER NOT NULL, + DstIsdID INTEGER NOT NULL, + DstAsID INTEGER NOT NULL, + SrcHostIP TEXT, + DstHostIP TEXT, + EpochBegin INTEGER NOT NULL, + EpochEnd INTEGER NOT NULL, + Key TEXT NOT NULL, + PRIMARY KEY (Protocol, Type, SrcIsdID, SrcAsID,` + + ` DstIsdID, DstAsID, SrcHostIP, DstHostIP, EpochBegin) + );` +) + +var _ drkey.Lvl2DB = (*Lvl2Backend)(nil) + +// Lvl2Backend implements a level 2 drkey DB with sqlite. +type Lvl2Backend struct { + dbBaseBackend + getLvl2KeyStmt *sql.Stmt + insertLvl2KeyStmt *sql.Stmt + removeOutdatedLvl2KeysStmt *sql.Stmt +} + +// NewLvl2Backend creates a database and prepares all statements. +func NewLvl2Backend(path string) (*Lvl2Backend, error) { + base, err := newBaseBackend(path, Lvl2Schema, Lvl2SchemaVersion) + if err != nil { + return nil, err + } + b := &Lvl2Backend{ + dbBaseBackend: *base, + } + stmts := preparedStmts{ + getLvl2Key: &b.getLvl2KeyStmt, + insertLvl2Key: &b.insertLvl2KeyStmt, + removeOutdatedLvl2Keys: &b.removeOutdatedLvl2KeysStmt, + } + if err := base.prepareAll(stmts); err != nil { + return nil, err + } + return b, nil +} + +const getLvl2Key = ` +SELECT EpochBegin, EpochEnd, Key +FROM DRKeyLvl2 WHERE Protocol=? AND Type=? AND SrcIsdID=? AND SrcAsID=? AND +DstIsdID=? AND DstAsID=? AND SrcHostIP=? AND DstHostIP=? +AND EpochBegin<=? AND ?= EpochEnd +` + +// RemoveOutdatedLvl2Keys removes all expired second level DRKeys, I.e. those keys +// which expiration time is strictly less than the cutoff +func (b *Lvl2Backend) RemoveOutdatedLvl2Keys(ctx context.Context, cutoff uint32) (int64, error) { + res, err := b.removeOutdatedLvl2KeysStmt.ExecContext(ctx, cutoff) + if err != nil { + return 0, err + } + return res.RowsAffected() +} diff --git a/go/lib/drkey/epoch.go b/go/lib/drkey/epoch.go new file mode 100644 index 0000000000..082feacfdc --- /dev/null +++ b/go/lib/drkey/epoch.go @@ -0,0 +1,48 @@ +// Copyright 2018 ETH Zurich +// +// 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 drkey + +import ( + "time" + + "github.com/scionproto/scion/go/lib/scrypto/cppki" + "github.com/scionproto/scion/go/lib/util" +) + +// Epoch represents a validity period. +type Epoch struct { + cppki.Validity +} + +// Equal returns true if both Epochs are identical. +func (e Epoch) Equal(other Epoch) bool { + return e.NotBefore == other.NotBefore && + e.NotAfter == other.NotAfter +} + +// NewEpoch constructs an Epoch from its uint32 encoded begin and end parts. +func NewEpoch(begin, end uint32) Epoch { + return Epoch{ + cppki.Validity{ + NotBefore: util.SecsToTime(begin).UTC(), + NotAfter: util.SecsToTime(end).UTC(), + }, + } +} + +// Contains indicates whether the time point is inside this Epoch. +func (e *Epoch) Contains(t time.Time) bool { + return e.Validity.Contains(t) +} diff --git a/go/lib/drkey/exchange/BUILD.bazel b/go/lib/drkey/exchange/BUILD.bazel new file mode 100644 index 0000000000..4b16531fdd --- /dev/null +++ b/go/lib/drkey/exchange/BUILD.bazel @@ -0,0 +1,15 @@ +load("//lint:go.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["grpc.go"], + importpath = "github.com/scionproto/scion/go/lib/drkey/exchange", + visibility = ["//visibility:public"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/scrypto/cppki:go_default_library", + "//go/lib/serrors:go_default_library", + "@org_golang_google_grpc//credentials:go_default_library", + "@org_golang_google_grpc//peer:go_default_library", + ], +) diff --git a/go/lib/drkey/exchange/grpc.go b/go/lib/drkey/exchange/grpc.go new file mode 100644 index 0000000000..286132f8eb --- /dev/null +++ b/go/lib/drkey/exchange/grpc.go @@ -0,0 +1,38 @@ +// Copyright 2020 ETH Zurich +// +// 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 exchange + +import ( + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/peer" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/scrypto/cppki" + "github.com/scionproto/scion/go/lib/serrors" +) + +func ExtractIAFromPeer(peer *peer.Peer) (addr.IA, error) { + tlsInfo, ok := peer.AuthInfo.(credentials.TLSInfo) + if !ok { + return addr.IA{}, serrors.New("auth info is not of type TLS info", + "peer", peer, "authType", peer.AuthInfo.AuthType()) + } + chain := tlsInfo.State.PeerCertificates + certIA, err := cppki.ExtractIA(chain[0].Subject) + if err != nil { + return addr.IA{}, serrors.WrapStr("extracting IA from peer cert", err) + } + return certIA, nil +} diff --git a/go/lib/drkey/level1.go b/go/lib/drkey/level1.go new file mode 100644 index 0000000000..8d25571eab --- /dev/null +++ b/go/lib/drkey/level1.go @@ -0,0 +1,44 @@ +// Copyright 2019 ETH Zurich +// +// 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 drkey + +import ( + "bytes" + + "github.com/scionproto/scion/go/lib/addr" +) + +// Lvl1Meta represents the information about a level 1 DRKey other than the key itself. +type Lvl1Meta struct { + Epoch Epoch + SrcIA addr.IA + DstIA addr.IA +} + +// Equal returns true if both meta are identical. +func (m Lvl1Meta) Equal(other Lvl1Meta) bool { + return m.Epoch.Equal(other.Epoch) && m.SrcIA.Equal(other.SrcIA) && m.DstIA.Equal(other.DstIA) +} + +// Lvl1Key represents a level 1 DRKey. +type Lvl1Key struct { + Lvl1Meta + Key DRKey +} + +// Equal returns true if both level 1 keys are identical. +func (k Lvl1Key) Equal(other Lvl1Key) bool { + return k.Lvl1Meta.Equal(other.Lvl1Meta) && bytes.Equal(k.Key, other.Key) +} diff --git a/go/lib/drkey/level2.go b/go/lib/drkey/level2.go new file mode 100644 index 0000000000..9f4b9f5dbf --- /dev/null +++ b/go/lib/drkey/level2.go @@ -0,0 +1,69 @@ +// Copyright 2019 ETH Zurich +// +// 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 drkey + +import ( + "bytes" + + "github.com/scionproto/scion/go/lib/addr" +) + +// Lvl2KeyType represents the different types of level 2 DRKeys (AS->AS, AS->host, host->host). +type Lvl2KeyType uint8 + +// Lvl2KeyType constants +const ( + AS2AS Lvl2KeyType = iota + AS2Host + Host2Host +) + +// Lvl2Meta represents the information about a level 2 DRKey, without the key itself. +type Lvl2Meta struct { + KeyType Lvl2KeyType + Protocol string + Epoch Epoch + SrcIA addr.IA + DstIA addr.IA + SrcHost addr.HostAddr + DstHost addr.HostAddr +} + +// Equal returns true if both meta are identical. +func (m Lvl2Meta) Equal(other Lvl2Meta) bool { + return m.KeyType == other.KeyType && m.Protocol == other.Protocol && + m.Epoch.Equal(other.Epoch) && m.SrcIA.Equal(other.SrcIA) && m.DstIA.Equal(other.DstIA) && + m.SrcHost.Equal(other.SrcHost) && m.DstHost.Equal(other.DstHost) +} + +// Lvl2Key represents a level 2 DRKey. +type Lvl2Key struct { + Lvl2Meta + Key DRKey +} + +// Equal returns true if both level 2 keys are identical. +func (k Lvl2Key) Equal(other Lvl2Key) bool { + return k.Lvl2Meta.Equal(other.Lvl2Meta) && bytes.Equal(k.Key, other.Key) +} + +// DelegationSecret is similar to a level 2 key, type AS to AS. +type DelegationSecret struct { + Protocol string + Epoch Epoch + SrcIA addr.IA + DstIA addr.IA + Key DRKey +} diff --git a/go/lib/drkey/protocol/BUILD.bazel b/go/lib/drkey/protocol/BUILD.bazel new file mode 100644 index 0000000000..9826d7b640 --- /dev/null +++ b/go/lib/drkey/protocol/BUILD.bazel @@ -0,0 +1,33 @@ +load("//lint:go.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "delegated.go", + "piskes.go", + "protocol.go", + "scmp.go", + "standard.go", + ], + importpath = "github.com/scionproto/scion/go/lib/drkey/protocol", + visibility = ["//visibility:public"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/scrypto:go_default_library", + "//go/lib/serrors:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["protocol_test.go"], + embed = [":go_default_library"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/xtest:go_default_library", + "@com_github_stretchr_testify//assert:go_default_library", + "@com_github_stretchr_testify//require:go_default_library", + ], +) diff --git a/go/lib/drkey/protocol/delegated.go b/go/lib/drkey/protocol/delegated.go new file mode 100644 index 0000000000..dee491e1cc --- /dev/null +++ b/go/lib/drkey/protocol/delegated.go @@ -0,0 +1,99 @@ +// Copyright 2019 ETH Zurich +// +// 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 protocol + +import ( + "errors" + + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/scrypto" + "github.com/scionproto/scion/go/lib/serrors" +) + +// Delegated implements the level 2 drkey derivation from level 1, without DS. It relies on the +// Standard implementation to derive the DS from the level 1 key. +type Delegated struct{} + +// DeriveLvl2 derives the level 2 DRKey without passing through a delegation secret. +func (p Delegated) DeriveLvl2(meta drkey.Lvl2Meta, key drkey.Lvl1Key) (drkey.Lvl2Key, error) { + metaForDS := meta + metaForDS.KeyType = drkey.AS2AS + dsKey, err := Standard{}.DeriveLvl2(metaForDS, key) + if err != nil { + return drkey.Lvl2Key{}, serrors.WrapStr("Error deriving DS", err) + } + ds := drkey.DelegationSecret{ + Protocol: meta.Protocol, + Epoch: meta.Epoch, + SrcIA: meta.SrcIA, + DstIA: meta.DstIA, + Key: dsKey.Key, + } + return p.DeriveLvl2FromDS(meta, ds) +} + +// DeriveLvl2FromDS will derive the level 2 key from a delegation secret. +func (p Delegated) DeriveLvl2FromDS(meta drkey.Lvl2Meta, ds drkey.DelegationSecret) ( + drkey.Lvl2Key, error) { + + h, err := scrypto.InitMac([]byte(ds.Key)) + if err != nil { + return drkey.Lvl2Key{}, err + } + + pLen := 0 + buffs := [][]byte{} + // add to buffs in reverse order: + switch meta.KeyType { + case drkey.Host2Host: + if meta.SrcHost.Size() == 0 { + return drkey.Lvl2Key{}, errors.New("Level 2 DRKey requires a src host, but it is empty") + } + b := meta.SrcHost.Pack() + buffs = [][]byte{ + b, + {byte(len(b))}, + } + pLen += len(b) + 1 + fallthrough + case drkey.AS2Host: + if meta.DstHost.Size() == 0 { + return drkey.Lvl2Key{}, errors.New("Level 2 DRKey requires a dst host, but it is empty") + } + b := meta.DstHost.Pack() + buffs = append(buffs, + b, + []byte{byte(len(b))}) + pLen += len(b) + 1 + case drkey.AS2AS: + return drkey.Lvl2Key{ + Lvl2Meta: meta, + Key: ds.Key, + }, nil + default: + return drkey.Lvl2Key{}, serrors.New("Unknown DRKey type") + } + all := make([]byte, pLen) + pLen = 0 + for i := len(buffs) - 1; i >= 0; i-- { + copy(all[pLen:], buffs[i]) + pLen += len(buffs[i]) + } + h.Write(all) + return drkey.Lvl2Key{ + Lvl2Meta: meta, + Key: drkey.DRKey(h.Sum(nil)), + }, nil +} diff --git a/go/lib/drkey/protocol/piskes.go b/go/lib/drkey/protocol/piskes.go new file mode 100644 index 0000000000..44bc88777d --- /dev/null +++ b/go/lib/drkey/protocol/piskes.go @@ -0,0 +1,45 @@ +// Copyright 2019 ETH Zurich +// +// 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 protocol + +import ( + "github.com/scionproto/scion/go/lib/drkey" +) + +var _ DelegatedDerivation = piskes{} + +// piskes implements the derivation for the PISKES protocol. +type piskes struct{} + +// Name returns scmp. +func (piskes) Name() string { + return "piskes" +} + +// DeriveLvl2 uses the standard derivation. +func (piskes) DeriveLvl2(meta drkey.Lvl2Meta, key drkey.Lvl1Key) (drkey.Lvl2Key, error) { + return Delegated{}.DeriveLvl2(meta, key) +} + +func (piskes) DeriveLvl2FromDS(meta drkey.Lvl2Meta, ds drkey.DelegationSecret) ( + drkey.Lvl2Key, error) { + + return Delegated{}.DeriveLvl2FromDS(meta, ds) +} + +func init() { + p := piskes{} + KnownDerivations[p.Name()] = p +} diff --git a/go/lib/drkey/protocol/protocol.go b/go/lib/drkey/protocol/protocol.go new file mode 100644 index 0000000000..d6f980d942 --- /dev/null +++ b/go/lib/drkey/protocol/protocol.go @@ -0,0 +1,51 @@ +// Copyright 2019 ETH Zurich +// +// 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 protocol + +import ( + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/scrypto" +) + +// Derivation specifies the interface to implement for a derivation method. +type Derivation interface { + Name() string + DeriveLvl2(meta drkey.Lvl2Meta, key drkey.Lvl1Key) (drkey.Lvl2Key, error) +} + +// DelegatedDerivation extends a Derivation with a derivation from a DS. +type DelegatedDerivation interface { + Derivation + DeriveLvl2FromDS(meta drkey.Lvl2Meta, ds drkey.DelegationSecret) (drkey.Lvl2Key, error) +} + +// KnownDerivations maps the derivation names to their implementations. +var KnownDerivations = make(map[string]Derivation) + +// DeriveLvl1 constructs a new level 1 DRKey. +func DeriveLvl1(meta drkey.Lvl1Meta, sv drkey.SV) (drkey.Lvl1Key, error) { + mac, err := scrypto.InitMac([]byte(sv.Key)) + if err != nil { + return drkey.Lvl1Key{}, err + } + all := make([]byte, addr.IABytes) + meta.DstIA.Write(all) + mac.Write(all) + return drkey.Lvl1Key{ + Lvl1Meta: meta, + Key: drkey.DRKey(mac.Sum(nil)), + }, nil +} diff --git a/go/lib/drkey/protocol/protocol_test.go b/go/lib/drkey/protocol/protocol_test.go new file mode 100644 index 0000000000..476758c55b --- /dev/null +++ b/go/lib/drkey/protocol/protocol_test.go @@ -0,0 +1,192 @@ +// Copyright 2019 ETH Zurich +// +// 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 protocol + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/xtest" +) + +func TestDeriveStandard(t *testing.T) { + lvl1 := getLvl1(t) + protoToKey := map[string][]byte{ + "foo": xtest.MustParseHexString("def3aa32ce47d4374469148b5c04fac5"), + "bar": xtest.MustParseHexString("8ada021cabf2b14765f468f3c8995edb"), + "fooo": xtest.MustParseHexString("7f8e507aecf38c09e4cb10a0ff0cc497"), + } + + for proto, key := range protoToKey { + meta := drkey.Lvl2Meta{ + Protocol: proto, + KeyType: drkey.AS2AS, + SrcIA: lvl1.SrcIA, + DstIA: lvl1.DstIA, + } + lvl2, err := Standard{}.DeriveLvl2(meta, lvl1) + require.NoError(t, err) + assert.EqualValues(t, key, lvl2.Key) + } + + dstHost := addr.HostFromIPStr("127.0.0.1") + protoToKey = map[string][]byte{ + "foo": xtest.MustParseHexString("84e628f7c9318d6831ff4f85827f7af3"), + "bar": xtest.MustParseHexString("f51fa0769a6e3d2b9570eefb788a92c0"), + "fooo": xtest.MustParseHexString("d88513be2ff73b11615053540146e960"), + } + for proto, key := range protoToKey { + meta := drkey.Lvl2Meta{ + Protocol: proto, + KeyType: drkey.AS2Host, + SrcIA: lvl1.SrcIA, + DstIA: lvl1.DstIA, + DstHost: dstHost, + } + lvl2, err := Standard{}.DeriveLvl2(meta, lvl1) + require.NoError(t, err) + assert.EqualValues(t, key, lvl2.Key) + } + + srcHost := addr.HostFromIPStr("127.0.0.2") + protoToKey = map[string][]byte{ + "foo": xtest.MustParseHexString("3ca3190844028277e05ebfaf3c2dd3b0"), + "bar": xtest.MustParseHexString("b0bc9ccbd6ca923bdfbad7d1ad358960"), + "fooo": xtest.MustParseHexString("5635ad5283cfe080e2c8e99e6c3306af"), + } + for proto, key := range protoToKey { + meta := drkey.Lvl2Meta{ + Protocol: proto, + KeyType: drkey.Host2Host, + SrcIA: lvl1.SrcIA, + DstIA: lvl1.DstIA, + SrcHost: srcHost, + DstHost: dstHost, + } + lvl2, err := Standard{}.DeriveLvl2(meta, lvl1) + require.NoError(t, err) + assert.EqualValues(t, key, lvl2.Key) + } +} + +func TestDeriveDelegated(t *testing.T) { + lvl1 := getLvl1(t) + for _, proto := range []string{"foo", "bar", "fooo"} { + meta := drkey.Lvl2Meta{ + Protocol: proto, + KeyType: drkey.AS2AS, + SrcIA: lvl1.SrcIA, + DstIA: lvl1.DstIA, + } + lvl2standard, err := Standard{}.DeriveLvl2(meta, lvl1) + require.NoError(t, err) + lvl2deleg, err := Delegated{}.DeriveLvl2(meta, lvl1) + require.NoError(t, err) + assert.Equal(t, lvl2standard.Key, lvl2deleg.Key) + } + + protoToLvl2 := map[string][]byte{ + "foo": xtest.MustParseHexString("b4279b032d7d81c38754ab7b253f5ac0"), + "bar": xtest.MustParseHexString("a30df8ad348bfce1ecdf1cf83c9e5265"), + "fooo": xtest.MustParseHexString("434817fb40cb602b36c80e88789aee46"), + } + for proto, key := range protoToLvl2 { + meta := drkey.Lvl2Meta{ + Protocol: proto, + KeyType: drkey.AS2Host, + SrcIA: lvl1.SrcIA, + DstIA: lvl1.DstIA, + DstHost: addr.HostFromIPStr("127.0.0.1"), + } + lvl2, err := Delegated{}.DeriveLvl2(meta, lvl1) + require.NoError(t, err) + assert.EqualValues(t, key, lvl2.Key) + } +} + +func TestDeriveDelegatedViaDS(t *testing.T) { + // derive DS and then derive key. Compare to derive directly key + lvl1Key := getLvl1(t) + meta := drkey.Lvl2Meta{ + Protocol: "piskes", + KeyType: drkey.AS2AS, + SrcIA: lvl1Key.SrcIA, + DstIA: lvl1Key.DstIA, + SrcHost: addr.HostNone{}, + DstHost: addr.HostNone{}, + } + lvl2Key, err := piskes{}.DeriveLvl2(meta, lvl1Key) + require.NoError(t, err) + ds := drkey.DelegationSecret{ + Protocol: lvl2Key.Protocol, + Epoch: lvl2Key.Epoch, + SrcIA: lvl2Key.SrcIA, + DstIA: lvl2Key.DstIA, + Key: lvl2Key.Key, + } + srcHost := addr.HostFromIPStr("1.1.1.1") + dstHost := addr.HostFromIPStr("2.2.2.2") + meta = drkey.Lvl2Meta{ + Protocol: meta.Protocol, + KeyType: drkey.Host2Host, + SrcIA: meta.SrcIA, + DstIA: meta.DstIA, + SrcHost: srcHost, + DstHost: dstHost, + } + lvl2KeyViaDS, err := piskes{}.DeriveLvl2FromDS(meta, ds) + require.NoError(t, err) + _ = lvl2KeyViaDS + // now get the level 2 key directly without explicitly going through DS + lvl2Key, err = piskes{}.DeriveLvl2(meta, lvl1Key) + require.NoError(t, err) + assert.Equal(t, lvl2Key, lvl2KeyViaDS) +} + +func getLvl1(t *testing.T) drkey.Lvl1Key { + meta := drkey.SVMeta{ + Epoch: drkey.NewEpoch(0, 1), + } + asSecret := []byte{0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7} + svTgtKey := xtest.MustParseHexString("47bfbb7d94706dc9e79825e5a837b006") + epoch := drkey.NewEpoch(0, 1) + srcIA, _ := addr.IAFromString("1-ff00:0:111") + dstIA, _ := addr.IAFromString("1-ff00:0:112") + sv, err := drkey.DeriveSV(meta, asSecret) + require.NoError(t, err) + require.EqualValues(t, svTgtKey, sv.Key) + + lvlTgtKey := xtest.MustParseHexString("51663adbc06e55f40a9ad899cf0775e5") + lvl1, err := DeriveLvl1(drkey.Lvl1Meta{ + Epoch: epoch, + SrcIA: srcIA, + DstIA: dstIA, + }, sv) + require.NoError(t, err) + require.EqualValues(t, lvlTgtKey, lvl1.Key) + + return lvl1 +} + +func TestExistingImplementations(t *testing.T) { + // we test that we have the two implementations we know for now (scmp,piskes) + require.Len(t, KnownDerivations, 2) + require.Contains(t, KnownDerivations, "scmp") + require.Contains(t, KnownDerivations, "piskes") +} diff --git a/go/lib/drkey/protocol/scmp.go b/go/lib/drkey/protocol/scmp.go new file mode 100644 index 0000000000..a3b788aacd --- /dev/null +++ b/go/lib/drkey/protocol/scmp.go @@ -0,0 +1,39 @@ +// Copyright 2019 ETH Zurich +// +// 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 protocol + +import ( + "github.com/scionproto/scion/go/lib/drkey" +) + +var _ Derivation = scmp{} + +// scmp implements the derivation for the SCMP protocol. +type scmp struct{} + +// Name returns scmp. +func (scmp) Name() string { + return "scmp" +} + +// DeriveLvl2 uses the standard derivation. +func (scmp) DeriveLvl2(meta drkey.Lvl2Meta, key drkey.Lvl1Key) (drkey.Lvl2Key, error) { + return Standard{}.DeriveLvl2(meta, key) +} + +func init() { + s := scmp{} + KnownDerivations[s.Name()] = s +} diff --git a/go/lib/drkey/protocol/standard.go b/go/lib/drkey/protocol/standard.go new file mode 100644 index 0000000000..5c1a318f38 --- /dev/null +++ b/go/lib/drkey/protocol/standard.go @@ -0,0 +1,87 @@ +// Copyright 2019 ETH Zurich +// +// 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 protocol + +import ( + "errors" + + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/scrypto" + "github.com/scionproto/scion/go/lib/serrors" +) + +// TODO(juagargi) the standard derivation (in this file) and delegated one will be just +// functions: won't implement any interface in particular. The way to configure +// a new protocol will look like the SCMP or PISKES protocols: new type with their functions, and +// registration with the correct name. No configuration will be allowed to change this (the +// configuration file will not include any mapping protocol->derivation). + +// Standard implements the level 2 drkey derivation from level 1, without DS. +type Standard struct{} + +// DeriveLvl2 derives the level 2 DRKey without passing through a delegation secret. +func (p Standard) DeriveLvl2(meta drkey.Lvl2Meta, key drkey.Lvl1Key) (drkey.Lvl2Key, error) { + h, err := scrypto.InitMac([]byte(key.Key)) + if err != nil { + return drkey.Lvl2Key{}, err + } + + pLen := 0 + // add to buffs in reverse order: + buffs := [][]byte{} + switch meta.KeyType { + case drkey.Host2Host: + if meta.SrcHost.Size() == 0 { + return drkey.Lvl2Key{}, errors.New("Level 2 DRKey requires a src host, but it is empty") + } + b := meta.SrcHost.Pack() + buffs = [][]byte{ + b, + {byte(len(b))}, + } + pLen += len(b) + 1 + fallthrough + case drkey.AS2Host: + if meta.DstHost.Size() == 0 { + return drkey.Lvl2Key{}, errors.New("Level 2 DRKey requires a dst host, but it is empty") + } + b := meta.DstHost.Pack() + buffs = append(buffs, + b, + []byte{byte(len(b))}) + pLen += len(b) + 1 + fallthrough + case drkey.AS2AS: + b := []byte(meta.Protocol) + buffs = append(buffs, + []byte{byte(meta.KeyType)}, + b, + []byte{byte(len(b))}) + pLen += len(b) + 2 + default: + return drkey.Lvl2Key{}, serrors.New("Unknown DRKey type") + } + all := make([]byte, pLen) + pLen = 0 + for i := len(buffs) - 1; i >= 0; i-- { + copy(all[pLen:], buffs[i]) + pLen += len(buffs[i]) + } + h.Write(all) + return drkey.Lvl2Key{ + Lvl2Meta: meta, + Key: drkey.DRKey(h.Sum(nil)), + }, nil +} diff --git a/go/lib/drkey/secret_value.go b/go/lib/drkey/secret_value.go new file mode 100644 index 0000000000..9439712947 --- /dev/null +++ b/go/lib/drkey/secret_value.go @@ -0,0 +1,63 @@ +// Copyright 2019 ETH Zurich +// +// 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 drkey + +import ( + "bytes" + "crypto/sha256" + "encoding/binary" + "errors" + + "golang.org/x/crypto/pbkdf2" + + "github.com/scionproto/scion/go/lib/util" +) + +const drkeySalt = "Derive DRKey Key" // same as in Python + +// SVMeta represents the information about a DRKey secret value. +type SVMeta struct { + Epoch Epoch +} + +// SV represents a DRKey secret value. +type SV struct { + SVMeta + Key DRKey +} + +// Equal returns true if both secret values are identical. +func (sv SV) Equal(other SV) bool { + return sv.Epoch.Equal(other.Epoch) && bytes.Equal(sv.Key, other.Key) +} + +// DeriveSV constructs a valid SV. asSecret is typically the AS master secret. +func DeriveSV(meta SVMeta, asSecret []byte) (SV, error) { + msLen := len(asSecret) + if msLen == 0 { + return SV{}, errors.New("Invalid zero sized secret") + } + all := make([]byte, 1+msLen+8) + copy(all, []byte{byte(msLen)}) + copy(all[1:], asSecret) + binary.LittleEndian.PutUint32(all[msLen+1:], util.TimeToSecs(meta.Epoch.NotBefore)) + binary.LittleEndian.PutUint32(all[msLen+5:], util.TimeToSecs(meta.Epoch.NotAfter)) + + key := pbkdf2.Key(all, []byte(drkeySalt), 1000, 16, sha256.New) + return SV{ + SVMeta: meta, + Key: DRKey(key), + }, nil +} diff --git a/go/lib/drkey/secret_value_test.go b/go/lib/drkey/secret_value_test.go new file mode 100644 index 0000000000..f299dcebb8 --- /dev/null +++ b/go/lib/drkey/secret_value_test.go @@ -0,0 +1,38 @@ +// Copyright 2020 ETH Zurich +// +// 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 drkey + +import ( + "encoding/hex" + "testing" + + "github.com/scionproto/scion/go/lib/xtest" +) + +func TestDeriveSV(t *testing.T) { + meta := SVMeta{NewEpoch(0, 1)} + asSecret := []byte{0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7} + targetKey := xtest.MustParseHexString("47bfbb7d94706dc9e79825e5a837b006") + + got, err := DeriveSV(meta, asSecret) + if err != nil { + t.Errorf("DeriveSV() error = %v", err) + return + } + if !got.Key.Equal(targetKey) { + t.Fatalf("Unexpected sv key: %s, expected: %s", + hex.EncodeToString(got.Key), hex.EncodeToString(targetKey)) + } +} diff --git a/go/lib/drkeystorage/BUILD.bazel b/go/lib/drkeystorage/BUILD.bazel new file mode 100644 index 0000000000..9e5640db1f --- /dev/null +++ b/go/lib/drkeystorage/BUILD.bazel @@ -0,0 +1,13 @@ +load("//lint:go.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["store.go"], + importpath = "github.com/scionproto/scion/go/lib/drkeystorage", + visibility = ["//visibility:public"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/infra/modules/cleaner:go_default_library", + ], +) diff --git a/go/lib/drkeystorage/mock_drkeystorage/BUILD.bazel b/go/lib/drkeystorage/mock_drkeystorage/BUILD.bazel new file mode 100644 index 0000000000..63e11eaaf9 --- /dev/null +++ b/go/lib/drkeystorage/mock_drkeystorage/BUILD.bazel @@ -0,0 +1,13 @@ +load("//lint:go.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["store.go"], + importpath = "github.com/scionproto/scion/go/lib/drkeystorage/mock_drkeystorage", + visibility = ["//visibility:public"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/drkey:go_default_library", + "@com_github_golang_mock//gomock:go_default_library", + ], +) diff --git a/go/lib/drkeystorage/mock_drkeystorage/store.go b/go/lib/drkeystorage/mock_drkeystorage/store.go new file mode 100644 index 0000000000..19c5ee3564 --- /dev/null +++ b/go/lib/drkeystorage/mock_drkeystorage/store.go @@ -0,0 +1,226 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/scionproto/scion/go/lib/drkeystorage (interfaces: SecretValueFactory,BaseStore,ServiceStore,ClientStore) + +// Package mock_drkeystorage is a generated GoMock package. +package mock_drkeystorage + +import ( + context "context" + gomock "github.com/golang/mock/gomock" + addr "github.com/scionproto/scion/go/lib/addr" + drkey "github.com/scionproto/scion/go/lib/drkey" + reflect "reflect" + time "time" +) + +// MockSecretValueFactory is a mock of SecretValueFactory interface +type MockSecretValueFactory struct { + ctrl *gomock.Controller + recorder *MockSecretValueFactoryMockRecorder +} + +// MockSecretValueFactoryMockRecorder is the mock recorder for MockSecretValueFactory +type MockSecretValueFactoryMockRecorder struct { + mock *MockSecretValueFactory +} + +// NewMockSecretValueFactory creates a new mock instance +func NewMockSecretValueFactory(ctrl *gomock.Controller) *MockSecretValueFactory { + mock := &MockSecretValueFactory{ctrl: ctrl} + mock.recorder = &MockSecretValueFactoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockSecretValueFactory) EXPECT() *MockSecretValueFactoryMockRecorder { + return m.recorder +} + +// GetSecretValue mocks base method +func (m *MockSecretValueFactory) GetSecretValue(arg0 time.Time) (drkey.SV, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSecretValue", arg0) + ret0, _ := ret[0].(drkey.SV) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetSecretValue indicates an expected call of GetSecretValue +func (mr *MockSecretValueFactoryMockRecorder) GetSecretValue(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSecretValue", reflect.TypeOf((*MockSecretValueFactory)(nil).GetSecretValue), arg0) +} + +// MockBaseStore is a mock of BaseStore interface +type MockBaseStore struct { + ctrl *gomock.Controller + recorder *MockBaseStoreMockRecorder +} + +// MockBaseStoreMockRecorder is the mock recorder for MockBaseStore +type MockBaseStoreMockRecorder struct { + mock *MockBaseStore +} + +// NewMockBaseStore creates a new mock instance +func NewMockBaseStore(ctrl *gomock.Controller) *MockBaseStore { + mock := &MockBaseStore{ctrl: ctrl} + mock.recorder = &MockBaseStoreMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockBaseStore) EXPECT() *MockBaseStoreMockRecorder { + return m.recorder +} + +// DeleteExpiredKeys mocks base method +func (m *MockBaseStore) DeleteExpiredKeys(arg0 context.Context) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteExpiredKeys", arg0) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteExpiredKeys indicates an expected call of DeleteExpiredKeys +func (mr *MockBaseStoreMockRecorder) DeleteExpiredKeys(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteExpiredKeys", reflect.TypeOf((*MockBaseStore)(nil).DeleteExpiredKeys), arg0) +} + +// MockServiceStore is a mock of ServiceStore interface +type MockServiceStore struct { + ctrl *gomock.Controller + recorder *MockServiceStoreMockRecorder +} + +// MockServiceStoreMockRecorder is the mock recorder for MockServiceStore +type MockServiceStoreMockRecorder struct { + mock *MockServiceStore +} + +// NewMockServiceStore creates a new mock instance +func NewMockServiceStore(ctrl *gomock.Controller) *MockServiceStore { + mock := &MockServiceStore{ctrl: ctrl} + mock.recorder = &MockServiceStoreMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockServiceStore) EXPECT() *MockServiceStoreMockRecorder { + return m.recorder +} + +// DeleteExpiredKeys mocks base method +func (m *MockServiceStore) DeleteExpiredKeys(arg0 context.Context) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteExpiredKeys", arg0) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteExpiredKeys indicates an expected call of DeleteExpiredKeys +func (mr *MockServiceStoreMockRecorder) DeleteExpiredKeys(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteExpiredKeys", reflect.TypeOf((*MockServiceStore)(nil).DeleteExpiredKeys), arg0) +} + +// DeriveLvl1 mocks base method +func (m *MockServiceStore) DeriveLvl1(arg0 addr.IA, arg1 time.Time) (drkey.Lvl1Key, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeriveLvl1", arg0, arg1) + ret0, _ := ret[0].(drkey.Lvl1Key) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeriveLvl1 indicates an expected call of DeriveLvl1 +func (mr *MockServiceStoreMockRecorder) DeriveLvl1(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeriveLvl1", reflect.TypeOf((*MockServiceStore)(nil).DeriveLvl1), arg0, arg1) +} + +// GetLvl1Key mocks base method +func (m *MockServiceStore) GetLvl1Key(arg0 context.Context, arg1 drkey.Lvl1Meta, arg2 time.Time) (drkey.Lvl1Key, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLvl1Key", arg0, arg1, arg2) + ret0, _ := ret[0].(drkey.Lvl1Key) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLvl1Key indicates an expected call of GetLvl1Key +func (mr *MockServiceStoreMockRecorder) GetLvl1Key(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLvl1Key", reflect.TypeOf((*MockServiceStore)(nil).GetLvl1Key), arg0, arg1, arg2) +} + +// KnownASes mocks base method +func (m *MockServiceStore) KnownASes(arg0 context.Context) ([]addr.IA, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "KnownASes", arg0) + ret0, _ := ret[0].([]addr.IA) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// KnownASes indicates an expected call of KnownASes +func (mr *MockServiceStoreMockRecorder) KnownASes(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KnownASes", reflect.TypeOf((*MockServiceStore)(nil).KnownASes), arg0) +} + +// MockClientStore is a mock of ClientStore interface +type MockClientStore struct { + ctrl *gomock.Controller + recorder *MockClientStoreMockRecorder +} + +// MockClientStoreMockRecorder is the mock recorder for MockClientStore +type MockClientStoreMockRecorder struct { + mock *MockClientStore +} + +// NewMockClientStore creates a new mock instance +func NewMockClientStore(ctrl *gomock.Controller) *MockClientStore { + mock := &MockClientStore{ctrl: ctrl} + mock.recorder = &MockClientStoreMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockClientStore) EXPECT() *MockClientStoreMockRecorder { + return m.recorder +} + +// DeleteExpiredKeys mocks base method +func (m *MockClientStore) DeleteExpiredKeys(arg0 context.Context) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteExpiredKeys", arg0) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteExpiredKeys indicates an expected call of DeleteExpiredKeys +func (mr *MockClientStoreMockRecorder) DeleteExpiredKeys(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteExpiredKeys", reflect.TypeOf((*MockClientStore)(nil).DeleteExpiredKeys), arg0) +} + +// GetLvl2Key mocks base method +func (m *MockClientStore) GetLvl2Key(arg0 context.Context, arg1 drkey.Lvl2Meta, arg2 time.Time) (drkey.Lvl2Key, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLvl2Key", arg0, arg1, arg2) + ret0, _ := ret[0].(drkey.Lvl2Key) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLvl2Key indicates an expected call of GetLvl2Key +func (mr *MockClientStoreMockRecorder) GetLvl2Key(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLvl2Key", reflect.TypeOf((*MockClientStore)(nil).GetLvl2Key), arg0, arg1, arg2) +} diff --git a/go/lib/drkeystorage/store.go b/go/lib/drkeystorage/store.go new file mode 100644 index 0000000000..cebb98ff34 --- /dev/null +++ b/go/lib/drkeystorage/store.go @@ -0,0 +1,59 @@ +// Copyright 2019 ETH Zurich +// +// 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 drkeystorage + +import ( + "context" + "time" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/infra/modules/cleaner" +) + +// SecretValueFactory has the functionality to store secret values. +type SecretValueFactory interface { + GetSecretValue(time.Time) (drkey.SV, error) +} + +// BaseStore is the common base for any drkey store. +type BaseStore interface { + DeleteExpiredKeys(ctx context.Context) (int, error) +} + +// ServiceStore is the level 1 drkey store, used by the CS. +// It will keep a cache of those keys that were retrieved from the network. +// It automatically removes expired keys. +type ServiceStore interface { + BaseStore + DeriveLvl1(dstIA addr.IA, valTime time.Time) (drkey.Lvl1Key, error) + GetLvl1Key(ctx context.Context, meta drkey.Lvl1Meta, valTime time.Time) (drkey.Lvl1Key, error) + KnownASes(ctx context.Context) ([]addr.IA, error) +} + +// ClientStore is the level 2 drkey store, used by sciond. +// It can get level 2 keys from its backes storage, or by +// asking a remote CS. +type ClientStore interface { + BaseStore + GetLvl2Key(ctx context.Context, meta drkey.Lvl2Meta, valTime time.Time) (drkey.Lvl2Key, error) +} + +// NewStoreCleaner creates a Cleaner task that removes expired level 1 drkeys. +func NewStoreCleaner(s BaseStore) *cleaner.Cleaner { + return cleaner.New(func(ctx context.Context) (int, error) { + return s.DeleteExpiredKeys(ctx) + }, "drkey") +} diff --git a/go/lib/infra/infraenv/infraenv.go b/go/lib/infra/infraenv/infraenv.go index 8f36399eaa..fca4c0715d 100644 --- a/go/lib/infra/infraenv/infraenv.go +++ b/go/lib/infra/infraenv/infraenv.go @@ -79,6 +79,8 @@ type NetworkConfig struct { type QUICStack struct { Listener *squic.ConnListener Dialer *squic.ConnDialer + TLSListener *squic.ConnListener + TLSDialer *squic.ConnDialer RedirectCloser func() } @@ -94,7 +96,7 @@ func (nc *NetworkConfig) QUICStack() (*QUICStack, error) { if nc.QUIC.Address == "" { nc.QUIC.Address = net.JoinHostPort(nc.Public.IP.String(), "0") } - client, server, err := nc.initQUICSockets() + client, server, err := nc.initQUICSockets(false) if err != nil { return nil, err } @@ -110,7 +112,26 @@ func (nc *NetworkConfig) QUICStack() (*QUICStack, error) { return nil, serrors.WrapStr("listening QUIC/SCION", err) } - cancel, err := nc.initSvcRedirect(server.LocalAddr().String()) + //TLS/QUIC part + // Calling initQUICSockets again will fail if nc.QUIC.Address has a port other than 0. + // As a workaround, forcefully set the port to 0 via a parameter. + tlsClient, tlsServer, err := nc.initQUICSockets(true) + if err != nil { + return nil, err + } + log.Info("TLS/QUIC server conn initialized", "local_addr", tlsServer.LocalAddr()) + log.Info("TLS/QUIC client conn initialized", "local_addr", tlsClient.LocalAddr()) + + tlsQuicConfig, err := GenerateTLSConfig() + if err != nil { + return nil, err + } + tlsListener, err := quic.Listen(tlsServer, tlsQuicConfig, nil) + if err != nil { + return nil, serrors.WrapStr("listening TLS/QUIC/SCION", err) + } + + cancel, err := nc.initSvcRedirect(server.LocalAddr().String(), tlsServer.LocalAddr().String()) if err != nil { return nil, serrors.WrapStr("starting service redirection", err) } @@ -121,6 +142,11 @@ func (nc *NetworkConfig) QUICStack() (*QUICStack, error) { Conn: client, TLSConfig: tlsConfig, }, + TLSListener: squic.NewConnListener(tlsListener), + TLSDialer: &squic.ConnDialer{ + Conn: tlsClient, + TLSConfig: tlsQuicConfig, + }, RedirectCloser: cancel, }, nil } @@ -198,10 +224,11 @@ func (nc *NetworkConfig) AddressRewriter( // initSvcRedirect creates the main control-plane UDP socket. SVC anycasts will be // delivered to this socket, which replies to SVC resolution requests. The // address will be included as the QUIC address in SVC resolution replies. -func (nc *NetworkConfig) initSvcRedirect(quicAddress string) (func(), error) { +func (nc *NetworkConfig) initSvcRedirect(quicAddress string, tlsQUICAdress string) (func(), error) { reply := &svc.Reply{ Transports: map[svc.Transport]string{ - svc.QUIC: quicAddress, + svc.QUIC: quicAddress, + svc.TLSQUIC: tlsQUICAdress, }, } @@ -249,7 +276,7 @@ func (nc *NetworkConfig) initSvcRedirect(quicAddress string) (func(), error) { return cancel, nil } -func (nc *NetworkConfig) initQUICSockets() (net.PacketConn, net.PacketConn, error) { +func (nc *NetworkConfig) initQUICSockets(ignorePort bool) (net.PacketConn, net.PacketConn, error) { dispatcherService := reliable.NewDispatcher("") if nc.ReconnectToDispatcher { dispatcherService = reconnect.NewDispatcherService(dispatcherService) @@ -269,6 +296,9 @@ func (nc *NetworkConfig) initQUICSockets() (net.PacketConn, net.PacketConn, erro if err != nil { return nil, nil, serrors.WrapStr("parsing server QUIC address", err) } + if ignorePort { + serverAddr.Port = 0 + } server, err := serverNet.Listen(context.Background(), "udp", serverAddr, addr.SvcNone) if err != nil { return nil, nil, serrors.WrapStr("creating server connection", err) diff --git a/go/lib/infra/messenger/addr.go b/go/lib/infra/messenger/addr.go index 34fbf3d399..c7771fc74f 100644 --- a/go/lib/infra/messenger/addr.go +++ b/go/lib/infra/messenger/addr.go @@ -72,6 +72,26 @@ type AddressRewriter struct { // If the address is already unicast, no redirection to QUIC is attempted. func (r AddressRewriter) RedirectToQUIC(ctx context.Context, address net.Addr) (net.Addr, bool, error) { + + ret, quicRedirect, err := r.redirectToQUIC(ctx, address, svc.QUIC) + if err != nil { + return nil, false, err + } + return ret, quicRedirect, err +} + +func (r AddressRewriter) RedirectToTLSQUIC(ctx context.Context, + address net.Addr) (net.Addr, bool, error) { + + ret, quicRedirect, err := r.redirectToQUIC(ctx, address, svc.TLSQUIC) + if err != nil { + return nil, false, err + } + return ret, quicRedirect, err +} + +func (r AddressRewriter) redirectToQUIC(ctx context.Context, + address net.Addr, transport svc.Transport) (net.Addr, bool, error) { logger := log.FromCtx(ctx) // FIXME(scrye): This is not legitimate use. It's only included for @@ -99,7 +119,7 @@ func (r AddressRewriter) RedirectToQUIC(ctx context.Context, } // During One-Hop Path operation, use SVC resolution to also bootstrap the path. - p, u, quicRedirect, err := r.resolveSVC(ctx, path, fa.SVC) + p, u, quicRedirect, err := r.resolveSVC(ctx, path, fa.SVC, transport) if err != nil { // For a revoked path we don't fallback we want to give the option // to retry with a new path. @@ -178,7 +198,7 @@ func (r AddressRewriter) buildFullAddress(ctx context.Context, // The returned path is the path contained in the reply; the path can be used // to talk to the remote AS after One-Hop Path construction. func (r AddressRewriter) resolveSVC(ctx context.Context, p snet.Path, - s addr.HostSVC) (snet.Path, *net.UDPAddr, bool, error) { + s addr.HostSVC, transport svc.Transport) (snet.Path, *net.UDPAddr, bool, error) { logger := log.FromCtx(ctx) if r.SVCResolutionFraction < 1.0 { var cancelF context.CancelFunc @@ -196,7 +216,7 @@ func (r AddressRewriter) resolveSVC(ctx context.Context, p snet.Path, } logger.Debug("SVC resolution successful", "reply", reply) - u, err := parseReply(reply) + u, err := parseReply(reply, transport) if err != nil { return nil, nil, false, err } @@ -216,14 +236,14 @@ func (r AddressRewriter) resolutionCtx(ctx context.Context) (context.Context, co // parseReply searches for a QUIC server on the remote address. If one is not // found, an error is returned. -func parseReply(reply *svc.Reply) (*net.UDPAddr, error) { +func parseReply(reply *svc.Reply, transport svc.Transport) (*net.UDPAddr, error) { if reply == nil { return nil, serrors.New("nil reply") } if reply.Transports == nil { return nil, serrors.New("empty reply") } - addressStr, ok := reply.Transports[svc.QUIC] + addressStr, ok := reply.Transports[transport] if !ok { return nil, serrors.New("QUIC server address not found") } diff --git a/go/lib/infra/messenger/export_test.go b/go/lib/infra/messenger/export_test.go index a4d5d6d3c3..1f206b4706 100644 --- a/go/lib/infra/messenger/export_test.go +++ b/go/lib/infra/messenger/export_test.go @@ -30,9 +30,9 @@ func (r AddressRewriter) BuildFullAddress(ctx context.Context, func (r AddressRewriter) ResolveSVC(ctx context.Context, p snet.Path, s addr.HostSVC) (snet.Path, *net.UDPAddr, bool, error) { - return r.resolveSVC(ctx, p, s) + return r.resolveSVC(ctx, p, s, svc.QUIC) } func ParseReply(reply *svc.Reply) (*net.UDPAddr, error) { - return parseReply(reply) + return parseReply(reply, svc.QUIC) } diff --git a/go/lib/svc/messages.go b/go/lib/svc/messages.go index d183f7fcfe..f2cc4cfe64 100644 --- a/go/lib/svc/messages.go +++ b/go/lib/svc/messages.go @@ -97,5 +97,6 @@ func (r *Reply) fromProtoFormat(protoReply *cppb.ServiceResolutionResponse) erro type Transport string const ( - QUIC Transport = "QUIC" + QUIC Transport = "QUIC" + TLSQUIC Transport = "TLSQUIC" ) diff --git a/go/pkg/cs/BUILD.bazel b/go/pkg/cs/BUILD.bazel index 6de9627414..13001e76fa 100644 --- a/go/pkg/cs/BUILD.bazel +++ b/go/pkg/cs/BUILD.bazel @@ -25,6 +25,7 @@ go_library( "//go/lib/config:go_default_library", "//go/lib/ctrl/path_mgmt:go_default_library", "//go/lib/ctrl/seg:go_default_library", + "//go/lib/drkeystorage:go_default_library", "//go/lib/env:go_default_library", "//go/lib/infra:go_default_library", "//go/lib/infra/modules/itopo:go_default_library", @@ -43,6 +44,7 @@ go_library( "//go/lib/snet/addrutil:go_default_library", "//go/lib/topology:go_default_library", "//go/pkg/ca/renewal:go_default_library", + "//go/pkg/cs/drkey:go_default_library", "//go/pkg/cs/trust:go_default_library", "//go/pkg/discovery:go_default_library", "//go/pkg/grpc:go_default_library", diff --git a/go/pkg/cs/drkey/BUILD.bazel b/go/pkg/cs/drkey/BUILD.bazel new file mode 100644 index 0000000000..3a2c55fac9 --- /dev/null +++ b/go/pkg/cs/drkey/BUILD.bazel @@ -0,0 +1,43 @@ +load("//lint:go.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "prefetcher.go", + "secret_value_store.go", + "service_store.go", + ], + importpath = "github.com/scionproto/scion/go/pkg/cs/drkey", + visibility = ["//visibility:public"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/drkey/protocol:go_default_library", + "//go/lib/drkeystorage:go_default_library", + "//go/lib/log:go_default_library", + "//go/lib/periodic:go_default_library", + "//go/lib/serrors:go_default_library", + "//go/lib/util:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = [ + "export_test.go", + "secret_value_store_test.go", + "service_store_test.go", + ], + embed = [":go_default_library"], + deps = [ + "//go/lib/drkey:go_default_library", + "//go/lib/drkey/drkeydbsqlite:go_default_library", + "//go/lib/util:go_default_library", + "//go/lib/xtest:go_default_library", + "//go/pkg/cs/drkey/mock_drkey:go_default_library", + "//go/pkg/cs/drkey/test:go_default_library", + "@com_github_golang_mock//gomock:go_default_library", + "@com_github_stretchr_testify//assert:go_default_library", + "@com_github_stretchr_testify//require:go_default_library", + ], +) diff --git a/go/pkg/cs/drkey/export_test.go b/go/pkg/cs/drkey/export_test.go new file mode 100644 index 0000000000..94db816dda --- /dev/null +++ b/go/pkg/cs/drkey/export_test.go @@ -0,0 +1,36 @@ +// Copyright 2020 ETH Zurich +// +// 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 drkey + +import ( + "time" + + "github.com/scionproto/scion/go/lib/drkey" +) + +func (c *SecretValueStore) SetTimeNowFunction(f func() time.Time) { + c.mutex.Lock() + defer c.mutex.Unlock() + c.timeNowFcn = f + +} + +func (c *SecretValueStore) CleanExpired() { + c.cleanExpired() +} + +func (c *SecretValueStore) Cache() map[int64]drkey.SV { + return c.cache +} diff --git a/go/pkg/cs/drkey/grpc/BUILD.bazel b/go/pkg/cs/drkey/grpc/BUILD.bazel new file mode 100644 index 0000000000..72fd3cd343 --- /dev/null +++ b/go/pkg/cs/drkey/grpc/BUILD.bazel @@ -0,0 +1,61 @@ +load("//lint:go.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "drkey_fetcher.go", + "drkey_service.go", + ], + importpath = "github.com/scionproto/scion/go/pkg/cs/drkey/grpc", + visibility = ["//visibility:public"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/common:go_default_library", + "//go/lib/ctrl/drkey:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/drkey/exchange:go_default_library", + "//go/lib/drkey/protocol:go_default_library", + "//go/lib/drkeystorage:go_default_library", + "//go/lib/log:go_default_library", + "//go/lib/serrors:go_default_library", + "//go/lib/snet:go_default_library", + "//go/pkg/cs/drkey:go_default_library", + "//go/pkg/grpc:go_default_library", + "//go/pkg/proto/control_plane:go_default_library", + "//go/pkg/proto/drkey:go_default_library", + "@org_golang_google_grpc//peer:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = [ + "drkey_fetcher_test.go", + "drkey_service_test.go", + "export_test.go", + "lvl1_exchange_test.go", + ], + data = glob(["testdata/**"]), + embed = [":go_default_library"], + deps = [ + "//go/lib/ctrl/drkey:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/drkeystorage/mock_drkeystorage:go_default_library", + "//go/lib/scrypto/cppki:go_default_library", + "//go/lib/util:go_default_library", + "//go/lib/xtest:go_default_library", + "//go/pkg/cs/drkey/grpc/mock_grpc:go_default_library", + "//go/pkg/cs/drkey/test:go_default_library", + "//go/pkg/proto/control_plane:go_default_library", + "//go/pkg/proto/drkey:go_default_library", + "//go/pkg/trust:go_default_library", + "//go/pkg/trust/mock_trust:go_default_library", + "@com_github_golang_mock//gomock:go_default_library", + "@com_github_golang_protobuf//ptypes:go_default_library_gen", + "@com_github_stretchr_testify//assert:go_default_library", + "@com_github_stretchr_testify//require:go_default_library", + "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//credentials:go_default_library", + "@org_golang_google_grpc//test/bufconn:go_default_library", + ], +) diff --git a/go/pkg/cs/drkey/grpc/drkey_fetcher.go b/go/pkg/cs/drkey/grpc/drkey_fetcher.go new file mode 100644 index 0000000000..03a04acab7 --- /dev/null +++ b/go/pkg/cs/drkey/grpc/drkey_fetcher.go @@ -0,0 +1,102 @@ +// Copyright 2020 ETH Zurich +// +// 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 grpc + +import ( + "context" + "time" + + "github.com/scionproto/scion/go/lib/addr" + ctrl "github.com/scionproto/scion/go/lib/ctrl/drkey" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/log" + "github.com/scionproto/scion/go/lib/serrors" + "github.com/scionproto/scion/go/lib/snet" + csdrkey "github.com/scionproto/scion/go/pkg/cs/drkey" + sc_grpc "github.com/scionproto/scion/go/pkg/grpc" + cppb "github.com/scionproto/scion/go/pkg/proto/control_plane" + dkpb "github.com/scionproto/scion/go/pkg/proto/drkey" +) + +type Lvl1KeyGetter interface { + GetLvl1Key(ctx context.Context, srcIA addr.IA, + req *dkpb.DRKeyLvl1Request) (*dkpb.DRKeyLvl1Response, error) +} + +type Lvl1KeyFetcher struct { + Dialer sc_grpc.Dialer + Router snet.Router +} + +var _ Lvl1KeyGetter = (*Lvl1KeyFetcher)(nil) + +func (f Lvl1KeyFetcher) GetLvl1Key(ctx context.Context, srcIA addr.IA, + req *dkpb.DRKeyLvl1Request) (*dkpb.DRKeyLvl1Response, error) { + logger := log.FromCtx(ctx) + + logger.Info("Resolving server", "srcIA", srcIA.String()) + path, err := f.Router.Route(ctx, srcIA) + if err != nil || path == nil { + return nil, serrors.WrapStr("unable to find path to", err, "IA", srcIA) + } + remote := &snet.SVCAddr{ + IA: srcIA, + Path: path.Path(), + NextHop: path.UnderlayNextHop(), + SVC: addr.SvcCS, + } + conn, err := f.Dialer.Dial(ctx, remote) + if err != nil { + return nil, serrors.WrapStr("dialing", err) + } + defer conn.Close() + client := cppb.NewDRKeyLvl1ServiceClient(conn) + rep, err := client.DRKeyLvl1(ctx, req) + if err != nil { + return nil, serrors.WrapStr("requesting level 1 key", err) + } + return rep, nil +} + +// DRKeyFetcher obtains Lvl1 DRKey from a remote CS. +type DRKeyFetcher struct { + Getter Lvl1KeyGetter +} + +var _ csdrkey.Fetcher = (*DRKeyFetcher)(nil) + +// GetLvl1FromOtherCS queries a CS for a level 1 key. +func (f DRKeyFetcher) GetLvl1FromOtherCS(ctx context.Context, + srcIA, dstIA addr.IA, valTime time.Time) (drkey.Lvl1Key, error) { + + lvl1req := ctrl.NewLvl1Req(valTime) + req, err := ctrl.Lvl1reqToProtoRequest(lvl1req) + if err != nil { + return drkey.Lvl1Key{}, + serrors.WrapStr("parsing lvl1 request to protobuf", err) + } + + rep, err := f.Getter.GetLvl1Key(ctx, srcIA, req) + if err != nil { + return drkey.Lvl1Key{}, err + } + + lvl1Key, err := ctrl.GetLvl1KeyFromReply(srcIA, dstIA, rep) + if err != nil { + return drkey.Lvl1Key{}, serrors.WrapStr("obtaining level 1 key from reply", err) + } + + return lvl1Key, nil +} diff --git a/go/pkg/cs/drkey/grpc/drkey_fetcher_test.go b/go/pkg/cs/drkey/grpc/drkey_fetcher_test.go new file mode 100644 index 0000000000..691dc14e6c --- /dev/null +++ b/go/pkg/cs/drkey/grpc/drkey_fetcher_test.go @@ -0,0 +1,79 @@ +// Copyright 2021 ETH Zurich +// +// 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 grpc_test + +import ( + "context" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/golang/protobuf/ptypes" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/scionproto/scion/go/lib/util" + "github.com/scionproto/scion/go/lib/xtest" + dk_grpc "github.com/scionproto/scion/go/pkg/cs/drkey/grpc" + mock_grpc "github.com/scionproto/scion/go/pkg/cs/drkey/grpc/mock_grpc" + dkpb "github.com/scionproto/scion/go/pkg/proto/drkey" +) + +func TestGetLvl1FromOtherCS(t *testing.T) { + srcIA := xtest.MustParseIA("1-ff00:0:111") + dstIA := xtest.MustParseIA("1-ff00:0:112") + epochBegin, err := ptypes.TimestampProto(util.SecsToTime(0)) + require.NoError(t, err) + epochEnd, err := ptypes.TimestampProto(util.SecsToTime(1)) + require.NoError(t, err) + key := xtest.MustParseHexString("7f8e507aecf38c09e4cb10a0ff0cc497") + + testCases := map[string]struct { + req *dkpb.DRKeyLvl1Request + rep *dkpb.DRKeyLvl1Response + getter func(ctrl *gomock.Controller) dk_grpc.Lvl1KeyGetter + assertErr assert.ErrorAssertionFunc + }{ + "valid": { + getter: func(ctrl *gomock.Controller) dk_grpc.Lvl1KeyGetter { + rep := &dkpb.DRKeyLvl1Response{ + EpochBegin: epochBegin, + EpochEnd: epochEnd, + Drkey: key, + } + getter := mock_grpc.NewMockLvl1KeyGetter(ctrl) + getter.EXPECT().GetLvl1Key(gomock.Any(), gomock.Eq(srcIA), + gomock.Any()).Return(rep, nil) + return getter + }, + assertErr: assert.NoError, + }, + } + + for name, tc := range testCases { + name, tc := name, tc + t.Run(name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + fetcher := dk_grpc.DRKeyFetcher{ + Getter: tc.getter(ctrl), + } + + _, err := fetcher.GetLvl1FromOtherCS(context.Background(), srcIA, dstIA, time.Now()) + tc.assertErr(t, err) + }) + } +} diff --git a/go/pkg/cs/drkey/grpc/drkey_service.go b/go/pkg/cs/drkey/grpc/drkey_service.go new file mode 100644 index 0000000000..0c78a8b281 --- /dev/null +++ b/go/pkg/cs/drkey/grpc/drkey_service.go @@ -0,0 +1,232 @@ +// Copyright 2020 ETH Zurich +// +// 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 grpc + +import ( + "context" + "net" + + "google.golang.org/grpc/peer" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/common" + ctrl "github.com/scionproto/scion/go/lib/ctrl/drkey" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/drkey/exchange" + "github.com/scionproto/scion/go/lib/drkey/protocol" + "github.com/scionproto/scion/go/lib/drkeystorage" + "github.com/scionproto/scion/go/lib/log" + "github.com/scionproto/scion/go/lib/serrors" + cppb "github.com/scionproto/scion/go/pkg/proto/control_plane" + dkpb "github.com/scionproto/scion/go/pkg/proto/drkey" +) + +// DRKeyServer keeps track of the level 1 drkey keys. It is backed by a drkey.DB . +type DRKeyServer struct { + LocalIA addr.IA + Store drkeystorage.ServiceStore + // AllowedDSs is a set of protocols per IP address (in 16 byte form). Represents the allowed + // protocols hosts can obtain delegation secrets for. + AllowedDSs map[[16]byte]map[string]struct{} +} + +var _ cppb.DRKeyLvl1ServiceServer = &DRKeyServer{} +var _ cppb.DRKeyLvl2ServiceServer = &DRKeyServer{} + +// DRKeyLvl1 handle a level 1 request and returns a level 1 response. +func (d *DRKeyServer) DRKeyLvl1(ctx context.Context, + req *dkpb.DRKeyLvl1Request) (*dkpb.DRKeyLvl1Response, error) { + logger := log.FromCtx(ctx) + peer, ok := peer.FromContext(ctx) + if !ok { + logger.Error("[DRKey gRPC server] Cannot retrieve peer from ctx") + return nil, serrors.New("retrieving peer information from ctx") + } + parsedReq, err := ctrl.RequestToLvl1Req(req) + if err != nil { + logger.Error("[DRKey gRPC server] Invalid DRKey Lvl1 request", + "peer", peer, "err", err) + return nil, err + } + + dstIA, err := exchange.ExtractIAFromPeer(peer) + if err != nil { + logger.Error("[DRKey gRPC server] Error retrieving auth info from certicate", + "err", err) + return nil, serrors.WrapStr("retrieving info from certficate", err) + } + + logger.Debug("[DRKey gRPC server] Received Lvl1 request", + "lvl1_req", parsedReq, "peer", peer.Addr.String(), "IA from cert", dstIA.String()) + lvl1Key, err := d.Store.DeriveLvl1(dstIA, parsedReq.ValTime) + if err != nil { + logger.Error("Error deriving level 1 key", "err", err) + return nil, err + } + resp, err := ctrl.KeyToLvl1Resp(lvl1Key) + if err != nil { + logger.Error("[DRKey gRPC server] Error parsing DRKey Lvl1 to protobuf resp", "err", err) + return nil, err + } + return resp, nil +} + +// DRKeyLvl2 handles a level 2 drkey request and returns a level 2 response. +func (d *DRKeyServer) DRKeyLvl2(ctx context.Context, + req *cppb.DRKeyLvl2Request) (*cppb.DRKeyLvl2Response, error) { + logger := log.FromCtx(ctx) + peer, ok := peer.FromContext(ctx) + if !ok { + logger.Error("[DRKey gRPC server] Cannot retrieve peer from ctx") + return nil, serrors.New("retrieving peer information from ctx") + } + + parsedReq, err := requestToLvl2Req(req) + if err != nil { + logger.Error("[DRKey gRPC server] Invalid DRKey Lvl2 request", + "peer", peer, "err", err) + return nil, err + } + if err := d.validateLvl2Req(parsedReq, peer.Addr); err != nil { + log.Error("[DRKey gRPC server] Error validating Lvl2 request", + "err", err) + return nil, err + } + + srcIA := parsedReq.SrcIA + dstIA := parsedReq.DstIA + logger.Debug(" [DRKey gRPC server] Received lvl2 request", + "Type", parsedReq.ReqType, "protocol", parsedReq.Protocol, + "SrcIA", srcIA, "DstIA", dstIA) + lvl1Meta := drkey.Lvl1Meta{ + SrcIA: srcIA, + DstIA: dstIA, + } + lvl1Key, err := d.Store.GetLvl1Key(ctx, lvl1Meta, parsedReq.ValTime) + if err != nil { + logger.Error("[DRKey gRPC server] Error getting the level 1 key", + "err", err) + return nil, err + } + lvl2Meta := drkey.Lvl2Meta{ + Epoch: lvl1Key.Epoch, + SrcIA: srcIA, + DstIA: dstIA, + KeyType: drkey.Lvl2KeyType(parsedReq.ReqType), + Protocol: parsedReq.Protocol, + SrcHost: parsedReq.SrcHost.ToHostAddr(), + DstHost: parsedReq.DstHost.ToHostAddr(), + } + + lvl2Key, err := deriveLvl2(lvl2Meta, lvl1Key) + if err != nil { + logger.Error("[DRKey gRPC server] Error deriving level 2 key", + "err", err) + return nil, err + } + + resp, err := keyToLvl2Resp(lvl2Key) + if err != nil { + logger.Debug("[DRKey gRPC server] Error parsing DRKey Lvl2 to protobuf resp", + "err", err) + return nil, err + } + return resp, nil +} + +func requestToLvl2Req(req *cppb.DRKeyLvl2Request) (ctrl.Lvl2Req, error) { + return ctrl.RequestToLvl2Req(req.BaseReq) +} + +func keyToLvl2Resp(drkey drkey.Lvl2Key) (*cppb.DRKeyLvl2Response, error) { + baseRep, err := ctrl.KeyToLvl2Resp(drkey) + if err != nil { + return nil, err + } + return &cppb.DRKeyLvl2Response{ + BaseRep: baseRep, + }, nil +} + +// deriveLvl2 will derive the level 2 key specified by the meta data and the level 1 key. +func deriveLvl2(meta drkey.Lvl2Meta, lvl1Key drkey.Lvl1Key) ( + drkey.Lvl2Key, error) { + + der, found := protocol.KnownDerivations[meta.Protocol] + if !found { + return drkey.Lvl2Key{}, serrors.New("no derivation found for protocol", + "protocol", meta.Protocol) + } + return der.DeriveLvl2(meta, lvl1Key) +} + +// validateLvl2Req checks that the requester is in the destination of the key +// if AS2Host or host2host, and checks that the requester is authorized as to +// get a DS if AS2AS (AS2AS == DS). +func (d *DRKeyServer) validateLvl2Req(req ctrl.Lvl2Req, peerAddr net.Addr) error { + tcpAddr, ok := peerAddr.(*net.TCPAddr) + if !ok { + return serrors.New("invalid peer address type, expected *net.TCPAddr", + "peer", peerAddr, "type", common.TypeOf(peerAddr)) + } + localAddr := addr.HostFromIP(tcpAddr.IP) + + if req.SrcIA != d.LocalIA && req.DstIA != d.LocalIA { + return serrors.New("invalid request, localIA not found in request", + "localIA", d.LocalIA, "srcIA", req.SrcIA, "dstIA", req.DstIA) + } + + switch drkey.Lvl2KeyType(req.ReqType) { + case drkey.Host2Host: + if req.SrcIA == d.LocalIA { + if localAddr.Equal(req.SrcHost.ToHostAddr()) { + break + } + } + fallthrough + case drkey.AS2Host: + if req.DstIA == d.LocalIA { + if localAddr.Equal(req.DstHost.ToHostAddr()) { + break + } + } + fallthrough + case drkey.AS2AS: + // check in the allowed endhosts list + var rawIP [16]byte + copy(rawIP[:], localAddr.IP().To16()) + protocolSet, foundSet := d.AllowedDSs[rawIP] + if foundSet { + if _, found := protocolSet[req.Protocol]; found { + log.Debug("Authorized delegated secret", + "reqType", req.ReqType, + "requester address", localAddr, + "srcHost", req.SrcHost.ToHostAddr().String(), + "dstHost", req.DstHost.ToHostAddr().String(), + ) + return nil + } + } + return serrors.New("endhost not allowed for DRKey request", + "reqType", req.ReqType, + "endhost address", localAddr, + "srcHost", req.SrcHost.ToHostAddr().String(), + "dstHost", req.DstHost.ToHostAddr().String(), + ) + default: + return serrors.New("unknown request type", "reqType", req.ReqType) + } + return nil +} diff --git a/go/pkg/cs/drkey/grpc/drkey_service_test.go b/go/pkg/cs/drkey/grpc/drkey_service_test.go new file mode 100644 index 0000000000..4a9663b8ff --- /dev/null +++ b/go/pkg/cs/drkey/grpc/drkey_service_test.go @@ -0,0 +1,36 @@ +// Copyright 2020 ETH Zurich +// +// 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 grpc_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/scionproto/scion/go/lib/xtest" + dk_grpc "github.com/scionproto/scion/go/pkg/cs/drkey/grpc" + "github.com/scionproto/scion/go/pkg/cs/drkey/test" +) + +func TestDeriveLvl2Key(t *testing.T) { + + expectedKey := xtest.MustParseHexString("b90ceff1586e5b5cc3313445df18f271") + + meta, lvl1Key := test.GetInputToDeriveLvl2Key(t) + + lvl2Key, err := dk_grpc.DeriveLvl2(meta, lvl1Key) + require.NoError(t, err) + require.EqualValues(t, expectedKey, lvl2Key.Key) +} diff --git a/go/pkg/cs/drkey/grpc/export_test.go b/go/pkg/cs/drkey/grpc/export_test.go new file mode 100644 index 0000000000..5e4f68b1fd --- /dev/null +++ b/go/pkg/cs/drkey/grpc/export_test.go @@ -0,0 +1,19 @@ +// Copyright 2020 ETH Zurich +// +// 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 grpc + +var ( + DeriveLvl2 = deriveLvl2 +) diff --git a/go/pkg/cs/drkey/grpc/lvl1_exchange_test.go b/go/pkg/cs/drkey/grpc/lvl1_exchange_test.go new file mode 100644 index 0000000000..1b43b5df54 --- /dev/null +++ b/go/pkg/cs/drkey/grpc/lvl1_exchange_test.go @@ -0,0 +1,199 @@ +// Copyright 2020 ETH Zurich +// +// 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 grpc_test + +import ( + "context" + "crypto/tls" + "log" + "net" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/test/bufconn" + + pb_ctrl "github.com/scionproto/scion/go/lib/ctrl/drkey" + "github.com/scionproto/scion/go/lib/drkey" + mock_st "github.com/scionproto/scion/go/lib/drkeystorage/mock_drkeystorage" + "github.com/scionproto/scion/go/lib/scrypto/cppki" + "github.com/scionproto/scion/go/lib/xtest" + dk_grpc "github.com/scionproto/scion/go/pkg/cs/drkey/grpc" + cppb "github.com/scionproto/scion/go/pkg/proto/control_plane" + "github.com/scionproto/scion/go/pkg/trust" + "github.com/scionproto/scion/go/pkg/trust/mock_trust" +) + +func dialer(creds credentials.TransportCredentials, + drkeyServer cppb.DRKeyLvl1ServiceServer) func(context.Context, string) (net.Conn, error) { + bufsize := 1024 * 1024 + listener := bufconn.Listen(bufsize) + + server := grpc.NewServer(grpc.Creds(creds)) + + cppb.RegisterDRKeyLvl1ServiceServer(server, drkeyServer) + + go func() { + if err := server.Serve(listener); err != nil { + log.Fatal(err) + } + }() + + return func(context.Context, string) (net.Conn, error) { + return listener.Dial() + } +} + +func TestLvl1KeyFetching(t *testing.T) { + trc := xtest.LoadTRC(t, "testdata/common/trcs/ISD1-B1-S1.trc") + crt111File := "testdata/common/ISD1/ASff00_0_111/crypto/as/ISD1-ASff00_0_111.pem" + key111File := "testdata/common/ISD1/ASff00_0_111/crypto/as/cp-as.key" + tlsCert, err := tls.LoadX509KeyPair(crt111File, key111File) + require.NoError(t, err) + chain, err := cppki.ReadPEMCerts(crt111File) + _ = chain + require.NoError(t, err) + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + lvl1db := mock_st.NewMockServiceStore(ctrl) + lvl1db.EXPECT().DeriveLvl1(gomock.Any(), gomock.Any()).Return(drkey.Lvl1Key{}, nil) + + mgrdb := mock_trust.NewMockDB(ctrl) + mgrdb.EXPECT().SignedTRC(gomock.Any(), gomock.Any()).AnyTimes().Return(trc, nil) + loader := mock_trust.NewMockX509KeyPairLoader(ctrl) + loader.EXPECT().LoadX509KeyPair().AnyTimes().Return(&tlsCert, nil) + mgr := trust.NewTLSCryptoManager(loader, mgrdb) + + drkeyServ := &dk_grpc.DRKeyServer{ + Store: lvl1db, + } + + serverConf := &tls.Config{ + InsecureSkipVerify: true, + GetCertificate: mgr.GetCertificate, + VerifyPeerCertificate: mgr.VerifyPeerCertificate, + ClientAuth: tls.RequireAnyClientCert, + } + serverCreds := credentials.NewTLS(serverConf) + + clientConf := &tls.Config{ + InsecureSkipVerify: true, + GetClientCertificate: mgr.GetClientCertificate, + VerifyPeerCertificate: mgr.VerifyPeerCertificate, + } + clientCreds := trust.NewClientCredentials(clientConf) + + conn, err := grpc.DialContext(context.Background(), + "1-ff00:0:111,127.0.0.1:10000", + grpc.WithTransportCredentials(clientCreds), + grpc.WithContextDialer(dialer(serverCreds, drkeyServ)), + ) + require.NoError(t, err) + defer conn.Close() + + client := cppb.NewDRKeyLvl1ServiceClient(conn) + + lvl1req := pb_ctrl.NewLvl1Req(time.Now()) + req, err := pb_ctrl.Lvl1reqToProtoRequest(lvl1req) + require.NoError(t, err) + _, err = client.DRKeyLvl1(context.Background(), req) + require.NoError(t, err) +} + +// XXX(JordiSubira) TestLvl1KeyFetching below checks correct Lvl1 key exchange as from Go1.15 +// which introduces VerifyConnection callback to access TLS state during handshake. + +// func TestLvl1KeyFetching(t *testing.T) { +// trc := xtest.LoadTRC(t, "testdata/common/trcs/ISD1-B1-S1.trc") +// crt111File := "testdata/common/ISD1/ASff00_0_111/crypto/as/ISD1-ASff00_0_111.pem" +// key111File := "testdata/common/ISD1/ASff00_0_111/crypto/as/cp-as.key" +// tlsCert, err := tls.LoadX509KeyPair(crt111File, key111File) +// require.NoError(t, err) +// chain, err := cppki.ReadPEMCerts(crt111File) +// _ = chain +// require.NoError(t, err) +// ia111 := xtest.MustParseIA("1-ff00:0:111") + +// ctrl := gomock.NewController(t) +// defer ctrl.Finish() + +// lvl1db := mock_st.NewMockServiceStore(ctrl) +// lvl1db.EXPECT().DeriveLvl1(gomock.Any(), gomock.Any()).Return(drkey.Lvl1Key{}, nil) + +// mgrdb := mock_trust.NewMockDB(ctrl) +// mgrdb.EXPECT().SignedTRC(gomock.Any(), gomock.Any()).AnyTimes().Return(trc, nil) +// loader := mock_trust.NewMockX509KeyPairLoader(ctrl) +// loader.EXPECT().LoadX509KeyPair().AnyTimes().Return(&tlsCert, nil) +// mgr := trust.NewTLSCryptoManager(loader, mgrdb) + +// drkeyServ := &DRKeyServer{ +// Store: lvl1db, +// } + +// serverConf := &tls.Config{ +// InsecureSkipVerify: true, +// GetCertificate: mgr.GetCertificate, +// VerifyPeerCertificate: mgr.VerifyPeerCertificate, +// ClientAuth: tls.RequireAnyClientCert, +// } +// serverCreds := credentials.NewTLS(serverConf) +// clientConf := &tls.Config{ +// InsecureSkipVerify: true, +// GetClientCertificate: mgr.GetClientCertificate, +// VerifyPeerCertificate: mgr.VerifyPeerCertificate, +// VerifyConnection: verifyConnection, +// } +// clientCreds := credentials.NewTLS(clientConf) + +// conn, err := grpc.DialContext(context.Background(), +// "1-ff00:0:112", +// grpc.WithTransportCredentials(clientCreds), +// grpc.WithContextDialer(dialer(serverCreds, drkeyServ)), +// ) +// // conn, err := grpc.DialContext(context.Background(), "", +// // grpc.WithInsecure(), +// // grpc.WithContextDialer(dialer(serverCreds, drkeyServ))) +// require.NoError(t, err) +// defer conn.Close() + +// client := cppb.NewDRKeyLvl1ServiceClient(conn) + +// lvl1req := pb_ctrl.NewLvl1Req(ia111, time.Now()) +// req, err := lvl1reqToProtoRequest(lvl1req) +// require.NoError(t, err) +// _, err = client.DRKeyLvl1(context.Background(), req) +// require.NoError(t, err) +// } + +// func verifyConnection(cs tls.ConnectionState) error { +// serverIA, err := addr.IAFromString(cs.ServerName) +// if err != nil { +// return serrors.WrapStr("extracting IA from server name", err) +// } +// certIA, err := cppki.ExtractIA(cs.PeerCertificates[0].Subject) +// if err != nil { +// return serrors.WrapStr("extracting IA from peer cert", err) +// } +// if !serverIA.Equal(*certIA) { +// return serrors.New("extracted IA from cert and server IA do not match", +// "peer IA", certIA, "server IA", serverIA) +// } +// return nil +// } diff --git a/go/pkg/cs/drkey/grpc/mock_grpc/BUILD.bazel b/go/pkg/cs/drkey/grpc/mock_grpc/BUILD.bazel new file mode 100644 index 0000000000..4212f8ef2f --- /dev/null +++ b/go/pkg/cs/drkey/grpc/mock_grpc/BUILD.bazel @@ -0,0 +1,22 @@ +load("//lint:go.bzl", "go_library") +load("@com_github_jmhodges_bazel_gomock//:gomock.bzl", "gomock") + +gomock( + name = "go_default_mock", + out = "mock.go", + interfaces = ["Lvl1KeyGetter"], + library = "//go/pkg/cs/drkey/grpc:go_default_library", + package = "mock_grpc", +) + +go_library( + name = "go_default_library", + srcs = ["mock.go"], + importpath = "github.com/scionproto/scion/go/pkg/cs/drkey/grpc/mock_grpc", + visibility = ["//visibility:public"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/pkg/proto/drkey:go_default_library", + "@com_github_golang_mock//gomock:go_default_library", + ], +) diff --git a/go/pkg/cs/drkey/grpc/mock_grpc/mock.go b/go/pkg/cs/drkey/grpc/mock_grpc/mock.go new file mode 100644 index 0000000000..5f5bca8e58 --- /dev/null +++ b/go/pkg/cs/drkey/grpc/mock_grpc/mock.go @@ -0,0 +1,52 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/scionproto/scion/go/pkg/cs/drkey/grpc (interfaces: Lvl1KeyGetter) + +// Package mock_grpc is a generated GoMock package. +package mock_grpc + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + addr "github.com/scionproto/scion/go/lib/addr" + drkey "github.com/scionproto/scion/go/pkg/proto/drkey" +) + +// MockLvl1KeyGetter is a mock of Lvl1KeyGetter interface. +type MockLvl1KeyGetter struct { + ctrl *gomock.Controller + recorder *MockLvl1KeyGetterMockRecorder +} + +// MockLvl1KeyGetterMockRecorder is the mock recorder for MockLvl1KeyGetter. +type MockLvl1KeyGetterMockRecorder struct { + mock *MockLvl1KeyGetter +} + +// NewMockLvl1KeyGetter creates a new mock instance. +func NewMockLvl1KeyGetter(ctrl *gomock.Controller) *MockLvl1KeyGetter { + mock := &MockLvl1KeyGetter{ctrl: ctrl} + mock.recorder = &MockLvl1KeyGetterMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockLvl1KeyGetter) EXPECT() *MockLvl1KeyGetterMockRecorder { + return m.recorder +} + +// GetLvl1Key mocks base method. +func (m *MockLvl1KeyGetter) GetLvl1Key(arg0 context.Context, arg1 addr.IA, arg2 *drkey.DRKeyLvl1Request) (*drkey.DRKeyLvl1Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLvl1Key", arg0, arg1, arg2) + ret0, _ := ret[0].(*drkey.DRKeyLvl1Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLvl1Key indicates an expected call of GetLvl1Key. +func (mr *MockLvl1KeyGetterMockRecorder) GetLvl1Key(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLvl1Key", reflect.TypeOf((*MockLvl1KeyGetter)(nil).GetLvl1Key), arg0, arg1, arg2) +} diff --git a/go/pkg/cs/drkey/grpc/testdata/ISD1-B1-S1.trc b/go/pkg/cs/drkey/grpc/testdata/ISD1-B1-S1.trc new file mode 100644 index 0000000000000000000000000000000000000000..17d98dafdc49ef594377a55435bbba312e48b3ba GIT binary patch literal 8935 zcmds-3piA11IK61j2YvSFbr9lVOr%<=ZsrO3AtqDepy0;abNc~muw9?ZV8EUT@xvv zkfIyf)Q((IE?Y}7eFuz@ z9l+oe;*8_Q1(8^Q86$fYjFD{zkVr@n8X}o7gahapLOxub z4ImL94!+|32b7f%qJR_-RHdkZ8W5~yFp+%jtaZs58ifYw7a@KShe6q*F`|IJF(d*m zo;u(az&ZXBd!a7G$KCs59d>%17$`c`j!!@UQvTF4NDd@TRr3ohnO;pa3GfWGrnwWX zgSS#WAXShu)d(e^IHQrVkC!(QZnZVUCoFRoK8C*&boFNB%NSUV2m($U2;U|xMryqd)AS4QjMd=~Xlxw|vAEYE?l{!@p z?+0k;H)q3zYv`kPE-EGaRe2|iy%=Ulxdzl?9ev^Drct~Nz_MLyeXCt&ICXj%S`s8o6AXpI@WSfx@L*BA(+NbGAV5Qags3f79^0N&Ug^>6P&1$q zWRR6}{&AXEj!u25O`D0h-f6f=X_O>pSH1n1b$Ir5ll9M1HmDWFp)Q~5ur6FZt`hO4 z2Il?}T!KHa?;)Qj#K%({uR6KqnCa=^PU{MuxaoHW=@;gYeG15teF`{>eGps;KOLBT z`A_V_jjU*1Tm7jaM7zK+p8&5pa}N{$hunV&o#f7Z)6M>b=Apw!L9zA(hr%YpKr{R4 z6R>|RF4PY|;5(PNkX?_JWG=l_mfl~q$V*es;btf+xj^oIVDPF?OZ~c^iuA$t(|GQm z^r%IctyPe#-$LV_6t8PgyJOf;KHb#IO0HRsL_><^3Y~p4DBi&MqIdmT3J94D3 z^_vp0@^exV)+I2`%)lEH2h_*fuFELy*~b`bG`Uwn?L4;IBS-vRO4HtpXJM4P;1c}- zXRSu!zh1u-Pbbv zyAk@OW%Rn#vs6EceU;`#9i@jXJ(ina1BmjMLzdWFu^r6~FpF2X`PPE325a1PW4H^aCl?zvnJ`#RY|v2nN3>Vv=n^yrmrfbtU1GI1x3|z)VtCM z5LzKj?JZ6mD4@q@`dPKSQ9d@wXVkj*Ytz=h5K`8tZ}+}^2B8_#EmCb*7bY%*v0`x{ zpIbaqFmPy5wEFh=%0Cwrpz1P4X& zybg~!yqfWHG3{W~YC|h5bqr!JyBQjd8!zn%WxNnyzFC*hbhvSrk4wC?lcH7xPNWZ4 z9mHMRB*q>u`<4sM+#zA+9v@b zjVDoL8@0K7O_)Z(Hsh`!3?)meaPw2#o(rcdve|>1V3MaN6bU`@nUZ+JwTRk7PS#R) zANC2ae>;=rc^tOqDm15r0@FOx$NywPnG4fjPFJ~;edXEGw%6IBq-{JW%dt$^j2|?I z4n269?Uv}_cg5iCgAUBOaF4R*lO5Nzdo-~xT<&aLDb1^7aL}(|#c|qNpWFwt$Tsp< zqCb$z(_!CV9YBq>7q%prGPsca{}T!|&EP;+?o)MhYlGj&--DG8dv$z!)_ELu_YDGa zn~C}WQTUhY{xDL~d4X_J3R3B|U%=wmG>4n~9iG>FTeMr9++ea>r}?ycQO-GOv2XWg zwm(ic)8ApJo2;{FCfW1o(<+>OT4i=Z;pEeBqrd3WDu1s}|6`rxPV*CGDWUqey90id z9_?@^kDN+*Ad{?}@B*iFD|6&hWa%Ayp|d(ET6x`T3KCw*iiK+^$V5t$jPh!ajyHzfaNTX2LxoxH zhResfq;Wgc!W`D=EK%*=@l37Gl1iproyqe&+SgpA=H%2c&!6SgbD{dn=_+@&Np2=| zOaqOiZ6O?NMxu-+=p|~bQdnluIf`=@d+7IYXAz##HAXEpb*g5LZz||NvElxCDL>mT z`BQ*eFyfaxv)I0PoZ%HaoVs+h>^M-dV?%m|%s1RJ2sfvGw@gAp47625bX;hsOA~&+ zmBvs*SSXTDD^^rBH#qKOvY>5ZaHRI1NE^ZUg}2&?>PCu29%Ju%7=4?Nv+h*&`pR<| zWf4#eKL(6JwoNTm(r?V`qTXCH1}7)}oWu;^IZh0w?^H19iJ-*qTNOAI1fTr4!GQ$7 z`uzaM0|`xA8HYf1N6`G!Su~`F)*WxfJ4X(Zrb}^M-t)YU2gE%(m&yfi{|2{cX2__bwq<*o ztBBT-dOokqO)Lh6YMmCqb6k%8_edHzsDRpw)fLG~NowD;wCc6o*X){W>XMtPb}Mz}|FlyK zmb8nw%Kl@*!Kf43) z9H+ALqU=KZ?|WtYk}d962VIF%wQyYhXmbiRwf4vg<1F(nrk)vQg)*^9u(CG}Au0VV zw&ms&e&U__#NA&@nOEzby_#<>@Z?5AsAMy&?6n0@cCH4@Nm+QK?6cA!1qARMw^9BT z%1(`}Bt(la#_FJh0m5^`iQKg&enZA5H~2)j8!?0uF!GknTaExR#C5Q=STJ7W$2O^# zj>_ue5jppxn9uHatYOBc+KOnNSRi5NYQvm_{rs2@|J8xhoMv8xU1&3YFYHdf2^Usc zu%chLWjXdn`g()92`t-9=ZL-yxh;Ir{>K1O`-mR8D@x7RCU^6`hwijhjz7yeUNYC% NZ{RBFi3uE&J8KD1!d64xP z$cgi!_!G!AM)EfGEsQh}W@88YhlvsDF=j?~W+w)gw|o3sCz^JI>dD;EdHD2&K$+9o zvmdXnI<>t1guEEHa_>a8)zS=I@0GV4jkbvb0ryHai z@BsrymY98k%-KR=#oh%Jj5{@BbR`#V^0L*xA65VEi*7#kHnV zv-(P=LjT%z>#S4QrJjf^y}uDT#9?uLWZBvV*@_8OtfyUXSv!a@R_ZM^eHLc8@vP8; z7D*$G>r4unme&}ggr3FxJNn$?WxbN|hY!_yJCZ)_2+5!3&fx#*0x+K60`VkRT)$m% zL!IO4wksP?T}i&JeD8buLdMs~HX8&R8W|Ws;#w0Wu7gwaiZe?x%Tj3&+cdEhcYMEh z|8CiARi?zJ*?sHo_63tg@+z~RKV*5QyZ?fvlGna%JlFao+-8_9>`yRDH~1U6VykA# zg7k=Em+t*&DgDWDdooe+jhwe9*m2A#ertN>=H=G2epl6FB0Y}_B8NJ&Cxd|-FmHdl zwR;11)kD5j!luofR?3TJ$Zj?G(x)Ufm)X=gRqb;!P|35oQH(!prz?CqsoT^!#hhj7 Ufr2;R6$Msr<^SWm;^lK|0CsZO_5c6? literal 0 HcmV?d00001 diff --git a/go/pkg/cs/drkey/grpc/testdata/common/ISD1/trcs/ISD1-B1-S1.pem.trc b/go/pkg/cs/drkey/grpc/testdata/common/ISD1/trcs/ISD1-B1-S1.pem.trc new file mode 100644 index 0000000000..0f780023aa --- /dev/null +++ b/go/pkg/cs/drkey/grpc/testdata/common/ISD1/trcs/ISD1-B1-S1.pem.trc @@ -0,0 +1,53 @@ +-----BEGIN TRC----- +MIIJaAYJKoZIhvcNAQcCoIIJWTCCCVUCAQExDTALBglghkgBZQMEAgMwggZ3Bgkq +hkiG9w0BBwGgggZoBIIGZDCCBmACAQAwCQIBAQIBAQIBATAiGA8yMDIxMDUxNDEx +MTEwMloYDzIwMjIwODA3MTExMTAyWgIBAAEBADAAAgEBMAwTCmZmMDA6MDoxMTAw +DBMKZmYwMDowOjExMAwYVGVzdGNyeXB0byBUUkMgZm9yIElTRCAxMIIF6TCCAggw +ggGuoAMCAQICFQCRLNVpkmUQP+nD/mE89SOvQtUHDzAKBggqhkjOPQQDAjBPMS4w +LAYDVQQDEyUxLWZmMDA6MDoxMTAgUm9vdCBDZXJ0aWZpY2F0ZSAtIEdFTiBJMR0w +GwYLKwYBBAGDsBwBAgETDDEtZmYwMDowOjExMDAeFw0yMTA1MTQxMTExMDJaFw0y +MzA1MTQxMTExMDJaME8xLjAsBgNVBAMTJTEtZmYwMDowOjExMCBSb290IENlcnRp +ZmljYXRlIC0gR0VOIEkxHTAbBgsrBgEEAYOwHAECARMMMS1mZjAwOjA6MTEwMFkw +EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7bxPhZE1iFUuHNws4eXoEHZCzc3x1arK +p3/IHxYLI42RBqsbAIrvI7TFWtHC+3UcDXREBEVjvYpnfTDbkH+LPqNnMGUwDgYD +VR0PAQH/BAQDAgIEMCAGA1UdJQQZMBcGCCsGAQUFBwMIBgsrBgEEAYOwHAEDAzAS +BgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBRqTPSqZsb5ejvQM6wfqhSw07jm ++zAKBggqhkjOPQQDAgNIADBFAiEAnLdfGlwmE0xUnAhWi+JntkuMcj2xNj+y7m6/ +p5AQL1ACIDElUM0tnVoICqH8ytdUTz2oDYQinfw14ywfzCvN44I+MIIB6DCCAY6g +AwIBAgIVAPYMBnpEh2n7th3XiMWHD6UytVMeMAoGCCqGSM49BAMCMFExMDAuBgNV +BAMTJzEtZmYwMDowOjExMCBSZWd1bGFyIFZvdGluZyBDZXJ0aWZpY2F0ZTEdMBsG +CysGAQQBg7AcAQIBEwwxLWZmMDA6MDoxMTAwHhcNMjEwNTE0MTExMTAyWhcNMjMw +NTE0MTExMTAyWjBRMTAwLgYDVQQDEycxLWZmMDA6MDoxMTAgUmVndWxhciBWb3Rp +bmcgQ2VydGlmaWNhdGUxHTAbBgsrBgEEAYOwHAECARMMMS1mZjAwOjA6MTEwMFkw +EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEic1CLay3bHp6vL/D05gwb+JbPKDecsdG +gLC5qnCYVswq4sE82CT/xGlAvA2jsoCCueMj2NPUl2bh7/0wDl+n2qNDMEEwIAYD +VR0lBBkwFwYIKwYBBQUHAwgGCysGAQQBg7AcAQMCMB0GA1UdDgQWBBQpIoMnqQJx +T32urjtkBxrkFKXfsTAKBggqhkjOPQQDAgNIADBFAiEAxKatgB14kHoFy0XaO0AU +AXkupTXmVjGxzRLghBkyKNcCIGk51gFaEuZc/sXnSOl/IjPw8HsuuGLyuFRvlkcA +T+rQMIIB7TCCAZKgAwIBAgIVAO2k2CcI5bbUscrUY9sj3vdnoQHrMAoGCCqGSM49 +BAMCMFMxMjAwBgNVBAMTKTEtZmYwMDowOjExMCBTZW5zaXRpdmUgVm90aW5nIENl +cnRpZmljYXRlMR0wGwYLKwYBBAGDsBwBAgETDDEtZmYwMDowOjExMDAeFw0yMTA1 +MTQxMTExMDJaFw0yMzA1MTQxMTExMDJaMFMxMjAwBgNVBAMTKTEtZmYwMDowOjEx +MCBTZW5zaXRpdmUgVm90aW5nIENlcnRpZmljYXRlMR0wGwYLKwYBBAGDsBwBAgET +DDEtZmYwMDowOjExMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABO9H9zmDOnYi +DimL2t23oJMUbnlr5+EE7i2/0DkiSr62DNaPWEaYNqGPYDZnMP1VqLUpZKBnWMbS +3viEdfkI25OjQzBBMCAGA1UdJQQZMBcGCCsGAQUFBwMIBgsrBgEEAYOwHAEDATAd +BgNVHQ4EFgQUkD4ImHPtNczZ04XNTtUnXFlJxxEwCgYIKoZIzj0EAwIDSQAwRgIh +APLau7ALeuEOqhM1gwk6I6KYHbUw9I4iGp0DNUNlJvNjAiEA5p1aAfl9lyDyyS2C +iZQ3BKXAcOz3IRCrtQ/8Tajp5zsxggLEMIIBXQIBATBqMFExMDAuBgNVBAMTJzEt +ZmYwMDowOjExMCBSZWd1bGFyIFZvdGluZyBDZXJ0aWZpY2F0ZTEdMBsGCysGAQQB +g7AcAQIBEwwxLWZmMDA6MDoxMTACFQD2DAZ6RIdp+7Yd14jFhw+lMrVTHjALBglg +hkgBZQMEAgOggYkwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0B +CQUxDxcNMjEwNTE0MTExMTAyWjBPBgkqhkiG9w0BCQQxQgRA0MzHJIKYkhuhKj+b +0nbrZ7wxF7Hq3fKxWtKTnxsIHlvXReBy92xQhnwhFSBVbBv7YDsZfyCuUwS8TKqH +eyqYODAKBggqhkjOPQQDBARHMEUCIDhfrlcZ0PFFO0dcizjXKBuGWDOnJkrGYic9 +PX2zg83YAiEAwDDXH0n9d32CDs2v12SzhUfDkCynQncHhciFpyMkaTwwggFfAgEB +MGwwUzEyMDAGA1UEAxMpMS1mZjAwOjA6MTEwIFNlbnNpdGl2ZSBWb3RpbmcgQ2Vy +dGlmaWNhdGUxHTAbBgsrBgEEAYOwHAECARMMMS1mZjAwOjA6MTEwAhUA7aTYJwjl +ttSxytRj2yPe92ehAeswCwYJYIZIAWUDBAIDoIGJMBgGCSqGSIb3DQEJAzELBgkq +hkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTIxMDUxNDExMTEwMlowTwYJKoZIhvcN +AQkEMUIEQNDMxySCmJIboSo/m9J262e8MRex6t3ysVrSk58bCB5b10XgcvdsUIZ8 +IRUgVWwb+2A7GX8grlMEvEyqh3sqmDgwCgYIKoZIzj0EAwQERzBFAiB3H5oV5uQU +ySfVYGfQnXCskpgRptxuWzd2lnaJt3cNPQIhAPZfl1e05VMLIsH/QV3WednSs0n7 +giJ0TJNuJUdxPLUL +-----END TRC----- diff --git a/go/pkg/cs/drkey/grpc/testdata/common/ISD1/trcs/ISD1-B1-S1.trc b/go/pkg/cs/drkey/grpc/testdata/common/ISD1/trcs/ISD1-B1-S1.trc new file mode 100644 index 0000000000000000000000000000000000000000..fd2affc33403373456849d56aceecceedb4cf148 GIT binary patch literal 2412 zcmXqL;>=*<)N1o+`_9YA&a|M3Gt!`mGn9#u(U8}Gn~gJ}&4V$OnT3hjpoy&0UCj0_D-4NVMzz`!U9EMR0{VPFmw0P0`_YGMHD zFyIm9N=q{^urja$szv4TNQ9&omn0We7L?>GgakP&q~#YWcm}&D7#cLOzBFiJ;xK4p zT(^LkiIIs(lwqRI)yzq$0`@Nt|4X#_s=VImDm%Xc7aIrAbLVVXn3)Xx4fPCk*qB3E zn1xjhbrF^-1m)+KC^)AUm1L%6CMTApD(EV>yZR}38p;|-vvF&)F|sf=Z;%1{PnZW; zpMjh>FN!~bTw^3}Q{Tc!17S9Huz#2sp&nyqWM_6_V0pX8zjdN%N2s369i4|yUkH>r zojv>U>Z()A>rcpwaVz&uWLquG(Dhz<%h9NdhklpJ@Rqo+xF+xIO0PAzJ)yqaZgILn zssSG`aAf%z8UM2YgNup9Kmo*8Wsx)xXX5~d0xK&!GY3+5Ff$tnfm8^CbZ{830Vz;~ z%7VoBSj1RFvV6X*N;~$m%KC!w8u?Ws8!qp7_8U1ym^~N_T$vOZ=4_9bicu5x37NwY z*8M1bn|DugY$ zC^fw_C$UH&EWac(FC95mP?{QOU?uMK(0SHLcg^;ks;WKv4_}^PkpC#!X2HFp<8BQb zcCIRz5q3uF(LtLVD*umUI_%+Hys4pS=VRp?m#<7ud-(pZ0bl&`TZ^3y90|rh6H;7j zDmAOGWGeKpUAN9Ug)P{n%M^_I1R2xFz*QqyN)h8xcc zJ!p|M(zwo~kZF01F-quJ%)g`0Jzmx;8Gratt+ylT(~gk*Y3>aEuPy-N`7IDng2naQ zB{$SLo^HFc@zj;%+sgO8r!QoDjcl_)u%VHG0VJ+9QQ|r{HLp0cB(p4)2C+>OOL52d zd-v~_%~oYfe45?2?rvW&StPGA`}sqbce?v8SSoq#+s1RPKf-N>*~0z=vvh;Mp)0m( zrYuO0ICkmYkCxJ(9JePE72n8tdx9OujN-SZXKr3@J?nQ>JtorgxFB+I_ zr(3%>a92I#TP1AT%xR^(Xol=ogD-tbQgfM2om165Cj*r{n;XUWvv#_|r<1x(om0$N zmL4d0^IcJ3^;Z5rzAIinw>E5IIs%OFSWw}TMT49RtUIul7s%D$g2qk*33&a-$!rLe zgw>ji1~PCCC#xYpTCHHd3$^TLUn+Z@zQ<5}Q|1+(n&S=C;xHNyfam|0ldfhDMdMf|#O z$qOG{t=(g~Ev{=ww?!B)SMxfSq;6|lySe%74PYQ2Ft{%7`M12biSO+C>nWRC-49RD zS?*NM-g=^Sxw1;84KRS?K>?gYlk5TvVyxM8=mc@O{4CLDPee|tUrk8AFt=dMq#1(C z?&L+AmrX0{++NOW3k>3K@zcY%JPqbnI{4o)_FCo5OPf7^Hz}3)OwLnvFSOap4FC~Y B(LDeF literal 0 HcmV?d00001 diff --git a/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.ca.crt b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.ca.crt new file mode 100644 index 0000000000..28dc78d1ed --- /dev/null +++ b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.ca.crt @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIICDDCCAbKgAwIBAgIVAKGSZvBdy4AH0jdmkgekU8yAGLvfMAoGCCqGSM49BAMC +ME8xLjAsBgNVBAMTJTEtZmYwMDowOjExMCBSb290IENlcnRpZmljYXRlIC0gR0VO +IEkxHTAbBgsrBgEEAYOwHAECARMMMS1mZjAwOjA6MTEwMB4XDTIxMDUxNDExMTEw +MloXDTIzMDQxNDExMTEwMlowVDEzMDEGA1UEAxMqMS1mZjAwOjA6MTEwIENBIENl +cnRpZmljYXRlIC0gR0VOIEkgMjAyMS4xMR0wGwYLKwYBBAGDsBwBAgETDDEtZmYw +MDowOjExMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI7+UCxkCJ5iiNpY9yfr +bfgT35KdoDY1jEiiOW11zCnd9o0ex9ewFI3iidG6c/3F8pgNlazegTger7aU5HmK +IoujZjBkMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud +DgQWBBQzfAQ4HwcgisnaWlxfnw71OocTmDAfBgNVHSMEGDAWgBRqTPSqZsb5ejvQ +M6wfqhSw07jm+zAKBggqhkjOPQQDAgNIADBFAiEAwvzpQrsFmg/qmltZUWdgUI0b +pgR2xV+75Pow4WRwcfcCIHihw7z7ypO96gCfqqXf1l202+I24zCt7rqzdW8Xiv8K +-----END CERTIFICATE----- diff --git a/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.pem b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.pem new file mode 100644 index 0000000000..1a47f77c41 --- /dev/null +++ b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIICFzCCAb2gAwIBAgIVAImCxGILp3cNtkHlxoGoAb2JShXwMAoGCCqGSM49BAMC +MFQxMzAxBgNVBAMTKjEtZmYwMDowOjExMCBDQSBDZXJ0aWZpY2F0ZSAtIEdFTiBJ +IDIwMjEuMTEdMBsGCysGAQQBg7AcAQIBEwwxLWZmMDA6MDoxMTAwHhcNMjEwNTE0 +MTExMTAyWhcNMjIwNTE0MTExMTAyWjBFMSQwIgYDVQQDExsxLWZmMDA6MDoxMTAg +QVMgQ2VydGlmaWNhdGUxHTAbBgsrBgEEAYOwHAECARMMMS1mZjAwOjA6MTEwMFkw +EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOsbRSNsTUZmq5P67xn+Kdq7kRCxxzjQI +9KhdEyTMkunyEqDKC4cFNkZleLIIsAn8mx7ryEN8g1eK3oomfsSXMKN7MHkwDgYD +VR0PAQH/BAQDAgeAMCcGA1UdJQQgMB4GCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYB +BQUHAwgwHQYDVR0OBBYEFFhjcv5ht9ag3Sj17Ees3W3MVlmDMB8GA1UdIwQYMBaA +FDN8BDgfByCKydpaXF+fDvU6hxOYMAoGCCqGSM49BAMCA0gAMEUCIFdQFhswPQJQ +E5sW3g3aH0VpC/52zg893wELpSPJy7gFAiEAjKj8jgjviwswOD4kcY90dvB1sLHt +R1XL4wxfKZDGEpg= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICDDCCAbKgAwIBAgIVAKGSZvBdy4AH0jdmkgekU8yAGLvfMAoGCCqGSM49BAMC +ME8xLjAsBgNVBAMTJTEtZmYwMDowOjExMCBSb290IENlcnRpZmljYXRlIC0gR0VO +IEkxHTAbBgsrBgEEAYOwHAECARMMMS1mZjAwOjA6MTEwMB4XDTIxMDUxNDExMTEw +MloXDTIzMDQxNDExMTEwMlowVDEzMDEGA1UEAxMqMS1mZjAwOjA6MTEwIENBIENl +cnRpZmljYXRlIC0gR0VOIEkgMjAyMS4xMR0wGwYLKwYBBAGDsBwBAgETDDEtZmYw +MDowOjExMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI7+UCxkCJ5iiNpY9yfr +bfgT35KdoDY1jEiiOW11zCnd9o0ex9ewFI3iidG6c/3F8pgNlazegTger7aU5HmK +IoujZjBkMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud +DgQWBBQzfAQ4HwcgisnaWlxfnw71OocTmDAfBgNVHSMEGDAWgBRqTPSqZsb5ejvQ +M6wfqhSw07jm+zAKBggqhkjOPQQDAgNIADBFAiEAwvzpQrsFmg/qmltZUWdgUI0b +pgR2xV+75Pow4WRwcfcCIHihw7z7ypO96gCfqqXf1l202+I24zCt7rqzdW8Xiv8K +-----END CERTIFICATE----- diff --git a/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.regular.crt b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.regular.crt new file mode 100644 index 0000000000..f10832ac7f --- /dev/null +++ b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.regular.crt @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB6DCCAY6gAwIBAgIVAPYMBnpEh2n7th3XiMWHD6UytVMeMAoGCCqGSM49BAMC +MFExMDAuBgNVBAMTJzEtZmYwMDowOjExMCBSZWd1bGFyIFZvdGluZyBDZXJ0aWZp +Y2F0ZTEdMBsGCysGAQQBg7AcAQIBEwwxLWZmMDA6MDoxMTAwHhcNMjEwNTE0MTEx +MTAyWhcNMjMwNTE0MTExMTAyWjBRMTAwLgYDVQQDEycxLWZmMDA6MDoxMTAgUmVn +dWxhciBWb3RpbmcgQ2VydGlmaWNhdGUxHTAbBgsrBgEEAYOwHAECARMMMS1mZjAw +OjA6MTEwMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEic1CLay3bHp6vL/D05gw +b+JbPKDecsdGgLC5qnCYVswq4sE82CT/xGlAvA2jsoCCueMj2NPUl2bh7/0wDl+n +2qNDMEEwIAYDVR0lBBkwFwYIKwYBBQUHAwgGCysGAQQBg7AcAQMCMB0GA1UdDgQW +BBQpIoMnqQJxT32urjtkBxrkFKXfsTAKBggqhkjOPQQDAgNIADBFAiEAxKatgB14 +kHoFy0XaO0AUAXkupTXmVjGxzRLghBkyKNcCIGk51gFaEuZc/sXnSOl/IjPw8Hsu +uGLyuFRvlkcAT+rQ +-----END CERTIFICATE----- diff --git a/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.regular.s2.crt b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.regular.s2.crt new file mode 100644 index 0000000000..1497ad3747 --- /dev/null +++ b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.regular.s2.crt @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB6TCCAY6gAwIBAgIVAPK6hd+6WWnS7scGwJsab43okvlMMAoGCCqGSM49BAMC +MFExMDAuBgNVBAMTJzEtZmYwMDowOjExMCBSZWd1bGFyIFZvdGluZyBDZXJ0aWZp +Y2F0ZTEdMBsGCysGAQQBg7AcAQIBEwwxLWZmMDA6MDoxMTAwHhcNMjEwNTE0MTEx +MTAzWhcNMjMwNTE0MTExMTAzWjBRMTAwLgYDVQQDEycxLWZmMDA6MDoxMTAgUmVn +dWxhciBWb3RpbmcgQ2VydGlmaWNhdGUxHTAbBgsrBgEEAYOwHAECARMMMS1mZjAw +OjA6MTEwMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEic1CLay3bHp6vL/D05gw +b+JbPKDecsdGgLC5qnCYVswq4sE82CT/xGlAvA2jsoCCueMj2NPUl2bh7/0wDl+n +2qNDMEEwIAYDVR0lBBkwFwYIKwYBBQUHAwgGCysGAQQBg7AcAQMCMB0GA1UdDgQW +BBQpIoMnqQJxT32urjtkBxrkFKXfsTAKBggqhkjOPQQDAgNJADBGAiEAgYK2rKJB +0Xn7AoVHW43zCYPmAifY1PUHZRi8J/SAXB8CIQCUw5kGF+FDicw537AI3Ll2gFIT +K1fi9vn6Yx0q0GrpBw== +-----END CERTIFICATE----- diff --git a/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.root.crt b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.root.crt new file mode 100644 index 0000000000..0fae954e3c --- /dev/null +++ b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.root.crt @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIICCDCCAa6gAwIBAgIVAJEs1WmSZRA/6cP+YTz1I69C1QcPMAoGCCqGSM49BAMC +ME8xLjAsBgNVBAMTJTEtZmYwMDowOjExMCBSb290IENlcnRpZmljYXRlIC0gR0VO +IEkxHTAbBgsrBgEEAYOwHAECARMMMS1mZjAwOjA6MTEwMB4XDTIxMDUxNDExMTEw +MloXDTIzMDUxNDExMTEwMlowTzEuMCwGA1UEAxMlMS1mZjAwOjA6MTEwIFJvb3Qg +Q2VydGlmaWNhdGUgLSBHRU4gSTEdMBsGCysGAQQBg7AcAQIBEwwxLWZmMDA6MDox +MTAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATtvE+FkTWIVS4c3Czh5egQdkLN +zfHVqsqnf8gfFgsjjZEGqxsAiu8jtMVa0cL7dRwNdEQERWO9imd9MNuQf4s+o2cw +ZTAOBgNVHQ8BAf8EBAMCAgQwIAYDVR0lBBkwFwYIKwYBBQUHAwgGCysGAQQBg7Ac +AQMDMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFGpM9Kpmxvl6O9AzrB+q +FLDTuOb7MAoGCCqGSM49BAMCA0gAMEUCIQCct18aXCYTTFScCFaL4me2S4xyPbE2 +P7Lubr+nkBAvUAIgMSVQzS2dWggKofzK11RPPagNhCKd/DXjLB/MK83jgj4= +-----END CERTIFICATE----- diff --git a/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.root.s2.crt b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.root.s2.crt new file mode 100644 index 0000000000..0d771a8858 --- /dev/null +++ b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.root.s2.crt @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIICBzCCAa6gAwIBAgIVAJGFoe/aWqewNWxlbNJumZb0IcRTMAoGCCqGSM49BAMC +ME8xLjAsBgNVBAMTJTEtZmYwMDowOjExMCBSb290IENlcnRpZmljYXRlIC0gR0VO +IEkxHTAbBgsrBgEEAYOwHAECARMMMS1mZjAwOjA6MTEwMB4XDTIxMDUxNDExMTEw +M1oXDTIzMDUxNDExMTEwM1owTzEuMCwGA1UEAxMlMS1mZjAwOjA6MTEwIFJvb3Qg +Q2VydGlmaWNhdGUgLSBHRU4gSTEdMBsGCysGAQQBg7AcAQIBEwwxLWZmMDA6MDox +MTAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATtvE+FkTWIVS4c3Czh5egQdkLN +zfHVqsqnf8gfFgsjjZEGqxsAiu8jtMVa0cL7dRwNdEQERWO9imd9MNuQf4s+o2cw +ZTAOBgNVHQ8BAf8EBAMCAgQwIAYDVR0lBBkwFwYIKwYBBQUHAwgGCysGAQQBg7Ac +AQMDMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFGpM9Kpmxvl6O9AzrB+q +FLDTuOb7MAoGCCqGSM49BAMCA0cAMEQCIFFe103ccfsbTHakkBhCsdHI6A+bogTW +XbHWhqfYLLrOAiA5wm/GdRCHxc7J8JKb1GbtejwGnf1ZIP/CQFLO3BYpXg== +-----END CERTIFICATE----- diff --git a/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.sensitive.crt b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.sensitive.crt new file mode 100644 index 0000000000..f730d5458d --- /dev/null +++ b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_110.sensitive.crt @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB7TCCAZKgAwIBAgIVAO2k2CcI5bbUscrUY9sj3vdnoQHrMAoGCCqGSM49BAMC +MFMxMjAwBgNVBAMTKTEtZmYwMDowOjExMCBTZW5zaXRpdmUgVm90aW5nIENlcnRp +ZmljYXRlMR0wGwYLKwYBBAGDsBwBAgETDDEtZmYwMDowOjExMDAeFw0yMTA1MTQx +MTExMDJaFw0yMzA1MTQxMTExMDJaMFMxMjAwBgNVBAMTKTEtZmYwMDowOjExMCBT +ZW5zaXRpdmUgVm90aW5nIENlcnRpZmljYXRlMR0wGwYLKwYBBAGDsBwBAgETDDEt +ZmYwMDowOjExMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABO9H9zmDOnYiDimL +2t23oJMUbnlr5+EE7i2/0DkiSr62DNaPWEaYNqGPYDZnMP1VqLUpZKBnWMbS3viE +dfkI25OjQzBBMCAGA1UdJQQZMBcGCCsGAQUFBwMIBgsrBgEEAYOwHAEDATAdBgNV +HQ4EFgQUkD4ImHPtNczZ04XNTtUnXFlJxxEwCgYIKoZIzj0EAwIDSQAwRgIhAPLa +u7ALeuEOqhM1gwk6I6KYHbUw9I4iGp0DNUNlJvNjAiEA5p1aAfl9lyDyyS2CiZQ3 +BKXAcOz3IRCrtQ/8Tajp5zs= +-----END CERTIFICATE----- diff --git a/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_111.pem b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_111.pem new file mode 100644 index 0000000000..71314567af --- /dev/null +++ b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_111.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIICGDCCAb2gAwIBAgIVANtvbV4hD4fMqxKQ3MoTdLjsgdwRMAoGCCqGSM49BAMC +MFQxMzAxBgNVBAMTKjEtZmYwMDowOjExMCBDQSBDZXJ0aWZpY2F0ZSAtIEdFTiBJ +IDIwMjEuMTEdMBsGCysGAQQBg7AcAQIBEwwxLWZmMDA6MDoxMTAwHhcNMjEwNTE0 +MTExMTAyWhcNMjIwNTE0MTExMTAyWjBFMSQwIgYDVQQDExsxLWZmMDA6MDoxMTEg +QVMgQ2VydGlmaWNhdGUxHTAbBgsrBgEEAYOwHAECARMMMS1mZjAwOjA6MTExMFkw +EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENe/lvHBKdgBEXMapZ5Z1pr5hqopIZ2S8 +Q0cEVIQBxk6c9ODMeVHOANswDG3zac11UmMqTSBYhfmB+NMcG33vyqN7MHkwDgYD +VR0PAQH/BAQDAgeAMCcGA1UdJQQgMB4GCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYB +BQUHAwgwHQYDVR0OBBYEFI/Sz9QOzkpOdCTieKAZpfVQktJKMB8GA1UdIwQYMBaA +FDN8BDgfByCKydpaXF+fDvU6hxOYMAoGCCqGSM49BAMCA0kAMEYCIQCgf11ZKULP +zExxFrhlDRQLMMEVCFwPP2N4g0C0Tpxf8gIhAJeuvoLKPBv30hkU5wCXrgqG8Hc4 +h4jPcrWI9K9BrtM3 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICDDCCAbKgAwIBAgIVAKGSZvBdy4AH0jdmkgekU8yAGLvfMAoGCCqGSM49BAMC +ME8xLjAsBgNVBAMTJTEtZmYwMDowOjExMCBSb290IENlcnRpZmljYXRlIC0gR0VO +IEkxHTAbBgsrBgEEAYOwHAECARMMMS1mZjAwOjA6MTEwMB4XDTIxMDUxNDExMTEw +MloXDTIzMDQxNDExMTEwMlowVDEzMDEGA1UEAxMqMS1mZjAwOjA6MTEwIENBIENl +cnRpZmljYXRlIC0gR0VOIEkgMjAyMS4xMR0wGwYLKwYBBAGDsBwBAgETDDEtZmYw +MDowOjExMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI7+UCxkCJ5iiNpY9yfr +bfgT35KdoDY1jEiiOW11zCnd9o0ex9ewFI3iidG6c/3F8pgNlazegTger7aU5HmK +IoujZjBkMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud +DgQWBBQzfAQ4HwcgisnaWlxfnw71OocTmDAfBgNVHSMEGDAWgBRqTPSqZsb5ejvQ +M6wfqhSw07jm+zAKBggqhkjOPQQDAgNIADBFAiEAwvzpQrsFmg/qmltZUWdgUI0b +pgR2xV+75Pow4WRwcfcCIHihw7z7ypO96gCfqqXf1l202+I24zCt7rqzdW8Xiv8K +-----END CERTIFICATE----- diff --git a/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_112.pem b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_112.pem new file mode 100644 index 0000000000..0d9886931e --- /dev/null +++ b/go/pkg/cs/drkey/grpc/testdata/common/certs/ISD1-ASff00_0_112.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIICFzCCAb2gAwIBAgIVAJKvRgwgUltD7cMUDhlPcuviKPlBMAoGCCqGSM49BAMC +MFQxMzAxBgNVBAMTKjEtZmYwMDowOjExMCBDQSBDZXJ0aWZpY2F0ZSAtIEdFTiBJ +IDIwMjEuMTEdMBsGCysGAQQBg7AcAQIBEwwxLWZmMDA6MDoxMTAwHhcNMjEwNTE0 +MTExMTAyWhcNMjIwNTE0MTExMTAyWjBFMSQwIgYDVQQDExsxLWZmMDA6MDoxMTIg +QVMgQ2VydGlmaWNhdGUxHTAbBgsrBgEEAYOwHAECARMMMS1mZjAwOjA6MTEyMFkw +EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJ7aSzyxsFDIxHHTND6EOqhPgMIFRF3y0 +0W89X/l7dO5UVKTtj6QXid+2Yj6C+zuFH4/ckdlutUrs4mgMnUiXjKN7MHkwDgYD +VR0PAQH/BAQDAgeAMCcGA1UdJQQgMB4GCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYB +BQUHAwgwHQYDVR0OBBYEFOFgSwMR2yMmWTG6aj4Vdq4B43DZMB8GA1UdIwQYMBaA +FDN8BDgfByCKydpaXF+fDvU6hxOYMAoGCCqGSM49BAMCA0gAMEUCIQCwpWLLPZw+ +ykyKCAqfy24x1mibn6DIROVAiqOGULLm/QIgTHKTY9vROekV6qEYSG/J+IMhJ9rI +xC4CZL9a/X1wRFU= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICDDCCAbKgAwIBAgIVAKGSZvBdy4AH0jdmkgekU8yAGLvfMAoGCCqGSM49BAMC +ME8xLjAsBgNVBAMTJTEtZmYwMDowOjExMCBSb290IENlcnRpZmljYXRlIC0gR0VO +IEkxHTAbBgsrBgEEAYOwHAECARMMMS1mZjAwOjA6MTEwMB4XDTIxMDUxNDExMTEw +MloXDTIzMDQxNDExMTEwMlowVDEzMDEGA1UEAxMqMS1mZjAwOjA6MTEwIENBIENl +cnRpZmljYXRlIC0gR0VOIEkgMjAyMS4xMR0wGwYLKwYBBAGDsBwBAgETDDEtZmYw +MDowOjExMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI7+UCxkCJ5iiNpY9yfr +bfgT35KdoDY1jEiiOW11zCnd9o0ex9ewFI3iidG6c/3F8pgNlazegTger7aU5HmK +IoujZjBkMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud +DgQWBBQzfAQ4HwcgisnaWlxfnw71OocTmDAfBgNVHSMEGDAWgBRqTPSqZsb5ejvQ +M6wfqhSw07jm+zAKBggqhkjOPQQDAgNIADBFAiEAwvzpQrsFmg/qmltZUWdgUI0b +pgR2xV+75Pow4WRwcfcCIHihw7z7ypO96gCfqqXf1l202+I24zCt7rqzdW8Xiv8K +-----END CERTIFICATE----- diff --git a/go/pkg/cs/drkey/grpc/testdata/common/certs/dummy.pem b/go/pkg/cs/drkey/grpc/testdata/common/certs/dummy.pem new file mode 100644 index 0000000000..e69de29bb2 diff --git a/go/pkg/cs/drkey/grpc/testdata/common/trcs/ISD1-B1-S1.trc b/go/pkg/cs/drkey/grpc/testdata/common/trcs/ISD1-B1-S1.trc new file mode 100644 index 0000000000000000000000000000000000000000..fd2affc33403373456849d56aceecceedb4cf148 GIT binary patch literal 2412 zcmXqL;>=*<)N1o+`_9YA&a|M3Gt!`mGn9#u(U8}Gn~gJ}&4V$OnT3hjpoy&0UCj0_D-4NVMzz`!U9EMR0{VPFmw0P0`_YGMHD zFyIm9N=q{^urja$szv4TNQ9&omn0We7L?>GgakP&q~#YWcm}&D7#cLOzBFiJ;xK4p zT(^LkiIIs(lwqRI)yzq$0`@Nt|4X#_s=VImDm%Xc7aIrAbLVVXn3)Xx4fPCk*qB3E zn1xjhbrF^-1m)+KC^)AUm1L%6CMTApD(EV>yZR}38p;|-vvF&)F|sf=Z;%1{PnZW; zpMjh>FN!~bTw^3}Q{Tc!17S9Huz#2sp&nyqWM_6_V0pX8zjdN%N2s369i4|yUkH>r zojv>U>Z()A>rcpwaVz&uWLquG(Dhz<%h9NdhklpJ@Rqo+xF+xIO0PAzJ)yqaZgILn zssSG`aAf%z8UM2YgNup9Kmo*8Wsx)xXX5~d0xK&!GY3+5Ff$tnfm8^CbZ{830Vz;~ z%7VoBSj1RFvV6X*N;~$m%KC!w8u?Ws8!qp7_8U1ym^~N_T$vOZ=4_9bicu5x37NwY z*8M1bn|DugY$ zC^fw_C$UH&EWac(FC95mP?{QOU?uMK(0SHLcg^;ks;WKv4_}^PkpC#!X2HFp<8BQb zcCIRz5q3uF(LtLVD*umUI_%+Hys4pS=VRp?m#<7ud-(pZ0bl&`TZ^3y90|rh6H;7j zDmAOGWGeKpUAN9Ug)P{n%M^_I1R2xFz*QqyN)h8xcc zJ!p|M(zwo~kZF01F-quJ%)g`0Jzmx;8Gratt+ylT(~gk*Y3>aEuPy-N`7IDng2naQ zB{$SLo^HFc@zj;%+sgO8r!QoDjcl_)u%VHG0VJ+9QQ|r{HLp0cB(p4)2C+>OOL52d zd-v~_%~oYfe45?2?rvW&StPGA`}sqbce?v8SSoq#+s1RPKf-N>*~0z=vvh;Mp)0m( zrYuO0ICkmYkCxJ(9JePE72n8tdx9OujN-SZXKr3@J?nQ>JtorgxFB+I_ zr(3%>a92I#TP1AT%xR^(Xol=ogD-tbQgfM2om165Cj*r{n;XUWvv#_|r<1x(om0$N zmL4d0^IcJ3^;Z5rzAIinw>E5IIs%OFSWw}TMT49RtUIul7s%D$g2qk*33&a-$!rLe zgw>ji1~PCCC#xYpTCHHd3$^TLUn+Z@zQ<5}Q|1+(n&S=C;xHNyfam|0ldfhDMdMf|#O z$qOG{t=(g~Ev{=ww?!B)SMxfSq;6|lySe%74PYQ2Ft{%7`M12biSO+C>nWRC-49RD zS?*NM-g=^Sxw1;84KRS?K>?gYlk5TvVyxM8=mc@O{4CLDPee|tUrk8AFt=dMq#1(C z?&L+AmrX0{++NOW3k>3K@zcY%JPqbnI{4o)_FCo5OPf7^Hz}3)OwLnvFSOap4FC~Y B(LDeF literal 0 HcmV?d00001 diff --git a/go/pkg/cs/drkey/grpc/testdata/common/trcs/ISD1-B1-S2.trc b/go/pkg/cs/drkey/grpc/testdata/common/trcs/ISD1-B1-S2.trc new file mode 100644 index 0000000000000000000000000000000000000000..04c6b5677c88b1da21f55fc3eb08a7dede5d95ca GIT binary patch literal 2664 zcmXqL;!0uT)N1o+`_9YA&a|M3E7YKgE0Bqi(U8}Gn~gJ}&4V$OnT3hbpoy&pp^$Mw z6I(7z6I&)wIF*T!!GIH}gNcy|NE#?f@EaKz85)=xniv9sfpHXAz{tSDz#J;T#LQ{c zzzEdF4A#bIz$46+mS$jJWncx=fXd^M2uUq2NiM1^D9Kj{3366Q%P&&!40cg4G-zUd zY0$*PZqUTIZUN9FCMHpaiLDFY--=qk!89i|=ThFxXBFi3uE&J z8K5VHd64xP$cgi!coxVtM)EuLEsQh}W@88YhlvsDF=j?~W+w)gw|o3sCz^JI>dD;E zdHD2&K$+9ovmdXnI<>t1guEEHa_>a8)zS=I@0GV4jkbvb0ryHai@BsrymYh`j&zDtc$9`5>Uoc)Hze;4olR{wJb>BOM zzomW3mQ0Xv+IaEA3;x-QSgyrxyw!cp^24OrSJK{A*|5$1 z8>#UBkVDY9J7St~z+?bS4vc-Ur0{81>-}AknU~%jXFD)kD!=!|q@O;>78?WtlbRmT zoxr4^jvS>5L8j^fB~zh)?Yec=DeO{DM3&y)h#ca~o(u+VOo|MRP21Kia=cjio2k`3 zy7x0@^D`#(8&|%vr%LQm|I!d64^%Sc@Ju%Ght8d6EbnjNxU;jYAxKy|{L#0czmjFO zE@Zs~<@vWjJP8)rZD`<}j#@ins52Em3#1_qGG)#-u=5}vsIZApJw;1yW1B`7Rjs3e*TcP8T~T25R{lS}D_%agHf&n zoRlhH|MKv^M4PY5>z%H$^P|*&3o;EP;58s8vmvl{gw>mj1~PCCC#xYpT9sg+kC0_C zRAN!kSj}L?U{Muka#KZvH$tsqP2!Teg_=wg_)@mN|K#MTX}}3D;aS`bT!F#!=lj|H z5n|pt=d0$fJl3XJcT2^)>+`0TC+8No&0|s!Zfts0%*@SovhLP_$*o*bY-Wvz z*tdlyH_G2FHJPnD7Z`X}puo$bLAeJEKCGoJasy(3g3k?9xj37@={or_!=XUWcV^`R zTlPoqrMk2I_S_IZzuL#~{p(^T1uw6BMUE|PMp+s5T8buX)Bg5O4rz=UNaP7|R zt*yY&v!P+=edA%Pa%s=}y-oId$I*8FrAAwWKD4|@=7?nY%q@bVE{~@`&=(1TzOJmBlzXl<4pOv7X_=D*Xif2W2)c?IT$=^ Ge;xpwC=>Sp literal 0 HcmV?d00001 diff --git a/go/pkg/cs/drkey/grpc/testdata/golden.topo b/go/pkg/cs/drkey/grpc/testdata/golden.topo new file mode 100644 index 0000000000..a75b35e49d --- /dev/null +++ b/go/pkg/cs/drkey/grpc/testdata/golden.topo @@ -0,0 +1,11 @@ +--- +ASes: + "1-ff00:0:110": + core: true + voting: true + authoritative: true + issuing: true + "1-ff00:0:111": + cert_issuer: 1-ff00:0:110 + "1-ff00:0:112": + cert_issuer: 1-ff00:0:110 diff --git a/go/pkg/cs/drkey/grpc/testdata/keys/invalid.key b/go/pkg/cs/drkey/grpc/testdata/keys/invalid.key new file mode 100644 index 0000000000..25a33fcef1 --- /dev/null +++ b/go/pkg/cs/drkey/grpc/testdata/keys/invalid.key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgQjh2MSNXUGPe3tYz +D13M2gZrO6KO2ZCf4EcbcOCw50ahRANCAASiNyv2DiCI1HVcxBsQEHxAA84qSjqo +WlAZP4nWg0QRqTKLsb/+MGXrgfedXNjk +-----END PRIVATE KEY----- diff --git a/go/pkg/cs/drkey/grpc/testdata/keys/non-key.key b/go/pkg/cs/drkey/grpc/testdata/keys/non-key.key new file mode 100644 index 0000000000..7b4b795986 --- /dev/null +++ b/go/pkg/cs/drkey/grpc/testdata/keys/non-key.key @@ -0,0 +1,5 @@ +-----BEGIN CERTIFICATE----- +MBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgQjh2MSNXUGPe3tYz +D13M2gZrO6KO2ZCf4EcbcOCw50ahRANCAASiNyv2DiCI1HVcxBsQEHxAA84qSjqo +WlAZP4nWg0QRqTKLsb/+MGXrgfedXNjk +-----END CERTIFICATE----- diff --git a/go/pkg/cs/drkey/grpc/testdata/keys/valid.key b/go/pkg/cs/drkey/grpc/testdata/keys/valid.key new file mode 100644 index 0000000000..24cf4e0b39 --- /dev/null +++ b/go/pkg/cs/drkey/grpc/testdata/keys/valid.key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgQjh2MSNXUGPe3tYz +D13M2gZrO6KO2ZCf4EcbcOCw50ahRANCAASiNyv2DiCI1HVcxBsQEHxAA84qSjqo +WlAZP4nWg0QRqTKLsb/+MGXrgfedXNjkTmzry6sUoOK3e2nMmkL8LCUW +-----END PRIVATE KEY----- diff --git a/go/pkg/cs/drkey/grpc/testdata/store/invalid-trc/dummy.trc b/go/pkg/cs/drkey/grpc/testdata/store/invalid-trc/dummy.trc new file mode 100644 index 0000000000..7ba48d695e --- /dev/null +++ b/go/pkg/cs/drkey/grpc/testdata/store/invalid-trc/dummy.trc @@ -0,0 +1 @@ +adsfsdf diff --git a/go/pkg/cs/drkey/mock_drkey/BUILD.bazel b/go/pkg/cs/drkey/mock_drkey/BUILD.bazel new file mode 100644 index 0000000000..a9aa2f8b9c --- /dev/null +++ b/go/pkg/cs/drkey/mock_drkey/BUILD.bazel @@ -0,0 +1,13 @@ +load("//lint:go.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["fetcher.go"], + importpath = "github.com/scionproto/scion/go/pkg/cs/drkey/mock_drkey", + visibility = ["//visibility:public"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/drkey:go_default_library", + "@com_github_golang_mock//gomock:go_default_library", + ], +) diff --git a/go/pkg/cs/drkey/mock_drkey/fetcher.go b/go/pkg/cs/drkey/mock_drkey/fetcher.go new file mode 100644 index 0000000000..2bc524535e --- /dev/null +++ b/go/pkg/cs/drkey/mock_drkey/fetcher.go @@ -0,0 +1,52 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/scionproto/scion/go/pkg/cs/drkey (interfaces: Fetcher) + +// Package mock_drkey is a generated GoMock package. +package mock_drkey + +import ( + context "context" + gomock "github.com/golang/mock/gomock" + addr "github.com/scionproto/scion/go/lib/addr" + drkey "github.com/scionproto/scion/go/lib/drkey" + reflect "reflect" + time "time" +) + +// MockFetcher is a mock of Fetcher interface +type MockFetcher struct { + ctrl *gomock.Controller + recorder *MockFetcherMockRecorder +} + +// MockFetcherMockRecorder is the mock recorder for MockFetcher +type MockFetcherMockRecorder struct { + mock *MockFetcher +} + +// NewMockFetcher creates a new mock instance +func NewMockFetcher(ctrl *gomock.Controller) *MockFetcher { + mock := &MockFetcher{ctrl: ctrl} + mock.recorder = &MockFetcherMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockFetcher) EXPECT() *MockFetcherMockRecorder { + return m.recorder +} + +// GetLvl1FromOtherCS mocks base method +func (m *MockFetcher) GetLvl1FromOtherCS(arg0 context.Context, arg1, arg2 addr.IA, arg3 time.Time) (drkey.Lvl1Key, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLvl1FromOtherCS", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(drkey.Lvl1Key) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLvl1FromOtherCS indicates an expected call of GetLvl1FromOtherCS +func (mr *MockFetcherMockRecorder) GetLvl1FromOtherCS(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLvl1FromOtherCS", reflect.TypeOf((*MockFetcher)(nil).GetLvl1FromOtherCS), arg0, arg1, arg2, arg3) +} diff --git a/go/pkg/cs/drkey/prefetcher.go b/go/pkg/cs/drkey/prefetcher.go new file mode 100644 index 0000000000..fa4d9e8551 --- /dev/null +++ b/go/pkg/cs/drkey/prefetcher.go @@ -0,0 +1,80 @@ +// Copyright 2019 ETH Zurich +// +// 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 drkey + +import ( + "context" + "sync" + "time" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/drkeystorage" + "github.com/scionproto/scion/go/lib/log" + "github.com/scionproto/scion/go/lib/periodic" +) + +var _ periodic.Task = (*Prefetcher)(nil) + +// Prefetcher is in charge of getting the level 1 keys before they expire. +type Prefetcher struct { + LocalIA addr.IA + Store drkeystorage.ServiceStore + // XXX(JordiSubira): At the moment we assume "global" KeyDuration, i.e. + // every AS involved uses the same EpochDuration. This will be improve + // further in the future, so that the prefetcher get keys in advance + // based on the epoch established by the AS which derived the first + // level key. + KeyDuration time.Duration +} + +// Name returns the tasks name. +func (f *Prefetcher) Name() string { + return "drkey.Prefetcher" +} + +// Run requests the level 1 keys to other CSs. +func (f *Prefetcher) Run(ctx context.Context) { + var wg sync.WaitGroup + ases, err := f.Store.KnownASes(ctx) + if err != nil { + log.Error("Could not prefetch level 1 keys", "error", err) + return + } + log.Debug("Prefetching level 1 DRKeys", "ASes", ases) + when := time.Now().Add(f.KeyDuration) + for _, srcIA := range ases { + srcIA := srcIA + wg.Add(1) + go func() { + defer log.HandlePanic() + getLvl1Key(ctx, f.Store, srcIA, f.LocalIA, when, &wg) + }() + } + wg.Wait() +} + +func getLvl1Key(ctx context.Context, store drkeystorage.ServiceStore, + srcIA, dstIA addr.IA, valTime time.Time, wg *sync.WaitGroup) { + defer wg.Done() + meta := drkey.Lvl1Meta{ + SrcIA: srcIA, + DstIA: dstIA, + } + _, err := store.GetLvl1Key(ctx, meta, valTime) + if err != nil { + log.Error("Failed to prefetch the level 1 key", "remote AS", srcIA.String(), "error", err) + } +} diff --git a/go/pkg/cs/drkey/secret_value_store.go b/go/pkg/cs/drkey/secret_value_store.go new file mode 100644 index 0000000000..b6d6824615 --- /dev/null +++ b/go/pkg/cs/drkey/secret_value_store.go @@ -0,0 +1,142 @@ +// Copyright 2019 ETH Zurich +// +// 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 drkey + +import ( + "runtime" + "sync" + "time" + + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/log" + "github.com/scionproto/scion/go/lib/serrors" +) + +// SecretValueStore keeps the current and next secret values and removes the expired ones. +type SecretValueStore struct { + // TODO(JordiSubira): simplify class to be more consistent with keeping current and next + // secret values. + cache map[int64]drkey.SV + mutex sync.Mutex + + keyDuration time.Duration + stopCleaning chan bool + timeNowFcn func() time.Time +} + +// NewSecretValueStore creates a new SecretValueStore and initializes the cleaner. +func NewSecretValueStore(keyDuration time.Duration) *SecretValueStore { + m := &SecretValueStore{ + cache: make(map[int64]drkey.SV), + keyDuration: keyDuration, + stopCleaning: make(chan bool), + timeNowFcn: time.Now, + } + runtime.SetFinalizer(m, stopCleaner) + go func() { + defer log.HandlePanic() + m.startCleaner() + }() + return m +} + +// Get returns the element, and an indicator of its presence. +func (m *SecretValueStore) Get(idx int64) (drkey.SV, bool) { + m.mutex.Lock() + defer m.mutex.Unlock() + + k, found := m.cache[idx] + return k, found +} + +// Set sets the key, and registers this element in this shard. +func (m *SecretValueStore) Set(idx int64, key drkey.SV) { + m.mutex.Lock() + defer m.mutex.Unlock() + + m.cache[idx] = key +} + +// cleanExpired removes the current shard at once. +func (m *SecretValueStore) cleanExpired() { + m.mutex.Lock() + defer m.mutex.Unlock() + + now := m.timeNowFcn() + for idx, value := range m.cache { + if !value.Epoch.Contains(now) { + delete(m.cache, idx) + } + } +} + +func stopCleaner(m *SecretValueStore) { + m.stopCleaning <- true +} + +func (m *SecretValueStore) startCleaner() { + ticker := time.NewTicker(2 * m.keyDuration) + for { + select { + case <-ticker.C: + m.cleanExpired() + case <-m.stopCleaning: + ticker.Stop() + return + } + } +} + +// SecretValueFactory stores the secret value +type SecretValueFactory struct { + keyDuration time.Duration + masterKey []byte + keyMap *SecretValueStore + mapMutex sync.Mutex +} + +// NewSecretValueFactory return a default initialized SecretValueFactory. +func NewSecretValueFactory(masterKey []byte, + keyDuration time.Duration) *SecretValueFactory { + + s := &SecretValueFactory{ + masterKey: masterKey, + keyDuration: keyDuration, + } + s.keyMap = NewSecretValueStore(s.keyDuration) + return s +} + +// GetSecretValue derives or reuses the secret value for this time stamp. +func (s *SecretValueFactory) GetSecretValue(t time.Time) (drkey.SV, error) { + s.mapMutex.Lock() + defer s.mapMutex.Unlock() + + duration := int64(s.keyDuration / time.Second) // duration in seconds + idx := t.Unix() / duration + k, found := s.keyMap.Get(idx) + if !found { + begin := uint32(idx * duration) + end := begin + uint32(duration) + epoch := drkey.NewEpoch(begin, end) + var err error + k, err = drkey.DeriveSV(drkey.SVMeta{Epoch: epoch}, s.masterKey) + if err != nil { + return drkey.SV{}, serrors.WrapStr("Cannot establish the DRKey secret value", err) + } + s.keyMap.Set(idx, k) + } + return k, nil +} diff --git a/go/pkg/cs/drkey/secret_value_store_test.go b/go/pkg/cs/drkey/secret_value_store_test.go new file mode 100644 index 0000000000..63b4856d05 --- /dev/null +++ b/go/pkg/cs/drkey/secret_value_store_test.go @@ -0,0 +1,128 @@ +// Copyright 2020 ETH Zurich +// +// 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 drkey_test + +import ( + "context" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/util" + csdrkey "github.com/scionproto/scion/go/pkg/cs/drkey" +) + +// waitCondWithTimeout waits for the condition cond and return true, or timeout and return false. +func waitCondWithTimeout(dur time.Duration, cond *sync.Cond) bool { + ctx, cancelF := context.WithTimeout(context.Background(), dur) + defer cancelF() + done := make(chan struct{}) + go func() { + cond.Wait() + done <- struct{}{} + }() + select { + case <-done: + return true + case <-ctx.Done(): + } + return false +} + +// TestSecretValueStoreTicker checks that the store starts a ticker to clean expired values. +func TestSecretValueStoreTicker(t *testing.T) { + var m sync.Mutex + cond := sync.NewCond(&m) + m.Lock() + c := csdrkey.NewSecretValueStore(time.Millisecond) + // This timeNowFcn is used to mock time.Now() to test expiring entries in the tests below. + // This _has_ to be called by the cleanup function. Therefore, we can (ab-)use this to check + // that the background cleaner is indeed running. + testTimeNowFunc := func() time.Time { + cond.Broadcast() + return time.Unix(0, 0) + } + c.SetTimeNowFunction(testTimeNowFunc) + ret := waitCondWithTimeout(time.Minute, cond) + require.True(t, ret) +} + +func TestSecretValueStore(t *testing.T) { + c := csdrkey.NewSecretValueStore(time.Hour) + var now atomic.Value + testTimeNowFunc := func() time.Time { + return now.Load().(time.Time) + } + c.SetTimeNowFunction(testTimeNowFunc) + now.Store(time.Unix(10, 0)) + + k1 := drkey.SV{ + SVMeta: drkey.SVMeta{Epoch: drkey.NewEpoch(10, 12)}, + Key: drkey.DRKey([]byte{1, 2, 3}), + } + c.Set(1, k1) + c.CleanExpired() + k, found := c.Get(1) + require.True(t, found) + require.Equal(t, k1, k) + require.Len(t, c.Cache(), 1) + + k2 := drkey.SV{ + SVMeta: drkey.SVMeta{Epoch: drkey.NewEpoch(11, 13)}, + Key: drkey.DRKey([]byte{2, 3, 4}), + } + now.Store(time.Unix(12, 0).Add(-1 * time.Nanosecond)) + c.Set(2, k2) + require.Len(t, c.Cache(), 2) + c.CleanExpired() + require.Len(t, c.Cache(), 2) + now.Store(time.Unix(12, 1)) + c.CleanExpired() + require.Len(t, c.Cache(), 1) + _, found = c.Get(1) + require.False(t, found) +} + +func TestSecretValueFactory(t *testing.T) { + master := []byte{} + fac := csdrkey.NewSecretValueFactory(master, 10*time.Second) + _, err := fac.GetSecretValue(time.Now()) + require.Error(t, err) + master = []byte{0, 1, 2, 3} + fac = csdrkey.NewSecretValueFactory(master, 10*time.Second) + k, err := fac.GetSecretValue(util.SecsToTime(10)) + require.NoError(t, err) + require.EqualValues(t, 10, k.Epoch.NotBefore.Unix()) + require.EqualValues(t, 20, k.Epoch.NotAfter.Unix()) + + now := time.Unix(10, 0) + k, _ = fac.GetSecretValue(now) + savedCurrSV := k + + // advance time 9 seconds + now = now.Add(9 * time.Second) + k, _ = fac.GetSecretValue(now) + require.Equal(t, savedCurrSV.Key, k.Key) + + // advance it so we are in total 10 seconds in the future of the original clock + now = now.Add(time.Second) + k, _ = fac.GetSecretValue(now) + require.NotEqual(t, savedCurrSV.Key, k.Key) + require.Equal(t, savedCurrSV.Epoch.NotAfter, k.Epoch.NotBefore) +} diff --git a/go/pkg/cs/drkey/service_store.go b/go/pkg/cs/drkey/service_store.go new file mode 100644 index 0000000000..d25df49787 --- /dev/null +++ b/go/pkg/cs/drkey/service_store.go @@ -0,0 +1,112 @@ +// Copyright 2020 ETH Zurich +// +// 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 drkey + +import ( + "context" + "database/sql" + "time" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/drkey/protocol" + "github.com/scionproto/scion/go/lib/drkeystorage" + "github.com/scionproto/scion/go/lib/log" + "github.com/scionproto/scion/go/lib/serrors" + "github.com/scionproto/scion/go/lib/util" +) + +// Fetcher obtains a Lvl1 DRKey from a remote CS. +type Fetcher interface { + GetLvl1FromOtherCS(ctx context.Context, + srcIA, dstIA addr.IA, valTime time.Time) (drkey.Lvl1Key, error) +} + +// ServiceStore keeps track of the level 1 drkey keys. It is backed by a drkey.DB . +type ServiceStore struct { + LocalIA addr.IA + DB drkey.Lvl1DB + SecretValues drkeystorage.SecretValueFactory + Fetcher Fetcher +} + +var _ drkeystorage.ServiceStore = (*ServiceStore)(nil) + +// GetLvl1Key returns the level 1 drkey from the local DB or if not found, by asking any CS in +// the source AS of the key. +func (s *ServiceStore) GetLvl1Key(ctx context.Context, meta drkey.Lvl1Meta, + valTime time.Time) (drkey.Lvl1Key, error) { + logger := log.FromCtx(ctx) + + if meta.SrcIA == s.LocalIA { + return s.DeriveLvl1(meta.DstIA, valTime) + } + + if meta.DstIA != s.LocalIA { + return drkey.Lvl1Key{}, + serrors.New("Neither srcIA nor dstIA matches localIA", "srcIA", meta.SrcIA, + "dstIA", meta.DstIA, "localIA", s.LocalIA) + } + + // look in the DB + k, err := s.DB.GetLvl1Key(ctx, meta, util.TimeToSecs(valTime)) + if err == nil { + logger.Debug("[DRKey ServiceStore] L1 key found in storage") + return k, err + } + if err != sql.ErrNoRows { + return drkey.Lvl1Key{}, serrors.WrapStr("retrieving key from DB", err) + } + // get it from another server + k, err = s.Fetcher.GetLvl1FromOtherCS(ctx, meta.SrcIA, meta.DstIA, valTime) + if err != nil { + return drkey.Lvl1Key{}, serrors.WrapStr("obtaining level 1 key from CS", err) + } + // keep it in our DB + err = s.DB.InsertLvl1Key(ctx, k) + if err != nil { + return drkey.Lvl1Key{}, serrors.WrapStr("storing obtained key in DB", err) + } + return k, nil +} + +// DeleteExpiredKeys will remove any expired keys. +func (s *ServiceStore) DeleteExpiredKeys(ctx context.Context) (int, error) { + i, err := s.DB.RemoveOutdatedLvl1Keys(ctx, util.TimeToSecs(time.Now())) + return int(i), err +} + +// KnownASes returns a list with distinct AS seen as sources in level 1 DRKeys. +func (s *ServiceStore) KnownASes(ctx context.Context) ([]addr.IA, error) { + return s.DB.GetLvl1SrcASes(ctx) +} + +// DeriveLvl1 returns a Lvl1 DRKey based on present information +func (s *ServiceStore) DeriveLvl1(dstIA addr.IA, valTime time.Time) (drkey.Lvl1Key, error) { + sv, err := s.SecretValues.GetSecretValue(valTime) + if err != nil { + return drkey.Lvl1Key{}, serrors.WrapStr("getting secret value", err) + } + meta := drkey.Lvl1Meta{ + Epoch: sv.Epoch, + SrcIA: s.LocalIA, + DstIA: dstIA, + } + key, err := protocol.DeriveLvl1(meta, sv) + if err != nil { + return drkey.Lvl1Key{}, serrors.WrapStr("deriving level 1 key", err) + } + return key, nil +} diff --git a/go/pkg/cs/drkey/service_store_test.go b/go/pkg/cs/drkey/service_store_test.go new file mode 100644 index 0000000000..5638baa4b8 --- /dev/null +++ b/go/pkg/cs/drkey/service_store_test.go @@ -0,0 +1,111 @@ +// Copyright 2020 ETH Zurich +// +// 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 drkey_test + +import ( + "context" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/drkey/drkeydbsqlite" + "github.com/scionproto/scion/go/lib/util" + "github.com/scionproto/scion/go/lib/xtest" + cs_drkey "github.com/scionproto/scion/go/pkg/cs/drkey" + "github.com/scionproto/scion/go/pkg/cs/drkey/mock_drkey" + "github.com/scionproto/scion/go/pkg/cs/drkey/test" +) + +func TestDeriveLvl1Key(t *testing.T) { + srcIA := xtest.MustParseIA("1-ff00:0:112") + dstIA := xtest.MustParseIA("1-ff00:0:111") + expectedKey := xtest.MustParseHexString("87ee10bcc9ef1501783949a267f8ec6b") + + store := cs_drkey.ServiceStore{ + LocalIA: srcIA, + SecretValues: test.GetSecretValueTestFactory(), + } + lvl1Key, err := store.DeriveLvl1(dstIA, time.Now()) + require.NoError(t, err) + require.EqualValues(t, expectedKey, lvl1Key.Key) +} + +func TestGetLvl1Key(t *testing.T) { + lvl1db := newLvl1Database(t) + defer lvl1db.Close() + localIA := xtest.MustParseIA("1-ff00:0:110") + dstIA := localIA + srcIA := xtest.MustParseIA("1-ff00:0:111") + k := xtest.MustParseHexString("c584cad32613547c64823c756651b6f5") // just a level 1 key + + firstLvl1Key := drkey.Lvl1Key{ + Key: k, + Lvl1Meta: drkey.Lvl1Meta{ + Epoch: drkey.NewEpoch(0, 2), + SrcIA: srcIA, + DstIA: dstIA, + }, + } + secondLvl1Key := drkey.Lvl1Key{ + Key: k, + Lvl1Meta: drkey.Lvl1Meta{ + Epoch: drkey.NewEpoch(2, 4), + SrcIA: srcIA, + DstIA: dstIA, + }, + } + + mctrl := gomock.NewController(t) + defer mctrl.Finish() + + fetcher := mock_drkey.NewMockFetcher(mctrl) + firstCall := fetcher.EXPECT().GetLvl1FromOtherCS(gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any()).Return(firstLvl1Key, nil) + fetcher.EXPECT().GetLvl1FromOtherCS(gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any()).Return(secondLvl1Key, nil).After(firstCall) + + store := &cs_drkey.ServiceStore{ + LocalIA: localIA, + DB: lvl1db, + Fetcher: fetcher, + } + + // it must fetch first key from remote + rcvKey1, err := store.GetLvl1Key(context.Background(), firstLvl1Key.Lvl1Meta, + util.SecsToTime(0).UTC()) + require.NoError(t, err) + assert.Equal(t, firstLvl1Key, rcvKey1) + // it must not fetch key from remote and return previous key + rcvKey2, err := store.GetLvl1Key(context.Background(), firstLvl1Key.Lvl1Meta, + util.SecsToTime(1).UTC()) + require.NoError(t, err) + assert.Equal(t, firstLvl1Key, rcvKey2) + // it must fetch second key from remote + rcvKey3, err := store.GetLvl1Key(context.Background(), firstLvl1Key.Lvl1Meta, + util.SecsToTime(3).UTC()) + require.NoError(t, err) + assert.Equal(t, secondLvl1Key, rcvKey3) +} + +func newLvl1Database(t *testing.T) *drkeydbsqlite.Lvl1Backend { + db, err := drkeydbsqlite.NewLvl1Backend("file::memory:") + require.NoError(t, err) + + return db +} diff --git a/go/pkg/cs/drkey/test/BUILD.bazel b/go/pkg/cs/drkey/test/BUILD.bazel new file mode 100644 index 0000000000..187dd2b0c0 --- /dev/null +++ b/go/pkg/cs/drkey/test/BUILD.bazel @@ -0,0 +1,17 @@ +load("//lint:go.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["testcommons.go"], + importpath = "github.com/scionproto/scion/go/pkg/cs/drkey/test", + visibility = ["//visibility:public"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/drkeystorage:go_default_library", + "//go/lib/util:go_default_library", + "//go/lib/xtest:go_default_library", + "//go/pkg/cs/drkey:go_default_library", + "@com_github_stretchr_testify//require:go_default_library", + ], +) diff --git a/go/pkg/cs/drkey/test/testcommons.go b/go/pkg/cs/drkey/test/testcommons.go new file mode 100644 index 0000000000..f160b598fc --- /dev/null +++ b/go/pkg/cs/drkey/test/testcommons.go @@ -0,0 +1,82 @@ +// Copyright 2020 ETH Zurich +// +// 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 test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/drkeystorage" + "github.com/scionproto/scion/go/lib/util" + "github.com/scionproto/scion/go/lib/xtest" + csdrkey "github.com/scionproto/scion/go/pkg/cs/drkey" +) + +func getTestMasterSecret() []byte { + return []byte{0, 1, 2, 3} +} + +// SecretValueTestFactory works as a SecretValueFactory but uses a user-controlled-variable instead +// of time.Now when calling GetSecretValue. +type SecretValueTestFactory struct { + csdrkey.SecretValueFactory + Now time.Time +} + +func (f *SecretValueTestFactory) GetSecretValue(_ time.Time) (drkey.SV, error) { + return f.SecretValueFactory.GetSecretValue(f.Now) +} + +func GetSecretValueTestFactory() drkeystorage.SecretValueFactory { + return &SecretValueTestFactory{ + SecretValueFactory: *csdrkey.NewSecretValueFactory(getTestMasterSecret(), 10*time.Second), + Now: util.SecsToTime(0), + } +} + +func GetInputToDeriveLvl2Key(t *testing.T) (drkey.Lvl2Meta, drkey.Lvl1Key) { + srcIA := xtest.MustParseIA("1-ff00:0:1") + dstIA := xtest.MustParseIA("1-ff00:0:2") + k := xtest.MustParseHexString("c584cad32613547c64823c756651b6f5") // just a level 1 key + + sv, err := GetSecretValueTestFactory().GetSecretValue(util.SecsToTime(0)) + require.NoError(t, err) + + lvl1Key := drkey.Lvl1Key{ + Key: k, + Lvl1Meta: drkey.Lvl1Meta{ + Epoch: sv.Epoch, + SrcIA: srcIA, + DstIA: dstIA, + }, + } + + var srcHost addr.HostAddr = addr.HostNone{} + var dstHost addr.HostAddr = addr.HostNone{} + meta := drkey.Lvl2Meta{ + KeyType: drkey.AS2AS, + Protocol: "scmp", + Epoch: lvl1Key.Epoch, + SrcIA: srcIA, + DstIA: dstIA, + SrcHost: srcHost, + DstHost: dstHost, + } + return meta, lvl1Key +} diff --git a/go/pkg/cs/tasks.go b/go/pkg/cs/tasks.go index 156c26c2bf..0589db704c 100644 --- a/go/pkg/cs/tasks.go +++ b/go/pkg/cs/tasks.go @@ -26,6 +26,7 @@ import ( "github.com/scionproto/scion/go/lib/addr" "github.com/scionproto/scion/go/lib/common" "github.com/scionproto/scion/go/lib/ctrl/seg" + "github.com/scionproto/scion/go/lib/drkeystorage" "github.com/scionproto/scion/go/lib/infra/modules/seghandler" "github.com/scionproto/scion/go/lib/metrics" "github.com/scionproto/scion/go/lib/pathdb" @@ -34,6 +35,7 @@ import ( "github.com/scionproto/scion/go/lib/snet" "github.com/scionproto/scion/go/lib/snet/addrutil" "github.com/scionproto/scion/go/lib/topology" + "github.com/scionproto/scion/go/pkg/cs/drkey" "github.com/scionproto/scion/go/pkg/hiddenpath" "github.com/scionproto/scion/go/pkg/trust" ) @@ -54,6 +56,7 @@ type TasksConfig struct { Signer seg.Signer Inspector trust.Inspector Metrics *Metrics + DRKeyStore drkeystorage.ServiceStore MACGen func() hash.Hash TopoProvider topology.Provider @@ -62,6 +65,7 @@ type TasksConfig struct { OriginationInterval time.Duration PropagationInterval time.Duration RegistrationInterval time.Duration + DRKeyEpochInterval time.Duration // HiddenPathRegistrationCfg contains the required options to configure // hidden paths down segment registration. If it is nil, normal path // registration is used instead. @@ -214,13 +218,41 @@ func (t *TasksConfig) extender(task string, ia addr.IA, mtu uint16, } } +func (t *TasksConfig) DRKeyCleaner() *periodic.Runner { + if t.DRKeyStore == nil { + return nil + } + // TODO(juagargi): if there has been a change in the duration, we need to keep + // the already sent keys (and their duration) as they were already handed to other entities + cleanerPeriod := 2 * t.DRKeyEpochInterval + return periodic.Start(drkeystorage.NewStoreCleaner(t.DRKeyStore), + cleanerPeriod, cleanerPeriod) +} + +func (t *TasksConfig) DRKeyPrefetcher() *periodic.Runner { + if t.DRKeyStore == nil { + return nil + } + topo := t.TopoProvider.Get() + prefetchPeriod := t.DRKeyEpochInterval / 2 + return periodic.Start( + &drkey.Prefetcher{ + LocalIA: topo.IA(), + Store: t.DRKeyStore, + KeyDuration: t.DRKeyEpochInterval, + }, + prefetchPeriod, prefetchPeriod) +} + // Tasks keeps track of the running tasks. type Tasks struct { - Originator *periodic.Runner - Propagator *periodic.Runner - Registrars []*periodic.Runner + Originator *periodic.Runner + Propagator *periodic.Runner + Registrars []*periodic.Runner + DRKeyPrefetcher *periodic.Runner - PathCleaner *periodic.Runner + PathCleaner *periodic.Runner + DRKeyCleaner *periodic.Runner } func StartTasks(cfg TasksConfig) (*Tasks, error) { @@ -228,9 +260,10 @@ func StartTasks(cfg TasksConfig) (*Tasks, error) { segCleaner := pathdb.NewCleaner(cfg.PathDB, "control_pathstorage_segments") segRevCleaner := revcache.NewCleaner(cfg.RevCache, "control_pathstorage_revocation") return &Tasks{ - Originator: cfg.Originator(), - Propagator: cfg.Propagator(), - Registrars: cfg.SegmentWriters(), + Originator: cfg.Originator(), + Propagator: cfg.Propagator(), + Registrars: cfg.SegmentWriters(), + DRKeyPrefetcher: cfg.DRKeyPrefetcher(), PathCleaner: periodic.Start( periodic.Func{ Task: func(ctx context.Context) { @@ -242,6 +275,7 @@ func StartTasks(cfg TasksConfig) (*Tasks, error) { 10*time.Second, 10*time.Second, ), + DRKeyCleaner: cfg.DRKeyCleaner(), }, nil } @@ -254,12 +288,16 @@ func (t *Tasks) Kill() { killRunners([]*periodic.Runner{ t.Originator, t.Propagator, + t.DRKeyPrefetcher, t.PathCleaner, + t.DRKeyCleaner, }) killRunners(t.Registrars) t.Originator = nil t.Propagator = nil + t.DRKeyPrefetcher = nil t.PathCleaner = nil + t.DRKeyCleaner = nil t.Registrars = nil } diff --git a/go/pkg/daemon/BUILD.bazel b/go/pkg/daemon/BUILD.bazel index bea41ecf75..7a44ef7650 100644 --- a/go/pkg/daemon/BUILD.bazel +++ b/go/pkg/daemon/BUILD.bazel @@ -7,6 +7,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//go/lib/daemon:go_default_library", + "//go/lib/drkeystorage:go_default_library", "//go/lib/env:go_default_library", "//go/lib/infra/modules/itopo:go_default_library", "//go/lib/log:go_default_library", diff --git a/go/pkg/daemon/config/config.go b/go/pkg/daemon/config/config.go index 8901af37b1..b0e0b56f8a 100644 --- a/go/pkg/daemon/config/config.go +++ b/go/pkg/daemon/config/config.go @@ -44,6 +44,7 @@ type Config struct { Tracing env.Tracing `toml:"tracing,omitempty"` TrustDB storage.DBConfig `toml:"trust_db,omitempty"` PathDB storage.DBConfig `toml:"path_db,omitempty"` + DRKeyDB storage.DBConfig `toml:"drkey_db,omitempty"` SD SDConfig `toml:"sd,omitempty"` TrustEngine trustengine.Config `toml:"trustengine,omitempty"` } @@ -70,6 +71,7 @@ func (cfg *Config) Validate() error { &cfg.Metrics, &cfg.TrustDB, &cfg.PathDB, + &cfg.DRKeyDB, &cfg.SD, &cfg.TrustEngine, ) @@ -96,6 +98,13 @@ func (cfg *Config) Sample(dst io.Writer, path config.Path, _ config.CtxMap) { ), "path_db", ), + config.OverrideName( + config.FormatData( + &cfg.DRKeyDB, + fmt.Sprintf(storage.DefaultDRKeyDBPath, "sd"), + ), + "drkey_db", + ), &cfg.SD, &cfg.TrustEngine, ) diff --git a/go/pkg/daemon/daemon.go b/go/pkg/daemon/daemon.go index b6cf0f83a4..368d1e6b70 100644 --- a/go/pkg/daemon/daemon.go +++ b/go/pkg/daemon/daemon.go @@ -26,6 +26,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/scionproto/scion/go/lib/daemon" + "github.com/scionproto/scion/go/lib/drkeystorage" "github.com/scionproto/scion/go/lib/env" "github.com/scionproto/scion/go/lib/infra/modules/itopo" "github.com/scionproto/scion/go/lib/log" @@ -106,6 +107,7 @@ type ServerConfig struct { RevCache revcache.RevCache Engine trust.Engine TopoProvider topology.Provider + DRKeyStore drkeystorage.ClientStore } // NewServer constructs a daemon API server. @@ -115,6 +117,7 @@ func NewServer(cfg ServerConfig) *servers.DaemonServer { ASInspector: cfg.Engine.Inspector, RevCache: cfg.RevCache, TopoProvider: cfg.TopoProvider, + DRKeyStore: cfg.DRKeyStore, Metrics: servers.Metrics{ PathsRequests: servers.RequestMetrics{ Requests: metrics.NewPromCounterFrom(prometheus.CounterOpts{ diff --git a/go/pkg/daemon/drkey/BUILD.bazel b/go/pkg/daemon/drkey/BUILD.bazel new file mode 100644 index 0000000000..b76b94faee --- /dev/null +++ b/go/pkg/daemon/drkey/BUILD.bazel @@ -0,0 +1,16 @@ +load("//lint:go.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["client_store.go"], + importpath = "github.com/scionproto/scion/go/pkg/daemon/drkey", + visibility = ["//visibility:public"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/drkeystorage: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/pkg/daemon/drkey/client_store.go b/go/pkg/daemon/drkey/client_store.go new file mode 100644 index 0000000000..dd99bf8096 --- /dev/null +++ b/go/pkg/daemon/drkey/client_store.go @@ -0,0 +1,86 @@ +// Copyright 2020 ETH Zurich +// +// 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 drkey + +import ( + "context" + "database/sql" + "time" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/drkeystorage" + "github.com/scionproto/scion/go/lib/log" + "github.com/scionproto/scion/go/lib/serrors" + "github.com/scionproto/scion/go/lib/util" +) + +// Fetcher obtains a Lvl2 DRKey from the local CS. +type Fetcher interface { + GetDRKeyLvl2(ctx context.Context, meta drkey.Lvl2Meta, a addr.IA, + valTime time.Time) (drkey.Lvl2Key, error) +} + +// ClientStore is the DRKey store used in the client side, i.e. sciond. +// It implements drkeystorage.ClientStore. +type ClientStore struct { + ia addr.IA + db drkey.Lvl2DB + fetcher Fetcher +} + +var _ drkeystorage.ClientStore = &ClientStore{} + +// NewClientStore constructs a new client store without assigned messenger. +func NewClientStore(local addr.IA, db drkey.Lvl2DB, fetcher Fetcher) *ClientStore { + return &ClientStore{ + ia: local, + db: db, + fetcher: fetcher, + } +} + +// GetLvl2Key returns the level 2 drkey from the local DB or if not found, by asking our local CS. +func (s *ClientStore) GetLvl2Key(ctx context.Context, meta drkey.Lvl2Meta, + valTime time.Time) (drkey.Lvl2Key, error) { + + logger := log.FromCtx(ctx) + // is it in storage? + k, err := s.db.GetLvl2Key(ctx, meta, util.TimeToSecs(valTime)) + if err == nil { + return k, err + } + if err != sql.ErrNoRows { + return drkey.Lvl2Key{}, serrors.WrapStr("looking up level 2 key in DB", err) + } + logger.Debug("[DRKey ClientStore] Level 2 key not stored. Requesting it to CS") + // if not, ask our CS for it + + k, err = s.fetcher.GetDRKeyLvl2(ctx, meta, s.ia, valTime) + if err != nil { + return drkey.Lvl2Key{}, serrors.WrapStr("fetching lvl2 key from local CS", err) + } + if err = s.db.InsertLvl2Key(ctx, k); err != nil { + logger.Error("[DRKey ClientStore] Could not insert level 2 in DB", "error", err) + return k, serrors.WrapStr("inserting level 2 key in DB", err) + } + return k, nil +} + +// DeleteExpiredKeys will remove any expired keys. +func (s *ClientStore) DeleteExpiredKeys(ctx context.Context) (int, error) { + i, err := s.db.RemoveOutdatedLvl2Keys(ctx, util.TimeToSecs(time.Now())) + return int(i), err +} diff --git a/go/pkg/daemon/drkey/grpc/BUILD.bazel b/go/pkg/daemon/drkey/grpc/BUILD.bazel new file mode 100644 index 0000000000..649ea98944 --- /dev/null +++ b/go/pkg/daemon/drkey/grpc/BUILD.bazel @@ -0,0 +1,37 @@ +load("//lint:go.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["lvl2_fetcher.go"], + importpath = "github.com/scionproto/scion/go/pkg/daemon/drkey/grpc", + visibility = ["//visibility:public"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/ctrl/drkey:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/serrors:go_default_library", + "//go/pkg/daemon/drkey:go_default_library", + "//go/pkg/grpc:go_default_library", + "//go/pkg/proto/control_plane:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["lvl2_fetching_test.go"], + deps = [ + ":go_default_library", + "//go/lib/addr:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/xtest:go_default_library", + "//go/pkg/grpc/mock_grpc:go_default_library", + "//go/pkg/proto/control_plane:go_default_library", + "//go/pkg/proto/control_plane/mock_control_plane:go_default_library", + "//go/pkg/proto/drkey:go_default_library", + "@com_github_golang_mock//gomock:go_default_library", + "@com_github_golang_protobuf//ptypes:go_default_library_gen", + "@com_github_stretchr_testify//require:go_default_library", + "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//test/bufconn:go_default_library", + ], +) diff --git a/go/pkg/daemon/drkey/grpc/lvl2_fetcher.go b/go/pkg/daemon/drkey/grpc/lvl2_fetcher.go new file mode 100644 index 0000000000..0b41a24129 --- /dev/null +++ b/go/pkg/daemon/drkey/grpc/lvl2_fetcher.go @@ -0,0 +1,81 @@ +// Copyright 2020 ETH Zurich +// +// 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 grpc + +import ( + "context" + "time" + + "github.com/scionproto/scion/go/lib/addr" + ctrl "github.com/scionproto/scion/go/lib/ctrl/drkey" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/serrors" + sd_drkey "github.com/scionproto/scion/go/pkg/daemon/drkey" + sc_grpc "github.com/scionproto/scion/go/pkg/grpc" + cppb "github.com/scionproto/scion/go/pkg/proto/control_plane" +) + +// DRKeyFetcher obtains Lvl2 DRKey from the local CS. +type DRKeyFetcher struct { + Dialer sc_grpc.Dialer +} + +var _ sd_drkey.Fetcher = (*DRKeyFetcher)(nil) + +// GetDRKeyLvl2 fetches the Lvl2Key corresponding to the metadata by requesting +// the CS. +func (f DRKeyFetcher) GetDRKeyLvl2(ctx context.Context, lvl2meta drkey.Lvl2Meta, + dstIA addr.IA, valTime time.Time) (drkey.Lvl2Key, error) { + + // logger := log.FromCtx(ctx) + conn, err := f.Dialer.Dial(ctx, addr.SvcCS) + if err != nil { + return drkey.Lvl2Key{}, serrors.WrapStr("dialing", err) + } + defer conn.Close() + client := cppb.NewDRKeyLvl2ServiceClient(conn) + lvl2req := ctrl.NewLvl2ReqFromMeta(lvl2meta, valTime) + req, err := lvl2reqToProtoRequest(lvl2req) + if err != nil { + return drkey.Lvl2Key{}, + serrors.WrapStr("parsing lvl2 request to protobuf", err) + } + rep, err := client.DRKeyLvl2(ctx, req) + if err != nil { + return drkey.Lvl2Key{}, serrors.WrapStr("requesting level 2 key", err) + } + + lvl2Key, err := getLvl2KeyFromReply(rep, lvl2meta) + if err != nil { + return drkey.Lvl2Key{}, serrors.WrapStr("obtaining level 2 key from reply", err) + } + + return lvl2Key, nil +} + +func lvl2reqToProtoRequest(req ctrl.Lvl2Req) (*cppb.DRKeyLvl2Request, error) { + baseReq, err := ctrl.Lvl2reqToProtoRequest(req) + if err != nil { + return nil, err + } + return &cppb.DRKeyLvl2Request{ + BaseReq: baseReq, + }, nil +} + +// getLvl2KeyFromReply decrypts and extracts the level 1 drkey from the reply. +func getLvl2KeyFromReply(rep *cppb.DRKeyLvl2Response, meta drkey.Lvl2Meta) (drkey.Lvl2Key, error) { + return ctrl.GetLvl2KeyFromReply(rep.BaseRep, meta) +} diff --git a/go/pkg/daemon/drkey/grpc/lvl2_fetching_test.go b/go/pkg/daemon/drkey/grpc/lvl2_fetching_test.go new file mode 100644 index 0000000000..e0b89f56ff --- /dev/null +++ b/go/pkg/daemon/drkey/grpc/lvl2_fetching_test.go @@ -0,0 +1,109 @@ +// Copyright 2020 ETH Zurich +// +// 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 grpc_test + +import ( + "context" + "log" + "net" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/golang/protobuf/ptypes" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/grpc/test/bufconn" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/xtest" + sd_grpc "github.com/scionproto/scion/go/pkg/daemon/drkey/grpc" + "github.com/scionproto/scion/go/pkg/grpc/mock_grpc" + cppb "github.com/scionproto/scion/go/pkg/proto/control_plane" + mock_cppb "github.com/scionproto/scion/go/pkg/proto/control_plane/mock_control_plane" + drkey_pb "github.com/scionproto/scion/go/pkg/proto/drkey" +) + +func dialer(drkeyServer cppb.DRKeyLvl2ServiceServer) func(context.Context, + string) (net.Conn, error) { + bufsize := 1024 * 1024 + listener := bufconn.Listen(bufsize) + + server := grpc.NewServer() + + cppb.RegisterDRKeyLvl2ServiceServer(server, drkeyServer) + + go func() { + if err := server.Serve(listener); err != nil { + log.Fatal(err) + } + }() + + return func(context.Context, string) (net.Conn, error) { + return listener.Dial() + } +} + +func TestLvl2KeyFetching(t *testing.T) { + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + now := time.Now().UTC() + epochBegin, err := ptypes.TimestampProto(now) + require.NoError(t, err) + epochEnd, err := ptypes.TimestampProto(now.Add(24 * time.Hour)) + require.NoError(t, err) + + timestamp, err := ptypes.TimestampProto(time.Now().UTC()) + require.NoError(t, err) + + resp := &cppb.DRKeyLvl2Response{ + BaseRep: &drkey_pb.DRKeyLvl2Response{ + Timestamp: timestamp, + Drkey: xtest.MustParseHexString("c584cad32613547c64823c756651b6f5"), + EpochBegin: epochBegin, + EpochEnd: epochEnd, + }, + } + + daemonSrv := mock_cppb.NewMockDRKeyLvl2ServiceServer(ctrl) + daemonSrv.EXPECT().DRKeyLvl2(gomock.Any(), + gomock.Any()).Return( + resp, + nil, + ) + + conn, err := grpc.DialContext(context.Background(), + "", + grpc.WithInsecure(), + grpc.WithContextDialer(dialer(daemonSrv)), + ) + require.NoError(t, err) + defer conn.Close() + + dialer := mock_grpc.NewMockDialer(ctrl) + dialer.EXPECT().Dial(gomock.Any(), gomock.Any()).Return(conn, nil) + + fetcher := sd_grpc.DRKeyFetcher{ + Dialer: dialer, + } + + meta := drkey.Lvl2Meta{} + dstIA := addr.IA{} + _, err = fetcher.GetDRKeyLvl2(context.Background(), meta, dstIA, now) + require.NoError(t, err) +} diff --git a/go/pkg/daemon/internal/servers/BUILD.bazel b/go/pkg/daemon/internal/servers/BUILD.bazel index 68a8e0ec86..e143f17c49 100644 --- a/go/pkg/daemon/internal/servers/BUILD.bazel +++ b/go/pkg/daemon/internal/servers/BUILD.bazel @@ -11,7 +11,10 @@ go_library( deps = [ "//go/lib/addr:go_default_library", "//go/lib/common:go_default_library", + "//go/lib/ctrl/drkey:go_default_library", "//go/lib/ctrl/path_mgmt:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/drkeystorage:go_default_library", "//go/lib/log:go_default_library", "//go/lib/metrics:go_default_library", "//go/lib/prom:go_default_library", diff --git a/go/pkg/daemon/internal/servers/grpc.go b/go/pkg/daemon/internal/servers/grpc.go index ecc1fcd752..aa7942b0cb 100644 --- a/go/pkg/daemon/internal/servers/grpc.go +++ b/go/pkg/daemon/internal/servers/grpc.go @@ -27,7 +27,10 @@ import ( "github.com/scionproto/scion/go/lib/addr" "github.com/scionproto/scion/go/lib/common" + ctrl_drkey "github.com/scionproto/scion/go/lib/ctrl/drkey" "github.com/scionproto/scion/go/lib/ctrl/path_mgmt" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/drkeystorage" "github.com/scionproto/scion/go/lib/log" "github.com/scionproto/scion/go/lib/prom" "github.com/scionproto/scion/go/lib/revcache" @@ -47,6 +50,7 @@ type DaemonServer struct { TopoProvider topology.Provider RevCache revcache.RevCache ASInspector trust.Inspector + DRKeyStore drkeystorage.ClientStore Metrics Metrics @@ -331,3 +335,44 @@ func (s *DaemonServer) notifyInterfaceDown(ctx context.Context, } return &sdpb.NotifyInterfaceDownResponse{}, nil } + +// DRKeyLvl2 serves a Lvl2Key request +func (s *DaemonServer) DRKeyLvl2(ctx context.Context, + req *sdpb.DRKeyLvl2Request) (*sdpb.DRKeyLvl2Response, error) { + + logger := log.FromCtx(ctx) + + parsedReq, err := requestToLvl2Req(req) + if err != nil { + logger.Error("[DRKey DeamonService] Invalid DRKey Lvl2 request", "err", err) + return nil, serrors.WrapStr("parsing protobuf Lvl2Req", err) + } + + lvl2Key, err := s.DRKeyStore.GetLvl2Key(ctx, parsedReq.ToMeta(), parsedReq.ValTime) + if err != nil { + logger.Error("[DRKey DeamonService] Error getting Lvl2Key", "err", err) + return nil, serrors.WrapStr("getting Lvl2Key from client store", err) + } + + resp, err := keyToLvl2Resp(lvl2Key) + if err != nil { + logger.Debug("[DRKey DeamonService] Error parsing DRKey Lvl2 to protobuf resp", + "err", err) + return nil, serrors.WrapStr("parsing to protobuf Lvl2Rep", err) + } + return resp, nil +} + +func requestToLvl2Req(req *sdpb.DRKeyLvl2Request) (ctrl_drkey.Lvl2Req, error) { + return ctrl_drkey.RequestToLvl2Req(req.BaseReq) +} + +func keyToLvl2Resp(drkey drkey.Lvl2Key) (*sdpb.DRKeyLvl2Response, error) { + baseRep, err := ctrl_drkey.KeyToLvl2Resp(drkey) + if err != nil { + return nil, err + } + return &sdpb.DRKeyLvl2Response{ + BaseRep: baseRep, + }, nil +} diff --git a/go/pkg/grpc/dialer.go b/go/pkg/grpc/dialer.go index abfccfc6fb..68ac7a1249 100644 --- a/go/pkg/grpc/dialer.go +++ b/go/pkg/grpc/dialer.go @@ -126,6 +126,10 @@ type AddressRewriter interface { RedirectToQUIC(ctx context.Context, address net.Addr) (net.Addr, bool, error) } +type TLSAddressRewriter interface { + RedirectToTLSQUIC(ctx context.Context, address net.Addr) (net.Addr, bool, error) +} + // ConnDialer dials a net.Conn. type ConnDialer interface { Dial(context.Context, net.Addr) (net.Conn, error) @@ -167,13 +171,14 @@ func (d *QUICDialer) Dial(ctx context.Context, addr net.Addr) (*grpc.ClientConn, // TLSQUICDialer dials a gRPC connection over TLS/QUIC/SCION. This dialer is meant to // be used for secure inter AS communication. type TLSQUICDialer struct { - *QUICDialer + Rewriter TLSAddressRewriter + Dialer ConnDialer Credentials credentials.TransportCredentials } // Dial dials a gRPC connection over TLS/QUIC/SCION. func (d *TLSQUICDialer) Dial(ctx context.Context, addr net.Addr) (*grpc.ClientConn, error) { - addr, _, err := d.Rewriter.RedirectToQUIC(ctx, addr) + addr, _, err := d.Rewriter.RedirectToTLSQUIC(ctx, addr) if err != nil { return nil, serrors.WrapStr("resolving SVC address", err) } diff --git a/go/pkg/grpc/mock_grpc/BUILD.bazel b/go/pkg/grpc/mock_grpc/BUILD.bazel new file mode 100644 index 0000000000..32e9407ace --- /dev/null +++ b/go/pkg/grpc/mock_grpc/BUILD.bazel @@ -0,0 +1,12 @@ +load("//lint:go.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["dialer.go"], + importpath = "github.com/scionproto/scion/go/pkg/grpc/mock_grpc", + visibility = ["//visibility:public"], + deps = [ + "@com_github_golang_mock//gomock:go_default_library", + "@org_golang_google_grpc//:go_default_library", + ], +) diff --git a/go/pkg/grpc/mock_grpc/dialer.go b/go/pkg/grpc/mock_grpc/dialer.go new file mode 100644 index 0000000000..e12f44389a --- /dev/null +++ b/go/pkg/grpc/mock_grpc/dialer.go @@ -0,0 +1,51 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/scionproto/scion/go/pkg/grpc (interfaces: Dialer) + +// Package mock_grpc is a generated GoMock package. +package mock_grpc + +import ( + context "context" + gomock "github.com/golang/mock/gomock" + grpc "google.golang.org/grpc" + net "net" + reflect "reflect" +) + +// MockDialer is a mock of Dialer interface +type MockDialer struct { + ctrl *gomock.Controller + recorder *MockDialerMockRecorder +} + +// MockDialerMockRecorder is the mock recorder for MockDialer +type MockDialerMockRecorder struct { + mock *MockDialer +} + +// NewMockDialer creates a new mock instance +func NewMockDialer(ctrl *gomock.Controller) *MockDialer { + mock := &MockDialer{ctrl: ctrl} + mock.recorder = &MockDialerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockDialer) EXPECT() *MockDialerMockRecorder { + return m.recorder +} + +// Dial mocks base method +func (m *MockDialer) Dial(arg0 context.Context, arg1 net.Addr) (*grpc.ClientConn, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Dial", arg0, arg1) + ret0, _ := ret[0].(*grpc.ClientConn) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Dial indicates an expected call of Dial +func (mr *MockDialerMockRecorder) Dial(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Dial", reflect.TypeOf((*MockDialer)(nil).Dial), arg0, arg1) +} diff --git a/go/pkg/proto/control_plane/BUILD.bazel b/go/pkg/proto/control_plane/BUILD.bazel index bc96d18684..c82b1f0ca3 100644 --- a/go/pkg/proto/control_plane/BUILD.bazel +++ b/go/pkg/proto/control_plane/BUILD.bazel @@ -9,5 +9,6 @@ go_proto_library( deps = [ "//go/pkg/proto/control_plane/experimental:go_default_library", "//go/pkg/proto/crypto:go_default_library", + "//go/pkg/proto/drkey:go_default_library", ], ) diff --git a/go/pkg/proto/control_plane/drkey.pb.go b/go/pkg/proto/control_plane/drkey.pb.go new file mode 100644 index 0000000000..c1e5d03e7a --- /dev/null +++ b/go/pkg/proto/control_plane/drkey.pb.go @@ -0,0 +1,399 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.15.3 +// source: proto/control_plane/v1/drkey.proto + +package control_plane + +import ( + context "context" + drkey "github.com/scionproto/scion/go/pkg/proto/drkey" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type DRKeyLvl2Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BaseReq *drkey.DRKeyLvl2Request `protobuf:"bytes,1,opt,name=base_req,json=baseReq,proto3" json:"base_req,omitempty"` +} + +func (x *DRKeyLvl2Request) Reset() { + *x = DRKeyLvl2Request{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DRKeyLvl2Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DRKeyLvl2Request) ProtoMessage() {} + +func (x *DRKeyLvl2Request) ProtoReflect() protoreflect.Message { + mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DRKeyLvl2Request.ProtoReflect.Descriptor instead. +func (*DRKeyLvl2Request) Descriptor() ([]byte, []int) { + return file_proto_control_plane_v1_drkey_proto_rawDescGZIP(), []int{0} +} + +func (x *DRKeyLvl2Request) GetBaseReq() *drkey.DRKeyLvl2Request { + if x != nil { + return x.BaseReq + } + return nil +} + +type DRKeyLvl2Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BaseRep *drkey.DRKeyLvl2Response `protobuf:"bytes,1,opt,name=base_rep,json=baseRep,proto3" json:"base_rep,omitempty"` +} + +func (x *DRKeyLvl2Response) Reset() { + *x = DRKeyLvl2Response{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DRKeyLvl2Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DRKeyLvl2Response) ProtoMessage() {} + +func (x *DRKeyLvl2Response) ProtoReflect() protoreflect.Message { + mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DRKeyLvl2Response.ProtoReflect.Descriptor instead. +func (*DRKeyLvl2Response) Descriptor() ([]byte, []int) { + return file_proto_control_plane_v1_drkey_proto_rawDescGZIP(), []int{1} +} + +func (x *DRKeyLvl2Response) GetBaseRep() *drkey.DRKeyLvl2Response { + if x != nil { + return x.BaseRep + } + return nil +} + +var File_proto_control_plane_v1_drkey_proto protoreflect.FileDescriptor + +var file_proto_control_plane_v1_drkey_proto_rawDesc = []byte{ + 0x0a, 0x22, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, + 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x1e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2f, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2f, 0x6d, 0x67, 0x6d, 0x74, 0x2f, 0x76, + 0x31, 0x2f, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x54, 0x0a, 0x10, + 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x40, 0x0a, 0x08, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, 0x79, + 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, + 0x6c, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x52, + 0x65, 0x71, 0x22, 0x56, 0x0a, 0x11, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x08, 0x62, 0x61, 0x73, 0x65, 0x5f, + 0x72, 0x65, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x70, 0x32, 0x70, 0x0a, 0x10, 0x44, 0x52, + 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x31, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5c, + 0x0a, 0x09, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x31, 0x12, 0x25, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x31, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, 0x79, + 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, + 0x6c, 0x31, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x32, 0x76, 0x0a, 0x10, + 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x12, 0x62, 0x0a, 0x09, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, 0x12, 0x28, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x70, 0x6c, + 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x42, 0x38, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x73, 0x63, 0x69, 0x6f, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x63, + 0x69, 0x6f, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_proto_control_plane_v1_drkey_proto_rawDescOnce sync.Once + file_proto_control_plane_v1_drkey_proto_rawDescData = file_proto_control_plane_v1_drkey_proto_rawDesc +) + +func file_proto_control_plane_v1_drkey_proto_rawDescGZIP() []byte { + file_proto_control_plane_v1_drkey_proto_rawDescOnce.Do(func() { + file_proto_control_plane_v1_drkey_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_control_plane_v1_drkey_proto_rawDescData) + }) + return file_proto_control_plane_v1_drkey_proto_rawDescData +} + +var file_proto_control_plane_v1_drkey_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_proto_control_plane_v1_drkey_proto_goTypes = []interface{}{ + (*DRKeyLvl2Request)(nil), // 0: proto.control_plane.v1.DRKeyLvl2Request + (*DRKeyLvl2Response)(nil), // 1: proto.control_plane.v1.DRKeyLvl2Response + (*drkey.DRKeyLvl2Request)(nil), // 2: proto.drkey.mgmt.v1.DRKeyLvl2Request + (*drkey.DRKeyLvl2Response)(nil), // 3: proto.drkey.mgmt.v1.DRKeyLvl2Response + (*drkey.DRKeyLvl1Request)(nil), // 4: proto.drkey.mgmt.v1.DRKeyLvl1Request + (*drkey.DRKeyLvl1Response)(nil), // 5: proto.drkey.mgmt.v1.DRKeyLvl1Response +} +var file_proto_control_plane_v1_drkey_proto_depIdxs = []int32{ + 2, // 0: proto.control_plane.v1.DRKeyLvl2Request.base_req:type_name -> proto.drkey.mgmt.v1.DRKeyLvl2Request + 3, // 1: proto.control_plane.v1.DRKeyLvl2Response.base_rep:type_name -> proto.drkey.mgmt.v1.DRKeyLvl2Response + 4, // 2: proto.control_plane.v1.DRKeyLvl1Service.DRKeyLvl1:input_type -> proto.drkey.mgmt.v1.DRKeyLvl1Request + 0, // 3: proto.control_plane.v1.DRKeyLvl2Service.DRKeyLvl2:input_type -> proto.control_plane.v1.DRKeyLvl2Request + 5, // 4: proto.control_plane.v1.DRKeyLvl1Service.DRKeyLvl1:output_type -> proto.drkey.mgmt.v1.DRKeyLvl1Response + 1, // 5: proto.control_plane.v1.DRKeyLvl2Service.DRKeyLvl2:output_type -> proto.control_plane.v1.DRKeyLvl2Response + 4, // [4:6] is the sub-list for method output_type + 2, // [2:4] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_proto_control_plane_v1_drkey_proto_init() } +func file_proto_control_plane_v1_drkey_proto_init() { + if File_proto_control_plane_v1_drkey_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_proto_control_plane_v1_drkey_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DRKeyLvl2Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_control_plane_v1_drkey_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DRKeyLvl2Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_proto_control_plane_v1_drkey_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 2, + }, + GoTypes: file_proto_control_plane_v1_drkey_proto_goTypes, + DependencyIndexes: file_proto_control_plane_v1_drkey_proto_depIdxs, + MessageInfos: file_proto_control_plane_v1_drkey_proto_msgTypes, + }.Build() + File_proto_control_plane_v1_drkey_proto = out.File + file_proto_control_plane_v1_drkey_proto_rawDesc = nil + file_proto_control_plane_v1_drkey_proto_goTypes = nil + file_proto_control_plane_v1_drkey_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// DRKeyLvl1ServiceClient is the client API for DRKeyLvl1Service service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type DRKeyLvl1ServiceClient interface { + DRKeyLvl1(ctx context.Context, in *drkey.DRKeyLvl1Request, opts ...grpc.CallOption) (*drkey.DRKeyLvl1Response, error) +} + +type dRKeyLvl1ServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewDRKeyLvl1ServiceClient(cc grpc.ClientConnInterface) DRKeyLvl1ServiceClient { + return &dRKeyLvl1ServiceClient{cc} +} + +func (c *dRKeyLvl1ServiceClient) DRKeyLvl1(ctx context.Context, in *drkey.DRKeyLvl1Request, opts ...grpc.CallOption) (*drkey.DRKeyLvl1Response, error) { + out := new(drkey.DRKeyLvl1Response) + err := c.cc.Invoke(ctx, "/proto.control_plane.v1.DRKeyLvl1Service/DRKeyLvl1", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// DRKeyLvl1ServiceServer is the server API for DRKeyLvl1Service service. +type DRKeyLvl1ServiceServer interface { + DRKeyLvl1(context.Context, *drkey.DRKeyLvl1Request) (*drkey.DRKeyLvl1Response, error) +} + +// UnimplementedDRKeyLvl1ServiceServer can be embedded to have forward compatible implementations. +type UnimplementedDRKeyLvl1ServiceServer struct { +} + +func (*UnimplementedDRKeyLvl1ServiceServer) DRKeyLvl1(context.Context, *drkey.DRKeyLvl1Request) (*drkey.DRKeyLvl1Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method DRKeyLvl1 not implemented") +} + +func RegisterDRKeyLvl1ServiceServer(s *grpc.Server, srv DRKeyLvl1ServiceServer) { + s.RegisterService(&_DRKeyLvl1Service_serviceDesc, srv) +} + +func _DRKeyLvl1Service_DRKeyLvl1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(drkey.DRKeyLvl1Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DRKeyLvl1ServiceServer).DRKeyLvl1(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.control_plane.v1.DRKeyLvl1Service/DRKeyLvl1", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DRKeyLvl1ServiceServer).DRKeyLvl1(ctx, req.(*drkey.DRKeyLvl1Request)) + } + return interceptor(ctx, in, info, handler) +} + +var _DRKeyLvl1Service_serviceDesc = grpc.ServiceDesc{ + ServiceName: "proto.control_plane.v1.DRKeyLvl1Service", + HandlerType: (*DRKeyLvl1ServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "DRKeyLvl1", + Handler: _DRKeyLvl1Service_DRKeyLvl1_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "proto/control_plane/v1/drkey.proto", +} + +// DRKeyLvl2ServiceClient is the client API for DRKeyLvl2Service service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type DRKeyLvl2ServiceClient interface { + DRKeyLvl2(ctx context.Context, in *DRKeyLvl2Request, opts ...grpc.CallOption) (*DRKeyLvl2Response, error) +} + +type dRKeyLvl2ServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewDRKeyLvl2ServiceClient(cc grpc.ClientConnInterface) DRKeyLvl2ServiceClient { + return &dRKeyLvl2ServiceClient{cc} +} + +func (c *dRKeyLvl2ServiceClient) DRKeyLvl2(ctx context.Context, in *DRKeyLvl2Request, opts ...grpc.CallOption) (*DRKeyLvl2Response, error) { + out := new(DRKeyLvl2Response) + err := c.cc.Invoke(ctx, "/proto.control_plane.v1.DRKeyLvl2Service/DRKeyLvl2", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// DRKeyLvl2ServiceServer is the server API for DRKeyLvl2Service service. +type DRKeyLvl2ServiceServer interface { + DRKeyLvl2(context.Context, *DRKeyLvl2Request) (*DRKeyLvl2Response, error) +} + +// UnimplementedDRKeyLvl2ServiceServer can be embedded to have forward compatible implementations. +type UnimplementedDRKeyLvl2ServiceServer struct { +} + +func (*UnimplementedDRKeyLvl2ServiceServer) DRKeyLvl2(context.Context, *DRKeyLvl2Request) (*DRKeyLvl2Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method DRKeyLvl2 not implemented") +} + +func RegisterDRKeyLvl2ServiceServer(s *grpc.Server, srv DRKeyLvl2ServiceServer) { + s.RegisterService(&_DRKeyLvl2Service_serviceDesc, srv) +} + +func _DRKeyLvl2Service_DRKeyLvl2_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DRKeyLvl2Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DRKeyLvl2ServiceServer).DRKeyLvl2(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.control_plane.v1.DRKeyLvl2Service/DRKeyLvl2", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DRKeyLvl2ServiceServer).DRKeyLvl2(ctx, req.(*DRKeyLvl2Request)) + } + return interceptor(ctx, in, info, handler) +} + +var _DRKeyLvl2Service_serviceDesc = grpc.ServiceDesc{ + ServiceName: "proto.control_plane.v1.DRKeyLvl2Service", + HandlerType: (*DRKeyLvl2ServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "DRKeyLvl2", + Handler: _DRKeyLvl2Service_DRKeyLvl2_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "proto/control_plane/v1/drkey.proto", +} diff --git a/go/pkg/proto/control_plane/mock_control_plane/BUILD.bazel b/go/pkg/proto/control_plane/mock_control_plane/BUILD.bazel index e795d2af74..fd27e091b4 100644 --- a/go/pkg/proto/control_plane/mock_control_plane/BUILD.bazel +++ b/go/pkg/proto/control_plane/mock_control_plane/BUILD.bazel @@ -7,6 +7,8 @@ gomock( interfaces = [ "ChainRenewalServiceServer", "TrustMaterialServiceServer", + "DRKeyLvl2ServiceServer", + "DRKeyLvl1ServiceServer", ], library = "//go/pkg/proto/control_plane:go_default_library", package = "mock_control_plane", @@ -19,6 +21,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//go/pkg/proto/control_plane:go_default_library", + "//go/pkg/proto/drkey:go_default_library", "@com_github_golang_mock//gomock:go_default_library", ], ) diff --git a/go/pkg/proto/control_plane/mock_control_plane/mock.go b/go/pkg/proto/control_plane/mock_control_plane/mock.go index 6fc5c64d00..aa4888da8e 100644 --- a/go/pkg/proto/control_plane/mock_control_plane/mock.go +++ b/go/pkg/proto/control_plane/mock_control_plane/mock.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/scionproto/scion/go/pkg/proto/control_plane (interfaces: ChainRenewalServiceServer,TrustMaterialServiceServer) +// Source: github.com/scionproto/scion/go/pkg/proto/control_plane (interfaces: ChainRenewalServiceServer,TrustMaterialServiceServer,DRKeyLvl2ServiceServer,DRKeyLvl1ServiceServer) // Package mock_control_plane is a generated GoMock package. package mock_control_plane @@ -10,6 +10,7 @@ import ( gomock "github.com/golang/mock/gomock" control_plane "github.com/scionproto/scion/go/pkg/proto/control_plane" + drkey "github.com/scionproto/scion/go/pkg/proto/drkey" ) // MockChainRenewalServiceServer is a mock of ChainRenewalServiceServer interface. @@ -102,3 +103,79 @@ func (mr *MockTrustMaterialServiceServerMockRecorder) TRC(arg0, arg1 interface{} mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TRC", reflect.TypeOf((*MockTrustMaterialServiceServer)(nil).TRC), arg0, arg1) } + +// MockDRKeyLvl2ServiceServer is a mock of DRKeyLvl2ServiceServer interface. +type MockDRKeyLvl2ServiceServer struct { + ctrl *gomock.Controller + recorder *MockDRKeyLvl2ServiceServerMockRecorder +} + +// MockDRKeyLvl2ServiceServerMockRecorder is the mock recorder for MockDRKeyLvl2ServiceServer. +type MockDRKeyLvl2ServiceServerMockRecorder struct { + mock *MockDRKeyLvl2ServiceServer +} + +// NewMockDRKeyLvl2ServiceServer creates a new mock instance. +func NewMockDRKeyLvl2ServiceServer(ctrl *gomock.Controller) *MockDRKeyLvl2ServiceServer { + mock := &MockDRKeyLvl2ServiceServer{ctrl: ctrl} + mock.recorder = &MockDRKeyLvl2ServiceServerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDRKeyLvl2ServiceServer) EXPECT() *MockDRKeyLvl2ServiceServerMockRecorder { + return m.recorder +} + +// DRKeyLvl2 mocks base method. +func (m *MockDRKeyLvl2ServiceServer) DRKeyLvl2(arg0 context.Context, arg1 *control_plane.DRKeyLvl2Request) (*control_plane.DRKeyLvl2Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DRKeyLvl2", arg0, arg1) + ret0, _ := ret[0].(*control_plane.DRKeyLvl2Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DRKeyLvl2 indicates an expected call of DRKeyLvl2. +func (mr *MockDRKeyLvl2ServiceServerMockRecorder) DRKeyLvl2(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DRKeyLvl2", reflect.TypeOf((*MockDRKeyLvl2ServiceServer)(nil).DRKeyLvl2), arg0, arg1) +} + +// MockDRKeyLvl1ServiceServer is a mock of DRKeyLvl1ServiceServer interface. +type MockDRKeyLvl1ServiceServer struct { + ctrl *gomock.Controller + recorder *MockDRKeyLvl1ServiceServerMockRecorder +} + +// MockDRKeyLvl1ServiceServerMockRecorder is the mock recorder for MockDRKeyLvl1ServiceServer. +type MockDRKeyLvl1ServiceServerMockRecorder struct { + mock *MockDRKeyLvl1ServiceServer +} + +// NewMockDRKeyLvl1ServiceServer creates a new mock instance. +func NewMockDRKeyLvl1ServiceServer(ctrl *gomock.Controller) *MockDRKeyLvl1ServiceServer { + mock := &MockDRKeyLvl1ServiceServer{ctrl: ctrl} + mock.recorder = &MockDRKeyLvl1ServiceServerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDRKeyLvl1ServiceServer) EXPECT() *MockDRKeyLvl1ServiceServerMockRecorder { + return m.recorder +} + +// DRKeyLvl1 mocks base method. +func (m *MockDRKeyLvl1ServiceServer) DRKeyLvl1(arg0 context.Context, arg1 *drkey.DRKeyLvl1Request) (*drkey.DRKeyLvl1Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DRKeyLvl1", arg0, arg1) + ret0, _ := ret[0].(*drkey.DRKeyLvl1Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DRKeyLvl1 indicates an expected call of DRKeyLvl1. +func (mr *MockDRKeyLvl1ServiceServerMockRecorder) DRKeyLvl1(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DRKeyLvl1", reflect.TypeOf((*MockDRKeyLvl1ServiceServer)(nil).DRKeyLvl1), arg0, arg1) +} diff --git a/go/pkg/proto/daemon/BUILD.bazel b/go/pkg/proto/daemon/BUILD.bazel index 562f60e2d0..fd7fab6035 100644 --- a/go/pkg/proto/daemon/BUILD.bazel +++ b/go/pkg/proto/daemon/BUILD.bazel @@ -6,4 +6,7 @@ go_proto_library( importpath = "github.com/scionproto/scion/go/pkg/proto/daemon", proto = "//proto/daemon/v1:daemon", visibility = ["//visibility:public"], + deps = [ + "//go/pkg/proto/drkey:go_default_library", + ], ) diff --git a/go/pkg/proto/daemon/daemon.pb.go b/go/pkg/proto/daemon/daemon.pb.go index 73e91f6476..bac9f0397b 100644 --- a/go/pkg/proto/daemon/daemon.pb.go +++ b/go/pkg/proto/daemon/daemon.pb.go @@ -8,6 +8,7 @@ package daemon import ( context "context" + drkey "github.com/scionproto/scion/go/pkg/proto/drkey" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" @@ -1002,12 +1003,108 @@ func (*NotifyInterfaceDownResponse) Descriptor() ([]byte, []int) { return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{16} } +type DRKeyLvl2Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BaseReq *drkey.DRKeyLvl2Request `protobuf:"bytes,1,opt,name=base_req,json=baseReq,proto3" json:"base_req,omitempty"` +} + +func (x *DRKeyLvl2Request) Reset() { + *x = DRKeyLvl2Request{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DRKeyLvl2Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DRKeyLvl2Request) ProtoMessage() {} + +func (x *DRKeyLvl2Request) ProtoReflect() protoreflect.Message { + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DRKeyLvl2Request.ProtoReflect.Descriptor instead. +func (*DRKeyLvl2Request) Descriptor() ([]byte, []int) { + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{17} +} + +func (x *DRKeyLvl2Request) GetBaseReq() *drkey.DRKeyLvl2Request { + if x != nil { + return x.BaseReq + } + return nil +} + +type DRKeyLvl2Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BaseRep *drkey.DRKeyLvl2Response `protobuf:"bytes,1,opt,name=base_rep,json=baseRep,proto3" json:"base_rep,omitempty"` +} + +func (x *DRKeyLvl2Response) Reset() { + *x = DRKeyLvl2Response{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DRKeyLvl2Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DRKeyLvl2Response) ProtoMessage() {} + +func (x *DRKeyLvl2Response) ProtoReflect() protoreflect.Message { + mi := &file_proto_daemon_v1_daemon_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DRKeyLvl2Response.ProtoReflect.Descriptor instead. +func (*DRKeyLvl2Response) Descriptor() ([]byte, []int) { + return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{18} +} + +func (x *DRKeyLvl2Response) GetBaseRep() *drkey.DRKeyLvl2Response { + if x != nil { + return x.BaseRep + } + return nil +} + var File_proto_daemon_v1_daemon_proto protoreflect.FileDescriptor var file_proto_daemon_v1_daemon_proto_rawDesc = []byte{ 0x0a, 0x1c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x1a, + 0x1e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2f, 0x6d, 0x67, 0x6d, + 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, @@ -1117,45 +1214,61 @@ var file_proto_daemon_v1_daemon_proto_rawDesc = []byte{ 0x52, 0x05, 0x69, 0x73, 0x64, 0x41, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0x1d, 0x0a, 0x1b, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x6c, 0x0a, 0x08, 0x4c, 0x69, 0x6e, 0x6b, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, - 0x10, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, - 0x54, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x5f, 0x48, 0x4f, 0x50, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, - 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4f, 0x50, 0x45, 0x4e, 0x5f, 0x4e, - 0x45, 0x54, 0x10, 0x03, 0x32, 0xba, 0x03, 0x0a, 0x0d, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x05, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, - 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, - 0x2e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x3f, 0x0a, 0x02, 0x41, 0x53, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, - 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, - 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x57, 0x0a, 0x0a, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x12, - 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, - 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x08, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x54, 0x0a, 0x10, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, + 0x76, 0x6c, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x62, 0x61, + 0x73, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x22, 0x56, 0x0a, 0x11, + 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x41, 0x0a, 0x08, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, + 0x79, 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, + 0x76, 0x6c, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x07, 0x62, 0x61, 0x73, + 0x65, 0x52, 0x65, 0x70, 0x2a, 0x6c, 0x0a, 0x08, 0x4c, 0x69, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x19, 0x0a, 0x15, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x4c, + 0x49, 0x4e, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x10, + 0x01, 0x12, 0x17, 0x0a, 0x13, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4d, + 0x55, 0x4c, 0x54, 0x49, 0x5f, 0x48, 0x4f, 0x50, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x4c, 0x49, + 0x4e, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4f, 0x50, 0x45, 0x4e, 0x5f, 0x4e, 0x45, 0x54, + 0x10, 0x03, 0x32, 0x90, 0x04, 0x0a, 0x0d, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x05, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x1d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, + 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3f, + 0x0a, 0x02, 0x41, 0x53, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, + 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x2e, 0x41, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x57, 0x0a, 0x0a, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x12, 0x22, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, + 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x08, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, + 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x72, 0x0a, - 0x13, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, - 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, - 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x74, - 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, - 0x61, 0x63, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x73, 0x63, 0x69, 0x6f, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x63, 0x69, 0x6f, 0x6e, - 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x64, 0x61, - 0x65, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x72, 0x0a, 0x13, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x44, 0x6f, + 0x77, 0x6e, 0x12, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, + 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, + 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, + 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x54, 0x0a, 0x09, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, 0x12, 0x21, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, + 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, + 0x31, 0x2e, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x63, 0x69, 0x6f, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, + 0x63, 0x69, 0x6f, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2f, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1171,7 +1284,7 @@ func file_proto_daemon_v1_daemon_proto_rawDescGZIP() []byte { } var file_proto_daemon_v1_daemon_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_proto_daemon_v1_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 19) +var file_proto_daemon_v1_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 21) var file_proto_daemon_v1_daemon_proto_goTypes = []interface{}{ (LinkType)(0), // 0: proto.daemon.v1.LinkType (*PathsRequest)(nil), // 1: proto.daemon.v1.PathsRequest @@ -1191,40 +1304,48 @@ var file_proto_daemon_v1_daemon_proto_goTypes = []interface{}{ (*Underlay)(nil), // 15: proto.daemon.v1.Underlay (*NotifyInterfaceDownRequest)(nil), // 16: proto.daemon.v1.NotifyInterfaceDownRequest (*NotifyInterfaceDownResponse)(nil), // 17: proto.daemon.v1.NotifyInterfaceDownResponse - nil, // 18: proto.daemon.v1.InterfacesResponse.InterfacesEntry - nil, // 19: proto.daemon.v1.ServicesResponse.ServicesEntry - (*timestamppb.Timestamp)(nil), // 20: google.protobuf.Timestamp - (*durationpb.Duration)(nil), // 21: google.protobuf.Duration + (*DRKeyLvl2Request)(nil), // 18: proto.daemon.v1.DRKeyLvl2Request + (*DRKeyLvl2Response)(nil), // 19: proto.daemon.v1.DRKeyLvl2Response + nil, // 20: proto.daemon.v1.InterfacesResponse.InterfacesEntry + nil, // 21: proto.daemon.v1.ServicesResponse.ServicesEntry + (*timestamppb.Timestamp)(nil), // 22: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 23: google.protobuf.Duration + (*drkey.DRKeyLvl2Request)(nil), // 24: proto.drkey.mgmt.v1.DRKeyLvl2Request + (*drkey.DRKeyLvl2Response)(nil), // 25: proto.drkey.mgmt.v1.DRKeyLvl2Response } var file_proto_daemon_v1_daemon_proto_depIdxs = []int32{ 3, // 0: proto.daemon.v1.PathsResponse.paths:type_name -> proto.daemon.v1.Path 10, // 1: proto.daemon.v1.Path.interface:type_name -> proto.daemon.v1.Interface 4, // 2: proto.daemon.v1.Path.interfaces:type_name -> proto.daemon.v1.PathInterface - 20, // 3: proto.daemon.v1.Path.expiration:type_name -> google.protobuf.Timestamp - 21, // 4: proto.daemon.v1.Path.latency:type_name -> google.protobuf.Duration + 22, // 3: proto.daemon.v1.Path.expiration:type_name -> google.protobuf.Timestamp + 23, // 4: proto.daemon.v1.Path.latency:type_name -> google.protobuf.Duration 5, // 5: proto.daemon.v1.Path.geo:type_name -> proto.daemon.v1.GeoCoordinates 0, // 6: proto.daemon.v1.Path.link_type:type_name -> proto.daemon.v1.LinkType - 18, // 7: proto.daemon.v1.InterfacesResponse.interfaces:type_name -> proto.daemon.v1.InterfacesResponse.InterfacesEntry + 20, // 7: proto.daemon.v1.InterfacesResponse.interfaces:type_name -> proto.daemon.v1.InterfacesResponse.InterfacesEntry 15, // 8: proto.daemon.v1.Interface.address:type_name -> proto.daemon.v1.Underlay - 19, // 9: proto.daemon.v1.ServicesResponse.services:type_name -> proto.daemon.v1.ServicesResponse.ServicesEntry + 21, // 9: proto.daemon.v1.ServicesResponse.services:type_name -> proto.daemon.v1.ServicesResponse.ServicesEntry 14, // 10: proto.daemon.v1.ListService.services:type_name -> proto.daemon.v1.Service - 10, // 11: proto.daemon.v1.InterfacesResponse.InterfacesEntry.value:type_name -> proto.daemon.v1.Interface - 13, // 12: proto.daemon.v1.ServicesResponse.ServicesEntry.value:type_name -> proto.daemon.v1.ListService - 1, // 13: proto.daemon.v1.DaemonService.Paths:input_type -> proto.daemon.v1.PathsRequest - 6, // 14: proto.daemon.v1.DaemonService.AS:input_type -> proto.daemon.v1.ASRequest - 8, // 15: proto.daemon.v1.DaemonService.Interfaces:input_type -> proto.daemon.v1.InterfacesRequest - 11, // 16: proto.daemon.v1.DaemonService.Services:input_type -> proto.daemon.v1.ServicesRequest - 16, // 17: proto.daemon.v1.DaemonService.NotifyInterfaceDown:input_type -> proto.daemon.v1.NotifyInterfaceDownRequest - 2, // 18: proto.daemon.v1.DaemonService.Paths:output_type -> proto.daemon.v1.PathsResponse - 7, // 19: proto.daemon.v1.DaemonService.AS:output_type -> proto.daemon.v1.ASResponse - 9, // 20: proto.daemon.v1.DaemonService.Interfaces:output_type -> proto.daemon.v1.InterfacesResponse - 12, // 21: proto.daemon.v1.DaemonService.Services:output_type -> proto.daemon.v1.ServicesResponse - 17, // 22: proto.daemon.v1.DaemonService.NotifyInterfaceDown:output_type -> proto.daemon.v1.NotifyInterfaceDownResponse - 18, // [18:23] is the sub-list for method output_type - 13, // [13:18] is the sub-list for method input_type - 13, // [13:13] is the sub-list for extension type_name - 13, // [13:13] is the sub-list for extension extendee - 0, // [0:13] is the sub-list for field type_name + 24, // 11: proto.daemon.v1.DRKeyLvl2Request.base_req:type_name -> proto.drkey.mgmt.v1.DRKeyLvl2Request + 25, // 12: proto.daemon.v1.DRKeyLvl2Response.base_rep:type_name -> proto.drkey.mgmt.v1.DRKeyLvl2Response + 10, // 13: proto.daemon.v1.InterfacesResponse.InterfacesEntry.value:type_name -> proto.daemon.v1.Interface + 13, // 14: proto.daemon.v1.ServicesResponse.ServicesEntry.value:type_name -> proto.daemon.v1.ListService + 1, // 15: proto.daemon.v1.DaemonService.Paths:input_type -> proto.daemon.v1.PathsRequest + 6, // 16: proto.daemon.v1.DaemonService.AS:input_type -> proto.daemon.v1.ASRequest + 8, // 17: proto.daemon.v1.DaemonService.Interfaces:input_type -> proto.daemon.v1.InterfacesRequest + 11, // 18: proto.daemon.v1.DaemonService.Services:input_type -> proto.daemon.v1.ServicesRequest + 16, // 19: proto.daemon.v1.DaemonService.NotifyInterfaceDown:input_type -> proto.daemon.v1.NotifyInterfaceDownRequest + 18, // 20: proto.daemon.v1.DaemonService.DRKeyLvl2:input_type -> proto.daemon.v1.DRKeyLvl2Request + 2, // 21: proto.daemon.v1.DaemonService.Paths:output_type -> proto.daemon.v1.PathsResponse + 7, // 22: proto.daemon.v1.DaemonService.AS:output_type -> proto.daemon.v1.ASResponse + 9, // 23: proto.daemon.v1.DaemonService.Interfaces:output_type -> proto.daemon.v1.InterfacesResponse + 12, // 24: proto.daemon.v1.DaemonService.Services:output_type -> proto.daemon.v1.ServicesResponse + 17, // 25: proto.daemon.v1.DaemonService.NotifyInterfaceDown:output_type -> proto.daemon.v1.NotifyInterfaceDownResponse + 19, // 26: proto.daemon.v1.DaemonService.DRKeyLvl2:output_type -> proto.daemon.v1.DRKeyLvl2Response + 21, // [21:27] is the sub-list for method output_type + 15, // [15:21] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name } func init() { file_proto_daemon_v1_daemon_proto_init() } @@ -1437,6 +1558,30 @@ func file_proto_daemon_v1_daemon_proto_init() { return nil } } + file_proto_daemon_v1_daemon_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DRKeyLvl2Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_daemon_v1_daemon_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DRKeyLvl2Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -1444,7 +1589,7 @@ func file_proto_daemon_v1_daemon_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_daemon_v1_daemon_proto_rawDesc, NumEnums: 1, - NumMessages: 19, + NumMessages: 21, NumExtensions: 0, NumServices: 1, }, @@ -1476,6 +1621,7 @@ type DaemonServiceClient interface { Interfaces(ctx context.Context, in *InterfacesRequest, opts ...grpc.CallOption) (*InterfacesResponse, error) Services(ctx context.Context, in *ServicesRequest, opts ...grpc.CallOption) (*ServicesResponse, error) NotifyInterfaceDown(ctx context.Context, in *NotifyInterfaceDownRequest, opts ...grpc.CallOption) (*NotifyInterfaceDownResponse, error) + DRKeyLvl2(ctx context.Context, in *DRKeyLvl2Request, opts ...grpc.CallOption) (*DRKeyLvl2Response, error) } type daemonServiceClient struct { @@ -1531,6 +1677,15 @@ func (c *daemonServiceClient) NotifyInterfaceDown(ctx context.Context, in *Notif return out, nil } +func (c *daemonServiceClient) DRKeyLvl2(ctx context.Context, in *DRKeyLvl2Request, opts ...grpc.CallOption) (*DRKeyLvl2Response, error) { + out := new(DRKeyLvl2Response) + err := c.cc.Invoke(ctx, "/proto.daemon.v1.DaemonService/DRKeyLvl2", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // DaemonServiceServer is the server API for DaemonService service. type DaemonServiceServer interface { Paths(context.Context, *PathsRequest) (*PathsResponse, error) @@ -1538,6 +1693,7 @@ type DaemonServiceServer interface { Interfaces(context.Context, *InterfacesRequest) (*InterfacesResponse, error) Services(context.Context, *ServicesRequest) (*ServicesResponse, error) NotifyInterfaceDown(context.Context, *NotifyInterfaceDownRequest) (*NotifyInterfaceDownResponse, error) + DRKeyLvl2(context.Context, *DRKeyLvl2Request) (*DRKeyLvl2Response, error) } // UnimplementedDaemonServiceServer can be embedded to have forward compatible implementations. @@ -1559,6 +1715,9 @@ func (*UnimplementedDaemonServiceServer) Services(context.Context, *ServicesRequ func (*UnimplementedDaemonServiceServer) NotifyInterfaceDown(context.Context, *NotifyInterfaceDownRequest) (*NotifyInterfaceDownResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method NotifyInterfaceDown not implemented") } +func (*UnimplementedDaemonServiceServer) DRKeyLvl2(context.Context, *DRKeyLvl2Request) (*DRKeyLvl2Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method DRKeyLvl2 not implemented") +} func RegisterDaemonServiceServer(s *grpc.Server, srv DaemonServiceServer) { s.RegisterService(&_DaemonService_serviceDesc, srv) @@ -1654,6 +1813,24 @@ func _DaemonService_NotifyInterfaceDown_Handler(srv interface{}, ctx context.Con return interceptor(ctx, in, info, handler) } +func _DaemonService_DRKeyLvl2_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DRKeyLvl2Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DaemonServiceServer).DRKeyLvl2(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.daemon.v1.DaemonService/DRKeyLvl2", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DaemonServiceServer).DRKeyLvl2(ctx, req.(*DRKeyLvl2Request)) + } + return interceptor(ctx, in, info, handler) +} + var _DaemonService_serviceDesc = grpc.ServiceDesc{ ServiceName: "proto.daemon.v1.DaemonService", HandlerType: (*DaemonServiceServer)(nil), @@ -1678,6 +1855,10 @@ var _DaemonService_serviceDesc = grpc.ServiceDesc{ MethodName: "NotifyInterfaceDown", Handler: _DaemonService_NotifyInterfaceDown_Handler, }, + { + MethodName: "DRKeyLvl2", + Handler: _DaemonService_DRKeyLvl2_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "proto/daemon/v1/daemon.proto", diff --git a/go/pkg/proto/daemon/mock_daemon/BUILD.bazel b/go/pkg/proto/daemon/mock_daemon/BUILD.bazel new file mode 100644 index 0000000000..7a898e601d --- /dev/null +++ b/go/pkg/proto/daemon/mock_daemon/BUILD.bazel @@ -0,0 +1,12 @@ +load("//lint:go.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["daemon.go"], + importpath = "github.com/scionproto/scion/go/pkg/proto/daemon/mock_daemon", + visibility = ["//visibility:public"], + deps = [ + "//go/pkg/proto/daemon:go_default_library", + "@com_github_golang_mock//gomock:go_default_library", + ], +) diff --git a/go/pkg/proto/daemon/mock_daemon/daemon.go b/go/pkg/proto/daemon/mock_daemon/daemon.go new file mode 100644 index 0000000000..5a0464b2f6 --- /dev/null +++ b/go/pkg/proto/daemon/mock_daemon/daemon.go @@ -0,0 +1,125 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/scionproto/scion/go/pkg/proto/daemon (interfaces: DaemonServiceServer) + +// Package mock_daemon is a generated GoMock package. +package mock_daemon + +import ( + context "context" + gomock "github.com/golang/mock/gomock" + daemon "github.com/scionproto/scion/go/pkg/proto/daemon" + reflect "reflect" +) + +// MockDaemonServiceServer is a mock of DaemonServiceServer interface +type MockDaemonServiceServer struct { + ctrl *gomock.Controller + recorder *MockDaemonServiceServerMockRecorder +} + +// MockDaemonServiceServerMockRecorder is the mock recorder for MockDaemonServiceServer +type MockDaemonServiceServerMockRecorder struct { + mock *MockDaemonServiceServer +} + +// NewMockDaemonServiceServer creates a new mock instance +func NewMockDaemonServiceServer(ctrl *gomock.Controller) *MockDaemonServiceServer { + mock := &MockDaemonServiceServer{ctrl: ctrl} + mock.recorder = &MockDaemonServiceServerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockDaemonServiceServer) EXPECT() *MockDaemonServiceServerMockRecorder { + return m.recorder +} + +// AS mocks base method +func (m *MockDaemonServiceServer) AS(arg0 context.Context, arg1 *daemon.ASRequest) (*daemon.ASResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AS", arg0, arg1) + ret0, _ := ret[0].(*daemon.ASResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AS indicates an expected call of AS +func (mr *MockDaemonServiceServerMockRecorder) AS(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AS", reflect.TypeOf((*MockDaemonServiceServer)(nil).AS), arg0, arg1) +} + +// DRKeyLvl2 mocks base method +func (m *MockDaemonServiceServer) DRKeyLvl2(arg0 context.Context, arg1 *daemon.DRKeyLvl2Request) (*daemon.DRKeyLvl2Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DRKeyLvl2", arg0, arg1) + ret0, _ := ret[0].(*daemon.DRKeyLvl2Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DRKeyLvl2 indicates an expected call of DRKeyLvl2 +func (mr *MockDaemonServiceServerMockRecorder) DRKeyLvl2(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DRKeyLvl2", reflect.TypeOf((*MockDaemonServiceServer)(nil).DRKeyLvl2), arg0, arg1) +} + +// Interfaces mocks base method +func (m *MockDaemonServiceServer) Interfaces(arg0 context.Context, arg1 *daemon.InterfacesRequest) (*daemon.InterfacesResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Interfaces", arg0, arg1) + ret0, _ := ret[0].(*daemon.InterfacesResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Interfaces indicates an expected call of Interfaces +func (mr *MockDaemonServiceServerMockRecorder) Interfaces(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Interfaces", reflect.TypeOf((*MockDaemonServiceServer)(nil).Interfaces), arg0, arg1) +} + +// NotifyInterfaceDown mocks base method +func (m *MockDaemonServiceServer) NotifyInterfaceDown(arg0 context.Context, arg1 *daemon.NotifyInterfaceDownRequest) (*daemon.NotifyInterfaceDownResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NotifyInterfaceDown", arg0, arg1) + ret0, _ := ret[0].(*daemon.NotifyInterfaceDownResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NotifyInterfaceDown indicates an expected call of NotifyInterfaceDown +func (mr *MockDaemonServiceServerMockRecorder) NotifyInterfaceDown(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NotifyInterfaceDown", reflect.TypeOf((*MockDaemonServiceServer)(nil).NotifyInterfaceDown), arg0, arg1) +} + +// Paths mocks base method +func (m *MockDaemonServiceServer) Paths(arg0 context.Context, arg1 *daemon.PathsRequest) (*daemon.PathsResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Paths", arg0, arg1) + ret0, _ := ret[0].(*daemon.PathsResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Paths indicates an expected call of Paths +func (mr *MockDaemonServiceServerMockRecorder) Paths(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Paths", reflect.TypeOf((*MockDaemonServiceServer)(nil).Paths), arg0, arg1) +} + +// Services mocks base method +func (m *MockDaemonServiceServer) Services(arg0 context.Context, arg1 *daemon.ServicesRequest) (*daemon.ServicesResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Services", arg0, arg1) + ret0, _ := ret[0].(*daemon.ServicesResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Services indicates an expected call of Services +func (mr *MockDaemonServiceServerMockRecorder) Services(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Services", reflect.TypeOf((*MockDaemonServiceServer)(nil).Services), arg0, arg1) +} diff --git a/go/pkg/proto/drkey/BUILD.bazel b/go/pkg/proto/drkey/BUILD.bazel new file mode 100644 index 0000000000..bdc0c3e9c1 --- /dev/null +++ b/go/pkg/proto/drkey/BUILD.bazel @@ -0,0 +1,21 @@ +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_pkg//:pkg.bzl", "pkg_tar") + +go_proto_library( + name = "go_default_library", + compiler = "@io_bazel_rules_go//proto:go_grpc", + importpath = "github.com/scionproto/scion/go/pkg/proto/drkey", + proto = "//proto/drkey/mgmt/v1:drkey", + visibility = ["//visibility:public"], +) + +filegroup( + name = "proto_src_files", + srcs = [":go_default_library"], + output_group = "go_generated_srcs", +) + +pkg_tar( + name = "proto_srcs", + srcs = [":proto_src_files"], +) diff --git a/go/pkg/proto/drkey/mgmt.pb.go b/go/pkg/proto/drkey/mgmt.pb.go new file mode 100644 index 0000000000..2940f2c106 --- /dev/null +++ b/go/pkg/proto/drkey/mgmt.pb.go @@ -0,0 +1,589 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.15.3 +// source: proto/drkey/mgmt/v1/mgmt.proto + +package drkey + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type DRKeyLvl1Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ValTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=val_time,json=valTime,proto3" json:"val_time,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` +} + +func (x *DRKeyLvl1Request) Reset() { + *x = DRKeyLvl1Request{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DRKeyLvl1Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DRKeyLvl1Request) ProtoMessage() {} + +func (x *DRKeyLvl1Request) ProtoReflect() protoreflect.Message { + mi := &file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DRKeyLvl1Request.ProtoReflect.Descriptor instead. +func (*DRKeyLvl1Request) Descriptor() ([]byte, []int) { + return file_proto_drkey_mgmt_v1_mgmt_proto_rawDescGZIP(), []int{0} +} + +func (x *DRKeyLvl1Request) GetValTime() *timestamppb.Timestamp { + if x != nil { + return x.ValTime + } + return nil +} + +func (x *DRKeyLvl1Request) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + +type DRKeyLvl1Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + EpochBegin *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=epoch_begin,json=epochBegin,proto3" json:"epoch_begin,omitempty"` + EpochEnd *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=epoch_end,json=epochEnd,proto3" json:"epoch_end,omitempty"` + Drkey []byte `protobuf:"bytes,3,opt,name=drkey,proto3" json:"drkey,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` +} + +func (x *DRKeyLvl1Response) Reset() { + *x = DRKeyLvl1Response{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DRKeyLvl1Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DRKeyLvl1Response) ProtoMessage() {} + +func (x *DRKeyLvl1Response) ProtoReflect() protoreflect.Message { + mi := &file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DRKeyLvl1Response.ProtoReflect.Descriptor instead. +func (*DRKeyLvl1Response) Descriptor() ([]byte, []int) { + return file_proto_drkey_mgmt_v1_mgmt_proto_rawDescGZIP(), []int{1} +} + +func (x *DRKeyLvl1Response) GetEpochBegin() *timestamppb.Timestamp { + if x != nil { + return x.EpochBegin + } + return nil +} + +func (x *DRKeyLvl1Response) GetEpochEnd() *timestamppb.Timestamp { + if x != nil { + return x.EpochEnd + } + return nil +} + +func (x *DRKeyLvl1Response) GetDrkey() []byte { + if x != nil { + return x.Drkey + } + return nil +} + +func (x *DRKeyLvl1Response) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + +type DRKeyLvl2Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Protocol string `protobuf:"bytes,1,opt,name=protocol,proto3" json:"protocol,omitempty"` + ReqType uint32 `protobuf:"varint,2,opt,name=req_type,json=reqType,proto3" json:"req_type,omitempty"` + ValTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=val_time,json=valTime,proto3" json:"val_time,omitempty"` + SrcIa uint64 `protobuf:"varint,4,opt,name=src_ia,json=srcIa,proto3" json:"src_ia,omitempty"` + DstIa uint64 `protobuf:"varint,5,opt,name=dst_ia,json=dstIa,proto3" json:"dst_ia,omitempty"` + SrcHost *DRKeyLvl2Request_DRKeyHost `protobuf:"bytes,6,opt,name=src_host,json=srcHost,proto3" json:"src_host,omitempty"` + DstHost *DRKeyLvl2Request_DRKeyHost `protobuf:"bytes,7,opt,name=dst_host,json=dstHost,proto3" json:"dst_host,omitempty"` + Misc []byte `protobuf:"bytes,8,opt,name=misc,proto3" json:"misc,omitempty"` +} + +func (x *DRKeyLvl2Request) Reset() { + *x = DRKeyLvl2Request{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DRKeyLvl2Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DRKeyLvl2Request) ProtoMessage() {} + +func (x *DRKeyLvl2Request) ProtoReflect() protoreflect.Message { + mi := &file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DRKeyLvl2Request.ProtoReflect.Descriptor instead. +func (*DRKeyLvl2Request) Descriptor() ([]byte, []int) { + return file_proto_drkey_mgmt_v1_mgmt_proto_rawDescGZIP(), []int{2} +} + +func (x *DRKeyLvl2Request) GetProtocol() string { + if x != nil { + return x.Protocol + } + return "" +} + +func (x *DRKeyLvl2Request) GetReqType() uint32 { + if x != nil { + return x.ReqType + } + return 0 +} + +func (x *DRKeyLvl2Request) GetValTime() *timestamppb.Timestamp { + if x != nil { + return x.ValTime + } + return nil +} + +func (x *DRKeyLvl2Request) GetSrcIa() uint64 { + if x != nil { + return x.SrcIa + } + return 0 +} + +func (x *DRKeyLvl2Request) GetDstIa() uint64 { + if x != nil { + return x.DstIa + } + return 0 +} + +func (x *DRKeyLvl2Request) GetSrcHost() *DRKeyLvl2Request_DRKeyHost { + if x != nil { + return x.SrcHost + } + return nil +} + +func (x *DRKeyLvl2Request) GetDstHost() *DRKeyLvl2Request_DRKeyHost { + if x != nil { + return x.DstHost + } + return nil +} + +func (x *DRKeyLvl2Request) GetMisc() []byte { + if x != nil { + return x.Misc + } + return nil +} + +type DRKeyLvl2Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Drkey []byte `protobuf:"bytes,2,opt,name=drkey,proto3" json:"drkey,omitempty"` + EpochBegin *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=epoch_begin,json=epochBegin,proto3" json:"epoch_begin,omitempty"` + EpochEnd *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=epoch_end,json=epochEnd,proto3" json:"epoch_end,omitempty"` + Misc []byte `protobuf:"bytes,5,opt,name=misc,proto3" json:"misc,omitempty"` +} + +func (x *DRKeyLvl2Response) Reset() { + *x = DRKeyLvl2Response{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DRKeyLvl2Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DRKeyLvl2Response) ProtoMessage() {} + +func (x *DRKeyLvl2Response) ProtoReflect() protoreflect.Message { + mi := &file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DRKeyLvl2Response.ProtoReflect.Descriptor instead. +func (*DRKeyLvl2Response) Descriptor() ([]byte, []int) { + return file_proto_drkey_mgmt_v1_mgmt_proto_rawDescGZIP(), []int{3} +} + +func (x *DRKeyLvl2Response) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + +func (x *DRKeyLvl2Response) GetDrkey() []byte { + if x != nil { + return x.Drkey + } + return nil +} + +func (x *DRKeyLvl2Response) GetEpochBegin() *timestamppb.Timestamp { + if x != nil { + return x.EpochBegin + } + return nil +} + +func (x *DRKeyLvl2Response) GetEpochEnd() *timestamppb.Timestamp { + if x != nil { + return x.EpochEnd + } + return nil +} + +func (x *DRKeyLvl2Response) GetMisc() []byte { + if x != nil { + return x.Misc + } + return nil +} + +type DRKeyLvl2Request_DRKeyHost struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type uint32 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty"` + Host []byte `protobuf:"bytes,2,opt,name=host,proto3" json:"host,omitempty"` +} + +func (x *DRKeyLvl2Request_DRKeyHost) Reset() { + *x = DRKeyLvl2Request_DRKeyHost{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DRKeyLvl2Request_DRKeyHost) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DRKeyLvl2Request_DRKeyHost) ProtoMessage() {} + +func (x *DRKeyLvl2Request_DRKeyHost) ProtoReflect() protoreflect.Message { + mi := &file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DRKeyLvl2Request_DRKeyHost.ProtoReflect.Descriptor instead. +func (*DRKeyLvl2Request_DRKeyHost) Descriptor() ([]byte, []int) { + return file_proto_drkey_mgmt_v1_mgmt_proto_rawDescGZIP(), []int{2, 0} +} + +func (x *DRKeyLvl2Request_DRKeyHost) GetType() uint32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *DRKeyLvl2Request_DRKeyHost) GetHost() []byte { + if x != nil { + return x.Host + } + return nil +} + +var File_proto_drkey_mgmt_v1_mgmt_proto protoreflect.FileDescriptor + +var file_proto_drkey_mgmt_v1_mgmt_proto_rawDesc = []byte{ + 0x0a, 0x1e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2f, 0x6d, 0x67, + 0x6d, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x13, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x6d, 0x67, + 0x6d, 0x74, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x83, 0x01, 0x0a, 0x10, 0x44, 0x52, 0x4b, 0x65, 0x79, + 0x4c, 0x76, 0x6c, 0x31, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x08, 0x76, + 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x76, 0x61, 0x6c, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xd9, 0x01, 0x0a, + 0x11, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x31, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x5f, 0x62, 0x65, 0x67, 0x69, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x42, 0x65, 0x67, 0x69, 0x6e, 0x12, + 0x37, 0x0a, 0x09, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x5f, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, + 0x65, 0x70, 0x6f, 0x63, 0x68, 0x45, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x72, 0x6b, 0x65, + 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x12, 0x38, + 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x8f, 0x03, 0x0a, 0x10, 0x44, 0x52, 0x4b, + 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, + 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x65, 0x71, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x72, 0x65, 0x71, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x76, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x52, 0x07, 0x76, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x73, + 0x72, 0x63, 0x5f, 0x69, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x72, 0x63, + 0x49, 0x61, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x73, 0x74, 0x5f, 0x69, 0x61, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x05, 0x64, 0x73, 0x74, 0x49, 0x61, 0x12, 0x4a, 0x0a, 0x08, 0x73, 0x72, 0x63, + 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x2e, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x07, 0x73, 0x72, + 0x63, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x4a, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x73, + 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x52, + 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x44, + 0x52, 0x4b, 0x65, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x07, 0x64, 0x73, 0x74, 0x48, 0x6f, 0x73, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x69, 0x73, 0x63, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x04, 0x6d, 0x69, 0x73, 0x63, 0x1a, 0x33, 0x0a, 0x09, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x48, 0x6f, + 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x22, 0xed, 0x01, 0x0a, 0x11, 0x44, + 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x76, 0x6c, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x72, + 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x64, 0x72, 0x6b, 0x65, 0x79, + 0x12, 0x3b, 0x0a, 0x0b, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x5f, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x0a, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x42, 0x65, 0x67, 0x69, 0x6e, 0x12, 0x37, 0x0a, + 0x09, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x5f, 0x65, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x65, 0x70, + 0x6f, 0x63, 0x68, 0x45, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x69, 0x73, 0x63, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6d, 0x69, 0x73, 0x63, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x63, 0x69, 0x6f, 0x6e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x63, 0x69, 0x6f, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x6b, 0x67, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_proto_drkey_mgmt_v1_mgmt_proto_rawDescOnce sync.Once + file_proto_drkey_mgmt_v1_mgmt_proto_rawDescData = file_proto_drkey_mgmt_v1_mgmt_proto_rawDesc +) + +func file_proto_drkey_mgmt_v1_mgmt_proto_rawDescGZIP() []byte { + file_proto_drkey_mgmt_v1_mgmt_proto_rawDescOnce.Do(func() { + file_proto_drkey_mgmt_v1_mgmt_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_drkey_mgmt_v1_mgmt_proto_rawDescData) + }) + return file_proto_drkey_mgmt_v1_mgmt_proto_rawDescData +} + +var file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_proto_drkey_mgmt_v1_mgmt_proto_goTypes = []interface{}{ + (*DRKeyLvl1Request)(nil), // 0: proto.drkey.mgmt.v1.DRKeyLvl1Request + (*DRKeyLvl1Response)(nil), // 1: proto.drkey.mgmt.v1.DRKeyLvl1Response + (*DRKeyLvl2Request)(nil), // 2: proto.drkey.mgmt.v1.DRKeyLvl2Request + (*DRKeyLvl2Response)(nil), // 3: proto.drkey.mgmt.v1.DRKeyLvl2Response + (*DRKeyLvl2Request_DRKeyHost)(nil), // 4: proto.drkey.mgmt.v1.DRKeyLvl2Request.DRKeyHost + (*timestamppb.Timestamp)(nil), // 5: google.protobuf.Timestamp +} +var file_proto_drkey_mgmt_v1_mgmt_proto_depIdxs = []int32{ + 5, // 0: proto.drkey.mgmt.v1.DRKeyLvl1Request.val_time:type_name -> google.protobuf.Timestamp + 5, // 1: proto.drkey.mgmt.v1.DRKeyLvl1Request.timestamp:type_name -> google.protobuf.Timestamp + 5, // 2: proto.drkey.mgmt.v1.DRKeyLvl1Response.epoch_begin:type_name -> google.protobuf.Timestamp + 5, // 3: proto.drkey.mgmt.v1.DRKeyLvl1Response.epoch_end:type_name -> google.protobuf.Timestamp + 5, // 4: proto.drkey.mgmt.v1.DRKeyLvl1Response.timestamp:type_name -> google.protobuf.Timestamp + 5, // 5: proto.drkey.mgmt.v1.DRKeyLvl2Request.val_time:type_name -> google.protobuf.Timestamp + 4, // 6: proto.drkey.mgmt.v1.DRKeyLvl2Request.src_host:type_name -> proto.drkey.mgmt.v1.DRKeyLvl2Request.DRKeyHost + 4, // 7: proto.drkey.mgmt.v1.DRKeyLvl2Request.dst_host:type_name -> proto.drkey.mgmt.v1.DRKeyLvl2Request.DRKeyHost + 5, // 8: proto.drkey.mgmt.v1.DRKeyLvl2Response.timestamp:type_name -> google.protobuf.Timestamp + 5, // 9: proto.drkey.mgmt.v1.DRKeyLvl2Response.epoch_begin:type_name -> google.protobuf.Timestamp + 5, // 10: proto.drkey.mgmt.v1.DRKeyLvl2Response.epoch_end:type_name -> google.protobuf.Timestamp + 11, // [11:11] is the sub-list for method output_type + 11, // [11:11] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name +} + +func init() { file_proto_drkey_mgmt_v1_mgmt_proto_init() } +func file_proto_drkey_mgmt_v1_mgmt_proto_init() { + if File_proto_drkey_mgmt_v1_mgmt_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DRKeyLvl1Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DRKeyLvl1Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DRKeyLvl2Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DRKeyLvl2Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DRKeyLvl2Request_DRKeyHost); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_proto_drkey_mgmt_v1_mgmt_proto_rawDesc, + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_proto_drkey_mgmt_v1_mgmt_proto_goTypes, + DependencyIndexes: file_proto_drkey_mgmt_v1_mgmt_proto_depIdxs, + MessageInfos: file_proto_drkey_mgmt_v1_mgmt_proto_msgTypes, + }.Build() + File_proto_drkey_mgmt_v1_mgmt_proto = out.File + file_proto_drkey_mgmt_v1_mgmt_proto_rawDesc = nil + file_proto_drkey_mgmt_v1_mgmt_proto_goTypes = nil + file_proto_drkey_mgmt_v1_mgmt_proto_depIdxs = nil +} diff --git a/go/pkg/storage/BUILD.bazel b/go/pkg/storage/BUILD.bazel index 8713958b02..6ab2dbf587 100644 --- a/go/pkg/storage/BUILD.bazel +++ b/go/pkg/storage/BUILD.bazel @@ -12,6 +12,8 @@ go_library( "//go/cs/beacon:go_default_library", "//go/lib/addr:go_default_library", "//go/lib/config:go_default_library", + "//go/lib/drkey:go_default_library", + "//go/lib/drkey/drkeydbsqlite:go_default_library", "//go/lib/infra/modules/cleaner:go_default_library", "//go/lib/infra/modules/db:go_default_library", "//go/lib/log:go_default_library", diff --git a/go/pkg/storage/storage.go b/go/pkg/storage/storage.go index ff18becc75..a560c0d40c 100644 --- a/go/pkg/storage/storage.go +++ b/go/pkg/storage/storage.go @@ -24,6 +24,8 @@ import ( "github.com/scionproto/scion/go/cs/beacon" "github.com/scionproto/scion/go/lib/addr" "github.com/scionproto/scion/go/lib/config" + "github.com/scionproto/scion/go/lib/drkey" + "github.com/scionproto/scion/go/lib/drkey/drkeydbsqlite" "github.com/scionproto/scion/go/lib/infra/modules/cleaner" "github.com/scionproto/scion/go/lib/infra/modules/db" "github.com/scionproto/scion/go/lib/log" @@ -48,6 +50,7 @@ const ( DefaultPath = "/share/scion.db" DefaultTrustDBPath = "/share/data/%s.trust.db" DefaultPathDBPath = "/share/cache/%s.path.db" + DefaultDRKeyDBPath = "/share/cache/%s.drkey.db" ) // Default samples for various databases. @@ -61,6 +64,9 @@ var ( SampleTrustDB = DBConfig{ Connection: DefaultTrustDBPath, } + SampleDRKeyDB = DBConfig{ + Connection: DefaultDRKeyDBPath, + } ) // SetID returns a clone of the configuration that has the ID set on the connection string. @@ -233,3 +239,23 @@ func NewTrustStorage(c DBConfig) (TrustDB, error) { SetConnLimits(db, c) return db, nil } + +func NewDRKeyLvl1Storage(c DBConfig) (drkey.Lvl1DB, error) { + log.Info("Connecting DRKeyDB", " ", BackendSqlite, "connection", c.Connection) + db, err := drkeydbsqlite.NewLvl1Backend(c.Connection) + if err != nil { + return nil, err + } + SetConnLimits(db, c) + return db, nil +} + +func NewDRKeyLvl2Storage(c DBConfig) (drkey.Lvl2DB, error) { + log.Info("Connecting DRKeyDB", " ", BackendSqlite, "connection", c.Connection) + db, err := drkeydbsqlite.NewLvl2Backend(c.Connection) + if err != nil { + return nil, err + } + SetConnLimits(db, c) + return db, nil +} diff --git a/go/pkg/trust/BUILD.bazel b/go/pkg/trust/BUILD.bazel index b31289e560..38447d4190 100644 --- a/go/pkg/trust/BUILD.bazel +++ b/go/pkg/trust/BUILD.bazel @@ -16,6 +16,7 @@ go_library( "signer_gen.go", "store.go", "tls_handshake.go", + "transport_credentials.go", "verifier.go", ], importpath = "github.com/scionproto/scion/go/pkg/trust", @@ -40,6 +41,7 @@ go_library( "@com_github_opentracing_opentracing_go//:go_default_library", "@com_github_opentracing_opentracing_go//ext:go_default_library", "@com_github_patrickmn_go_cache//:go_default_library", + "@org_golang_google_grpc//credentials:go_default_library", "@org_golang_google_protobuf//proto:go_default_library", ], ) diff --git a/go/pkg/trust/tls_handshake.go b/go/pkg/trust/tls_handshake.go index c23f5c3a2f..0fe00566d7 100644 --- a/go/pkg/trust/tls_handshake.go +++ b/go/pkg/trust/tls_handshake.go @@ -106,3 +106,18 @@ func verifyChain(chain []*x509.Certificate, trcs []cppki.SignedTRC) error { } return errs.ToError() } + +// FileLoader loads key pair from file +type FileLoader struct { + CertFile string + KeyFile string +} + +// LoadX509KeyPair returns the TLS certificate to be provided during a TLS handshake. +func (l FileLoader) LoadX509KeyPair() (*tls.Certificate, error) { + cert, err := tls.LoadX509KeyPair(l.CertFile, l.KeyFile) + if err != nil { + return nil, serrors.WrapStr("loading certificates for DRKey gRPCs", err) + } + return &cert, nil +} diff --git a/go/pkg/trust/transport_credentials.go b/go/pkg/trust/transport_credentials.go new file mode 100644 index 0000000000..cf60e1fa77 --- /dev/null +++ b/go/pkg/trust/transport_credentials.go @@ -0,0 +1,117 @@ +// Copyright 2020 ETH Zurich +// +// 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" + "crypto/tls" + "net" + "strings" + + "google.golang.org/grpc/credentials" + + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/scrypto/cppki" + "github.com/scionproto/scion/go/lib/serrors" +) + +// XXX(JordiSubira): ClientCredentials enables hooking a procedure to validate +// the TLS state during the client handshake. Note that the current implementation +// extends the grpc/credentials callback for TLS credentials by carrying out the +// validation after the handshake has been completed (this last using the provided +// TLS config). +// Go1.15 introduces the VerifyConnection callback within TLS Config which would +// enable hooking the procedure to validate the TLS state within the TLS client +// handshake. Therefore, if Go1.15 (or greater) is used ClientCredentials should +// be deprecated using the aforementioned alternative. + +// ClientCredentials implements credentials.TransportCredentials extending +// the ClientHandshake callback +type ClientCredentials struct { + credentials.TransportCredentials +} + +// NewClientCredentials returns a new instance which embeds tlsCred, which in turn +// implements credentials.TransportCredentials interface +func NewClientCredentials(conf *tls.Config) credentials.TransportCredentials { + return &ClientCredentials{ + credentials.NewTLS(conf), + } +} + +// ClientHandshake extends the embedded TransportCredentials callback by verifying the peer's name +// and the information provided in the certificate. Upon error the connection is closed and a +// non-temporary error is returned. +func (c *ClientCredentials) ClientHandshake(ctx context.Context, authority string, + rawConn net.Conn) (_ net.Conn, _ credentials.AuthInfo, err error) { + conn, authInfo, err := c.TransportCredentials.ClientHandshake(ctx, authority, rawConn) + if err != nil { + return nil, nil, err + } + + tlsInfo, ok := authInfo.(credentials.TLSInfo) + if !ok { + conn.Close() + return nil, nil, &nonTempWrapper{ + serrors.New("authInfo should be type tlsInfo and is", + "authInfoType", authInfo.AuthType()), + } + } + // XXX (JordiSubira): In Go1.13 tls.ConnectionState.ServerName is only set + // on the server side. Thus, we pass authority as the serverName. + if err = verifyConnection(tlsInfo.State, authority); err != nil { + conn.Close() + return nil, nil, &nonTempWrapper{ + serrors.WrapStr("verifying connection in client handshake", err), + } + } + return conn, tlsInfo, nil +} + +type nonTempWrapper struct { + error +} + +func (e *nonTempWrapper) Temporary() bool { + return false +} + +func verifyConnection(cs tls.ConnectionState, serverName string) error { + serverNameIA := strings.Split(serverName, ",")[0] + serverIA, err := addr.IAFromString(serverNameIA) + if err != nil { + return serrors.WrapStr("extracting IA from server name", err) + } + certIA, err := cppki.ExtractIA(cs.PeerCertificates[0].Subject) + if err != nil { + return serrors.WrapStr("extracting IA from peer cert", err) + } + if !serverIA.Equal(certIA) { + return serrors.New("extracted IA from cert and server IA do not match", + "peer IA", certIA, "server IA", serverIA) + } + return nil +} + +// GetTansportCredentials returns a configuration which implements TransportCredentials +// interface, based on the provided TLSCryptoManager +func GetTansportCredentials(mgr *TLSCryptoManager) credentials.TransportCredentials { + config := &tls.Config{ + InsecureSkipVerify: true, + GetClientCertificate: mgr.GetClientCertificate, + VerifyPeerCertificate: mgr.VerifyPeerCertificate, + } + return NewClientCredentials(config) +} diff --git a/proto/control_plane/v1/BUILD.bazel b/proto/control_plane/v1/BUILD.bazel index df8521537e..dee1160aa5 100644 --- a/proto/control_plane/v1/BUILD.bazel +++ b/proto/control_plane/v1/BUILD.bazel @@ -4,6 +4,7 @@ proto_library( name = "control_plane", srcs = [ "cppki.proto", + "drkey.proto", "renewal.proto", "seg.proto", "seg_extensions.proto", @@ -13,6 +14,7 @@ proto_library( deps = [ "//proto/control_plane/experimental/v1:experimental", "//proto/crypto/v1:crypto", + "//proto/drkey/mgmt/v1:drkey", "@com_google_protobuf//:timestamp_proto", ], ) diff --git a/proto/control_plane/v1/drkey.proto b/proto/control_plane/v1/drkey.proto new file mode 100644 index 0000000000..4434ad044b --- /dev/null +++ b/proto/control_plane/v1/drkey.proto @@ -0,0 +1,41 @@ +// Copyright 2020 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. + +syntax = "proto3"; + +option go_package = "github.com/scionproto/scion/go/pkg/proto/control_plane"; + +package proto.control_plane.v1; + +import "proto/drkey/mgmt/v1/mgmt.proto"; + +service DRKeyLvl1Service{ + // Return the Lvl1Key that matches the request + rpc DRKeyLvl1(proto.drkey.mgmt.v1.DRKeyLvl1Request) returns (proto.drkey.mgmt.v1.DRKeyLvl1Response) {} +} + +service DRKeyLvl2Service{ + // Return the Lvl2Key that matches the request + rpc DRKeyLvl2(DRKeyLvl2Request) returns (DRKeyLvl2Response) {} +} + +message DRKeyLvl2Request{ + // BaseReq contains the basic information for the Lvl2 request + proto.drkey.mgmt.v1.DRKeyLvl2Request base_req = 1; +} + +message DRKeyLvl2Response{ + // BaseRep contains the basic information for the Lvl2 response + proto.drkey.mgmt.v1.DRKeyLvl2Response base_rep = 1; +} diff --git a/proto/daemon/v1/BUILD.bazel b/proto/daemon/v1/BUILD.bazel index 8a7d07cff6..0e7cde9070 100644 --- a/proto/daemon/v1/BUILD.bazel +++ b/proto/daemon/v1/BUILD.bazel @@ -7,6 +7,7 @@ proto_library( ], visibility = ["//visibility:public"], deps = [ + "//proto/drkey/mgmt/v1:drkey", "@com_google_protobuf//:duration_proto", "@com_google_protobuf//:timestamp_proto", ], diff --git a/proto/daemon/v1/daemon.proto b/proto/daemon/v1/daemon.proto index 51e4f1549d..ca246648f8 100644 --- a/proto/daemon/v1/daemon.proto +++ b/proto/daemon/v1/daemon.proto @@ -18,6 +18,7 @@ option go_package = "github.com/scionproto/scion/go/pkg/proto/daemon"; package proto.daemon.v1; +import "proto/drkey/mgmt/v1/mgmt.proto"; import "google/protobuf/timestamp.proto"; import "google/protobuf/duration.proto"; @@ -34,6 +35,8 @@ service DaemonService { rpc Services(ServicesRequest) returns (ServicesResponse) {} // Inform the SCION Daemon of a revocation. rpc NotifyInterfaceDown(NotifyInterfaceDownRequest) returns (NotifyInterfaceDownResponse) {} + // Return the Lvl2Key that matches the request + rpc DRKeyLvl2(DRKeyLvl2Request) returns (DRKeyLvl2Response) {} } message PathsRequest { @@ -182,3 +185,13 @@ message NotifyInterfaceDownRequest { } message NotifyInterfaceDownResponse {}; + +message DRKeyLvl2Request{ + // BaseReq contains the basic information for the Lvl2 request + proto.drkey.mgmt.v1.DRKeyLvl2Request base_req = 1; +} + +message DRKeyLvl2Response{ + // BaseRep contains the basic information for the Lvl2 response + proto.drkey.mgmt.v1.DRKeyLvl2Response base_rep = 1; +} \ No newline at end of file diff --git a/proto/drkey/mgmt/v1/BUILD.bazel b/proto/drkey/mgmt/v1/BUILD.bazel new file mode 100644 index 0000000000..d22d175487 --- /dev/null +++ b/proto/drkey/mgmt/v1/BUILD.bazel @@ -0,0 +1,10 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") + +proto_library( + name = "drkey", + srcs = [ + "mgmt.proto", + ], + visibility = ["//visibility:public"], + deps = ["@com_google_protobuf//:timestamp_proto"], +) diff --git a/proto/drkey/mgmt/v1/mgmt.proto b/proto/drkey/mgmt/v1/mgmt.proto new file mode 100644 index 0000000000..cd8efbc015 --- /dev/null +++ b/proto/drkey/mgmt/v1/mgmt.proto @@ -0,0 +1,82 @@ +// Copyright 2020 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. + +syntax = "proto3"; + +option go_package = "github.com/scionproto/scion/go/pkg/proto/drkey"; + +package proto.drkey.mgmt.v1; + +import "google/protobuf/timestamp.proto"; + +// DRKeyLvl1Request leaves out the 'dstIA' field which can be extracted from +// the transport itself (ideally from authenticated information). +message DRKeyLvl1Request{ + // Point in time where requested DRKey is valid. Used to identify the epoch + google.protobuf.Timestamp val_time = 1; + // Point in time when the request was created + google.protobuf.Timestamp timestamp = 2; + +} + +// DRKeyLvl1Response leaves out the 'dstIA' and 'srcIA' fields which can be +// extracted from the transport itself (ideally from authenticated information). +message DRKeyLvl1Response{ + // Begin of validity period of DRKey + google.protobuf.Timestamp epoch_begin = 1; + // End of validity period of DRKey + google.protobuf.Timestamp epoch_end = 2; + // Lvl1 DRKey + bytes drkey = 3; + // Creation time of this reply + google.protobuf.Timestamp timestamp = 4; +} + +message DRKeyLvl2Request{ + message DRKeyHost{ + // AddrType + uint32 type = 1; + // Host address + bytes host = 2; + } + // Protocol identifier + string protocol = 1; + // Requested DRKeyProtoKeyType + uint32 req_type = 2; + // Point in time where requested DRKey is valid. Used to identify the epoch + google.protobuf.Timestamp val_time = 3; + // Src ISD-AS of the requested DRKey + uint64 src_ia = 4; + // Dst ISD-AS of the requested DRKey + uint64 dst_ia = 5; + // Src Host of the request DRKey (optional) + DRKeyHost src_host = 6; + // Dst Host of the request DRKey (optional) + DRKeyHost dst_host = 7; + // Additional information (optional) + bytes misc = 8; +} + +message DRKeyLvl2Response{ + // Timestamp + google.protobuf.Timestamp timestamp = 1; + // Derived DRKey + bytes drkey = 2; + // Begin of validity period of DRKey + google.protobuf.Timestamp epoch_begin = 3; + // End of validity period of DRKey + google.protobuf.Timestamp epoch_end = 4; + // Additional information (optional) + bytes misc = 5; +}