From 510027681a770d395286f8663e2f4d6e46814a7e Mon Sep 17 00:00:00 2001
From: Fabian Seidl <fabian.seidl@h-da.de>
Date: Fri, 21 Jun 2024 09:49:07 +0000
Subject: [PATCH] Resolve "Integration test for etsi14 server in KMS"

See merge request danet/quant!155
---
 .gitlab-ci.yml                                |   2 +
 goKMS/etsi/etsi14/etsi14Server/server.go      |   4 +-
 goKMS/kms/kms.go                              |   8 +-
 goKMS/kms/kmsintercom.go                      |   4 +-
 .../etsi14GetKeyTest/etsi14_GetKey_test.go    | 146 ++++++++++++++++++
 .../etsi14GetKeyTest/etsi14_GetKey_utility.go |  42 +++++
 .../code/getKSAKeyTest/getKSA_key_test.go     |  68 +-------
 .../integrationTestUtils.go                   |  73 +++++++++
 integration-tests/config/kms/kms_1.yaml       |   3 +
 integration-tests/config/kms/kms_2.yaml       |   3 +
 .../docker-compose_integration_test.yml       |   2 +
 11 files changed, 283 insertions(+), 72 deletions(-)
 create mode 100644 integration-tests/code/etsi14GetKeyTest/etsi14_GetKey_test.go
 create mode 100644 integration-tests/code/etsi14GetKeyTest/etsi14_GetKey_utility.go

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e5384cb9..e2b42c53 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -157,6 +157,8 @@ integration-test-kms:
         INTEGRATION_TEST_KMS1_AKMS_URL: kms_1:9696
         INTEGRATION_TEST_LOG_FILE1_URL: akms-simulator_1:4444
         INTEGRATION_TEST_LOG_FILE2_URL: akms-simulator_2:4444
+        INTEGRATION_TEST_KMS1_ETSI14_URL: kms_1:1414
+        INTEGRATION_TEST_KMS2_ETSI14_URL: kms_2:1414
     services:
         - name: $IMAGE_PATH/akms-simulator:$CI_COMMIT_REF_SLUG
           alias: akms-simulator_1
diff --git a/goKMS/etsi/etsi14/etsi14Server/server.go b/goKMS/etsi/etsi14/etsi14Server/server.go
index f9912f0b..94b77503 100644
--- a/goKMS/etsi/etsi14/etsi14Server/server.go
+++ b/goKMS/etsi/etsi14/etsi14Server/server.go
@@ -18,6 +18,8 @@ import (
 	"github.com/sirupsen/logrus"
 )
 
