From 40ccf413bcea8ba26c3ef825d02eaf73036caa73 Mon Sep 17 00:00:00 2001
From: Fabian Seidl <fabian.seidl@h-da.de>
Date: Wed, 19 Jun 2024 11:28:49 +0000
Subject: [PATCH] Resolve "Add etsi14 server to KMS"

See merge request danet/quant!148
---
 config/goKMS/example01.yaml                   |   3 +
 config/goKMS/example04.yaml                   |   3 +
 goKMS/config/config.go                        |   6 +
 .../etsi14/client}/restclient.go              |   0
 goKMS/etsi/etsi14/etsi14Server/server.go      | 243 ++++++++++++++++++
 goKMS/kms/akms/client/client.go               |   4 +-
 goKMS/kms/akms/server/server.go               |  15 +-
 goKMS/kms/kms.go                              |  91 ++++++-
 goKMS/kms/kmsintercom.go                      |  11 +-
 goKMS/kms/peers/qmodule.go                    |   2 +-
 .../kms/{akms/server => receiver}/receiver.go |  14 +-
 goKMS/main.go                                 |  21 +-
 12 files changed, 386 insertions(+), 27 deletions(-)
 rename goKMS/{restclient => etsi/etsi14/client}/restclient.go (100%)
 create mode 100644 goKMS/etsi/etsi14/etsi14Server/server.go
 rename goKMS/kms/{akms/server => receiver}/receiver.go (76%)

diff --git a/config/goKMS/example01.yaml b/config/goKMS/example01.yaml
index a7360a20..5162b5e0 100644
--- a/config/goKMS/example01.yaml
+++ b/config/goKMS/example01.yaml
@@ -36,3 +36,6 @@ Peers:
       Address: 172.100.20.18
 QkdnManagerServer:
   Address: ":8090"
+ETSI14Server:
+  Address: ":1414"
+  RemoteCKMSID: "968fd594-b0e7-41f0-ba4b-de259047a933"
diff --git a/config/goKMS/example04.yaml b/config/goKMS/example04.yaml
index c16622a4..2d452687 100644
--- a/config/goKMS/example04.yaml
+++ b/config/goKMS/example04.yaml
@@ -36,3 +36,6 @@ Peers:
       Address: 172.100.20.21
 QkdnManagerServer:
   Address: ":8090"
+ETSI14Server:
+  Address: ":1414"
+  RemoteCKMSID: "0ff33c82-7fe1-482b-a0ca-67565806ee4b"
diff --git a/goKMS/config/config.go b/goKMS/config/config.go
index f36739f2..f3c73ec2 100644
--- a/goKMS/config/config.go
+++ b/goKMS/config/config.go
@@ -16,6 +16,7 @@ type Config struct {
 	KmsTLS             TLSConfig          `yaml:"KmsTLS"`
 	QuantumModuleTLS   TLSConfig          `yaml:"QuantumModuleTLS"`
 	AkmsCkmsTLS        TLSConfig          `yaml:"AkmsCkmsTLS"`
+	ETSI14Server       *ETSI14Server      `yaml:"ETSI14Server,omitempty"`
 	QkdnManagerServer  *QkdnManagerServer `yaml:"QkdnManagerServer,omitempty"`
 }
 
@@ -43,6 +44,11 @@ type QuantumModule struct {
 	MasterMode  bool   `yaml:"MasterMode"`
 }
 
+type ETSI14Server struct {
+	Address      string `yaml:"Address"`
+	RemoteCKMSID string `yaml:"RemoteCKMSID"`
+}
+
 type QkdnManagerServer struct {
 	Address string `yaml:"Address"`
 }
