Repository: scionproto/scion
Pull request #4217 (2022-06-10 12:27:47)

drkey: public library and protobuf definitions
This PR is the first of a series of PRs which add the DRKey feature.

This PR contains:
- pkg/drkey: public drkey library.
- private/drkey/protocoltest: common utils for UT.
- proto/drkey: pb messages.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/scionproto/scion/4217)
<!-- Reviewable:end -->



Patch:
diff --git a/pkg/drkey/BUILD.bazel b/pkg/drkey/BUILD.bazel
new file mode 100644
index 000000000..45d90b984
--- /dev/null
+++ b/pkg/drkey/BUILD.bazel
@@ -0,0 +1,33 @@
+load("//tools/lint:go.bzl", "go_library", "go_test")
+
+go_library(
+    name = "go_default_library",
+    srcs = [
+        "db.go",
+        "drkey.go",
+        "protocol.go",
+    ],
+    importpath = "github.com/scionproto/scion/pkg/drkey",
+    visibility = ["//visibility:public"],
+    deps = [
+        "//pkg/addr:go_default_library",
+        "//pkg/private/serrors:go_default_library",
+        "//pkg/private/util:go_default_library",
+        "//pkg/proto/drkey:go_default_library",
+        "//pkg/scrypto/cppki:go_default_library",
+        "//pkg/slayers:go_default_library",
+        "//private/storage/db:go_default_library",
+        "@org_golang_x_crypto//pbkdf2:go_default_library",
+    ],
+)
+
+go_test(
+    name = "go_default_test",
+    srcs = ["secret_value_test.go"],
+    data = glob(["testdata/**"]),
+    deps = [
+        ":go_default_library",
+        "//pkg/private/xtest:go_default_library",
+        "@com_github_stretchr_testify//require:go_default_library",
+    ],
+)
diff --git a/pkg/drkey/db.go b/pkg/drkey/db.go
new file mode 100644
index 000000000..d0c289479
--- /dev/null
+++ b/pkg/drkey/db.go
@@ -0,0 +1,60 @@
+// 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"
+	"time"
+
+	"github.com/scionproto/scion/pkg/private/serrors"
+	"github.com/scionproto/scion/private/storage/db"
+)
+
+var ErrKeyNotFound = serrors.New("key not found")
+
+// SecretValueDB is the database for Secret Values.
+type SecretValueDB interface {
+	GetValue(ctx context.Context, meta SecretValueMeta) (SecretValue, error)
+	InsertValue(ctx context.Context, key SecretValue) error
+	DeleteExpiredValues(ctx context.Context, cutoff time.Time) (int64, error)
+
+	io.Closer
+	db.LimitSetter
+}
+
+// Level1DB is the drkey database interface for level 1.
+type Level1DB interface {
+	GetLevel1Key(ctx context.Context, meta Level1Meta) (Level1Key, error)
+	InsertLevel1Key(ctx context.Context, key Level1Key) error
+	DeleteExpiredLevel1Keys(ctx context.Context, cutoff time.Time) (int64, error)
+
+	io.Closer
+	db.LimitSetter
+}
+
+// Level2DB is the drkey database interface for end-host keys.
+type Level2DB interface {
+	GetASHostKey(ctx context.Context, meta ASHostMeta) (ASHostKey, error)
+	GetHostASKey(ctx context.Context, meta HostASMeta) (HostASKey, error)
+	GetHostHostKey(ctx context.Context, meta HostHostMeta) (HostHostKey, error)
+	InsertASHostKey(ctx context.Context, key ASHostKey) error
+	InsertHostASKey(ctx context.Context, key HostASKey) error
+	InsertHostHostKey(ctx context.Context, key HostHostKey) error
+	DeleteExpiredLevel2Keys(ctx context.Context, cutoff time.Time) (int64, error)
+
+	io.Closer
+	db.LimitSetter
+}
diff --git a/pkg/drkey/drkey.go b/pkg/drkey/drkey.go
new file mode 100644
index 000000000..a80ac8592
--- /dev/null
+++ b/pkg/drkey/drkey.go
@@ -0,0 +1,200 @@
+// 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 (
+	"crypto/sha256"
+	"encoding/binary"
+	"fmt"
+	"time"
+
+	"golang.org/x/crypto/pbkdf2"
+
+	"github.com/scionproto/scion/pkg/addr"
+	"github.com/scionproto/scion/pkg/private/serrors"
+	"github.com/scionproto/scion/pkg/private/util"
+	pb "github.com/scionproto/scion/pkg/proto/drkey"
+	"github.com/scionproto/scion/pkg/scrypto/cppki"
+)
+
+// DRKey protocol types.
+const (
+	Generic = Protocol(pb.Protocol_PROTOCOL_GENERIC_UNSPECIFIED)
+	SCMP    = Protocol(pb.Protocol_PROTOCOL_SCMP)
+)
+
+// Epoch represents a validity period.
+type Epoch struct {
+	cppki.Validity
+}
+
+// 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(),
+		},
+	}
+}
+
+// Protocol is the 2-byte size protocol identifier
+type Protocol uint16
+
+func (p Protocol) String() string {
+	name, ok := pb.Protocol_name[int32(p)]
+	if !ok {
+		return fmt.Sprintf("UNKNOWN(%d)", p)
+	}
+	return name
+}
+
+// IsPredefined checks whether this is a well-known, built-in protocol
+// identifier, i.e. Generic, SCMP or DNS. Returns false for all other
+// protocol identifiers ("niche protocols").
+func (p Protocol) IsPredefined() bool {
+	_, ok := pb.Protocol_name[int32(p)]
+	return ok
+}
+
+func ProtocolStringToId(protocol string) (Protocol, bool) {
+	id, ok := pb.Protocol_value[protocol]
+	return Protocol(id), ok
+}
+
+// Key represents a raw binary key
+type Key [16]byte
+
+func (k Key) String() string {
+	return "[redacted key]"
+}
+
+const drkeySalt = "Derive DRKey Key"
+
+// SecretValueMeta represents the information about a DRKey secret value.
+type SecretValueMeta struct {
+	Validity time.Time
+	ProtoId  Protocol
+}
+
+// SecretValue represents a DRKey secret value.
+type SecretValue struct {
+	Epoch   Epoch
+	ProtoId Protocol
+	Key     Key
+}
+
+// DeriveSV constructs a valid SV. asSecret is typically the AS master secret.
+func DeriveSV(protoID Protocol, epoch Epoch, asSecret []byte) (SecretValue, error) {
+	msLen := len(asSecret)
+	if msLen == 0 {
+		return SecretValue{}, serrors.New("Invalid zero sized secret")
+	}
+
+	totalLen := msLen + 18
+	buf := make([]byte, totalLen)
+	offset := 0
+	binary.BigEndian.PutUint64(buf[:], uint64(msLen))
+	offset += 8
+	copy(buf[offset:], asSecret)
+	offset += msLen
+	binary.BigEndian.PutUint16(buf[offset:], uint16(protoID))
+	offset += 2
+	binary.BigEndian.PutUint32(buf[offset:], util.TimeToSecs(epoch.NotBefore))
+	offset += 4
+	binary.BigEndian.PutUint32(buf[offset:], util.TimeToSecs(epoch.NotAfter))
+
+	key := pbkdf2.Key(buf, []byte(drkeySalt), 1000, 16, sha256.New)
+	sv := SecretValue{
+		Epoch:   epoch,
+		ProtoId: protoID,
+	}
+	copy(sv.Key[:], key)
+	return sv, nil
+}
+
+// / Level1Meta contains metadata to obtain a Level1 key.
+type Level1Meta struct {
+	Validity     time.Time
+	ProtoId      Protocol
+	SrcIA, DstIA addr.IA
+}
+
+// Level1Key represents a level 1 DRKey.
+type Level1Key struct {
+	Epoch        Epoch
+	ProtoId      Protocol
+	SrcIA, DstIA addr.IA
+	Key          Key
+}
+
+// ASHostMeta represents the associated information for the ASHost key.
+type ASHostMeta struct {
+	ProtoId  Protocol
+	Validity time.Time
+	SrcIA    addr.IA
+	DstIA    addr.IA
+	DstHost  string
+}
+
+// ASHostKey represents a ASHost key.
+type ASHostKey struct {
+	ProtoId Protocol
+	Epoch   Epoch
+	SrcIA   addr.IA
+	DstIA   addr.IA
+	DstHost string
+	Key     Key
+}
+
+// HostASMeta represents the associated information for the HostAS key.
+type HostASMeta struct {
+	ProtoId  Protocol
+	Validity time.Time
+	SrcIA    addr.IA
+	DstIA    addr.IA
+	SrcHost  string
+}
+
+// HostASKey represents a Host-AS key.
+type HostASKey struct {
+	ProtoId Protocol
+	Epoch   Epoch
+	SrcIA   addr.IA
+	DstIA   addr.IA
+	SrcHost string
+	Key     Key
+}
+
+// HostHostMeta represents the associated information for the HostHostMeta key.
+type HostHostMeta struct {
+	ProtoId  Protocol
+	Validity time.Time
+	SrcIA    addr.IA
+	DstIA    addr.IA
+	SrcHost  string
+	DstHost  string
+}
+
+// HostHostKey represents a Host-Host DRKey.
+type HostHostKey struct {
+	ProtoId Protocol
+	Epoch   Epoch
+	SrcIA   addr.IA
+	DstIA   addr.IA
+	SrcHost string
+	DstHost string
+	Key     Key
+}
diff --git a/pkg/drkey/generic/BUILD.bazel b/pkg/drkey/generic/BUILD.bazel
new file mode 100644
index 000000000..1655a57ff
--- /dev/null
+++ b/pkg/drkey/generic/BUILD.bazel
@@ -0,0 +1,25 @@
+load("//tools/lint:go.bzl", "go_library", "go_test")
+
+go_library(
+    name = "go_default_library",
+    srcs = ["generic.go"],
+    importpath = "github.com/scionproto/scion/pkg/drkey/generic",
+    visibility = ["//visibility:public"],
+    deps = [
+        "//pkg/drkey:go_default_library",
+        "//pkg/private/serrors:go_default_library",
+    ],
+)
+
+go_test(
+    name = "go_default_test",
+    srcs = ["generic_test.go"],
+    data = glob(["testdata/**"]),
+    deps = [
+        "//pkg/drkey:go_default_library",
+        "//pkg/private/xtest:go_default_library",
+        "//private/drkey/drkeytest:go_default_library",
+        "@com_github_stretchr_testify//assert:go_default_library",
+        "@com_github_stretchr_testify//require:go_default_library",
+    ],
+)
diff --git a/pkg/drkey/generic/generic.go b/pkg/drkey/generic/generic.go
new file mode 100644
index 000000000..9daaf3627
--- /dev/null
+++ b/pkg/drkey/generic/generic.go
@@ -0,0 +1,86 @@
+// 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 generic
+
+import (
+	"encoding/binary"
+
+	"github.com/scionproto/scion/pkg/drkey"
+	"github.com/scionproto/scion/pkg/private/serrors"
+)
+
+// Deriver implements the level 2/3 generic drkey derivation.
+type Deriver struct{}
+
+// DeriveASHost returns the ASHost derived key.
+func (d *Deriver) DeriveASHost(proto drkey.Protocol, dstHost string,
+	key drkey.Key) (drkey.Key, error) {
+	host, err := drkey.HostAddrFromString(dstHost)
+	if err != nil {
+		return drkey.Key{}, serrors.WrapStr("parsing dst host", err)
+	}
+	buf := make([]byte, 32)
+	len := d.serializeLevel2Input(buf, drkey.AsToHost, proto, host)
+	outKey, err := drkey.DeriveKey(buf[:len], key)
+	return outKey, err
+}
+
+// DeriveHostAS returns the HostAS derived key.
+func (d *Deriver) DeriveHostAS(proto drkey.Protocol, srcHost string,
+	key drkey.Key) (drkey.Key, error) {
+	host, err := drkey.HostAddrFromString(srcHost)
+	if err != nil {
+		return drkey.Key{}, serrors.WrapStr("parsing src host", err)
+	}
+	buf := make([]byte, 32)
+	len := d.serializeLevel2Input(buf, drkey.HostToAS, proto, host)
+	outKey, err := drkey.DeriveKey(buf[:len], key)
+	return outKey, err
+}
+
+// DeriveHostToHost returns the HostHost derived key.
+func (d *Deriver) DeriveHostToHost(dstHost string,
+	key drkey.Key) (drkey.Key, error) {
+	host, err := drkey.HostAddrFromString(dstHost)
+	if err != nil {
+		return drkey.Key{}, serrors.WrapStr("deriving input H2H", err)
+	}
+	buf := make([]byte, 32)
+	len := drkey.SerializeHostToHostInput(buf[:], host)
+	outKey, err := drkey.DeriveKey(buf[:len], key)
+	return outKey, err
+}
+
+// serializeLevel2Input serializes the input for a ASHost or HostAS key,
+// as explained in
+// https://docs.scion.org/en/latest/cryptography/drkey.html#generic-protocol-derivation
+func (d *Deriver) serializeLevel2Input(input []byte, derType drkey.KeyType,
+	proto drkey.Protocol, host drkey.HostAddr) int {
+	hostAddr := host.RawAddr
+	l := len(hostAddr)
+
+	// Calculate a multiple of 16 such that the input fits in
+	nrBlocks := (4+l-1)/16 + 1
+	inputLength := 16 * nrBlocks
+
+	_ = input[inputLength-1]
+	input[0] = uint8(derType)
+	binary.BigEndian.PutUint16(input[1:], uint16(proto))
+	input[3] = uint8(host.AddrType&0x3)<<2 | uint8(host.AddrLen&0x3)
+	copy(input[4:], hostAddr)
+	copy(input[4+l:inputLength], drkey.ZeroBlock[:])
+
+	return inputLength
+}
diff --git a/pkg/drkey/protocol.go b/pkg/drkey/protocol.go
new file mode 100644
index 000000000..b320dfa30
--- /dev/null
+++ b/pkg/drkey/protocol.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 drkey
+
+import (
+	"crypto/aes"
+	"crypto/cipher"
+	"encoding/binary"
+	"net"
+
+	"github.com/scionproto/scion/pkg/addr"
+	"github.com/scionproto/scion/pkg/private/serrors"
+	"github.com/scionproto/scion/pkg/slayers"
+)
+
+// keyType represents the different types of keys (host->AS, AS->host, host->host).
+type KeyType uint8
+
+// Key types.
+const (
+	AsToAs KeyType = iota
+	AsToHost
+	HostToAS
+	HostToHost
+)
+
+var (
+	ZeroBlock [aes.BlockSize]byte
+)
+
+// HostAddr is the address representation of a host as defined in the SCION header.
+type HostAddr struct {
+	AddrLen  slayers.AddrLen
+	AddrType slayers.AddrType
+	RawAddr  []byte
+}
+
+// AddrToString returns the string representation of the HostAddr.
+func (h *HostAddr) String() string {
+	switch h.AddrLen {
+	case slayers.AddrLen4:
+		switch h.AddrType {
+		case slayers.T4Ip:
+			addr := &net.IPAddr{IP: net.IP(h.RawAddr)}
+			return addr.String()
+		case slayers.T4Svc:
+			addr := addr.HostSVC(binary.BigEndian.Uint16(h.RawAddr[:addr.HostLenSVC]))
+			return addr.String()
+		}
+	case slayers.AddrLen16:
+		switch h.AddrType {
+		case slayers.T16Ip:
+			addr := &net.IPAddr{IP: net.IP(h.RawAddr)}
+			return addr.String()
+		}
+	}
+	return ""
+}
+
+// packtoHostAddr returns a HostAddr parsing a given address in string format.
+func HostAddrFromString(host string) (HostAddr, error) {
+	// trying IP
+	ipAddr := addr.HostFromIPStr(host)
+	if ipAddr != nil {
+		if ip := ipAddr.IP().To4(); ip != nil {
+			return HostAddr{
+				AddrLen:  slayers.AddrLen4,
+				AddrType: slayers.T4Ip,
+				RawAddr:  ip,
+			}, nil
+		}
+		return HostAddr{
+			AddrLen:  slayers.AddrLen16,
+			AddrType: slayers.T16Ip,
+			RawAddr:  ipAddr.IP(),
+		}, nil
+	}
+	// trying SVC
+	svcAddr := addr.HostSVCFromString(host)
+	if svcAddr != addr.SvcNone {
+		return HostAddr{
+			AddrLen:  slayers.AddrLen4,
+			AddrType: slayers.T4Svc,
+			RawAddr:  svcAddr.PackWithPad(2),
+		}, nil
+	}
+	return HostAddr{}, serrors.New("unsupported address", "addr", host)
+}
+
+// SerializeHostToHostInput serializes the input for deriving a HostToHost key,
+// as explained in
+// https://docs.scion.org/en/latest/cryptography/drkey.html#level-derivation.
+// This derivation is common for Generic and Specific derivations.
+func SerializeHostToHostInput(input []byte, host HostAddr) int {
+	hostAddr := host.RawAddr
+	l := len(hostAddr)
+
+	// Calculate a multiple of 16 such that the input fits in
+	nrBlocks := (2+l-1)/16 + 1
+
+	inputLength := 16 * nrBlocks
+
+	_ = input[inputLength-1]
+	input[0] = uint8(HostToHost)
+	input[1] = uint8(host.AddrType&0x3)<<2 | uint8(host.AddrLen&0x3)
+	copy(input[2:], hostAddr)
+	copy(input[2+l:inputLength], ZeroBlock[:])
+
+	return inputLength
+}
+
+// DeriveKey derives the following key given an input and a higher-level key,
+// as stated in
+// https://docs.scion.org/en/latest/cryptography/drkey.html#prf-derivation-specification
+// The input buffer is overwritten.
+func DeriveKey(input []byte, upperLevelKey Key) (Key, error) {
+	var key Key
+	b, err := initAESCBC(upperLevelKey[:])
+	if err != nil {
+		return key, err
+	}
+	mac := cbcMac(b, input[:])
+	copy(key[:], mac)
+	return key, nil
+}
+
+func initAESCBC(key []byte) (cipher.BlockMode, error) {
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, serrors.New("Unable to initialize AES cipher")
+	}
+	mode := cipher.NewCBCEncrypter(block, ZeroBlock[:])
+	return mode, nil
+}
+
+func cbcMac(block cipher.BlockMode, b []byte) []byte {
+	block.CryptBlocks(b, b)
+	return b[len(b)-aes.BlockSize:]
+}
diff --git a/pkg/drkey/specific/BUILD.bazel b/pkg/drkey/specific/BUILD.bazel
new file mode 100644
index 000000000..c3316a6a9
--- /dev/null
+++ b/pkg/drkey/specific/BUILD.bazel
@@ -0,0 +1,27 @@
+load("//tools/lint:go.bzl", "go_library", "go_test")
+
+go_library(
+    name = "go_default_library",
+    srcs = ["specific.go"],
+    importpath = "github.com/scionproto/scion/pkg/drkey/specific",
+    visibility = ["//visibility:public"],
+    deps = [
+        "//pkg/addr:go_default_library",
+        "//pkg/drkey:go_default_library",
+        "//pkg/private/serrors:go_default_library",
+    ],
+)
+
+go_test(
+    name = "go_default_test",
+    srcs = ["specific_test.go"],
+    data = glob(["testdata/**"]),
+    deps = [
+        ":go_default_library",
+        "//pkg/drkey:go_default_library",
+        "//pkg/private/xtest:go_default_library",
+        "//private/drkey/drkeytest:go_default_library",
+        "@com_github_stretchr_testify//assert:go_default_library",
+        "@com_github_stretchr_testify//require:go_default_library",
+    ],
+)
diff --git a/pkg/drkey/specific/specific.go b/pkg/drkey/specific/specific.go
new file mode 100644
index 000000000..f46db30a4
--- /dev/null
+++ b/pkg/drkey/specific/specific.go
@@ -0,0 +1,106 @@
+// 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 specific
+
+import (
+	"crypto/aes"
+	"encoding/binary"
+
+	"github.com/scionproto/scion/pkg/addr"
+	"github.com/scionproto/scion/pkg/drkey"
+	"github.com/scionproto/scion/pkg/private/serrors"
+)
+
+// SpecificDeriver implements the specific drkey derivation.
+type Deriver struct{}
+
+// DeriveLevel1 returns the Level1 derived key.
+func (d *Deriver) DeriveLevel1(dstIA addr.IA,
+	key drkey.Key) (drkey.Key, error) {
+	buf := make([]byte, aes.BlockSize)
+	len := serializeLevel1Input(buf, dstIA)
+	outKey, err := drkey.DeriveKey(buf[:len], key)
+	return outKey, err
+}
+
+// DeriveASHost returns the ASHost derived key.
+func (d *Deriver) DeriveASHost(dstHost string,
+	key drkey.Key) (drkey.Key, error) {
+	host, err := drkey.HostAddrFromString(dstHost)
+	if err != nil {
+		return drkey.Key{}, serrors.WrapStr("parsing dst host", err)
+	}
+	buf := make([]byte, 32)
+	len := d.serializeLevel2Input(buf, drkey.AsToHost, host)
+	outKey, err := drkey.DeriveKey(buf[:len], key)
+	return outKey, err
+}
+
+// DeriveHostAS returns the HostAS derived key.
+func (p *Deriver) DeriveHostAS(srcHost string, key drkey.Key) (drkey.Key, error) {
+	host, err := drkey.HostAddrFromString(srcHost)
+	if err != nil {
+		return drkey.Key{}, serrors.WrapStr("parsing src host", err)
+	}
+	buf := make([]byte, 32)
+	len := p.serializeLevel2Input(buf, drkey.HostToAS, host)
+	outKey, err := drkey.DeriveKey(buf[:len], key)
+	return outKey, err
+}
+
+// DeriveHostToHost returns the HostHost derived key.
+func (d *Deriver) DeriveHostToHost(dstHost string, key drkey.Key) (drkey.Key, error) {
+	host, err := drkey.HostAddrFromString(dstHost)
+	if err != nil {
+		return drkey.Key{}, serrors.WrapStr("deriving input H2H", err)
+	}
+	buf := make([]byte, 32)
+	len := drkey.SerializeHostToHostInput(buf, host)
+	outKey, err := drkey.DeriveKey(buf[:len], key)
+	return outKey, err
+}
+
+// serializeLevel2Input serializes the input for a ASHost or HostAS key,
+// as explained in
+// https://docs.scion.org/en/latest/cryptography/drkey.html#protocol-specific-derivation
+func (d *Deriver) serializeLevel2Input(input []byte, derType drkey.KeyType,
+	host drkey.HostAddr) int {
+	hostAddr := host.RawAddr
+	l := len(hostAddr)
+
+	// Calculate a multiple of 16 such that the input fits in
+	nrBlocks := (2+l-1)/16 + 1
+	inputLength := 16 * nrBlocks
+
+	_ = input[inputLength-1]
+	input[0] = uint8(derType)
+	input[1] = uint8(host.AddrType&0x3)<<2 | uint8(host.AddrLen&0x3)
+	copy(input[2:], hostAddr)
+	copy(input[2+l:inputLength], drkey.ZeroBlock[:])
+
+	return inputLength
+}
+
+// serializeLevel1Input serializes the input for a Level1 key,
+// as explained in
+// https://docs.scion.org/en/latest/cryptography/drkey.html#protocol-specific-derivation
+func serializeLevel1Input(buf []byte, dstIA addr.IA) int {
+	_ = buf[aes.BlockSize-1]
+	buf[0] = byte(drkey.AsToAs)
+	binary.BigEndian.PutUint64(buf[1:], uint64(dstIA))
+	copy(buf[9:], drkey.ZeroBlock[:])
+
+	return aes.BlockSize
+}
diff --git a/pkg/proto/control_plane/BUILD.bazel b/pkg/proto/control_plane/BUILD.bazel
index f25680a38..f3c4cb887 100644
--- a/pkg/proto/control_plane/BUILD.bazel
+++ b/pkg/proto/control_plane/BUILD.bazel
@@ -9,5 +9,6 @@ go_proto_library(
     deps = [
         "//pkg/proto/control_plane/experimental:go_default_library",
         "//pkg/proto/crypto:go_default_library",
+        "//pkg/proto/drkey:go_default_library",
     ],
 )