+const etsi014RequestID = "etsi014"
+
 type ETSI14RESTService struct {
 	serviceAddress  string
 	remoteCKMSID    uuid.UUID
@@ -204,7 +206,7 @@ func (s *ETSI14RESTService) GetStatus(ctx context.Context, slaveSAEID string) (r
 
 // 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
+	keys, err := s.kms.ExchangeKeyAfterETSI14GetKeyRequest(s.remoteCKMSID, number, etsi014RequestID) // Note: we should have a mapping mechanism here to support multiple endpoints in the future
 	if err != nil {
 		return nil, err
 	}
diff --git a/goKMS/kms/kms.go b/goKMS/kms/kms.go
index 67e2f7bd..7948cd69 100644
--- a/goKMS/kms/kms.go
+++ b/goKMS/kms/kms.go
@@ -634,7 +634,7 @@ func (kms *KMS) sendKSAKeysToPlatformKmsPeer(kmsPeerAddress, platformKeyID, requ
 	return nil
 }
 
-func (kms *KMS) ExchangeKeyAfterETSI14GetKeyRequest(receivingCKMSID uuid.UUID, number int64) ([]client.KSAKey, error) {
+func (kms *KMS) ExchangeKeyAfterETSI14GetKeyRequest(receivingCKMSID uuid.UUID, number int64, requestID string) ([]client.KSAKey, error) {
 	// CreateRouteRequest
 	pathID := uuid.New()
 	log.Debugf("(ETSI14) created new path id: %s, for incoming ETSI14 key request", pathID)
@@ -662,10 +662,10 @@ func (kms *KMS) ExchangeKeyAfterETSI14GetKeyRequest(receivingCKMSID uuid.UUID, n
 	}
 
 	// GenerateAndSend
-	return kms.generateAndReturnKsaKey(receivingCKMSID, pathID, number)
+	return kms.generateAndReturnKsaKey(receivingCKMSID, pathID, number, requestID)
 }
 
-func (kms *KMS) generateAndReturnKsaKey(receivingCKMSID, pathID uuid.UUID, number int64) ([]client.KSAKey, error) {
+func (kms *KMS) generateAndReturnKsaKey(receivingCKMSID, pathID uuid.UUID, number int64, requestID string) ([]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)
@@ -700,7 +700,7 @@ func (kms *KMS) generateAndReturnKsaKey(receivingCKMSID, pathID uuid.UUID, numbe
 
 	remoteKMSAdrress := fmt.Sprintf("%s:%d", remoteKMS.Address, remoteKMS.Port)
 
-	err = kms.sendKSAKeysToPlatformKmsPeer(remoteKMSAdrress, platformKey.Id.String(), "", ksaKeysToSendToRemoteKMS)
+	err = kms.sendKSAKeysToPlatformKmsPeer(remoteKMSAdrress, platformKey.Id.String(), requestID, ksaKeysToSendToRemoteKMS)
 	if err != nil {
 		log.Error(err)
 		return nil, err
diff --git a/goKMS/kms/kmsintercom.go b/goKMS/kms/kmsintercom.go
index e6e3949f..00d8806c 100644
--- a/goKMS/kms/kmsintercom.go
+++ b/goKMS/kms/kmsintercom.go
@@ -25,6 +25,8 @@ import (
 	"google.golang.org/grpc/status"
 )
 
+const etsi014RequestID = "etsi014"
+
 type kmsTalkerServer struct {
 	pb.UnimplementedKmsTalkerServer
 	keyNegotationMutex sync.Mutex
@@ -328,7 +330,7 @@ func (s *kmsTalkerServer) KeyDelivery(ctx context.Context, in *pb.KeyDeliveryReq
 		}
 	}
 
-	if s.KMS.KeyStoreChannel != nil {
+	if s.KMS.KeyStoreChannel != nil && in.GetRequestId() == etsi014RequestID {
 		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 {
diff --git a/integration-tests/code/etsi14GetKeyTest/etsi14_GetKey_test.go b/integration-tests/code/etsi14GetKeyTest/etsi14_GetKey_test.go
new file mode 100644
index 00000000..36d01bac
--- /dev/null
+++ b/integration-tests/code/etsi14GetKeyTest/etsi14_GetKey_test.go
@@ -0,0 +1,146 @@
+package integration_tests
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"os"
+	"strings"
+	"testing"
+	"time"
+
+	integration_test_utils "code.fbi.h-da.de/danet/quant/integration-tests/code/integrationTestUtils"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestETSI14GetKey(t *testing.T) { //nolint:gocyclo
+	kms2URL := "127.0.0.1:7031"
+	kms2URL_ENV := os.Getenv("INTEGRATION_TEST_KMS2_URL")
+	if kms2URL_ENV != "" {
+		kms2URL = kms2URL_ENV
+	}
+	kms1URL := "127.0.0.1:7030"
+	kms1URL_ENV := os.Getenv("INTEGRATION_TEST_KMS1_URL")
+	if kms1URL_ENV != "" {
+		kms1URL = kms1URL_ENV
+	}
+	kms1ETSI14URL := "127.0.0.1:1414"
+	kms1ETSI14URL_ENV := os.Getenv("INTEGRATION_TEST_KMS1_ETSI14_URL")
+	if kms1ETSI14URL_ENV != "" {
+		kms1ETSI14URL = kms1ETSI14URL_ENV
+	}
+	kms2ETSI14URL := "127.0.0.1:1415"
+	kms2ETSI14URL_ENV := os.Getenv("INTEGRATION_TEST_KMS2_ETSI14_URL")
+	if kms2ETSI14URL_ENV != "" {
+		kms2ETSI14URL = kms2ETSI14URL_ENV
+	}
+
+	url := fmt.Sprintf("http://%s/api/v1/keys/slave_SAE_ID/enc_keys", kms1ETSI14URL)
+	data := ETSI14RequestData{
+		Number: 1,
+	}
+
+	jsonData, err := json.Marshal(data)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+
+	var respKms1 *http.Response
+	go func() {
+		respKms1, err = http.Post(url, "application/json", bytes.NewBuffer(jsonData))
+		if err != nil {
+			t.Errorf("Error making HTTP request: %s", err)
+			return
+		}
+
+		if respKms1.StatusCode != http.StatusOK {
+			t.Errorf("Expected status code 200 OK, but got %d", respKms1.StatusCode)
+		}
+	}()
+
+	time.Sleep(time.Duration(2) * time.Second)
+
+	output, err := integration_test_utils.GnmicCommand(kms1URL, "get", "--path", "create-route-requests")
+	if err != nil {
+		t.Errorf("Error getting create-route-requests: %s; %s", err, output)
+	}
+
+	output = strings.Split(output, "\"kms-path-id\": \"")[1]
+	output = strings.Split(output, "\",")[0]
+
+	path := fmt.Sprintf("key-routing-sessions/routing-sessions[path-id=%s]", output)
+
+	config01 := integration_test_utils.BuildKms1RoutingConfig(path, output)
+
+	config02 := integration_test_utils.BuildKms2RoutingConfig(path, output)
+
+	argsKMS1 := []string{"set"}
+	for _, update := range config01 {
+		argsKMS1 = append(argsKMS1, "--update-path", update.Path, "--update-value", update.JSON)
+	}
+
+	argsKMS2 := []string{"set"}
+	for _, update := range config02 {
+		argsKMS2 = append(argsKMS2, "--update-path", update.Path, "--update-value", update.JSON)
+	}
+
+	output, err = integration_test_utils.GnmicCommand(kms2URL, argsKMS2...)
+	if err != nil {
+		t.Errorf("Error setting routing-session: %s; %s", err, output)
+	}
+
+	output, err = integration_test_utils.GnmicCommand(kms1URL, argsKMS1...)
+	if err != nil {
+		t.Errorf("Error setting routing-session: %s; %s", err, output)
+	}
+
+	time.Sleep(time.Duration(2) * time.Second)
+
+	kms1KeyContainer, err := getKeyContainerFromResponse(respKms1)
+	if err != nil {
+		t.Errorf("Error getting Key Container from resp: %v, err: %v", respKms1, err)
+	}
+
+	assert.NotNil(t, kms1KeyContainer.Keys)
+
+	url = fmt.Sprintf("http://%s/api/v1/keys/master_SAE_ID/dec_keys", kms2ETSI14URL)
+	data = ETSI14RequestData{
+		KeyIDs: []KeyIdsRequestKeyIdsInner{
+			{
+				KeyID: kms1KeyContainer.Keys[0].KeyID,
+			},
+		},
+	}
+
+	jsonData, err = json.Marshal(data)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+
+	var respKms2 *http.Response
+	go func() {
+		respKms2, err = http.Post(url, "application/json", bytes.NewBuffer(jsonData))
+		if err != nil {
+			t.Errorf("Error making HTTP request: %s", err)
+			return
+		}
+
+		if respKms2.StatusCode != http.StatusOK {
+			t.Errorf("Expected status code 200 OK, but got %d", respKms2.StatusCode)
+		}
+	}()
+
+	time.Sleep(time.Duration(2) * time.Second)
+
+	kms2KeyContainer, err := getKeyContainerFromResponse(respKms2)
+	if err != nil {
+		t.Errorf("Error getting Key Container from resp: %v, err: %v", respKms1, err)
+	}
+
+	assert.NotNil(t, kms2KeyContainer.Keys)
+
+	assert.Equal(t, kms1KeyContainer, kms2KeyContainer)
+}
diff --git a/integration-tests/code/etsi14GetKeyTest/etsi14_GetKey_utility.go b/integration-tests/code/etsi14GetKeyTest/etsi14_GetKey_utility.go
new file mode 100644
index 00000000..98188acd
--- /dev/null
+++ b/integration-tests/code/etsi14GetKeyTest/etsi14_GetKey_utility.go
@@ -0,0 +1,42 @@
+package integration_tests
+
+import (
+	"encoding/json"
+	"io"
+	"net/http"
+)
+
+type ETSI14RequestData struct {
+	Number int64                      `json:"number,omitempty"`
+	KeyIDs []KeyIdsRequestKeyIdsInner `json:"key_IDs,omitempty"`
+}
+
+type KeyIdsRequestKeyIdsInner struct {
+	KeyID string `json:"key_ID"`
+}
+
+type ETSI14ResponseData struct {
+	Keys []KeyContainerKeysInner `json:"Keys,omitempty"`
+}
+
+type KeyContainerKeysInner struct {
+	KeyID string `json:"key_ID,omitempty"`
+
+	Key string `json:"key,omitempty"`
+}
+
+func getKeyContainerFromResponse(kmsResp *http.Response) (*ETSI14ResponseData, error) {
+	defer kmsResp.Body.Close() //nolint:errcheck
+	body, err := io.ReadAll(kmsResp.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	kmsKeyContainer := &ETSI14ResponseData{}
+	err = json.Unmarshal([]byte(body), kmsKeyContainer)
+	if err != nil {
+		return nil, err
+	}
+
+	return kmsKeyContainer, nil
+}
diff --git a/integration-tests/code/getKSAKeyTest/getKSA_key_test.go b/integration-tests/code/getKSAKeyTest/getKSA_key_test.go
index f042522a..ba39bc2b 100644
--- a/integration-tests/code/getKSAKeyTest/getKSA_key_test.go
+++ b/integration-tests/code/getKSAKeyTest/getKSA_key_test.go
@@ -17,12 +17,6 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-type Update struct {
-	Path  string
-	Value string
-	JSON  string
-}
-
 // For log file.
 type LogFile struct {
 	Source string            `json:"source"`
@@ -125,67 +119,9 @@ func TestGetKSAKey(t *testing.T) { //nolint:gocyclo
 
 	path := fmt.Sprintf("key-routing-sessions/routing-sessions[path-id=%s]", output)
 
-	config01 := []Update{
-		{
-			Path: path,
-			JSON: fmt.Sprintf(`{"path-id": "%s"}`, output),
-		},
-		{
-			Path: fmt.Sprint(path, "/next-hop"),
-			JSON: fmt.Sprintf(`{"node-id": "%s"}`, "5e41c291-6121-4335-84f6-41e04b8bdaa2"),
-		},
-		{
-			Path: fmt.Sprint(path, "/next-hop"),
-			JSON: fmt.Sprintf(`{"hostname": "%s"}`, "kms_2"),
-		},
-		{
-			Path: fmt.Sprint(path, "/next-hop"),
-			JSON: fmt.Sprintf(`{"port": %d}`, 50910),
-		},
-		{
-			Path: fmt.Sprint(path, "/initiating-kms-address"),
-			JSON: fmt.Sprintf(`{"node-id": "%s"}`, "5e41c291-6121-4335-84f6-41e04b8bdaa2"),
-		},
-		{
-			Path: fmt.Sprint(path, "/initiating-kms-address"),
-			JSON: fmt.Sprintf(`{"hostname": "%s"}`, "kms_2"),
-		},
-		{
-			Path: fmt.Sprint(path, "/initiating-kms-address"),
-			JSON: fmt.Sprintf(`{"port": %d}`, 50910),
-		},
-	}
+	config01 := integration_test_utils.BuildKms1RoutingConfig(path, output)
 
-	config02 := []Update{
-		{
-			Path: path,
-			JSON: fmt.Sprintf(`{"path-id": "%s"}`, output),
-		},
-		{
-			Path: fmt.Sprint(path, "/prev-hop"),
-			JSON: fmt.Sprintf(`{"node-id": "%s"}`, "0ff33c82-7fe1-482b-a0ca-67565806ee4b"),
-		},
-		{
-			Path: fmt.Sprint(path, "/prev-hop"),
-			JSON: fmt.Sprintf(`{"hostname": "%s"}`, "kms_1"),
-		},
-		{
-			Path: fmt.Sprint(path, "/prev-hop"),
-			JSON: fmt.Sprintf(`{"port": %d}`, 50910),
-		},
-		{
-			Path: fmt.Sprint(path, "/initiating-kms-address"),
-			JSON: fmt.Sprintf(`{"node-id": "%s"}`, "0ff33c82-7fe1-482b-a0ca-67565806ee4b"),
-		},
-		{
-			Path: fmt.Sprint(path, "/initiating-kms-address"),
-			JSON: fmt.Sprintf(`{"hostname": "%s"}`, "kms_1"),
-		},
-		{
-			Path: fmt.Sprint(path, "/initiating-kms-address"),
-			JSON: fmt.Sprintf(`{"port": %d}`, 50910),
-		},
-	}
+	config02 := integration_test_utils.BuildKms2RoutingConfig(path, output)
 
 	argsKMS1 := []string{"set"}
 	for _, update := range config01 {
diff --git a/integration-tests/code/integrationTestUtils/integrationTestUtils.go b/integration-tests/code/integrationTestUtils/integrationTestUtils.go
index 856d9646..19ed596a 100644
--- a/integration-tests/code/integrationTestUtils/integrationTestUtils.go
+++ b/integration-tests/code/integrationTestUtils/integrationTestUtils.go
@@ -1,9 +1,16 @@
 package utils
 
 import (
+	"fmt"
 	"os/exec"
 )
 
+type Update struct {
+	Path  string
+	Value string
+	JSON  string
+}
+
 func GnmicCommand(address string, args ...string) (string, error) {
 	cmd := exec.Command("gnmic", "-a", address, "-u", "admin", "-p", "admin", "--insecure", "-e", "JSON_IETF")
 	cmd.Args = append(cmd.Args, args...)
@@ -15,3 +22,69 @@ func GnmicCommand(address string, args ...string) (string, error) {
 	}
 	return outputString, nil
 }
+
+func BuildKms1RoutingConfig(path, pathID string) []Update {
+	return []Update{
+		{
+			Path: path,
+			JSON: fmt.Sprintf(`{"path-id": "%s"}`, pathID),
+		},
+		{
+			Path: fmt.Sprint(path, "/next-hop"),
+			JSON: fmt.Sprintf(`{"node-id": "%s"}`, "5e41c291-6121-4335-84f6-41e04b8bdaa2"),
+		},
+		{
+			Path: fmt.Sprint(path, "/next-hop"),
+			JSON: fmt.Sprintf(`{"hostname": "%s"}`, "kms_2"),
+		},
+		{
+			Path: fmt.Sprint(path, "/next-hop"),
+			JSON: fmt.Sprintf(`{"port": %d}`, 50910),
+		},
+		{
+			Path: fmt.Sprint(path, "/initiating-kms-address"),
+			JSON: fmt.Sprintf(`{"node-id": "%s"}`, "5e41c291-6121-4335-84f6-41e04b8bdaa2"),
+		},
+		{
+			Path: fmt.Sprint(path, "/initiating-kms-address"),
+			JSON: fmt.Sprintf(`{"hostname": "%s"}`, "kms_2"),
+		},
+		{
+			Path: fmt.Sprint(path, "/initiating-kms-address"),
+			JSON: fmt.Sprintf(`{"port": %d}`, 50910),
+		},
+	}
+}
+
+func BuildKms2RoutingConfig(path, pathID string) []Update {
+	return []Update{
+		{
+			Path: path,
+			JSON: fmt.Sprintf(`{"path-id": "%s"}`, pathID),
+		},
+		{
+			Path: fmt.Sprint(path, "/prev-hop"),
+			JSON: fmt.Sprintf(`{"node-id": "%s"}`, "0ff33c82-7fe1-482b-a0ca-67565806ee4b"),
+		},
+		{
+			Path: fmt.Sprint(path, "/prev-hop"),
+			JSON: fmt.Sprintf(`{"hostname": "%s"}`, "kms_1"),
+		},
+		{
+			Path: fmt.Sprint(path, "/prev-hop"),
+			JSON: fmt.Sprintf(`{"port": %d}`, 50910),
+		},
+		{
+			Path: fmt.Sprint(path, "/initiating-kms-address"),
+			JSON: fmt.Sprintf(`{"node-id": "%s"}`, "0ff33c82-7fe1-482b-a0ca-67565806ee4b"),
+		},
+		{
+			Path: fmt.Sprint(path, "/initiating-kms-address"),
+			JSON: fmt.Sprintf(`{"hostname": "%s"}`, "kms_1"),
+		},
+		{
+			Path: fmt.Sprint(path, "/initiating-kms-address"),
+			JSON: fmt.Sprintf(`{"port": %d}`, 50910),
+		},
+	}
+}
diff --git a/integration-tests/config/kms/kms_1.yaml b/integration-tests/config/kms/kms_1.yaml
index 273b4440..4c7a9289 100644
--- a/integration-tests/config/kms/kms_1.yaml
+++ b/integration-tests/config/kms/kms_1.yaml
@@ -20,3 +20,6 @@ Peers:
       QuantumModule:
           Type: emulated
           Hostname: quantumlayer_1
+ETSI14Server:
+  Address: ":1414"
+  RemoteCKMSID: "5e41c291-6121-4335-84f6-41e04b8bdaa2"
diff --git a/integration-tests/config/kms/kms_2.yaml b/integration-tests/config/kms/kms_2.yaml
index 319da986..a887c49c 100644
--- a/integration-tests/config/kms/kms_2.yaml
+++ b/integration-tests/config/kms/kms_2.yaml
@@ -20,3 +20,6 @@ Peers:
       QuantumModule:
           Type: emulated
           Hostname: quantumlayer_2
+ETSI14Server:
+  Address: ":1414"
+  RemoteCKMSID: "0ff33c82-7fe1-482b-a0ca-67565806ee4b"
diff --git a/integration-tests/docker-compose_integration_test.yml b/integration-tests/docker-compose_integration_test.yml
index 8576fc0a..80eed985 100644
--- a/integration-tests/docker-compose_integration_test.yml
+++ b/integration-tests/docker-compose_integration_test.yml
@@ -14,6 +14,7 @@ services:
         ports:
             - "127.0.0.1:7030:7030"
             - "127.0.0.1:9696:9696"
+            - "127.0.0.1:1414:1414"
 
     kms_2:
         image: gokms
@@ -29,6 +30,7 @@ services:
             - ../artifacts/integration-tests/ssl:/config/ssl
         ports:
             - "127.0.0.1:7031:7030"
+            - "127.0.0.1:1415:1414"
 
     quantumlayer_1:
         image: quantumlayer
-- 
GitLab