diff --git a/goKMS/restclient/restclient.go b/goKMS/etsi/etsi14/client/restclient.go
similarity index 100%
rename from goKMS/restclient/restclient.go
rename to goKMS/etsi/etsi14/client/restclient.go
diff --git a/goKMS/etsi/etsi14/etsi14Server/server.go b/goKMS/etsi/etsi14/etsi14Server/server.go
new file mode 100644
index 00000000..f9912f0b
--- /dev/null
+++ b/goKMS/etsi/etsi14/etsi14Server/server.go
@@ -0,0 +1,243 @@
+package etsi14Server
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"net/http"
+	"os"
+	"os/signal"
+	"sync"
+	"syscall"
+	"time"
+
+	restserver "code.fbi.h-da.de/danet/quant/etsi014/go/rest/etsi/server/go"
+	"code.fbi.h-da.de/danet/quant/goKMS/kms"
+	"code.fbi.h-da.de/danet/quant/goKMS/kms/akms/client"
+	"github.com/google/uuid"
+	"github.com/sirupsen/logrus"
+)
+
+type ETSI14RESTService struct {
+	serviceAddress  string
+	remoteCKMSID    uuid.UUID
+	kms             *kms.KMS
+	keyStoreMutex   sync.RWMutex
+	keyStore        map[string]string
+	KeyStoreChannel chan []client.KSAKey
+	httpServer      *http.Server
+}
+
+func NewETSI14RESTService(serviceAddress string, remoteCKMSID uuid.UUID, kms *kms.KMS) *ETSI14RESTService {
+	return &ETSI14RESTService{
+		serviceAddress:  serviceAddress,
+		remoteCKMSID:    remoteCKMSID,
+		kms:             kms,
+		keyStore:        make(map[string]string, 0),
+		KeyStoreChannel: make(chan []client.KSAKey, 10),
+	}
+}
+
+// Run initiates all the necessities and starts the etsi14 server.
+func Run(etsi14RESTService *ETSI14RESTService) {
+	logrus.Info("Starting ETSI14 server...")
+
+	etsi14APIController := restserver.NewDefaultAPIController(etsi14RESTService)
+
+	router := restserver.NewRouter(etsi14APIController)
+
+	etsi14RESTService.httpServer = &http.Server{
+		Addr:              etsi14RESTService.serviceAddress,
+		Handler:           router,
+		ReadHeaderTimeout: 15 * time.Second,
+		ReadTimeout:       15 * time.Second,
+		WriteTimeout:      10 * time.Second,
+		IdleTimeout:       30 * time.Second,
+	}
+
+	go etsi14RESTService.startServer()
+
+	ctx, cancel := context.WithCancel(context.Background())
+	stopChannel := make(chan os.Signal, 1)
+	signal.Notify(stopChannel, syscall.SIGINT)
+
+	defer func() {
+		logrus.Info("Shutting down ETSI14 server...")
+		if err := etsi14RESTService.httpServer.Shutdown(ctx); err != nil {
+			logrus.Errorf("Error shutting down server: %v", err)
+			_ = etsi14RESTService.httpServer.Close()
+			return
+		}
+		logrus.Info("Gracefully shutdown server completed.")
+	}()
+
+	logrus.Infof("ETSI14 server running on: %s", etsi14RESTService.serviceAddress)
+
+	go etsi14RESTService.runKeyStoreChannel()
+
+	<-stopChannel
+
+	cancel()
+}
+
+// startServer starts the listener of the etsi14 HTTP server.
+func (s *ETSI14RESTService) startServer() {
+	if err := s.httpServer.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
+		logrus.Error(err)
+	}
+
+	logrus.Info("Stopped serving new connections.")
+}
+
+// runKeyStoreChannel sets up a listener for when a key needs to be added to the servers key store.
+func (s *ETSI14RESTService) runKeyStoreChannel() {
+	for {
+		select {
+		case keys := <-s.KeyStoreChannel:
+			logrus.Debugf("(ETSI14) KeyStoreChannel received: %v", keys)
+			s.pushKeysToStoreAfterExchange(keys)
+		}
+	}
+}
+
+// GetKey returns a number of keys of specified size and safes the slaveSAEID for further use.
+func (s *ETSI14RESTService) GetKey(ctx context.Context, slaveSAEID string, number int64, size int64) (restserver.ImplResponse, error) {
+	keyContainer, err := s.getKeyContainerFromKeyExchange(number)
+	if err != nil {
+		return restserver.Response(http.StatusInternalServerError, keyContainer), err
+	}
+
+	logrus.Debugf("(ETSI14) GetKey: Sending %d keys, Incoming ctx: %s", number, ctx)
+
+	return restserver.Response(http.StatusOK, keyContainer), nil
+}
+
+// GetKeyPost returns a number of keys of specified size and safes the slaveSAEID for further use.
+func (s *ETSI14RESTService) GetKeyPost(ctx context.Context, slaveSAEID string, keyRequest restserver.KeyRequest) (restserver.ImplResponse, error) {
+	if keyRequest.Number < 1 {
+		logrus.Errorf("(ETSI14) number must be positive and at least 1, provided: %d\n", keyRequest.Number)
+		return restserver.Response(http.StatusBadRequest, nil), fmt.Errorf("requested invalid number of keys")
+	}
+
+	keyContainer, err := s.getKeyContainerFromKeyExchange(keyRequest.Number)
+	if err != nil {
+		return restserver.Response(http.StatusInternalServerError, keyContainer), err
+	}
+
+	logrus.Debugf("(ETSI14) GetKey: Sending %d keys, Incoming ctx: %s", keyRequest.Number, ctx)
+
+	return restserver.Response(http.StatusOK, keyContainer), nil
+}
+
+// GetKeyWithIds returns a key with a specific ID related to the masterSAEID.
+func (s *ETSI14RESTService) GetKeyWithIds(ctx context.Context, masterSAEID string, keyID string) (restserver.ImplResponse, error) {
+	s.keyStoreMutex.RLock()
+	key, ok := s.keyStore[keyID]
+	if !ok {
+		logrus.Errorf("(ETSI14) Key with ID %s not found", keyID)
+		return restserver.Response(http.StatusBadRequest, nil), nil
+	}
+	s.keyStoreMutex.RUnlock()
+
+	keyContainer := &restserver.KeyContainer{
+		Keys: []restserver.KeyContainerKeysInner{
+			{
+				KeyID: keyID,
+				Key:   key,
+			},
+		},
+	}
+
+	logrus.Debugf("(ETSI14) GetKeyWithIds: Sending key with ID: %s, Incoming ctx: %s", keyID, ctx)
+
+	return restserver.Response(http.StatusOK, keyContainer), nil
+}
+
+// GetKeyWithIdsPost returns a key with a specific ID related to the masterSAEID.
+func (s *ETSI14RESTService) GetKeyWithIdsPost(ctx context.Context, masterSAEID string, keyIdsRequest restserver.KeyIdsRequest) (restserver.ImplResponse, error) {
+	if keyIdsRequest.KeyIDs == nil {
+		logrus.Error("(ETSI14) GetKeyWithIdsPost: Empty KeyIdsRequest.KeyIDs")
+		return restserver.Response(http.StatusBadRequest, nil), nil
+	}
+
+	s.keyStoreMutex.RLock()
+	key, ok := s.keyStore[keyIdsRequest.KeyIDs[0].KeyID]
+	if !ok {
+		logrus.Errorf("(ETSI14) Key with ID %s not found", keyIdsRequest.KeyIDs[0].KeyID)
+		logrus.Debugf("Current store: %v", s.keyStore)
+		return restserver.Response(http.StatusBadRequest, nil), nil
+	}
+	s.keyStoreMutex.RUnlock()
+
+	keyContainer := &restserver.KeyContainer{
+		Keys: []restserver.KeyContainerKeysInner{
+			{
+				KeyID: keyIdsRequest.KeyIDs[0].KeyID,
+				Key:   key,
+			},
+		},
+	}
+
+	logrus.Debugf("(ETSI14) GetKeyWithIdsPost: Sending key with ID: %s, Incoming ctx: %s", keyIdsRequest.KeyIDs[0].KeyID, ctx)
+
+	return restserver.Response(http.StatusOK, keyContainer), nil
+}
+
+// GetStatus returns status information of this network element.
+func (s *ETSI14RESTService) GetStatus(ctx context.Context, slaveSAEID string) (restserver.ImplResponse, error) {
+	status := restserver.Status{
+		SourceKMEID:      "AAAABBBBCCCCDDDD",
+		TargetKMEID:      "EEEEFFFFGGGGHHHH",
+		MasterSAEID:      "IIIIJJJJKKKKLLLL",
+		SlaveSAEID:       "MMMMNNNNOOOOPPPP",
+		KeySize:          352,
+		StoredKeyCount:   25000,
+		MaxKeyCount:      100000,
+		MaxKeyPerRequest: 128,
+		MaxKeySize:       1024,
+		MinKeySize:       64,
+		MaxSAEIDCount:    0,
+	}
+
+	return restserver.Response(http.StatusNotImplemented, status), nil
+}
+
+// getKeyContainerFromKeyExchange starts the key exchange using the underlying QKD forwarding and returns the resulting KSA keys.
+func (s *ETSI14RESTService) getKeyContainerFromKeyExchange(number int64) (*restserver.KeyContainer, error) {
+	keys, err := s.kms.ExchangeKeyAfterETSI14GetKeyRequest(s.remoteCKMSID, number) // Note: we should have a mapping mechanism here to support multiple endpoints in the future
+	if err != nil {
+		return nil, err
+	}
+
+	keyContainer := &restserver.KeyContainer{}
+	for _, key := range keys {
+		keyContainer.Keys = append(keyContainer.Keys,
+			restserver.KeyContainerKeysInner{
+				KeyID: key.KeyID,
+				Key:   key.Key,
+			})
+
+		s.pushToKeyStore(key)
+
+		logrus.Debugf("(ETSI14) GetKey: Adding key with ID: %s to store", key.KeyID)
+	}
+
+	return keyContainer, nil
+}
+
+// pushKeysToStoreAfterExchange pushes all the KSA keys received on server side to the local key store.
+func (s *ETSI14RESTService) pushKeysToStoreAfterExchange(keys []client.KSAKey) {
+	for _, key := range keys {
+		s.pushToKeyStore(key)
+	}
+}
+
+// pushToKeyStore pushes one KSA key to the local key store.
+func (s *ETSI14RESTService) pushToKeyStore(key client.KSAKey) {
+	s.keyStoreMutex.Lock()
+	defer s.keyStoreMutex.Unlock()
+
+	s.keyStore[key.KeyID] = key.Key
+
+	logrus.Debugf("(ETSI14) Pushed key with ID: %s to keystore", key.KeyID)
+}
diff --git a/goKMS/kms/akms/client/client.go b/goKMS/kms/akms/client/client.go
index c8f7430c..7f2d88b3 100644
--- a/goKMS/kms/akms/client/client.go
+++ b/goKMS/kms/akms/client/client.go
@@ -12,8 +12,8 @@ type CkmsAkmsClient struct {
 	url string
 }
 