diff --git a/pkg/proto/control_plane/drkey.pb.go b/pkg/proto/control_plane/drkey.pb.go
new file mode 100644
index 000000000..c137f7852
--- /dev/null
+++ b/pkg/proto/control_plane/drkey.pb.go
@@ -0,0 +1,1002 @@
+// 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 (
+	drkey "github.com/scionproto/scion/pkg/proto/drkey"
+	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 DRKeySecretValueRequest 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"`
+	ProtocolId drkey.Protocol         `protobuf:"varint,2,opt,name=protocol_id,json=protocolId,proto3,enum=proto.drkey.v1.Protocol" json:"protocol_id,omitempty"`
+}
+
+func (x *DRKeySecretValueRequest) Reset() {
+	*x = DRKeySecretValueRequest{}
+	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 *DRKeySecretValueRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeySecretValueRequest) ProtoMessage() {}
+
+func (x *DRKeySecretValueRequest) 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 DRKeySecretValueRequest.ProtoReflect.Descriptor instead.
+func (*DRKeySecretValueRequest) Descriptor() ([]byte, []int) {
+	return file_proto_control_plane_v1_drkey_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *DRKeySecretValueRequest) GetValTime() *timestamppb.Timestamp {
+	if x != nil {
+		return x.ValTime
+	}
+	return nil
+}
+
+func (x *DRKeySecretValueRequest) GetProtocolId() drkey.Protocol {
+	if x != nil {
+		return x.ProtocolId
+	}
+	return drkey.Protocol(0)
+}
+
+type DRKeySecretValueResponse 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"`
+	Key        []byte                 `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`
+}
+
+func (x *DRKeySecretValueResponse) Reset() {
+	*x = DRKeySecretValueResponse{}
+	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 *DRKeySecretValueResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeySecretValueResponse) ProtoMessage() {}
+
+func (x *DRKeySecretValueResponse) 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 DRKeySecretValueResponse.ProtoReflect.Descriptor instead.
+func (*DRKeySecretValueResponse) Descriptor() ([]byte, []int) {
+	return file_proto_control_plane_v1_drkey_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *DRKeySecretValueResponse) GetEpochBegin() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochBegin
+	}
+	return nil
+}
+
+func (x *DRKeySecretValueResponse) GetEpochEnd() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochEnd
+	}
+	return nil
+}
+
+func (x *DRKeySecretValueResponse) GetKey() []byte {
+	if x != nil {
+		return x.Key
+	}
+	return nil
+}
+
+type DRKeyLevel1Request 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"`
+	ProtocolId drkey.Protocol         `protobuf:"varint,2,opt,name=protocol_id,json=protocolId,proto3,enum=proto.drkey.v1.Protocol" json:"protocol_id,omitempty"`
+}
+
+func (x *DRKeyLevel1Request) Reset() {
+	*x = DRKeyLevel1Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DRKeyLevel1Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeyLevel1Request) ProtoMessage() {}
+
+func (x *DRKeyLevel1Request) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_control_plane_v1_drkey_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 DRKeyLevel1Request.ProtoReflect.Descriptor instead.
+func (*DRKeyLevel1Request) Descriptor() ([]byte, []int) {
+	return file_proto_control_plane_v1_drkey_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *DRKeyLevel1Request) GetValTime() *timestamppb.Timestamp {
+	if x != nil {
+		return x.ValTime
+	}
+	return nil
+}
+
+func (x *DRKeyLevel1Request) GetProtocolId() drkey.Protocol {
+	if x != nil {
+		return x.ProtocolId
+	}
+	return drkey.Protocol(0)
+}
+
+type DRKeyLevel1Response 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"`
+	Key        []byte                 `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`
+}
+
+func (x *DRKeyLevel1Response) Reset() {
+	*x = DRKeyLevel1Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DRKeyLevel1Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeyLevel1Response) ProtoMessage() {}
+
+func (x *DRKeyLevel1Response) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_control_plane_v1_drkey_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 DRKeyLevel1Response.ProtoReflect.Descriptor instead.
+func (*DRKeyLevel1Response) Descriptor() ([]byte, []int) {
+	return file_proto_control_plane_v1_drkey_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *DRKeyLevel1Response) GetEpochBegin() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochBegin
+	}
+	return nil
+}
+
+func (x *DRKeyLevel1Response) GetEpochEnd() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochEnd
+	}
+	return nil
+}
+
+func (x *DRKeyLevel1Response) GetKey() []byte {
+	if x != nil {
+		return x.Key
+	}
+	return nil
+}
+
+type DRKeyIntraLevel1Request 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"`
+	ProtocolId drkey.Protocol         `protobuf:"varint,2,opt,name=protocol_id,json=protocolId,proto3,enum=proto.drkey.v1.Protocol" json:"protocol_id,omitempty"`
+	SrcIa      uint64                 `protobuf:"varint,3,opt,name=src_ia,json=srcIa,proto3" json:"src_ia,omitempty"`
+	DstIa      uint64                 `protobuf:"varint,4,opt,name=dst_ia,json=dstIa,proto3" json:"dst_ia,omitempty"`
+}
+
+func (x *DRKeyIntraLevel1Request) Reset() {
+	*x = DRKeyIntraLevel1Request{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DRKeyIntraLevel1Request) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeyIntraLevel1Request) ProtoMessage() {}
+
+func (x *DRKeyIntraLevel1Request) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_control_plane_v1_drkey_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 DRKeyIntraLevel1Request.ProtoReflect.Descriptor instead.
+func (*DRKeyIntraLevel1Request) Descriptor() ([]byte, []int) {
+	return file_proto_control_plane_v1_drkey_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *DRKeyIntraLevel1Request) GetValTime() *timestamppb.Timestamp {
+	if x != nil {
+		return x.ValTime
+	}
+	return nil
+}
+
+func (x *DRKeyIntraLevel1Request) GetProtocolId() drkey.Protocol {
+	if x != nil {
+		return x.ProtocolId
+	}
+	return drkey.Protocol(0)
+}
+
+func (x *DRKeyIntraLevel1Request) GetSrcIa() uint64 {
+	if x != nil {
+		return x.SrcIa
+	}
+	return 0
+}
+
+func (x *DRKeyIntraLevel1Request) GetDstIa() uint64 {
+	if x != nil {
+		return x.DstIa
+	}
+	return 0
+}
+
+type DRKeyIntraLevel1Response 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"`
+	Key        []byte                 `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`
+}
+
+func (x *DRKeyIntraLevel1Response) Reset() {
+	*x = DRKeyIntraLevel1Response{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DRKeyIntraLevel1Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeyIntraLevel1Response) ProtoMessage() {}
+
+func (x *DRKeyIntraLevel1Response) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[5]
+	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 DRKeyIntraLevel1Response.ProtoReflect.Descriptor instead.
+func (*DRKeyIntraLevel1Response) Descriptor() ([]byte, []int) {
+	return file_proto_control_plane_v1_drkey_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *DRKeyIntraLevel1Response) GetEpochBegin() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochBegin
+	}
+	return nil
+}
+
+func (x *DRKeyIntraLevel1Response) GetEpochEnd() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochEnd
+	}
+	return nil
+}
+
+func (x *DRKeyIntraLevel1Response) GetKey() []byte {
+	if x != nil {
+		return x.Key
+	}
+	return nil
+}
+
+type DRKeyHostASRequest 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"`
+	ProtocolId drkey.Protocol         `protobuf:"varint,2,opt,name=protocol_id,json=protocolId,proto3,enum=proto.drkey.v1.Protocol" json:"protocol_id,omitempty"`
+	SrcIa      uint64                 `protobuf:"varint,3,opt,name=src_ia,json=srcIa,proto3" json:"src_ia,omitempty"`
+	DstIa      uint64                 `protobuf:"varint,4,opt,name=dst_ia,json=dstIa,proto3" json:"dst_ia,omitempty"`
+	SrcHost    string                 `protobuf:"bytes,5,opt,name=src_host,json=srcHost,proto3" json:"src_host,omitempty"`
+}
+
+func (x *DRKeyHostASRequest) Reset() {
+	*x = DRKeyHostASRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DRKeyHostASRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeyHostASRequest) ProtoMessage() {}
+
+func (x *DRKeyHostASRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[6]
+	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 DRKeyHostASRequest.ProtoReflect.Descriptor instead.
+func (*DRKeyHostASRequest) Descriptor() ([]byte, []int) {
+	return file_proto_control_plane_v1_drkey_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *DRKeyHostASRequest) GetValTime() *timestamppb.Timestamp {
+	if x != nil {
+		return x.ValTime
+	}
+	return nil
+}
+
+func (x *DRKeyHostASRequest) GetProtocolId() drkey.Protocol {
+	if x != nil {
+		return x.ProtocolId
+	}
+	return drkey.Protocol(0)
+}
+
+func (x *DRKeyHostASRequest) GetSrcIa() uint64 {
+	if x != nil {
+		return x.SrcIa
+	}
+	return 0
+}
+
+func (x *DRKeyHostASRequest) GetDstIa() uint64 {
+	if x != nil {
+		return x.DstIa
+	}
+	return 0
+}
+
+func (x *DRKeyHostASRequest) GetSrcHost() string {
+	if x != nil {
+		return x.SrcHost
+	}
+	return ""
+}
+
+type DRKeyHostASResponse 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"`
+	Key        []byte                 `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`
+}
+
+func (x *DRKeyHostASResponse) Reset() {
+	*x = DRKeyHostASResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DRKeyHostASResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeyHostASResponse) ProtoMessage() {}
+
+func (x *DRKeyHostASResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[7]
+	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 DRKeyHostASResponse.ProtoReflect.Descriptor instead.
+func (*DRKeyHostASResponse) Descriptor() ([]byte, []int) {
+	return file_proto_control_plane_v1_drkey_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *DRKeyHostASResponse) GetEpochBegin() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochBegin
+	}
+	return nil
+}
+
+func (x *DRKeyHostASResponse) GetEpochEnd() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochEnd
+	}
+	return nil
+}
+
+func (x *DRKeyHostASResponse) GetKey() []byte {
+	if x != nil {
+		return x.Key
+	}
+	return nil
+}
+
+type DRKeyASHostRequest 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"`
+	ProtocolId drkey.Protocol         `protobuf:"varint,2,opt,name=protocol_id,json=protocolId,proto3,enum=proto.drkey.v1.Protocol" json:"protocol_id,omitempty"`
+	SrcIa      uint64                 `protobuf:"varint,3,opt,name=src_ia,json=srcIa,proto3" json:"src_ia,omitempty"`
+	DstIa      uint64                 `protobuf:"varint,4,opt,name=dst_ia,json=dstIa,proto3" json:"dst_ia,omitempty"`
+	DstHost    string                 `protobuf:"bytes,5,opt,name=dst_host,json=dstHost,proto3" json:"dst_host,omitempty"`
+}
+
+func (x *DRKeyASHostRequest) Reset() {
+	*x = DRKeyASHostRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[8]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DRKeyASHostRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeyASHostRequest) ProtoMessage() {}
+
+func (x *DRKeyASHostRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[8]
+	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 DRKeyASHostRequest.ProtoReflect.Descriptor instead.
+func (*DRKeyASHostRequest) Descriptor() ([]byte, []int) {
+	return file_proto_control_plane_v1_drkey_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *DRKeyASHostRequest) GetValTime() *timestamppb.Timestamp {
+	if x != nil {
+		return x.ValTime
+	}
+	return nil
+}
+
+func (x *DRKeyASHostRequest) GetProtocolId() drkey.Protocol {
+	if x != nil {
+		return x.ProtocolId
+	}
+	return drkey.Protocol(0)
+}
+
+func (x *DRKeyASHostRequest) GetSrcIa() uint64 {
+	if x != nil {
+		return x.SrcIa
+	}
+	return 0
+}
+
+func (x *DRKeyASHostRequest) GetDstIa() uint64 {
+	if x != nil {
+		return x.DstIa
+	}
+	return 0
+}
+
+func (x *DRKeyASHostRequest) GetDstHost() string {
+	if x != nil {
+		return x.DstHost
+	}
+	return ""
+}
+
+type DRKeyASHostResponse 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"`
+	Key        []byte                 `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`
+}
+
+func (x *DRKeyASHostResponse) Reset() {
+	*x = DRKeyASHostResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[9]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DRKeyASHostResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeyASHostResponse) ProtoMessage() {}
+
+func (x *DRKeyASHostResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_control_plane_v1_drkey_proto_msgTypes[9]
+	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 DRKeyASHostResponse.ProtoReflect.Descriptor instead.
+func (*DRKeyASHostResponse) Descriptor() ([]byte, []int) {
+	return file_proto_control_plane_v1_drkey_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *DRKeyASHostResponse) GetEpochBegin() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochBegin
+	}
+	return nil
+}
+
+func (x *DRKeyASHostResponse) GetEpochEnd() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochEnd
+	}
+	return nil
+}
+
+func (x *DRKeyASHostResponse) GetKey() []byte {
+	if x != nil {
+		return x.Key
+	}
+	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, 0x1a, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x2f, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x72, 0x6b,
+	0x65, 0x79, 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, 0x22, 0x8b, 0x01, 0x0a, 0x17, 0x44, 0x52,
+	0x4b, 0x65, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 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, 0x39, 0x0a, 0x0b,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x0e, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e,
+	0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x0a, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49, 0x64, 0x22, 0xa2, 0x01, 0x0a, 0x18, 0x44, 0x52, 0x4b, 0x65,
+	0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 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, 0x10, 0x0a, 0x03, 0x6b, 0x65,
+	0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x86, 0x01, 0x0a,
+	0x12, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c, 0x65, 0x76, 0x65, 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, 0x39, 0x0a, 0x0b, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,
+	0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x76, 0x31,
+	0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x63, 0x6f, 0x6c, 0x49, 0x64, 0x22, 0x9d, 0x01, 0x0a, 0x13, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x4c,
+	0x65, 0x76, 0x65, 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, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c,
+	0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0xb9, 0x01, 0x0a, 0x17, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x49,
+	0x6e, 0x74, 0x72, 0x61, 0x4c, 0x65, 0x76, 0x65, 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, 0x39, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50,
+	0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
+	0x6c, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x72, 0x63, 0x5f, 0x69, 0x61, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x72, 0x63, 0x49, 0x61, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x73,
+	0x74, 0x5f, 0x69, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x64, 0x73, 0x74, 0x49,
+	0x61, 0x22, 0xa2, 0x01, 0x0a, 0x18, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x49, 0x6e, 0x74, 0x72, 0x61,
+	0x4c, 0x65, 0x76, 0x65, 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, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0xcf, 0x01, 0x0a, 0x12, 0x44, 0x52, 0x4b, 0x65, 0x79,
+	0x48, 0x6f, 0x73, 0x74, 0x41, 0x53, 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, 0x39, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
+	0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f,
+	0x63, 0x6f, 0x6c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49, 0x64, 0x12,
+	0x15, 0x0a, 0x06, 0x73, 0x72, 0x63, 0x5f, 0x69, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x05, 0x73, 0x72, 0x63, 0x49, 0x61, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x73, 0x74, 0x5f, 0x69, 0x61,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x64, 0x73, 0x74, 0x49, 0x61, 0x12, 0x19, 0x0a,
+	0x08, 0x73, 0x72, 0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x07, 0x73, 0x72, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x22, 0x9d, 0x01, 0x0a, 0x13, 0x44, 0x52, 0x4b,
+	0x65, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x41, 0x53, 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, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0xcf, 0x01, 0x0a, 0x12, 0x44, 0x52, 0x4b,
+	0x65, 0x79, 0x41, 0x53, 0x48, 0x6f, 0x73, 0x74, 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, 0x39, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x6f, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49,
+	0x64, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x72, 0x63, 0x5f, 0x69, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x04, 0x52, 0x05, 0x73, 0x72, 0x63, 0x49, 0x61, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x73, 0x74, 0x5f,
+	0x69, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x64, 0x73, 0x74, 0x49, 0x61, 0x12,
+	0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x07, 0x64, 0x73, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x22, 0x9d, 0x01, 0x0a, 0x13, 0x44,
+	0x52, 0x4b, 0x65, 0x79, 0x41, 0x53, 0x48, 0x6f, 0x73, 0x74, 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, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x42, 0x35, 0x5a, 0x33, 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, 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, 10)
+var file_proto_control_plane_v1_drkey_proto_goTypes = []interface{}{
+	(*DRKeySecretValueRequest)(nil),  // 0: proto.control_plane.v1.DRKeySecretValueRequest
+	(*DRKeySecretValueResponse)(nil), // 1: proto.control_plane.v1.DRKeySecretValueResponse
+	(*DRKeyLevel1Request)(nil),       // 2: proto.control_plane.v1.DRKeyLevel1Request
+	(*DRKeyLevel1Response)(nil),      // 3: proto.control_plane.v1.DRKeyLevel1Response
+	(*DRKeyIntraLevel1Request)(nil),  // 4: proto.control_plane.v1.DRKeyIntraLevel1Request
+	(*DRKeyIntraLevel1Response)(nil), // 5: proto.control_plane.v1.DRKeyIntraLevel1Response
+	(*DRKeyHostASRequest)(nil),       // 6: proto.control_plane.v1.DRKeyHostASRequest
+	(*DRKeyHostASResponse)(nil),      // 7: proto.control_plane.v1.DRKeyHostASResponse
+	(*DRKeyASHostRequest)(nil),       // 8: proto.control_plane.v1.DRKeyASHostRequest
+	(*DRKeyASHostResponse)(nil),      // 9: proto.control_plane.v1.DRKeyASHostResponse
+	(*timestamppb.Timestamp)(nil),    // 10: google.protobuf.Timestamp
+	(drkey.Protocol)(0),              // 11: proto.drkey.v1.Protocol
+}
+var file_proto_control_plane_v1_drkey_proto_depIdxs = []int32{
+	10, // 0: proto.control_plane.v1.DRKeySecretValueRequest.val_time:type_name -> google.protobuf.Timestamp
+	11, // 1: proto.control_plane.v1.DRKeySecretValueRequest.protocol_id:type_name -> proto.drkey.v1.Protocol
+	10, // 2: proto.control_plane.v1.DRKeySecretValueResponse.epoch_begin:type_name -> google.protobuf.Timestamp
+	10, // 3: proto.control_plane.v1.DRKeySecretValueResponse.epoch_end:type_name -> google.protobuf.Timestamp
+	10, // 4: proto.control_plane.v1.DRKeyLevel1Request.val_time:type_name -> google.protobuf.Timestamp
+	11, // 5: proto.control_plane.v1.DRKeyLevel1Request.protocol_id:type_name -> proto.drkey.v1.Protocol
+	10, // 6: proto.control_plane.v1.DRKeyLevel1Response.epoch_begin:type_name -> google.protobuf.Timestamp
+	10, // 7: proto.control_plane.v1.DRKeyLevel1Response.epoch_end:type_name -> google.protobuf.Timestamp
+	10, // 8: proto.control_plane.v1.DRKeyIntraLevel1Request.val_time:type_name -> google.protobuf.Timestamp
+	11, // 9: proto.control_plane.v1.DRKeyIntraLevel1Request.protocol_id:type_name -> proto.drkey.v1.Protocol
+	10, // 10: proto.control_plane.v1.DRKeyIntraLevel1Response.epoch_begin:type_name -> google.protobuf.Timestamp
+	10, // 11: proto.control_plane.v1.DRKeyIntraLevel1Response.epoch_end:type_name -> google.protobuf.Timestamp
+	10, // 12: proto.control_plane.v1.DRKeyHostASRequest.val_time:type_name -> google.protobuf.Timestamp
+	11, // 13: proto.control_plane.v1.DRKeyHostASRequest.protocol_id:type_name -> proto.drkey.v1.Protocol
+	10, // 14: proto.control_plane.v1.DRKeyHostASResponse.epoch_begin:type_name -> google.protobuf.Timestamp
+	10, // 15: proto.control_plane.v1.DRKeyHostASResponse.epoch_end:type_name -> google.protobuf.Timestamp
+	10, // 16: proto.control_plane.v1.DRKeyASHostRequest.val_time:type_name -> google.protobuf.Timestamp
+	11, // 17: proto.control_plane.v1.DRKeyASHostRequest.protocol_id:type_name -> proto.drkey.v1.Protocol
+	10, // 18: proto.control_plane.v1.DRKeyASHostResponse.epoch_begin:type_name -> google.protobuf.Timestamp
+	10, // 19: proto.control_plane.v1.DRKeyASHostResponse.epoch_end:type_name -> google.protobuf.Timestamp
+	20, // [20:20] is the sub-list for method output_type
+	20, // [20:20] is the sub-list for method input_type
+	20, // [20:20] is the sub-list for extension type_name
+	20, // [20:20] is the sub-list for extension extendee
+	0,  // [0:20] 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.(*DRKeySecretValueRequest); 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.(*DRKeySecretValueResponse); 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[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DRKeyLevel1Request); 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[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DRKeyLevel1Response); 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[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DRKeyIntraLevel1Request); 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[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DRKeyIntraLevel1Response); 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[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DRKeyHostASRequest); 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[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DRKeyHostASResponse); 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[8].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DRKeyASHostRequest); 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[9].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DRKeyASHostResponse); 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:   10,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		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
+}
diff --git a/pkg/proto/daemon/BUILD.bazel b/pkg/proto/daemon/BUILD.bazel
index f09dc111f..97a549ec9 100644
--- a/pkg/proto/daemon/BUILD.bazel
+++ b/pkg/proto/daemon/BUILD.bazel
@@ -6,4 +6,7 @@ go_proto_library(
     importpath = "github.com/scionproto/scion/pkg/proto/daemon",
     proto = "//proto/daemon/v1:daemon",
     visibility = ["//visibility:public"],
+    deps = [
+        "//pkg/proto/drkey:go_default_library",
+    ],
 )
diff --git a/pkg/proto/daemon/daemon.pb.go b/pkg/proto/daemon/daemon.pb.go
index 27277d9b3..c183fa590 100644
--- a/pkg/proto/daemon/daemon.pb.go
+++ b/pkg/proto/daemon/daemon.pb.go
@@ -8,6 +8,7 @@ package daemon
 
 import (
 	context "context"
+	drkey "github.com/scionproto/scion/pkg/proto/drkey"
 	grpc "google.golang.org/grpc"
 	codes "google.golang.org/grpc/codes"
 	status "google.golang.org/grpc/status"
@@ -1065,6 +1066,440 @@ func (*NotifyInterfaceDownResponse) Descriptor() ([]byte, []int) {
 	return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{17}
 }
 
+type DRKeyHostASRequest 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"`
+	ProtocolId drkey.Protocol         `protobuf:"varint,2,opt,name=protocol_id,json=protocolId,proto3,enum=proto.drkey.v1.Protocol" json:"protocol_id,omitempty"`
+	SrcIa      uint64                 `protobuf:"varint,3,opt,name=src_ia,json=srcIa,proto3" json:"src_ia,omitempty"`
+	DstIa      uint64                 `protobuf:"varint,4,opt,name=dst_ia,json=dstIa,proto3" json:"dst_ia,omitempty"`
+	SrcHost    string                 `protobuf:"bytes,5,opt,name=src_host,json=srcHost,proto3" json:"src_host,omitempty"`
+}
+
+func (x *DRKeyHostASRequest) Reset() {
+	*x = DRKeyHostASRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_daemon_v1_daemon_proto_msgTypes[18]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DRKeyHostASRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeyHostASRequest) ProtoMessage() {}
+
+func (x *DRKeyHostASRequest) 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 DRKeyHostASRequest.ProtoReflect.Descriptor instead.
+func (*DRKeyHostASRequest) Descriptor() ([]byte, []int) {
+	return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{18}
+}
+
+func (x *DRKeyHostASRequest) GetValTime() *timestamppb.Timestamp {
+	if x != nil {
+		return x.ValTime
+	}
+	return nil
+}
+
+func (x *DRKeyHostASRequest) GetProtocolId() drkey.Protocol {
+	if x != nil {
+		return x.ProtocolId
+	}
+	return drkey.Protocol(0)
+}
+
+func (x *DRKeyHostASRequest) GetSrcIa() uint64 {
+	if x != nil {
+		return x.SrcIa
+	}
+	return 0
+}
+
+func (x *DRKeyHostASRequest) GetDstIa() uint64 {
+	if x != nil {
+		return x.DstIa
+	}
+	return 0
+}
+
+func (x *DRKeyHostASRequest) GetSrcHost() string {
+	if x != nil {
+		return x.SrcHost
+	}
+	return ""
+}
+
+type DRKeyHostASResponse 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"`
+	Key        []byte                 `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`
+}
+
+func (x *DRKeyHostASResponse) Reset() {
+	*x = DRKeyHostASResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_daemon_v1_daemon_proto_msgTypes[19]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DRKeyHostASResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeyHostASResponse) ProtoMessage() {}
+
+func (x *DRKeyHostASResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_daemon_v1_daemon_proto_msgTypes[19]
+	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 DRKeyHostASResponse.ProtoReflect.Descriptor instead.
+func (*DRKeyHostASResponse) Descriptor() ([]byte, []int) {
+	return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{19}
+}
+
+func (x *DRKeyHostASResponse) GetEpochBegin() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochBegin
+	}
+	return nil
+}
+
+func (x *DRKeyHostASResponse) GetEpochEnd() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochEnd
+	}
+	return nil
+}
+
+func (x *DRKeyHostASResponse) GetKey() []byte {
+	if x != nil {
+		return x.Key
+	}
+	return nil
+}
+
+type DRKeyASHostRequest 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"`
+	ProtocolId drkey.Protocol         `protobuf:"varint,2,opt,name=protocol_id,json=protocolId,proto3,enum=proto.drkey.v1.Protocol" json:"protocol_id,omitempty"`
+	SrcIa      uint64                 `protobuf:"varint,3,opt,name=src_ia,json=srcIa,proto3" json:"src_ia,omitempty"`
+	DstIa      uint64                 `protobuf:"varint,4,opt,name=dst_ia,json=dstIa,proto3" json:"dst_ia,omitempty"`
+	DstHost    string                 `protobuf:"bytes,5,opt,name=dst_host,json=dstHost,proto3" json:"dst_host,omitempty"`
+}
+
+func (x *DRKeyASHostRequest) Reset() {
+	*x = DRKeyASHostRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_daemon_v1_daemon_proto_msgTypes[20]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DRKeyASHostRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeyASHostRequest) ProtoMessage() {}
+
+func (x *DRKeyASHostRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_daemon_v1_daemon_proto_msgTypes[20]
+	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 DRKeyASHostRequest.ProtoReflect.Descriptor instead.
+func (*DRKeyASHostRequest) Descriptor() ([]byte, []int) {
+	return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{20}
+}
+
+func (x *DRKeyASHostRequest) GetValTime() *timestamppb.Timestamp {
+	if x != nil {
+		return x.ValTime
+	}
+	return nil
+}
+
+func (x *DRKeyASHostRequest) GetProtocolId() drkey.Protocol {
+	if x != nil {
+		return x.ProtocolId
+	}
+	return drkey.Protocol(0)
+}
+
+func (x *DRKeyASHostRequest) GetSrcIa() uint64 {
+	if x != nil {
+		return x.SrcIa
+	}
+	return 0
+}
+
+func (x *DRKeyASHostRequest) GetDstIa() uint64 {
+	if x != nil {
+		return x.DstIa
+	}
+	return 0
+}
+
+func (x *DRKeyASHostRequest) GetDstHost() string {
+	if x != nil {
+		return x.DstHost
+	}
+	return ""
+}
+
+type DRKeyASHostResponse 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"`
+	Key        []byte                 `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`
+}
+
+func (x *DRKeyASHostResponse) Reset() {
+	*x = DRKeyASHostResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_daemon_v1_daemon_proto_msgTypes[21]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DRKeyASHostResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeyASHostResponse) ProtoMessage() {}
+
+func (x *DRKeyASHostResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_daemon_v1_daemon_proto_msgTypes[21]
+	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 DRKeyASHostResponse.ProtoReflect.Descriptor instead.
+func (*DRKeyASHostResponse) Descriptor() ([]byte, []int) {
+	return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{21}
+}
+
+func (x *DRKeyASHostResponse) GetEpochBegin() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochBegin
+	}
+	return nil
+}
+
+func (x *DRKeyASHostResponse) GetEpochEnd() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochEnd
+	}
+	return nil
+}
+
+func (x *DRKeyASHostResponse) GetKey() []byte {
+	if x != nil {
+		return x.Key
+	}
+	return nil
+}
+
+type DRKeyHostHostRequest 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"`
+	ProtocolId drkey.Protocol         `protobuf:"varint,2,opt,name=protocol_id,json=protocolId,proto3,enum=proto.drkey.v1.Protocol" json:"protocol_id,omitempty"`
+	SrcIa      uint64                 `protobuf:"varint,3,opt,name=src_ia,json=srcIa,proto3" json:"src_ia,omitempty"`
+	DstIa      uint64                 `protobuf:"varint,4,opt,name=dst_ia,json=dstIa,proto3" json:"dst_ia,omitempty"`
+	SrcHost    string                 `protobuf:"bytes,5,opt,name=src_host,json=srcHost,proto3" json:"src_host,omitempty"`
+	DstHost    string                 `protobuf:"bytes,6,opt,name=dst_host,json=dstHost,proto3" json:"dst_host,omitempty"`
+}
+
+func (x *DRKeyHostHostRequest) Reset() {
+	*x = DRKeyHostHostRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_daemon_v1_daemon_proto_msgTypes[22]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DRKeyHostHostRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeyHostHostRequest) ProtoMessage() {}
+
+func (x *DRKeyHostHostRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_daemon_v1_daemon_proto_msgTypes[22]
+	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 DRKeyHostHostRequest.ProtoReflect.Descriptor instead.
+func (*DRKeyHostHostRequest) Descriptor() ([]byte, []int) {
+	return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{22}
+}
+
+func (x *DRKeyHostHostRequest) GetValTime() *timestamppb.Timestamp {
+	if x != nil {
+		return x.ValTime
+	}
+	return nil
+}
+
+func (x *DRKeyHostHostRequest) GetProtocolId() drkey.Protocol {
+	if x != nil {
+		return x.ProtocolId
+	}
+	return drkey.Protocol(0)
+}
+
+func (x *DRKeyHostHostRequest) GetSrcIa() uint64 {
+	if x != nil {
+		return x.SrcIa
+	}
+	return 0
+}
+
+func (x *DRKeyHostHostRequest) GetDstIa() uint64 {
+	if x != nil {
+		return x.DstIa
+	}
+	return 0
+}
+
+func (x *DRKeyHostHostRequest) GetSrcHost() string {
+	if x != nil {
+		return x.SrcHost
+	}
+	return ""
+}
+
+func (x *DRKeyHostHostRequest) GetDstHost() string {
+	if x != nil {
+		return x.DstHost
+	}
+	return ""
+}
+
+type DRKeyHostHostResponse 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"`
+	Key        []byte                 `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`
+}
+
+func (x *DRKeyHostHostResponse) Reset() {
+	*x = DRKeyHostHostResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_daemon_v1_daemon_proto_msgTypes[23]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DRKeyHostHostResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DRKeyHostHostResponse) ProtoMessage() {}
+
+func (x *DRKeyHostHostResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_daemon_v1_daemon_proto_msgTypes[23]
+	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 DRKeyHostHostResponse.ProtoReflect.Descriptor instead.
+func (*DRKeyHostHostResponse) Descriptor() ([]byte, []int) {
+	return file_proto_daemon_v1_daemon_proto_rawDescGZIP(), []int{23}
+}
+
+func (x *DRKeyHostHostResponse) GetEpochBegin() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochBegin
+	}
+	return nil
+}
+
+func (x *DRKeyHostHostResponse) GetEpochEnd() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EpochEnd
+	}
+	return nil
+}
+
+func (x *DRKeyHostHostResponse) GetKey() []byte {
+	if x != nil {
+		return x.Key
+	}
+	return nil
+}
+
 var File_proto_daemon_v1_daemon_proto protoreflect.FileDescriptor
 
 var file_proto_daemon_v1_daemon_proto_rawDesc = []byte{
@@ -1075,158 +1510,231 @@ var file_proto_daemon_v1_daemon_proto_rawDesc = []byte{
 	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,
 	0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x22, 0x92, 0x01, 0x0a, 0x0c, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
-	0x74, 0x12, 0x22, 0x0a, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x73, 0x64, 0x5f,
-	0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
-	0x49, 0x73, 0x64, 0x41, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61,
-	0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x04, 0x52, 0x10, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x73,
-	0x64, 0x41, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x18, 0x03,
-	0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x16, 0x0a,
-	0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x68,
-	0x69, 0x64, 0x64, 0x65, 0x6e, 0x22, 0x3c, 0x0a, 0x0d, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65,
-	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18,
-	0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61,
-	0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x52, 0x05, 0x70, 0x61,
-	0x74, 0x68, 0x73, 0x22, 0x94, 0x04, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x10, 0x0a, 0x03,
-	0x72, 0x61, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x72, 0x61, 0x77, 0x12, 0x38,
-	0x0a, 0x09, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x0b, 0x32, 0x1a, 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, 0x52, 0x09, 0x69,
-	0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x65,
-	0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50,
-	0x61, 0x74, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x0a, 0x69, 0x6e,
-	0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x74, 0x75, 0x18,
-	0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6d, 0x74, 0x75, 0x12, 0x3a, 0x0a, 0x0a, 0x65, 0x78,
-	0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 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, 0x78, 0x70, 0x69,
-	0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x07, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63,
-	0x79, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
-	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69,
-	0x6f, 0x6e, 0x52, 0x07, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x62,
-	0x61, 0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x07, 0x20, 0x03, 0x28, 0x04, 0x52, 0x09,
-	0x62, 0x61, 0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x31, 0x0a, 0x03, 0x67, 0x65, 0x6f,
-	0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64,
-	0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x6f, 0x43, 0x6f, 0x6f, 0x72,
-	0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x73, 0x52, 0x03, 0x67, 0x65, 0x6f, 0x12, 0x36, 0x0a, 0x09,
-	0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0e, 0x32,
-	0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76,
-	0x31, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x6c, 0x69, 0x6e, 0x6b,
-	0x54, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
-	0x5f, 0x68, 0x6f, 0x70, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x69, 0x6e, 0x74,
-	0x65, 0x72, 0x6e, 0x61, 0x6c, 0x48, 0x6f, 0x70, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x74,
-	0x65, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x12,
-	0x39, 0x0a, 0x0a, 0x65, 0x70, 0x69, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x73, 0x18, 0x0c, 0x20,
-	0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d,
-	0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x70, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x73, 0x52,
-	0x09, 0x65, 0x70, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x73, 0x22, 0x45, 0x0a, 0x09, 0x45, 0x70,
-	0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f,
-	0x70, 0x68, 0x76, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68,
-	0x50, 0x68, 0x76, 0x66, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6c, 0x68, 0x76,
-	0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x4c, 0x68, 0x76,
-	0x66, 0x22, 0x36, 0x0a, 0x0d, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61,
-	0x63, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x04, 0x52, 0x05, 0x69, 0x73, 0x64, 0x41, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0x64, 0x0a, 0x0e, 0x47, 0x65, 0x6f,
-	0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c,
-	0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, 0x52, 0x08, 0x6c,
-	0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69,
-	0x74, 0x75, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67,
-	0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
-	0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22,
-	0x22, 0x0a, 0x09, 0x41, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06,
-	0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x73,
-	0x64, 0x41, 0x73, 0x22, 0x49, 0x0a, 0x0a, 0x41, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x12, 0x15, 0x0a, 0x06, 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x04, 0x52, 0x05, 0x69, 0x73, 0x64, 0x41, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x72, 0x65,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x10, 0x0a, 0x03,
-	0x6d, 0x74, 0x75, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6d, 0x74, 0x75, 0x22, 0x13,
-	0x0a, 0x11, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75,
-	0x65, 0x73, 0x74, 0x22, 0xc4, 0x01, 0x0a, 0x12, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63,
-	0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x0a, 0x69, 0x6e,
-	0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33,
-	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, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x45, 0x6e,
-	0x74, 0x72, 0x79, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x1a,
-	0x59, 0x0a, 0x0f, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74,
-	0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52,
-	0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x0b, 0x32, 0x1a, 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, 0x52,
-	0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x40, 0x0a, 0x09, 0x49, 0x6e,
-	0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,
-	0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x64, 0x65, 0x72,
-	0x6c, 0x61, 0x79, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x11, 0x0a, 0x0f,
-	0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22,
-	0xba, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
-	0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 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, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
-	0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
-	0x73, 0x1a, 0x59, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74,
-	0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x03, 0x6b, 0x65, 0x79, 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d,
-	0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
-	0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x43, 0x0a, 0x0b,
-	0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x08, 0x73,
-	0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e,
+	0x1a, 0x1a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2f, 0x76, 0x31,
+	0x2f, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x92, 0x01, 0x0a,
+	0x0c, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a,
+	0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x73, 0x64, 0x41,
+	0x73, 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x5f, 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x64,
+	0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x73, 0x64, 0x41, 0x73, 0x12,
+	0x18, 0x0a, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
+	0x52, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x69, 0x64,
+	0x64, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x68, 0x69, 0x64, 0x64, 0x65,
+	0x6e, 0x22, 0x3c, 0x0a, 0x0d, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e,
+	0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x52, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x22,
+	0x94, 0x04, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x61, 0x77, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x72, 0x61, 0x77, 0x12, 0x38, 0x0a, 0x09, 0x69, 0x6e,
+	0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
 	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e,
-	0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
-	0x73, 0x22, 0x1b, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03,
-	0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x22, 0x24,
-	0x0a, 0x08, 0x55, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64,
-	0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64,
-	0x72, 0x65, 0x73, 0x73, 0x22, 0x43, 0x0a, 0x1a, 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, 0x12, 0x15, 0x0a, 0x06, 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x04, 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, 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, 0x2e, 0x5a, 0x2c, 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, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x64, 0x61, 0x65,
-	0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x09, 0x69, 0x6e, 0x74, 0x65, 0x72,
+	0x66, 0x61, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63,
+	0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x49,
+	0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66,
+	0x61, 0x63, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x74, 0x75, 0x18, 0x04, 0x20, 0x01, 0x28,
+	0x0d, 0x52, 0x03, 0x6d, 0x74, 0x75, 0x12, 0x3a, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61,
+	0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 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, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x07, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x06, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07,
+	0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x61, 0x6e, 0x64, 0x77,
+	0x69, 0x64, 0x74, 0x68, 0x18, 0x07, 0x20, 0x03, 0x28, 0x04, 0x52, 0x09, 0x62, 0x61, 0x6e, 0x64,
+	0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x31, 0x0a, 0x03, 0x67, 0x65, 0x6f, 0x18, 0x08, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f,
+	0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x6f, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61,
+	0x74, 0x65, 0x73, 0x52, 0x03, 0x67, 0x65, 0x6f, 0x12, 0x36, 0x0a, 0x09, 0x6c, 0x69, 0x6e, 0x6b,
+	0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69,
+	0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x6c, 0x69, 0x6e, 0x6b, 0x54, 0x79, 0x70, 0x65,
+	0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x68, 0x6f, 0x70,
+	0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
+	0x6c, 0x48, 0x6f, 0x70, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x18, 0x0b,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x65,
+	0x70, 0x69, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76,
+	0x31, 0x2e, 0x45, 0x70, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x73, 0x52, 0x09, 0x65, 0x70, 0x69,
+	0x63, 0x41, 0x75, 0x74, 0x68, 0x73, 0x22, 0x45, 0x0a, 0x09, 0x45, 0x70, 0x69, 0x63, 0x41, 0x75,
+	0x74, 0x68, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x68, 0x76, 0x66,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x50, 0x68, 0x76, 0x66,
+	0x12, 0x1b, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6c, 0x68, 0x76, 0x66, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x4c, 0x68, 0x76, 0x66, 0x22, 0x36, 0x0a,
+	0x0d, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x15,
+	0x0a, 0x06, 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05,
+	0x69, 0x73, 0x64, 0x41, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0x64, 0x0a, 0x0e, 0x47, 0x65, 0x6f, 0x43, 0x6f, 0x6f, 0x72,
+	0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74,
+	0x75, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, 0x52, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74,
+	0x75, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64,
+	0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x22, 0x0a, 0x09, 0x41,
+	0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x69, 0x73, 0x64, 0x5f,
+	0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x73, 0x64, 0x41, 0x73, 0x22,
+	0x49, 0x0a, 0x0a, 0x41, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x15, 0x0a,
+	0x06, 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69,
+	0x73, 0x64, 0x41, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x08, 0x52, 0x04, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x74, 0x75, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6d, 0x74, 0x75, 0x22, 0x13, 0x0a, 0x11, 0x49, 0x6e,
+	0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22,
+	0xc4, 0x01, 0x0a, 0x12, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66,
+	0x61, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 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, 0x2e,
+	0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
+	0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x1a, 0x59, 0x0a, 0x0f, 0x49,
+	0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
+	0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x6b, 0x65, 0x79,
+	0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x1a, 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, 0x52, 0x05, 0x76, 0x61, 0x6c,
+	0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x40, 0x0a, 0x09, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66,
+	0x61, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65,
+	0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x79, 0x52,
+	0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76,
+	0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xba, 0x01, 0x0a, 0x10,
+	0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x12, 0x4b, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x2f, 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, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e,
+	0x74, 0x72, 0x79, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x1a, 0x59, 0x0a,
+	0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
+	0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
+	0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76,
+	0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x05, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x43, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74,
+	0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69,
+	0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x2e, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76,
+	0x69, 0x63, 0x65, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22, 0x1b, 0x0a,
+	0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x22, 0x24, 0x0a, 0x08, 0x55, 0x6e,
+	0x64, 0x65, 0x72, 0x6c, 0x61, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
+	0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
+	0x22, 0x43, 0x0a, 0x1a, 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, 0x12, 0x15,
+	0x0a, 0x06, 0x69, 0x73, 0x64, 0x5f, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 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, 0x22, 0xcf, 0x01, 0x0a, 0x12, 0x44, 0x52, 0x4b, 0x65, 0x79, 0x48, 0x6f,
+	0x73, 0x74, 0x41, 0x53, 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, 0x39, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x69,
+	0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
+	0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
+	0x6c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49, 0x64, 0x12, 0x15, 0x0a,
+	0x06, 0x73, 0x72, 0x63, 0x5f, 0x69, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73,
+	0x72, 0x63, 0x49, 0x61, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x73, 0x74, 0x5f, 0x69, 0x61, 0x18, 0x04,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x64, 0x73, 0x74, 0x49, 0x61, 0x12, 0x19, 0x0a, 0x08, 0x73,
+	0x72, 0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73,
+	0x72, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x22, 0x9d, 0x01, 0x0a, 0x13, 0x44, 0x52, 0x4b, 0x65, 0x79,
+	0x48, 0x6f, 0x73, 0x74, 0x41, 0x53, 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, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0xcf, 0x01, 0x0a, 0x12, 0x44, 0x52, 0x4b, 0x65, 0x79,
+	0x41, 0x53, 0x48, 0x6f, 0x73, 0x74, 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, 0x39, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
+	0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f,
+	0x63, 0x6f, 0x6c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49, 0x64, 0x12,
+	0x15, 0x0a, 0x06, 0x73, 0x72, 0x63, 0x5f, 0x69, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x05, 0x73, 0x72, 0x63, 0x49, 0x61, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x73, 0x74, 0x5f, 0x69, 0x61,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x64, 0x73, 0x74, 0x49, 0x61, 0x12, 0x19, 0x0a,
+	0x08, 0x64, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x07, 0x64, 0x73, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x22, 0x9d, 0x01, 0x0a, 0x13, 0x44, 0x52, 0x4b,
+	0x65, 0x79, 0x41, 0x53, 0x48, 0x6f, 0x73, 0x74, 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, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0xec, 0x01, 0x0a, 0x14, 0x44, 0x52, 0x4b,
+	0x65, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x48, 0x6f, 0x73, 0x74, 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, 0x39, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50,
+	0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
+	0x6c, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x72, 0x63, 0x5f, 0x69, 0x61, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x72, 0x63, 0x49, 0x61, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x73,
+	0x74, 0x5f, 0x69, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x64, 0x73, 0x74, 0x49,
+	0x61, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x72, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08,
+	0x64, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
+	0x64, 0x73, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x22, 0x9f, 0x01, 0x0a, 0x15, 0x44, 0x52, 0x4b, 0x65,
+	0x79, 0x48, 0x6f, 0x73, 0x74, 0x48, 0x6f, 0x73, 0x74, 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, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 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, 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, 0x2e, 0x5a, 0x2c, 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, 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 (
@@ -1242,7 +1750,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, 20)
+var file_proto_daemon_v1_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 26)
 var file_proto_daemon_v1_daemon_proto_goTypes = []interface{}{
 	(LinkType)(0),                       // 0: proto.daemon.v1.LinkType
 	(*PathsRequest)(nil),                // 1: proto.daemon.v1.PathsRequest
@@ -1263,41 +1771,60 @@ var file_proto_daemon_v1_daemon_proto_goTypes = []interface{}{
 	(*Underlay)(nil),                    // 16: proto.daemon.v1.Underlay
 	(*NotifyInterfaceDownRequest)(nil),  // 17: proto.daemon.v1.NotifyInterfaceDownRequest
 	(*NotifyInterfaceDownResponse)(nil), // 18: proto.daemon.v1.NotifyInterfaceDownResponse
-	nil,                                 // 19: proto.daemon.v1.InterfacesResponse.InterfacesEntry
-	nil,                                 // 20: proto.daemon.v1.ServicesResponse.ServicesEntry
-	(*timestamppb.Timestamp)(nil),       // 21: google.protobuf.Timestamp
-	(*durationpb.Duration)(nil),         // 22: google.protobuf.Duration
+	(*DRKeyHostASRequest)(nil),          // 19: proto.daemon.v1.DRKeyHostASRequest
+	(*DRKeyHostASResponse)(nil),         // 20: proto.daemon.v1.DRKeyHostASResponse
+	(*DRKeyASHostRequest)(nil),          // 21: proto.daemon.v1.DRKeyASHostRequest
+	(*DRKeyASHostResponse)(nil),         // 22: proto.daemon.v1.DRKeyASHostResponse
+	(*DRKeyHostHostRequest)(nil),        // 23: proto.daemon.v1.DRKeyHostHostRequest
+	(*DRKeyHostHostResponse)(nil),       // 24: proto.daemon.v1.DRKeyHostHostResponse
+	nil,                                 // 25: proto.daemon.v1.InterfacesResponse.InterfacesEntry
+	nil,                                 // 26: proto.daemon.v1.ServicesResponse.ServicesEntry
+	(*timestamppb.Timestamp)(nil),       // 27: google.protobuf.Timestamp
+	(*durationpb.Duration)(nil),         // 28: google.protobuf.Duration
+	(drkey.Protocol)(0),                 // 29: proto.drkey.v1.Protocol
 }
 var file_proto_daemon_v1_daemon_proto_depIdxs = []int32{
 	3,  // 0: proto.daemon.v1.PathsResponse.paths:type_name -> proto.daemon.v1.Path
 	11, // 1: proto.daemon.v1.Path.interface:type_name -> proto.daemon.v1.Interface
 	5,  // 2: proto.daemon.v1.Path.interfaces:type_name -> proto.daemon.v1.PathInterface
-	21, // 3: proto.daemon.v1.Path.expiration:type_name -> google.protobuf.Timestamp
-	22, // 4: proto.daemon.v1.Path.latency:type_name -> google.protobuf.Duration
+	27, // 3: proto.daemon.v1.Path.expiration:type_name -> google.protobuf.Timestamp
+	28, // 4: proto.daemon.v1.Path.latency:type_name -> google.protobuf.Duration
 	6,  // 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
 	4,  // 7: proto.daemon.v1.Path.epic_auths:type_name -> proto.daemon.v1.EpicAuths
-	19, // 8: proto.daemon.v1.InterfacesResponse.interfaces:type_name -> proto.daemon.v1.InterfacesResponse.InterfacesEntry
+	25, // 8: proto.daemon.v1.InterfacesResponse.interfaces:type_name -> proto.daemon.v1.InterfacesResponse.InterfacesEntry
 	16, // 9: proto.daemon.v1.Interface.address:type_name -> proto.daemon.v1.Underlay
-	20, // 10: proto.daemon.v1.ServicesResponse.services:type_name -> proto.daemon.v1.ServicesResponse.ServicesEntry
+	26, // 10: proto.daemon.v1.ServicesResponse.services:type_name -> proto.daemon.v1.ServicesResponse.ServicesEntry
 	15, // 11: proto.daemon.v1.ListService.services:type_name -> proto.daemon.v1.Service
-	11, // 12: proto.daemon.v1.InterfacesResponse.InterfacesEntry.value:type_name -> proto.daemon.v1.Interface
-	14, // 13: proto.daemon.v1.ServicesResponse.ServicesEntry.value:type_name -> proto.daemon.v1.ListService
-	1,  // 14: proto.daemon.v1.DaemonService.Paths:input_type -> proto.daemon.v1.PathsRequest
-	7,  // 15: proto.daemon.v1.DaemonService.AS:input_type -> proto.daemon.v1.ASRequest
-	9,  // 16: proto.daemon.v1.DaemonService.Interfaces:input_type -> proto.daemon.v1.InterfacesRequest
-	12, // 17: proto.daemon.v1.DaemonService.Services:input_type -> proto.daemon.v1.ServicesRequest
-	17, // 18: proto.daemon.v1.DaemonService.NotifyInterfaceDown:input_type -> proto.daemon.v1.NotifyInterfaceDownRequest
-	2,  // 19: proto.daemon.v1.DaemonService.Paths:output_type -> proto.daemon.v1.PathsResponse
-	8,  // 20: proto.daemon.v1.DaemonService.AS:output_type -> proto.daemon.v1.ASResponse
-	10, // 21: proto.daemon.v1.DaemonService.Interfaces:output_type -> proto.daemon.v1.InterfacesResponse
-	13, // 22: proto.daemon.v1.DaemonService.Services:output_type -> proto.daemon.v1.ServicesResponse
-	18, // 23: proto.daemon.v1.DaemonService.NotifyInterfaceDown:output_type -> proto.daemon.v1.NotifyInterfaceDownResponse
-	19, // [19:24] is the sub-list for method output_type
-	14, // [14:19] is the sub-list for method input_type
-	14, // [14:14] is the sub-list for extension type_name
-	14, // [14:14] is the sub-list for extension extendee
-	0,  // [0:14] is the sub-list for field type_name
+	27, // 12: proto.daemon.v1.DRKeyHostASRequest.val_time:type_name -> google.protobuf.Timestamp
+	29, // 13: proto.daemon.v1.DRKeyHostASRequest.protocol_id:type_name -> proto.drkey.v1.Protocol
+	27, // 14: proto.daemon.v1.DRKeyHostASResponse.epoch_begin:type_name -> google.protobuf.Timestamp
+	27, // 15: proto.daemon.v1.DRKeyHostASResponse.epoch_end:type_name -> google.protobuf.Timestamp
+	27, // 16: proto.daemon.v1.DRKeyASHostRequest.val_time:type_name -> google.protobuf.Timestamp
+	29, // 17: proto.daemon.v1.DRKeyASHostRequest.protocol_id:type_name -> proto.drkey.v1.Protocol
+	27, // 18: proto.daemon.v1.DRKeyASHostResponse.epoch_begin:type_name -> google.protobuf.Timestamp
+	27, // 19: proto.daemon.v1.DRKeyASHostResponse.epoch_end:type_name -> google.protobuf.Timestamp
+	27, // 20: proto.daemon.v1.DRKeyHostHostRequest.val_time:type_name -> google.protobuf.Timestamp
+	29, // 21: proto.daemon.v1.DRKeyHostHostRequest.protocol_id:type_name -> proto.drkey.v1.Protocol
+	27, // 22: proto.daemon.v1.DRKeyHostHostResponse.epoch_begin:type_name -> google.protobuf.Timestamp
+	27, // 23: proto.daemon.v1.DRKeyHostHostResponse.epoch_end:type_name -> google.protobuf.Timestamp
+	11, // 24: proto.daemon.v1.InterfacesResponse.InterfacesEntry.value:type_name -> proto.daemon.v1.Interface
+	14, // 25: proto.daemon.v1.ServicesResponse.ServicesEntry.value:type_name -> proto.daemon.v1.ListService
+	1,  // 26: proto.daemon.v1.DaemonService.Paths:input_type -> proto.daemon.v1.PathsRequest
+	7,  // 27: proto.daemon.v1.DaemonService.AS:input_type -> proto.daemon.v1.ASRequest
+	9,  // 28: proto.daemon.v1.DaemonService.Interfaces:input_type -> proto.daemon.v1.InterfacesRequest
+	12, // 29: proto.daemon.v1.DaemonService.Services:input_type -> proto.daemon.v1.ServicesRequest
+	17, // 30: proto.daemon.v1.DaemonService.NotifyInterfaceDown:input_type -> proto.daemon.v1.NotifyInterfaceDownRequest
+	2,  // 31: proto.daemon.v1.DaemonService.Paths:output_type -> proto.daemon.v1.PathsResponse
+	8,  // 32: proto.daemon.v1.DaemonService.AS:output_type -> proto.daemon.v1.ASResponse
+	10, // 33: proto.daemon.v1.DaemonService.Interfaces:output_type -> proto.daemon.v1.InterfacesResponse
+	13, // 34: proto.daemon.v1.DaemonService.Services:output_type -> proto.daemon.v1.ServicesResponse
+	18, // 35: proto.daemon.v1.DaemonService.NotifyInterfaceDown:output_type -> proto.daemon.v1.NotifyInterfaceDownResponse
+	31, // [31:36] is the sub-list for method output_type
+	26, // [26:31] is the sub-list for method input_type
+	26, // [26:26] is the sub-list for extension type_name
+	26, // [26:26] is the sub-list for extension extendee
+	0,  // [0:26] is the sub-list for field type_name
 }
 
 func init() { file_proto_daemon_v1_daemon_proto_init() }
@@ -1522,6 +2049,78 @@ func file_proto_daemon_v1_daemon_proto_init() {
 				return nil
 			}
 		}
+		file_proto_daemon_v1_daemon_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DRKeyHostASRequest); 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[19].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DRKeyHostASResponse); 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[20].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DRKeyASHostRequest); 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[21].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DRKeyASHostResponse); 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[22].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DRKeyHostHostRequest); 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[23].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DRKeyHostHostResponse); 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{
@@ -1529,7 +2128,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:   20,
+			NumMessages:   26,
 			NumExtensions: 0,
 			NumServices:   1,
 		},