-func NewCkmsAkmsClient(url string) CkmsAkmsClient {
-	return CkmsAkmsClient{
+func NewCkmsAkmsClient(url string) *CkmsAkmsClient {
+	return &CkmsAkmsClient{
 		url: url,
 	}
 }
diff --git a/goKMS/kms/akms/server/server.go b/goKMS/kms/akms/server/server.go
index b3cb5dfa..76e7e439 100644
--- a/goKMS/kms/akms/server/server.go
+++ b/goKMS/kms/akms/server/server.go
@@ -7,22 +7,18 @@ import (
 	"time"
 
 	"code.fbi.h-da.de/danet/quant/goKMS/kms/event"
+	"code.fbi.h-da.de/danet/quant/goKMS/kms/receiver"
 	"github.com/google/uuid"
 	"github.com/sirupsen/logrus"
 )
 
 type AKMSReceiverServer struct {
-	server   *http.Server
-	Receiver *Receiver
+	server *http.Server
 }
 
-func NewAKMSReceiver(port string, eventBus *event.EventBus, generateAndSend func(string, uuid.UUID, string, int) error) *AKMSReceiverServer {
+func NewAKMSReceiver(port string, eventBus *event.EventBus, receiver *receiver.Receiver, generateAndSend func(string, uuid.UUID, string, int) error) *AKMSReceiverServer {
 	router := http.NewServeMux()
 
-	receiver := &Receiver{
-		receivers: make(map[uuid.UUID]chan<- struct{}),
-	}
-
 	router.HandleFunc("/api/v1/keys/ksa_key_req", ksaReqHandler(eventBus, receiver, generateAndSend))
 
 	server := &http.Server{
@@ -31,8 +27,7 @@ func NewAKMSReceiver(port string, eventBus *event.EventBus, generateAndSend func
 	}
 
 	AKMSReceiver := &AKMSReceiverServer{
-		server:   server,
-		Receiver: receiver,
+		server: server,
 	}
 
 	return AKMSReceiver
@@ -55,7 +50,7 @@ type KMSKeyRequest struct {
 	KeyProperties   KeyProperties `json:"key_properties"`
 }
 
-func ksaReqHandler(eventBus *event.EventBus, receiver *Receiver, generateAndSend func(string, uuid.UUID, string, int) error) http.HandlerFunc {
+func ksaReqHandler(eventBus *event.EventBus, receiver *receiver.Receiver, generateAndSend func(string, uuid.UUID, string, int) error) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var kmsKeyRequest KMSKeyRequest
 		err := json.NewDecoder(r.Body).Decode(&kmsKeyRequest)
diff --git a/goKMS/kms/kms.go b/goKMS/kms/kms.go
index 050fe7fc..67e2f7bd 100644
--- a/goKMS/kms/kms.go
+++ b/goKMS/kms/kms.go
@@ -26,6 +26,7 @@ import (
 	"code.fbi.h-da.de/danet/quant/goKMS/kms/crypto"
 	"code.fbi.h-da.de/danet/quant/goKMS/kms/event"
 	"code.fbi.h-da.de/danet/quant/goKMS/kms/peers"
+	"code.fbi.h-da.de/danet/quant/goKMS/kms/receiver"
 	"code.fbi.h-da.de/danet/quant/goKMS/kms/store"
 	kmstls "code.fbi.h-da.de/danet/quant/goKMS/kms/tls"
 	"code.fbi.h-da.de/danet/quant/goKMS/kms/util"
@@ -77,8 +78,11 @@ type KMS struct {
 	pbIC.UnimplementedKmsTalkerServer
 	supportedKeyLengths map[BitKeyLength]bool
 	eventBus            *event.EventBus
-	CKMSAkmsClient      client.CkmsAkmsClient
+	CKMSAkmsClient      *client.CkmsAkmsClient
 	CKMSAkmsServer      *server.AKMSReceiverServer
+	// ETSI14 Server things
+	KeyStoreChannel chan []client.KSAKey
+	receiver        *receiver.Receiver
 }
 
 // Will keep information about the quantum elements that this EKMS is talking to
@@ -89,7 +93,7 @@ type QuantumElementInterface interface {
 	GetQlID() qlElementId
 }*/
 
-func NewKMS(kmsUUID uuid.UUID, logOutput io.Writer, logLevel log.Level, logInJson bool, config *config.Config) (newKMS *KMS) {
+func NewKMS(kmsUUID uuid.UUID, logOutput io.Writer, logLevel log.Level, logInJson bool, config *config.Config, receiver *receiver.Receiver) (newKMS *KMS) {
 	/*
 	 * Setup logging
 	 */
@@ -110,7 +114,10 @@ func NewKMS(kmsUUID uuid.UUID, logOutput io.Writer, logLevel log.Level, logInJso
 		log.SetReportCaller(false)
 	}
 
-	ckmsAkmsClient := client.NewCkmsAkmsClient(config.AkmsURL)
+	var ckmsAkmsClient *client.CkmsAkmsClient
+	if config.AkmsURL != "" {
+		ckmsAkmsClient = client.NewCkmsAkmsClient(config.AkmsURL)
+	}
 
 	createdKMS := &KMS{
 		kmsName:             config.Name,
@@ -126,6 +133,7 @@ func NewKMS(kmsUUID uuid.UUID, logOutput io.Writer, logLevel log.Level, logInJso
 		supportedKeyLengths: make(map[BitKeyLength]bool),
 		eventBus:            event.NewEventBus(),
 		CKMSAkmsClient:      ckmsAkmsClient,
+		receiver:            receiver,
 	}
 
 	createdKMS.supportedKeyLengths[BitKeyLen256] = true
@@ -141,7 +149,7 @@ func NewKMS(kmsUUID uuid.UUID, logOutput io.Writer, logLevel log.Level, logInJso
 
 	// Start the akmsCkmsReceiverServer
 	if config.AkmsCkmsServerPort != "" {
-		createdKMS.CKMSAkmsServer = server.NewAKMSReceiver(config.AkmsCkmsServerPort, createdKMS.eventBus, createdKMS.GenerateAndSendKSAKey)
+		createdKMS.CKMSAkmsServer = server.NewAKMSReceiver(config.AkmsCkmsServerPort, createdKMS.eventBus, receiver, createdKMS.GenerateAndSendKSAKey)
 		log.Infof("Starting AKMS receiver server on port: %s", config.AkmsCkmsServerPort)
 		go createdKMS.CKMSAkmsServer.Serve()
 	}
@@ -626,6 +634,81 @@ func (kms *KMS) sendKSAKeysToPlatformKmsPeer(kmsPeerAddress, platformKeyID, requ
 	return nil
 }
 
+func (kms *KMS) ExchangeKeyAfterETSI14GetKeyRequest(receivingCKMSID uuid.UUID, number int64) ([]client.KSAKey, error) {
+	// CreateRouteRequest
+	pathID := uuid.New()
+	log.Debugf("(ETSI14) created new path id: %s, for incoming ETSI14 key request", pathID)
+
+	receiverChan, err := kms.receiver.RequestReceiverChannel(pathID)
+	if err != nil {
+		log.Error(err)
+		return nil, err
+	}
+
+	err = kms.eventBus.Publish(event.NewCreateRouteEvent(pathID.String(), receivingCKMSID.String()))
+	if err != nil {
+		log.Errorf("(ETSI14) Failed sending a create route request: %s", err)
+		return nil, err
+	}
+
+	select {
+	case <-receiverChan:
+	case <-time.After(20 * time.Second):
+		if err := kms.receiver.RemoveReceiver(pathID); err != nil {
+			log.Errorf("Failed removing receiver for pathId: %s ; err: %v", pathID, err)
+		}
+		log.Errorf("(ETSI14) Platform Key exchange failed for PathID: %s", pathID)
+		return nil, fmt.Errorf("Platform Key exchange failed for PathID: %s", pathID)
+	}
+
+	// GenerateAndSend
+	return kms.generateAndReturnKsaKey(receivingCKMSID, pathID, number)
+}
+
+func (kms *KMS) generateAndReturnKsaKey(receivingCKMSID, pathID uuid.UUID, number int64) ([]client.KSAKey, error) {
+	if number < 1 {
+		log.Errorf("number must be positive and at least 1, provided: %d\n", number)
+		return nil, fmt.Errorf("number must be positive and at least 1, provided: %d", number)
+	}
+
+	log.Infof("KMS store: %v", kms.remoteKMSMapping)
+	remoteKMS, err := kms.GetRemoteKMS(receivingCKMSID.String())
+	if err != nil {
+		log.Error(err)
+		return nil, err
+	}
+
+	platformKey, err := kms.GetSpecificPlatformKey(receivingCKMSID.String(), pathID)
+	if err != nil {
+		log.Error(err)
+		return nil, err
+	}
+
+	ksaKeysToSendToRemoteKMS := make([]*pbIC.Key, number)
+	ksaKeysToReturn := make([]client.KSAKey, number)
+	cryptoAlgo := crypto.NewAES()
+	for i := int64(0); i < number; i++ {
+		remoteKSAKey, localKSAKey, err := generateNewKSAKey(cryptoAlgo, platformKey.Value)
+		if err != nil {
+			log.Error(err)
+			return nil, err
+		}
+
+		ksaKeysToReturn[i] = *localKSAKey
+		ksaKeysToSendToRemoteKMS[i] = remoteKSAKey
+	}
+
+	remoteKMSAdrress := fmt.Sprintf("%s:%d", remoteKMS.Address, remoteKMS.Port)
+
+	err = kms.sendKSAKeysToPlatformKmsPeer(remoteKMSAdrress, platformKey.Id.String(), "", ksaKeysToSendToRemoteKMS)
+	if err != nil {
+		log.Error(err)
+		return nil, err
+	}
+
+	return ksaKeysToReturn, nil
+}
+
 func (kms *KMS) GetID() uuid.UUID {
 	return kms.kmsUUID
 }
diff --git a/goKMS/kms/kmsintercom.go b/goKMS/kms/kmsintercom.go
index 42eb8afc..e6e3949f 100644
--- a/goKMS/kms/kmsintercom.go
+++ b/goKMS/kms/kmsintercom.go
@@ -284,7 +284,7 @@ func (s *kmsTalkerServer) AckKeyForwarding(ctx context.Context, in *pb.AckKeyFor
 	// - Are pathId and processId valid?
 	// - Is the keyId valid?
 
-	err = s.KMS.CKMSAkmsServer.Receiver.InformReceiver(pathId)
+	err = s.KMS.receiver.InformReceiver(pathId)
 	if err != nil {
 		return nil, status.Errorf(codes.InvalidArgument, "Failed while informing Receiver; err: %v", err)
 	}
@@ -328,7 +328,12 @@ func (s *kmsTalkerServer) KeyDelivery(ctx context.Context, in *pb.KeyDeliveryReq
 		}
 	}
 
-	go s.KMS.CKMSAkmsClient.SendKSAKeysToRequestingInstances(in.GetRequestId(), platformKey.ProcessId, akmsKSAKeys) //nolint:errcheck
+	if s.KMS.KeyStoreChannel != nil {
+		log.Debugf("(ETSI14) Pushing to KeyStoreChannel: %v in %s", s.KMS.KeyStoreChannel, s.KMS.kmsName)
+		s.KMS.KeyStoreChannel <- akmsKSAKeys
+	} else if s.KMS.CKMSAkmsClient != nil {
+		go s.KMS.CKMSAkmsClient.SendKSAKeysToRequestingInstances(in.GetRequestId(), platformKey.ProcessId, akmsKSAKeys) //nolint:errcheck
+	}
 
 	return &pb.KeyDeliveryResponse{Timestamp: time.Now().Unix()}, nil
 }
@@ -400,5 +405,7 @@ func (s *kmsTalkerServer) sendAcknowledgeKeyForwarding(ctx context.Context, remo
 		return err
 	}
 
+	log.Debugf("Successfully send ACK for pathID: %s to %s", pathID, remoteKmsAddr)
+
 	return nil
 }
diff --git a/goKMS/kms/peers/qmodule.go b/goKMS/kms/peers/qmodule.go
index 5d140f3e..545b4cf2 100644
--- a/goKMS/kms/peers/qmodule.go
+++ b/goKMS/kms/peers/qmodule.go
@@ -12,11 +12,11 @@ import (
 	etsi14 "code.fbi.h-da.de/danet/quant/etsi014/go/rest/etsi/client"
 	pbIC "code.fbi.h-da.de/danet/quant/goKMS/api/gen/proto/go/kmsintercom"
 	"code.fbi.h-da.de/danet/quant/goKMS/config"
+	restclient "code.fbi.h-da.de/danet/quant/goKMS/etsi/etsi14/client"
 	"code.fbi.h-da.de/danet/quant/goKMS/kms/event"
 	"code.fbi.h-da.de/danet/quant/goKMS/kms/store"
 	kmstls "code.fbi.h-da.de/danet/quant/goKMS/kms/tls"
 	"code.fbi.h-da.de/danet/quant/goKMS/kms/util"
-	restclient "code.fbi.h-da.de/danet/quant/goKMS/restclient"
 	"code.fbi.h-da.de/danet/quant/quantumlayer"
 	"github.com/google/uuid"
 	log "github.com/sirupsen/logrus"
diff --git a/goKMS/kms/akms/server/receiver.go b/goKMS/kms/receiver/receiver.go
similarity index 76%
rename from goKMS/kms/akms/server/receiver.go
rename to goKMS/kms/receiver/receiver.go
index 893b627b..3aad5bcb 100644
--- a/goKMS/kms/akms/server/receiver.go
+++ b/goKMS/kms/receiver/receiver.go
@@ -1,4 +1,4 @@
-package server
+package receiver
 
 import (
 	"fmt"
@@ -10,7 +10,7 @@ import (
 
 type Receiver struct {
 	mu        sync.RWMutex
-	receivers map[uuid.UUID]chan<- struct{}
+	Receivers map[uuid.UUID]chan<- struct{}
 }
 
 func (r *Receiver) RequestReceiverChannel(pathId uuid.UUID) (<-chan struct{}, error) {
@@ -18,7 +18,7 @@ func (r *Receiver) RequestReceiverChannel(pathId uuid.UUID) (<-chan struct{}, er
 
 	r.mu.Lock()
 	defer r.mu.Unlock()
-	r.receivers[pathId] = newSubChan
+	r.Receivers[pathId] = newSubChan
 
 	return newSubChan, nil
 }
@@ -27,14 +27,14 @@ func (r *Receiver) RemoveReceiver(pathId uuid.UUID) error {
 	r.mu.Lock()
 	defer r.mu.Unlock()
 
-	if channel, ok := r.receivers[pathId]; ok {
+	if channel, ok := r.Receivers[pathId]; ok {
 		close(channel)
-		delete(r.receivers, pathId)
+		delete(r.Receivers, pathId)
 	} else {
 		return fmt.Errorf("There are no active subscribers for pathId: %s", pathId)
 	}
 
-	logrus.Debugf("Current active receivers after removing receiver for pathId: %s; Receivers: %v", pathId, r.receivers)
+	logrus.Debugf("Current active receivers after removing receiver for pathId: %s; Receivers: %v", pathId, r.Receivers)
 	return nil
 }
 
@@ -42,7 +42,7 @@ func (r *Receiver) InformReceiver(pathId uuid.UUID) error {
 	r.mu.RLock()
 	defer r.mu.RUnlock()
 
-	if receiver, ok := r.receivers[pathId]; ok {
+	if receiver, ok := r.Receivers[pathId]; ok {
 		go func() { receiver <- struct{}{} }()
 	} else {
 		return fmt.Errorf("There are no active subscribers for pathId: %s", pathId)
diff --git a/goKMS/main.go b/goKMS/main.go
index 7d00b3c9..df9d1083 100644
--- a/goKMS/main.go
+++ b/goKMS/main.go
@@ -40,9 +40,11 @@ import (
 	gnmitarget "code.fbi.h-da.de/danet/gnmi-target"
 	"code.fbi.h-da.de/danet/gnmi-target/handler"
 	"code.fbi.h-da.de/danet/quant/goKMS/config"
+	etsiServer "code.fbi.h-da.de/danet/quant/goKMS/etsi/etsi14/etsi14Server"
 	kmsHandler "code.fbi.h-da.de/danet/quant/goKMS/gnmiHandlers/kms"
 	"code.fbi.h-da.de/danet/quant/goKMS/gnmiHandlers/system"
 	"code.fbi.h-da.de/danet/quant/goKMS/kms"
+	"code.fbi.h-da.de/danet/quant/goKMS/kms/receiver"
 	gnmitargetygot "code.fbi.h-da.de/danet/quant/goKMS/model"
 	qkdnmanager "code.fbi.h-da.de/danet/quant/goKMS/qkdnManager"
 	"github.com/google/uuid"
@@ -105,8 +107,25 @@ func main() {
 
 	outputTlsSettings(kmsConfig)
 	kmsInfo := generateKMSInfo(kmsId)
+	receiver := &receiver.Receiver{
+		Receivers: make(map[uuid.UUID]chan<- struct{}),
+	}
+
+	kms := kms.NewKMS(kmsId, os.Stdout, log.GetLevel(), false, kmsConfig, receiver)
+
+	// Setup ETSI14 Server if info is in config
+	if kmsConfig.ETSI14Server != nil {
+		remoteCKMSID, err := uuid.Parse(kmsConfig.ETSI14Server.RemoteCKMSID)
+		if err != nil {
+			log.Error(err)
+		}
 
-	kms := kms.NewKMS(kmsId, os.Stdout, log.GetLevel(), false, kmsConfig)
+		etsi14Service := etsiServer.NewETSI14RESTService(kmsConfig.ETSI14Server.Address, remoteCKMSID, kms)
+		go etsiServer.Run(etsi14Service)
+		kms.KeyStoreChannel = etsi14Service.KeyStoreChannel
+	} else {
+		log.Info("No ETSI14 server running.")
+	}
 
 	// start Qkdn Manager server, if there is info about it in the config
 	if kmsConfig.QkdnManagerServer != nil {
-- 
GitLab