diff --git a/pkg/proto/drkey/BUILD.bazel b/pkg/proto/drkey/BUILD.bazel
new file mode 100644
index 000000000..7f6992210
--- /dev/null
+++ b/pkg/proto/drkey/BUILD.bazel
@@ -0,0 +1,9 @@
+load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
+
+go_proto_library(
+    name = "go_default_library",
+    compiler = "@io_bazel_rules_go//proto:go_grpc",
+    importpath = "github.com/scionproto/scion/pkg/proto/drkey",
+    proto = "//proto/drkey/v1:drkey",
+    visibility = ["//visibility:public"],
+)
diff --git a/pkg/proto/drkey/drkey.pb.go b/pkg/proto/drkey/drkey.pb.go
new file mode 100644
index 000000000..d6e85f661
--- /dev/null
+++ b/pkg/proto/drkey/drkey.pb.go
@@ -0,0 +1,132 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.27.1
+// 	protoc        v3.15.3
+// source: proto/drkey/v1/drkey.proto
+
+package drkey
+
+import (
+	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 Protocol int32
+
+const (
+	Protocol_PROTOCOL_GENERIC_UNSPECIFIED Protocol = 0
+	Protocol_PROTOCOL_SCMP                Protocol = 1
+)
+
+// Enum value maps for Protocol.
+var (
+	Protocol_name = map[int32]string{
+		0: "PROTOCOL_GENERIC_UNSPECIFIED",
+		1: "PROTOCOL_SCMP",
+	}
+	Protocol_value = map[string]int32{
+		"PROTOCOL_GENERIC_UNSPECIFIED": 0,
+		"PROTOCOL_SCMP":                1,
+	}
+)
+
+func (x Protocol) Enum() *Protocol {
+	p := new(Protocol)
+	*p = x
+	return p
+}
+
+func (x Protocol) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Protocol) Descriptor() protoreflect.EnumDescriptor {
+	return file_proto_drkey_v1_drkey_proto_enumTypes[0].Descriptor()
+}
+
+func (Protocol) Type() protoreflect.EnumType {
+	return &file_proto_drkey_v1_drkey_proto_enumTypes[0]
+}
+
+func (x Protocol) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Protocol.Descriptor instead.
+func (Protocol) EnumDescriptor() ([]byte, []int) {
+	return file_proto_drkey_v1_drkey_proto_rawDescGZIP(), []int{0}
+}
+
+var File_proto_drkey_v1_drkey_proto protoreflect.FileDescriptor
+
+var file_proto_drkey_v1_drkey_proto_rawDesc = []byte{
+	0x0a, 0x1a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2f, 0x76, 0x31,
+	0x2f, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x72, 0x6b, 0x65, 0x79, 0x2e, 0x76, 0x31, 0x2a, 0x4b, 0x0a, 0x08,
+	0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x20, 0x0a, 0x1c, 0x50, 0x52, 0x4f, 0x54,
+	0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x49, 0x43, 0x5f, 0x55, 0x4e, 0x53,
+	0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52,
+	0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x53, 0x43, 0x4d, 0x50, 0x10, 0x01, 0x22, 0x0a, 0x08,
+	0x80, 0x80, 0x04, 0x10, 0xff, 0xff, 0xff, 0xff, 0x07, 0x42, 0x2d, 0x5a, 0x2b, 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, 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_v1_drkey_proto_rawDescOnce sync.Once
+	file_proto_drkey_v1_drkey_proto_rawDescData = file_proto_drkey_v1_drkey_proto_rawDesc
+)
+
+func file_proto_drkey_v1_drkey_proto_rawDescGZIP() []byte {
+	file_proto_drkey_v1_drkey_proto_rawDescOnce.Do(func() {
+		file_proto_drkey_v1_drkey_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_drkey_v1_drkey_proto_rawDescData)
+	})
+	return file_proto_drkey_v1_drkey_proto_rawDescData
+}
+
+var file_proto_drkey_v1_drkey_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_proto_drkey_v1_drkey_proto_goTypes = []interface{}{
+	(Protocol)(0), // 0: proto.drkey.v1.Protocol
+}
+var file_proto_drkey_v1_drkey_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_proto_drkey_v1_drkey_proto_init() }
+func file_proto_drkey_v1_drkey_proto_init() {
+	if File_proto_drkey_v1_drkey_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_proto_drkey_v1_drkey_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   0,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_proto_drkey_v1_drkey_proto_goTypes,
+		DependencyIndexes: file_proto_drkey_v1_drkey_proto_depIdxs,
+		EnumInfos:         file_proto_drkey_v1_drkey_proto_enumTypes,
+	}.Build()
+	File_proto_drkey_v1_drkey_proto = out.File
+	file_proto_drkey_v1_drkey_proto_rawDesc = nil
+	file_proto_drkey_v1_drkey_proto_goTypes = nil
+	file_proto_drkey_v1_drkey_proto_depIdxs = nil
+}
diff --git a/private/proto/drkey/BUILD.bazel b/private/proto/drkey/BUILD.bazel
new file mode 100644
index 000000000..b4fe224d7
--- /dev/null
+++ b/private/proto/drkey/BUILD.bazel
@@ -0,0 +1,13 @@
+load("//tools/lint:go.bzl", "go_test")
+
+go_test(
+    name = "go_default_test",
+    srcs = ["eq_definiton_test.go"],
+    deps = [
+        "//pkg/proto/control_plane:go_default_library",
+        "//pkg/proto/daemon:go_default_library",
+        "@com_github_stretchr_testify//assert:go_default_library",
+        "@com_github_stretchr_testify//require:go_default_library",
+        "@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
+    ],
+)
diff --git a/proto/control_plane/v1/BUILD.bazel b/proto/control_plane/v1/BUILD.bazel
index df8521537..7a0e59f88 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/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 000000000..f33dad984
--- /dev/null
+++ b/proto/control_plane/v1/drkey.proto
@@ -0,0 +1,123 @@
+// 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.
+
+syntax = "proto3";
+
+option go_package = "github.com/scionproto/scion/pkg/proto/control_plane";
+
+package proto.control_plane.v1;
+
+import "proto/drkey/v1/drkey.proto";
+import "google/protobuf/timestamp.proto";
+
+message DRKeySecretValueRequest{
+    // Point in time when the requested key is valid.
+    google.protobuf.Timestamp val_time = 1;
+    // Protocol value.
+    proto.drkey.v1.Protocol protocol_id = 2;
+}
+
+message DRKeySecretValueResponse{
+    // Begin of the validity period.
+    google.protobuf.Timestamp epoch_begin = 1;
+    // End of the validity period.
+    google.protobuf.Timestamp epoch_end = 2;
+    // SecretValue key.
+    bytes key = 3;
+}
+
+// DRKeyLevel1Request leaves out the 'dstIA' field which can be extracted from
+// the transport itself (ideally from authenticated information).
+message DRKeyLevel1Request{
+    // Point in time where requested key is valid.
+    google.protobuf.Timestamp val_time = 1;
+    // Protocol value.
+    proto.drkey.v1.Protocol protocol_id = 2;
+
+}
+
+// DRKeyLevel1Response leaves out the 'dstIA' and 'srcIA' fields which can be
+// extracted from the transport itself (ideally from authenticated information).
+message DRKeyLevel1Response{
+    // Begin of the validity period
+    google.protobuf.Timestamp epoch_begin = 1;
+    // End of the validity period
+    google.protobuf.Timestamp epoch_end = 2;
+    // Level1 key
+    bytes key = 3;
+}
+
+message DRKeyIntraLevel1Request{
+    // Point in time where requested key is valid.
+    google.protobuf.Timestamp val_time = 1;
+    // Protocol value.
+    proto.drkey.v1.Protocol protocol_id = 2;
+    // Src ISD-AS of the requested DRKey.
+    uint64 src_ia = 3;
+    // Dst ISD-AS of the requested DRKey.
+    uint64 dst_ia = 4;
+}
+
+message DRKeyIntraLevel1Response{
+    // Begin of validity period of DRKey.
+    google.protobuf.Timestamp epoch_begin = 1;
+    // End of validity period of DRKey.
+    google.protobuf.Timestamp epoch_end = 2;
+    // Level1 key.
+    bytes key = 3;
+}
+
+message DRKeyHostASRequest{
+    // Point in time where requested key is valid.
+    google.protobuf.Timestamp val_time = 1;
+    // Protocol value.
+    proto.drkey.v1.Protocol protocol_id = 2;
+    // Src ISD-AS of the requested DRKey.
+    uint64 src_ia = 3;
+    // Dst ISD-AS of the requested DRKey.
+    uint64 dst_ia = 4;
+    // Src Host of the request DRKey.
+    string src_host = 5;
+}
+
+message DRKeyHostASResponse{
+    // Begin of validity period of DRKey.
+    google.protobuf.Timestamp epoch_begin = 1;
+    // End of validity period of DRKey.
+    google.protobuf.Timestamp epoch_end = 2;
+    // Level2 key.
+    bytes key = 3;
+}
+
+message DRKeyASHostRequest{
+    // Point in time where requested key is valid.
+    google.protobuf.Timestamp val_time = 1;
+    // Protocol value.
+    proto.drkey.v1.Protocol protocol_id = 2;
+    // Src ISD-AS of the requested DRKey.
+    uint64 src_ia = 3;
+    // Dst ISD-AS of the requested DRKey.
+    uint64 dst_ia = 4;
+    // Dst Host of the request DRKey.
+    string dst_host = 5;
+}
+
+message DRKeyASHostResponse{
+    // Begin of validity period of DRKey.
+    google.protobuf.Timestamp epoch_begin = 1;
+    // End of validity period of DRKey.
+    google.protobuf.Timestamp epoch_end = 2;
+    // Level2 key.
+    bytes key = 3;
+}
diff --git a/proto/daemon/v1/BUILD.bazel b/proto/daemon/v1/BUILD.bazel
index 8a7d07cff..cf258adad 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/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 9dec9a87a..b50c7443a 100644
--- a/proto/daemon/v1/daemon.proto
+++ b/proto/daemon/v1/daemon.proto
@@ -20,6 +20,7 @@ package proto.daemon.v1;
 
 import "google/protobuf/timestamp.proto";
 import "google/protobuf/duration.proto";
+import "proto/drkey/v1/drkey.proto";
 
 service DaemonService {
     // Return a set of paths to the requested destination.
@@ -191,3 +192,71 @@ message NotifyInterfaceDownRequest {
 }
 
 message NotifyInterfaceDownResponse {};
+
+message DRKeyHostASRequest{
+    // Point in time where requested key is valid.
+    google.protobuf.Timestamp val_time = 1;
+    // Protocol value.
+    proto.drkey.v1.Protocol protocol_id = 2;
+    // Src ISD-AS of the requested DRKey.
+    uint64 src_ia = 3;
+    // Dst ISD-AS of the requested DRKey.
+    uint64 dst_ia = 4;
+    // Src Host of the request DRKey.
+    string src_host = 5;
+}
+
+message DRKeyHostASResponse{
+    // Begin of validity period of DRKey.
+    google.protobuf.Timestamp epoch_begin = 1;
+    // End of validity period of DRKey.
+    google.protobuf.Timestamp epoch_end = 2;
+    // Level2 key.
+    bytes key = 3;
+}
+
+message DRKeyASHostRequest{
+    // Point in time where requested key is valid.
+    google.protobuf.Timestamp val_time = 1;
+    // Protocol value.
+    proto.drkey.v1.Protocol protocol_id = 2;
+    // Src ISD-AS of the requested DRKey.
+    uint64 src_ia = 3;
+    // Dst ISD-AS of the requested DRKey.
+    uint64 dst_ia = 4;
+    // Dst Host of the request DRKey.
+    string dst_host = 5;
+}
+
+message DRKeyASHostResponse{
+    // Begin of validity period of DRKey.
+    google.protobuf.Timestamp epoch_begin = 1;
+    // End of validity period of DRKey.
+    google.protobuf.Timestamp epoch_end = 2;
+    // Level2 key.
+    bytes key = 3;
+}
+
+message DRKeyHostHostRequest{
+    // Point in time where requested key is valid.
+    google.protobuf.Timestamp val_time = 1;
+    // Protocol value.
+    proto.drkey.v1.Protocol protocol_id = 2;
+    // Src ISD-AS of the requested DRKey.
+    uint64 src_ia = 3;
+    // Dst ISD-AS of the requested DRKey.
+    uint64 dst_ia = 4;
+    // Src Host of the request DRKey.
+    string src_host = 5;
+    // Dst Host of the request DRKey.
+    string dst_host = 6;
+}
+
+message DRKeyHostHostResponse{
+    // Begin of validity period of DRKey.
+    google.protobuf.Timestamp epoch_begin = 1;
+    // End of validity period of DRKey.
+    google.protobuf.Timestamp epoch_end = 2;
+    // Level2 key.
+    bytes key = 3;
+}
diff --git a/proto/drkey/v1/BUILD.bazel b/proto/drkey/v1/BUILD.bazel
new file mode 100644
index 000000000..6e702d770
--- /dev/null
+++ b/proto/drkey/v1/BUILD.bazel
@@ -0,0 +1,9 @@
+load("@rules_proto//proto:defs.bzl", "proto_library")
+
+proto_library(
+    name = "drkey",
+    srcs = [
+        "drkey.proto",
+    ],
+    visibility = ["//visibility:public"],
+)
diff --git a/proto/drkey/v1/drkey.proto b/proto/drkey/v1/drkey.proto
new file mode 100644
index 000000000..f3393366f
--- /dev/null
+++ b/proto/drkey/v1/drkey.proto
@@ -0,0 +1,28 @@
+// Copyright 2020 ETH Zürich
+//
+// 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/pkg/proto/drkey";
+
+package proto.drkey.v1;
+
+enum Protocol{
+    // Generic is used to derive keys in the generic derivation scheme
+    PROTOCOL_GENERIC_UNSPECIFIED = 0;
+    // SCMP protocol
+    PROTOCOL_SCMP = 1;
+    reserved 65536 to max; // only 16-bit values allowed
+}
+


Test patch:
diff --git a/pkg/drkey/generic/generic_test.go b/pkg/drkey/generic/generic_test.go
new file mode 100644
index 000000000..2e9e63d8c
--- /dev/null
+++ b/pkg/drkey/generic/generic_test.go
@@ -0,0 +1,197 @@
+// 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 generic_test
+
+import (
+	"encoding/hex"
+	"os"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"github.com/scionproto/scion/pkg/drkey"
+	"github.com/scionproto/scion/pkg/private/xtest"
+	"github.com/scionproto/scion/private/drkey/drkeytest"
+)
+
+var (
+	update  = xtest.UpdateGoldenFiles()
+	protoId = drkey.Generic
+	epoch   = drkey.NewEpoch(0, 1)
+	srcIA   = xtest.MustParseIA("1-ff00:0:111")
+	dstIA   = xtest.MustParseIA("1-ff00:0:112")
+	srcHost = "127.0.0.2"
+	dstHost = "127.0.0.1"
+)
+
+func TestDeriveASHostGeneric(t *testing.T) {
+	level1Key := drkeytest.GetLevel1(t, protoId, epoch, srcIA, dstIA)
+
+	testCases := map[string]struct {
+		meta            drkey.ASHostMeta
+		assertFormatErr assert.ErrorAssertionFunc
+	}{
+		"wrong no-host": {
+			meta: drkey.ASHostMeta{
+				ProtoId: drkey.Protocol(10000),
+			},
+			assertFormatErr: assert.Error,
+		},
+		"invalid as-host": {
+			meta: drkey.ASHostMeta{
+				ProtoId: drkey.Protocol(10000),
+				DstHost: "<malformed address>",
+			},
+			assertFormatErr: assert.Error,
+		},
+		"valid as-host": {
+			meta: drkey.ASHostMeta{
+				ProtoId: drkey.Protocol(10000),
+				DstHost: dstHost,
+			},
+			assertFormatErr: assert.NoError,
+		},
+	}
+	for name, tc := range testCases {
+		name, tc := name, tc
+		t.Run(name, func(t *testing.T) {
+
+			key, err := drkeytest.DeriveASHostGeneric(tc.meta, level1Key)
+			tc.assertFormatErr(t, err)
+			if err != nil {
+				return
+			}
+			goldenFile := "testdata/" + xtest.SanitizedName(t)
+			if *update {
+				keyStr := hex.EncodeToString(key.Key[:])
+				require.NoError(t, os.WriteFile(goldenFile, []byte(keyStr), 0666))
+			}
+			goldenRaw, err := os.ReadFile(goldenFile)
+			require.NoError(t, err)
+
+			var expectedKey drkey.Key
+			goldenKey, err := hex.DecodeString(string(goldenRaw))
+			require.NoError(t, err)
+			copy(expectedKey[:], goldenKey)
+			require.Equal(t, expectedKey, key.Key)
+		})
+	}
+}
+
+func TestDeriveGenericHostAS(t *testing.T) {
+	level1Key := drkeytest.GetLevel1(t, protoId, epoch, srcIA, dstIA)
+	testCases := map[string]struct {
+		meta            drkey.HostASMeta
+		assertFormatErr assert.ErrorAssertionFunc
+	}{
+		"valid host-as": {
+			meta: drkey.HostASMeta{
+				ProtoId: drkey.Protocol(10000),
+				SrcHost: srcHost,
+			},
+			assertFormatErr: assert.NoError,
+		},
+		"invalid host-as": {
+			meta: drkey.HostASMeta{
+				ProtoId: drkey.Protocol(10000),
+				SrcHost: "<malformed address>",
+			},
+			assertFormatErr: assert.Error,
+		},
+	}
+	for name, tc := range testCases {
+		name, tc := name, tc
+		t.Run(name, func(t *testing.T) {
+
+			key, err := drkeytest.DeriveHostASGeneric(tc.meta, level1Key)
+			tc.assertFormatErr(t, err)
+			if err != nil {
+				return
+			}
+			goldenFile := "testdata/" + xtest.SanitizedName(t)
+			if *update {
+				keyStr := hex.EncodeToString(key.Key[:])
+				require.NoError(t, os.WriteFile(goldenFile, []byte(keyStr), 0666))
+			}
+			goldenRaw, err := os.ReadFile(goldenFile)
+			require.NoError(t, err)
+
+			var expectedKey drkey.Key
+			goldenKey, err := hex.DecodeString(string(goldenRaw))
+			require.NoError(t, err)
+			copy(expectedKey[:], goldenKey)
+			require.Equal(t, expectedKey, key.Key)
+		})
+	}
+}
+
+func TestDeriveGenericHostHost(t *testing.T) {
+	level1Key := drkeytest.GetLevel1(t, protoId, epoch, srcIA, dstIA)
+
+	testCases := map[string]struct {
+		meta            drkey.HostHostMeta
+		assertFormatErr assert.ErrorAssertionFunc
+	}{
+		"valid host-host": {
+			meta: drkey.HostHostMeta{
+				ProtoId: drkey.Protocol(10000),
+				SrcHost: srcHost,
+				DstHost: dstHost,
+			},
+			assertFormatErr: assert.NoError,
+		},
+		"invalid host-host src": {
+			meta: drkey.HostHostMeta{
+				ProtoId: drkey.Protocol(10000),
+				SrcHost: "<malformed address>",
+				DstHost: dstHost,
+			},
+			assertFormatErr: assert.Error,
+		},
+		"invalid host-host dst": {
+			meta: drkey.HostHostMeta{
+				ProtoId: drkey.Protocol(10000),
+				SrcHost: srcHost,
+				DstHost: "<malformed address>",
+			},
+			assertFormatErr: assert.Error,
+		},
+	}
+	for name, tc := range testCases {
+		name, tc := name, tc
+		t.Run(name, func(t *testing.T) {
+
+			key, err := drkeytest.DeriveHostHostGeneric(tc.meta, level1Key)
+			tc.assertFormatErr(t, err)
+			if err != nil {
+				return
+			}
+			goldenFile := "testdata/" + xtest.SanitizedName(t)
+			if *update {
+				keyStr := hex.EncodeToString(key.Key[:])
+				require.NoError(t, os.WriteFile(goldenFile, []byte(keyStr), 0666))
+			}
+			goldenRaw, err := os.ReadFile(goldenFile)
+			require.NoError(t, err)
+
+			var expectedKey drkey.Key
+			goldenKey, err := hex.DecodeString(string(goldenRaw))
+			require.NoError(t, err)
+			copy(expectedKey[:], goldenKey)
+			require.Equal(t, expectedKey, key.Key)
+		})
+	}
+}
diff --git a/pkg/drkey/generic/testdata/TestDeriveASHostGeneric_valid_as-host b/pkg/drkey/generic/testdata/TestDeriveASHostGeneric_valid_as-host
new file mode 100644
index 000000000..da375f46f
--- /dev/null
+++ b/pkg/drkey/generic/testdata/TestDeriveASHostGeneric_valid_as-host
@@ -0,0 +1,1 @@
+2bc8fbb9455531a804cf7fd5e5e512a4
\ No newline at end of file
diff --git a/pkg/drkey/generic/testdata/TestDeriveGenericHostAS_valid_host-as b/pkg/drkey/generic/testdata/TestDeriveGenericHostAS_valid_host-as
new file mode 100644
index 000000000..0d1515a1e
--- /dev/null
+++ b/pkg/drkey/generic/testdata/TestDeriveGenericHostAS_valid_host-as
@@ -0,0 +1,1 @@
+3341fe339ec9492dd15509ce3a08b960
\ No newline at end of file
diff --git a/pkg/drkey/generic/testdata/TestDeriveGenericHostHost_valid_host-host b/pkg/drkey/generic/testdata/TestDeriveGenericHostHost_valid_host-host
new file mode 100644
index 000000000..baf92dd0c
--- /dev/null
+++ b/pkg/drkey/generic/testdata/TestDeriveGenericHostHost_valid_host-host
@@ -0,0 +1,1 @@
+f7f4d42ced8b7d040be51b2f6837f886
\ No newline at end of file
diff --git a/pkg/drkey/secret_value_test.go b/pkg/drkey/secret_value_test.go
new file mode 100644
index 000000000..ac047f38e
--- /dev/null
+++ b/pkg/drkey/secret_value_test.go
@@ -0,0 +1,52 @@
+// 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 (
+	"encoding/hex"
+	"os"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+
+	"github.com/scionproto/scion/pkg/drkey"
+	"github.com/scionproto/scion/pkg/private/xtest"
+)
+
+var (
+	update = xtest.UpdateGoldenFiles()
+)
+
+func TestDeriveSV(t *testing.T) {
+
+	asSecret := []byte{0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7}
+
+	got, err := drkey.DeriveSV(0, drkey.NewEpoch(0, 1), asSecret)
+	require.NoError(t, err)
+
+	goldenFile := "testdata/" + xtest.SanitizedName(t)
+	if *update {
+		keyStr := hex.EncodeToString(got.Key[:])
+		require.NoError(t, os.WriteFile(goldenFile, []byte(keyStr), 0666))
+	}
+	goldenRaw, err := os.ReadFile(goldenFile)
+	require.NoError(t, err)
+
+	var expectedKey drkey.Key
+	goldenKey, err := hex.DecodeString(string(goldenRaw))
+	require.NoError(t, err)
+	copy(expectedKey[:], goldenKey)
+	require.Equal(t, expectedKey, got.Key)
+}
diff --git a/pkg/drkey/specific/specific_test.go b/pkg/drkey/specific/specific_test.go
new file mode 100644
index 000000000..6ef59c308
--- /dev/null
+++ b/pkg/drkey/specific/specific_test.go
@@ -0,0 +1,223 @@
+// 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 specific_test
+
+import (
+	"encoding/hex"
+	"os"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"github.com/scionproto/scion/pkg/drkey"
+	"github.com/scionproto/scion/pkg/drkey/specific"
+	"github.com/scionproto/scion/pkg/private/xtest"
+	"github.com/scionproto/scion/private/drkey/drkeytest"
+)
+
+var (
+	update  = xtest.UpdateGoldenFiles()
+	protoId = drkey.SCMP
+	epoch   = drkey.NewEpoch(0, 1)
+	srcIA   = xtest.MustParseIA("1-ff00:0:111")
+	dstIA   = xtest.MustParseIA("1-ff00:0:112")
+	srcHost = "127.0.0.2"
+	dstHost = "127.0.0.1"
+)
+
+func TestDeriveASHostSpecific(t *testing.T) {
+	level1Key := drkeytest.GetLevel1(t, protoId, epoch, srcIA, dstIA)
+
+	testCases := map[string]struct {
+		meta            drkey.ASHostMeta
+		assertFormatErr assert.ErrorAssertionFunc
+	}{
+		"wrong no-host": {
+			meta: drkey.ASHostMeta{
+				ProtoId: drkey.Protocol(10000),
+			},
+			assertFormatErr: assert.Error,
+		},
+		"invalid as-host": {
+			meta: drkey.ASHostMeta{
+				ProtoId: drkey.Protocol(10000),
+				DstHost: "<malformed address>",
+			},
+			assertFormatErr: assert.Error,
+		},
+		"valid as-host": {
+			meta: drkey.ASHostMeta{
+				ProtoId: drkey.Protocol(10000),
+				DstHost: dstHost,
+			},
+			assertFormatErr: assert.NoError,
+		},
+	}
+	for name, tc := range testCases {
+		name, tc := name, tc
+		t.Run(name, func(t *testing.T) {
+
+			key, err := drkeytest.DeriveASHostSpecific(tc.meta, level1Key)
+			tc.assertFormatErr(t, err)
+			if err != nil {
+				return
+			}
+			goldenFile := "testdata/" + xtest.SanitizedName(t)
+			if *update {
+				keyStr := hex.EncodeToString(key.Key[:])
+				require.NoError(t, os.WriteFile(goldenFile, []byte(keyStr), 0666))
+			}
+			goldenRaw, err := os.ReadFile(goldenFile)
+			require.NoError(t, err)
+
+			var expectedKey drkey.Key
+			goldenKey, err := hex.DecodeString(string(goldenRaw))
+			require.NoError(t, err)
+			copy(expectedKey[:], goldenKey)
+			require.Equal(t, expectedKey, key.Key)
+		})
+	}
+}
+
+func TestDeriveSpecificHostAS(t *testing.T) {
+	level1Key := drkeytest.GetLevel1(t, protoId, epoch, srcIA, dstIA)
+	testCases := map[string]struct {
+		meta            drkey.HostASMeta
+		assertFormatErr assert.ErrorAssertionFunc
+	}{
+		"valid host-as": {
+			meta: drkey.HostASMeta{
+				ProtoId: drkey.Protocol(10000),
+				SrcHost: srcHost,
+			},
+			assertFormatErr: assert.NoError,
+		},
+		"invalid host-as": {
+			meta: drkey.HostASMeta{
+				ProtoId: drkey.Protocol(10000),
+				SrcHost: "<malformed address>",
+			},
+			assertFormatErr: assert.Error,
+		},
+	}
+	for name, tc := range testCases {
+		name, tc := name, tc
+		t.Run(name, func(t *testing.T) {
+
+			key, err := drkeytest.DeriveHostASSpecific(tc.meta, level1Key)
+			tc.assertFormatErr(t, err)
+			if err != nil {
+				return
+			}
+			goldenFile := "testdata/" + xtest.SanitizedName(t)
+			if *update {
+				keyStr := hex.EncodeToString(key.Key[:])
+				require.NoError(t, os.WriteFile(goldenFile, []byte(keyStr), 0666))
+			}
+			goldenRaw, err := os.ReadFile(goldenFile)
+			require.NoError(t, err)
+
+			var expectedKey drkey.Key
+			goldenKey, err := hex.DecodeString(string(goldenRaw))
+			require.NoError(t, err)
+			copy(expectedKey[:], goldenKey)
+			require.Equal(t, expectedKey, key.Key)
+		})
+	}
+}
+
+func TestDeriveSpecificHostHost(t *testing.T) {
+	level1Key := drkeytest.GetLevel1(t, protoId, epoch, srcIA, dstIA)
+
+	testCases := map[string]struct {
+		meta            drkey.HostHostMeta
+		assertFormatErr assert.ErrorAssertionFunc
+	}{
+		"valid host-host": {
+			meta: drkey.HostHostMeta{
+				ProtoId: drkey.Protocol(10000),
+				SrcHost: srcHost,
+				DstHost: dstHost,
+			},
+			assertFormatErr: assert.NoError,
+		},
+		"invalid host-host src": {
+			meta: drkey.HostHostMeta{
+				ProtoId: drkey.Protocol(10000),
+				SrcHost: "<malformed address>",
+				DstHost: dstHost,
+			},
+			assertFormatErr: assert.Error,
+		},
+		"invalid host-host dst": {
+			meta: drkey.HostHostMeta{
+				ProtoId: drkey.Protocol(10000),
+				SrcHost: srcHost,
+				DstHost: "<malformed address>",
+			},
+			assertFormatErr: assert.Error,
+		},
+	}
+	for name, tc := range testCases {
+		name, tc := name, tc
+		t.Run(name, func(t *testing.T) {
+
+			key, err := drkeytest.DeriveHostHostSpecific(tc.meta, level1Key)
+			tc.assertFormatErr(t, err)
+			if err != nil {
+				return
+			}
+			goldenFile := "testdata/" + xtest.SanitizedName(t)
+			if *update {
+				keyStr := hex.EncodeToString(key.Key[:])
+				require.NoError(t, os.WriteFile(goldenFile, []byte(keyStr), 0666))
+			}
+			goldenRaw, err := os.ReadFile(goldenFile)
+			require.NoError(t, err)
+
+			var expectedKey drkey.Key
+			goldenKey, err := hex.DecodeString(string(goldenRaw))
+			require.NoError(t, err)
+			copy(expectedKey[:], goldenKey)
+			require.Equal(t, expectedKey, key.Key)
+		})
+	}
+}
+
+func TestDeriveLevel1(t *testing.T) {
+	asSecret := []byte{0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7}
+	sv, err := drkey.DeriveSV(drkey.SCMP, drkey.NewEpoch(0, 1), asSecret)
+	require.NoError(t, err)
+
+	deriver := &specific.Deriver{}
+
+	dstIA := xtest.MustParseIA("1-ff00:0:112")
+
+	level1Target := drkey.Key{0xa8, 0x23, 0xf5, 0xb9, 0x56, 0xde,
+		0x7c, 0xc, 0xbc, 0x5a, 0x69, 0x42, 0xf5, 0xb6, 0xfc, 0x10}
+
+	key, err := deriver.DeriveLevel1(dstIA, sv.Key)
+	require.NoError(t, err)
+	assert.Equal(t, level1Target, key)
+
+	// Calling a second time with the same deriver should yield the
+	// same key
+	key, err = deriver.DeriveLevel1(dstIA, sv.Key)
+	require.NoError(t, err)
+
+	assert.Equal(t, level1Target, key)
+
+}
diff --git a/pkg/drkey/specific/testdata/TestDeriveASHostSpecific_valid_as-host b/pkg/drkey/specific/testdata/TestDeriveASHostSpecific_valid_as-host
new file mode 100644
index 000000000..6e686259d
--- /dev/null
+++ b/pkg/drkey/specific/testdata/TestDeriveASHostSpecific_valid_as-host
@@ -0,0 +1,1 @@
+b5a756caa2e030f3a2b6dbfb03e03eb0
\ No newline at end of file
diff --git a/pkg/drkey/specific/testdata/TestDeriveSpecificHostAS_valid_host-as b/pkg/drkey/specific/testdata/TestDeriveSpecificHostAS_valid_host-as
new file mode 100644
index 000000000..562160bb4
--- /dev/null
+++ b/pkg/drkey/specific/testdata/TestDeriveSpecificHostAS_valid_host-as
@@ -0,0 +1,1 @@
+4cca42cd61ec9f84802b65f7774e9854
\ No newline at end of file
diff --git a/pkg/drkey/specific/testdata/TestDeriveSpecificHostHost_valid_host-host b/pkg/drkey/specific/testdata/TestDeriveSpecificHostHost_valid_host-host
new file mode 100644
index 000000000..3a545dc7a
--- /dev/null
+++ b/pkg/drkey/specific/testdata/TestDeriveSpecificHostHost_valid_host-host
@@ -0,0 +1,1 @@
+164fc8460825bc1abf88b4689c70f559
\ No newline at end of file
diff --git a/pkg/drkey/testdata/TestDeriveSV b/pkg/drkey/testdata/TestDeriveSV
new file mode 100644
index 000000000..cf6155737
--- /dev/null
+++ b/pkg/drkey/testdata/TestDeriveSV
@@ -0,0 +1,1 @@
+c3b4843c990314f9ac554f9b781cdeb7
\ No newline at end of file
diff --git a/private/drkey/drkeytest/BUILD.bazel b/private/drkey/drkeytest/BUILD.bazel
new file mode 100644
index 000000000..93256fe17
--- /dev/null
+++ b/private/drkey/drkeytest/BUILD.bazel
@@ -0,0 +1,15 @@
+load("//tools/lint:go.bzl", "go_library")
+
+go_library(
+    name = "go_default_library",
+    srcs = ["commons.go"],
+    importpath = "github.com/scionproto/scion/private/drkey/drkeytest",
+    visibility = ["//visibility:public"],
+    deps = [
+        "//pkg/addr:go_default_library",
+        "//pkg/drkey:go_default_library",
+        "//pkg/drkey/generic:go_default_library",
+        "//pkg/drkey/specific:go_default_library",
+        "@com_github_stretchr_testify//require:go_default_library",
+    ],
+)
diff --git a/private/drkey/drkeytest/commons.go b/private/drkey/drkeytest/commons.go
new file mode 100644
index 000000000..e98387e33
--- /dev/null
+++ b/private/drkey/drkeytest/commons.go
@@ -0,0 +1,164 @@
+// 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 drkeytest
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+
+	"github.com/scionproto/scion/pkg/addr"
+	"github.com/scionproto/scion/pkg/drkey"
+	"github.com/scionproto/scion/pkg/drkey/generic"
+	"github.com/scionproto/scion/pkg/drkey/specific"
+)
+
+func GetLevel1(t *testing.T, protoID drkey.Protocol, epoch drkey.Epoch,
+	srcIA, dstIA addr.IA) drkey.Level1Key {
+	asSecret := []byte{0, 1, 2, 3, 4, 5, 6, 7}
+	asSecret = append(asSecret, byte(srcIA))
+	sv, err := drkey.DeriveSV(protoID, epoch, asSecret)
+	require.NoError(t, err)
+
+	key, err := (&specific.Deriver{}).DeriveLevel1(dstIA, sv.Key)
+	require.NoError(t, err)
+	return drkey.Level1Key{
+		Epoch:   sv.Epoch,
+		SrcIA:   srcIA,
+		DstIA:   dstIA,
+		ProtoId: sv.ProtoId,
+		Key:     key,
+	}
+}
+
+func DeriveASHostGeneric(meta drkey.ASHostMeta,
+	level1key drkey.Level1Key) (drkey.ASHostKey, error) {
+
+	derivedKey, err := (&generic.Deriver{}).DeriveASHost(meta.ProtoId, meta.DstHost,
+		level1key.Key)
+	if err != nil {
+		return drkey.ASHostKey{}, err
+	}
+
+	return drkey.ASHostKey{
+		ProtoId: meta.ProtoId,
+		Epoch:   level1key.Epoch,
+		SrcIA:   level1key.SrcIA,
+		DstIA:   level1key.DstIA,
+		DstHost: meta.DstHost,
+		Key:     derivedKey,
+	}, nil
+}
+
+func DeriveHostASGeneric(meta drkey.HostASMeta,
+	level1key drkey.Level1Key) (drkey.HostASKey, error) {
+	derivedKey, err := (&generic.Deriver{}).DeriveHostAS(meta.ProtoId, meta.SrcHost,
+		level1key.Key)
+	if err != nil {
+		return drkey.HostASKey{}, err
+	}
+
+	return drkey.HostASKey{
+		ProtoId: meta.ProtoId,
+		Epoch:   level1key.Epoch,
+		SrcIA:   level1key.SrcIA,
+		DstIA:   level1key.DstIA,
+		SrcHost: meta.SrcHost,
+		Key:     derivedKey,
+	}, nil
+}
+
+func DeriveHostHostGeneric(meta drkey.HostHostMeta,
+	level1key drkey.Level1Key) (drkey.HostHostKey, error) {
+
+	hostASKey, err := (&generic.Deriver{}).DeriveHostAS(meta.ProtoId, meta.SrcHost,
+		level1key.Key)
+	if err != nil {
+		return drkey.HostHostKey{}, err
+	}
+	h2hKey, err := (&generic.Deriver{}).DeriveHostToHost(meta.DstHost, hostASKey)
+	if err != nil {
+		return drkey.HostHostKey{}, err
+	}
+
+	return drkey.HostHostKey{
+		ProtoId: meta.ProtoId,
+		Epoch:   level1key.Epoch,
+		SrcIA:   level1key.SrcIA,
+		DstIA:   level1key.DstIA,
+		SrcHost: meta.SrcHost,
+		DstHost: meta.DstHost,
+		Key:     h2hKey,
+	}, nil
+}
+
+func DeriveASHostSpecific(meta drkey.ASHostMeta,
+	level1key drkey.Level1Key) (drkey.ASHostKey, error) {
+
+	derivedKey, err := (&specific.Deriver{}).DeriveASHost(meta.DstHost, level1key.Key)
+	if err != nil {
+		return drkey.ASHostKey{}, err
+	}
+
+	return drkey.ASHostKey{
+		ProtoId: meta.ProtoId,
+		Epoch:   level1key.Epoch,
+		SrcIA:   level1key.SrcIA,
+		DstIA:   level1key.DstIA,
+		DstHost: meta.DstHost,
+		Key:     derivedKey,
+	}, nil
+}
+
+func DeriveHostASSpecific(meta drkey.HostASMeta,
+	level1key drkey.Level1Key) (drkey.HostASKey, error) {
+
+	derivedKey, err := (&specific.Deriver{}).DeriveHostAS(meta.SrcHost, level1key.Key)
+	if err != nil {
+		return drkey.HostASKey{}, err
+	}
+
+	return drkey.HostASKey{
+		ProtoId: meta.ProtoId,
+		Epoch:   level1key.Epoch,
+		SrcIA:   level1key.SrcIA,
+		DstIA:   level1key.DstIA,
+		SrcHost: meta.SrcHost,
+		Key:     derivedKey,
+	}, nil
+}
+
+func DeriveHostHostSpecific(meta drkey.HostHostMeta,
+	level1key drkey.Level1Key) (drkey.HostHostKey, error) {
+
+	hostASKey, err := (&specific.Deriver{}).DeriveHostAS(meta.SrcHost, level1key.Key)
+	if err != nil {
+		return drkey.HostHostKey{}, err
+	}
+	h2hKey, err := (&specific.Deriver{}).DeriveHostToHost(meta.DstHost, hostASKey)
+	if err != nil {
+		return drkey.HostHostKey{}, err
+	}
+
+	return drkey.HostHostKey{
+		ProtoId: meta.ProtoId,
+		Epoch:   level1key.Epoch,
+		SrcIA:   level1key.SrcIA,
+		DstIA:   level1key.DstIA,
+		SrcHost: meta.SrcHost,
+		DstHost: meta.DstHost,
+		Key:     h2hKey,
+	}, nil
+}
diff --git a/private/proto/drkey/eq_definiton_test.go b/private/proto/drkey/eq_definiton_test.go
new file mode 100644
index 000000000..33c288f74
--- /dev/null
+++ b/private/proto/drkey/eq_definiton_test.go
@@ -0,0 +1,68 @@
+// Copyright 2022 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"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"google.golang.org/protobuf/reflect/protoreflect"
+
+	pb_cp "github.com/scionproto/scion/pkg/proto/control_plane"
+	pb_daemon "github.com/scionproto/scion/pkg/proto/daemon"
+)
+
+func TestEqualASHostRequest(t *testing.T) {
+	controlFields := (&pb_cp.DRKeyASHostRequest{}).ProtoReflect().Descriptor().Fields()
+	daemonFields := (&pb_daemon.DRKeyASHostRequest{}).ProtoReflect().Descriptor().Fields()
+	checkEquals(t, controlFields, daemonFields)
+}
+
+func TestEqualASHostResponse(t *testing.T) {
+	controlFields := (&pb_cp.DRKeyASHostResponse{}).ProtoReflect().Descriptor().Fields()
+	daemonFields := (&pb_daemon.DRKeyASHostResponse{}).ProtoReflect().Descriptor().Fields()
+	checkEquals(t, controlFields, daemonFields)
+}
+
+func TestEqualHostASRequest(t *testing.T) {
+	controlFields := (&pb_cp.DRKeyHostASRequest{}).ProtoReflect().Descriptor().Fields()
+	daemonFields := (&pb_daemon.DRKeyHostASRequest{}).ProtoReflect().Descriptor().Fields()
+	checkEquals(t, controlFields, daemonFields)
+}
+
+func TestEqualHostASResponse(t *testing.T) {
+	controlFields := (&pb_cp.DRKeyHostASResponse{}).ProtoReflect().Descriptor().Fields()
+	daemonFields := (&pb_daemon.DRKeyHostASResponse{}).ProtoReflect().Descriptor().Fields()
+	checkEquals(t, controlFields, daemonFields)
+}
+
+func checkEquals(t *testing.T, controlFields, daemonFields protoreflect.FieldDescriptors) {
+	require.Equal(t, controlFields.Len(), daemonFields.Len())
+	for i := 0; i < controlFields.Len(); i++ {
+		assert.Equal(t, controlFields.Get(i).Name(),
+			daemonFields.Get(i).Name())
+		assert.Equal(t, controlFields.Get(i).Cardinality(),
+			daemonFields.Get(i).Cardinality())
+		assert.Equal(t, controlFields.Get(i).Kind(),
+			daemonFields.Get(i).Kind())
+		assert.Equal(t, controlFields.Get(i).HasJSONName(),
+			daemonFields.Get(i).HasJSONName())
+		assert.Equal(t, controlFields.Get(i).TextName(),
+			daemonFields.Get(i).TextName())
+		assert.Equal(t, controlFields.Get(i).JSONName(),
+			daemonFields.Get(i).JSONName())
+	}
+}