diff --git a/go.mod b/go.mod index 88c297be87bdc3b80e5d33beae02f9d51c3b0609..d181fee7a23bf168fa8f0f290a833850e1a1af4c 100644 --- a/go.mod +++ b/go.mod @@ -3,18 +3,18 @@ module code.fbi.h-da.de/danet/proto-kms go 1.21 require ( + code.fbi.h-da.de/danet/ekms v0.0.0-20231101170413-671634b8e3b3 + code.fbi.h-da.de/danet/quipsec/gen/go/quipsec v0.0.0-20231113131315-e0a0cd3d28e3 github.com/google/uuid v1.3.1 github.com/sirupsen/logrus v1.9.3 - google.golang.org/grpc v1.58.2 + google.golang.org/grpc v1.59.0 google.golang.org/protobuf v1.31.0 ) require ( - code.fbi.h-da.de/danet/ekms v0.0.0-20231031082917-60e1f07a8617 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20231030212536-12f9cba37c9d.2 // indirect + code.fbi.h-da.de/danet/quantumlayer v0.0.0-20231113142846-ae276faa2a9a // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/stretchr/testify v1.8.4 // indirect golang.org/x/net v0.15.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect diff --git a/go.sum b/go.sum index ae1df24502653a73e8917bc1b557cdad887315ca..1161aaaa3886541d9a6c969d3e559ad23b552c98 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,11 @@ -code.fbi.h-da.de/danet/ekms v0.0.0-20231027141805-c77e2d25accb h1:6PbnWyn8QwhZWPVN5L3cSO148gGxk7X5GGYkL5awMl8= -code.fbi.h-da.de/danet/ekms v0.0.0-20231027141805-c77e2d25accb/go.mod h1:qVaZ1wGJ+XrE+S3eW1CEB0gAarzClnxYEog06BLnD4k= -code.fbi.h-da.de/danet/ekms v0.0.0-20231030172039-48ca51ab722d h1:wfjIMNVdMf0fr1xMgNwImlE9UsWgDBRj/bQY9QtzlW8= -code.fbi.h-da.de/danet/ekms v0.0.0-20231030172039-48ca51ab722d/go.mod h1:qVaZ1wGJ+XrE+S3eW1CEB0gAarzClnxYEog06BLnD4k= -code.fbi.h-da.de/danet/ekms v0.0.0-20231030180651-55420c3dc33f h1:JXRwaYLIcQ1uuH1PVRJ8jcXvLjXKmup2RLlDpnUYqvo= -code.fbi.h-da.de/danet/ekms v0.0.0-20231030180651-55420c3dc33f/go.mod h1:qVaZ1wGJ+XrE+S3eW1CEB0gAarzClnxYEog06BLnD4k= -code.fbi.h-da.de/danet/ekms v0.0.0-20231031082917-60e1f07a8617 h1:tceO3twY87RXD5Jet7YZdC0SXo5NuWHr0IZ/IvCO/0s= -code.fbi.h-da.de/danet/ekms v0.0.0-20231031082917-60e1f07a8617/go.mod h1:qVaZ1wGJ+XrE+S3eW1CEB0gAarzClnxYEog06BLnD4k= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20231030212536-12f9cba37c9d.2 h1:m8rKyv88R8ZIR1549RMXckZ4FZJGxrq/7aRYl6U3WHc= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20231030212536-12f9cba37c9d.2/go.mod h1:xafc+XIsTxTy76GJQ1TKgvJWsSugFBqMaN27WhUblew= +code.fbi.h-da.de/danet/ekms v0.0.0-20231101170413-671634b8e3b3 h1:ABpjLMNTDQIykwpDQOxBZ9ukm+suBu8oJHqq3GZCzzc= +code.fbi.h-da.de/danet/ekms v0.0.0-20231101170413-671634b8e3b3/go.mod h1:qVaZ1wGJ+XrE+S3eW1CEB0gAarzClnxYEog06BLnD4k= +code.fbi.h-da.de/danet/quantumlayer v0.0.0-20231113142846-ae276faa2a9a h1:urBXx1zWxvP/0QdEkIbViPqaILJV2BMhPJ34r0d5omk= +code.fbi.h-da.de/danet/quantumlayer v0.0.0-20231113142846-ae276faa2a9a/go.mod h1:L+el1b356QSGNH21HuA0uSqs58Ix5HyySYsTRmsBEaA= +code.fbi.h-da.de/danet/quipsec/gen/go/quipsec v0.0.0-20231113131315-e0a0cd3d28e3 h1:PXz62uU6MEdcafEZnVwKINPRxSL0y0Ht0Pzp/NSSTew= +code.fbi.h-da.de/danet/quipsec/gen/go/quipsec v0.0.0-20231113131315-e0a0cd3d28e3/go.mod h1:lPCd19Jk8aL5B3xSk+h6y5sziXVPqyCXgO7dILvJFfQ= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -37,8 +37,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM= google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= -google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= -google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= diff --git a/kms/kms.go b/kms/kms.go index 322de28041e0dd3ea94b5ff63b809ec3e715cf45..5360a60ebc7aead0ddab6500fd193b5417dc6bef 100644 --- a/kms/kms.go +++ b/kms/kms.go @@ -7,12 +7,17 @@ package kms import ( "fmt" "io" + "net" "sync" log "github.com/sirupsen/logrus" + "google.golang.org/grpc" + "google.golang.org/grpc/health" + healthpb "google.golang.org/grpc/health/grpc_health_v1" pbETSI "code.fbi.h-da.de/danet/proto-kms/api/gen/proto/go/kmsetsi" pbIC "code.fbi.h-da.de/danet/proto-kms/api/gen/proto/go/kmsintercom" + pbQS "code.fbi.h-da.de/danet/quipsec/gen/go/quipsec" "github.com/google/uuid" ) @@ -46,7 +51,7 @@ type EKMS struct { kmsUUID uuid.UUID interComAddr string qleMapMutex sync.Mutex - quantumModules map[uuid.UUID]QuantumModule + quantumModules map[string]QuantumModule quantumModulesMutex sync.RWMutex externalNotifierQLE chan uint32 kmsPeersMutex sync.Mutex @@ -94,7 +99,7 @@ func NewEKMS(kmsName string, kmsUUID uuid.UUID, logOutput io.Writer, logLevel lo kmsName: kmsName, kmsUUID: kmsUUID, interComAddr: interComAddr, - quantumModules: make(map[uuid.UUID]QuantumModule), + quantumModules: make(map[string]QuantumModule), routingTable: make(map[uuid.UUID]*Route), KmsPeers: make(map[string]*kmsPeer), externalNotifierQLE: nil, // just be surely set to nil! @@ -105,14 +110,46 @@ func NewEKMS(kmsName string, kmsUUID uuid.UUID, logOutput io.Writer, logLevel lo createdEKMS.supportedKeyLengths[BitKeyLen256] = true // start the inter communication gRPC server - go StartInterComm(interComAddr, createdEKMS) + go createdEKMS.startGRPC(interComAddr) return createdEKMS } +func (kms *EKMS) startGRPC(interComAddr string) { + lis, err := net.Listen("tcp", interComAddr) + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + s := grpc.NewServer() + healthCheck := health.NewServer() + + healthpb.RegisterHealthServer(s, healthCheck) + pbIC.RegisterKmsTalkerServer(s, &kmsTalkerServer{ + keyNegotiationMap: make(map[uuid.UUID]*kmsKSElement), + eKMS: kms, + }) + pbQS.RegisterKmsQkdmCommunicationServiceServer(s, &quipSecServer{ + eKMS: kms, + }) + + go func() { + // set status to serving + healthCheck.SetServingStatus(pbIC.KmsTalker_ServiceDesc.ServiceName, healthpb.HealthCheckResponse_SERVING) + // TODO: add logic for adjusting health status based on operating status of + // the services + // for{} + }() + + log.Infof("server listening at %v", lis.Addr()) + if err := s.Serve(lis); err != nil { + log.Fatalf("failed to serve: %v", err) + } +} + func (kms *EKMS) AddQuantumElement(qm QuantumModule) error { kms.quantumModulesMutex.Lock() - kms.quantumModules[qm.ID()] = qm + log.Info(qm.Address()) + kms.quantumModules[qm.Address()] = qm kms.quantumModulesMutex.Unlock() return nil } diff --git a/kms/kmsetsi.go b/kms/kmsetsi.go index 8e907c8f0828e7e951bec9c05ecf5d83155c6ac0..f6e2cbba0dba79667095df46f365edcda8142846 100644 --- a/kms/kmsetsi.go +++ b/kms/kmsetsi.go @@ -42,7 +42,7 @@ func (es *etsiServer) ETSIGetQuantumInterfaces(ctx context.Context, in *pb.ETSIK for _, qlWorks := range es.handlingEkms.quantumModules { qleElement := pb.QuantumElementInfo{ QleID: qlWorks.ID().String(), - UdpAddr: qlWorks.Address().String(), + UdpAddr: qlWorks.Address(), } qleList = append(qleList, &qleElement) } @@ -51,13 +51,14 @@ func (es *etsiServer) ETSIGetQuantumInterfaces(ctx context.Context, in *pb.ETSIK }, nil } +// TODO: reimplement func (es *etsiServer) ETSIAddKMSPeer(ctx context.Context, in *pb.ETSIKMSPeerRequest) (*pb.ETSIKMSPeerReply, error) { //determine the kms structure to call log.Debugf("AddKMSPeer called.") // Check first if KmsLocalQLEId is actually one of ours... qleID := uuid.MustParse(in.KmsLocalQLEId) - servingQLE, _ := es.handlingEkms.quantumModules[qleID] + servingQLE, _ := es.handlingEkms.quantumModules[""] if servingQLE == nil { //no such element! err := errors.New(fmt.Sprintf("Unknown local quantum element with ID %d", qleID)) @@ -127,7 +128,7 @@ func (es *etsiServer) ETSIAssignForwarding(ctx context.Context, in *pb.ETSIAssig Next: nextHop, } - log.Info("ROUTINGTABLE: ", es.handlingEkms.routingTable) + log.Infof("%s added a routing table entry for path id: %s", es.handlingEkms.kmsName, pathId.String()) return &pb.ETSIAssignForwardingReply{ Timestamp: time.Now().Unix(), diff --git a/kms/kmsintercom.go b/kms/kmsintercom.go index c7ec9ebbd2421208f360f400cf00a4eea96d2a11..7bf01c609c04a2e1fbd906638e727dbbfbc5e884 100644 --- a/kms/kmsintercom.go +++ b/kms/kmsintercom.go @@ -3,9 +3,7 @@ package kms import ( "context" "encoding/base64" - "flag" "io/ioutil" - "net" "time" "github.com/google/uuid" @@ -13,10 +11,7 @@ import ( etsi14 "code.fbi.h-da.de/danet/ekms/api/go/rest/etsi/client" pb "code.fbi.h-da.de/danet/proto-kms/api/gen/proto/go/kmsintercom" - "google.golang.org/grpc" "google.golang.org/grpc/codes" - "google.golang.org/grpc/health" - healthpb "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/status" ) @@ -251,33 +246,3 @@ func (s *kmsTalkerServer) KeyForwarding(ctx context.Context, in *pb.KeyForwardin return &pb.KeyForwardingResponse{Timestamp: time.Now().Unix()}, nil } - -func StartInterComm(addr string, eKMS *EKMS) { - flag.Parse() - - lis, err := net.Listen("tcp", addr) - if err != nil { - log.Fatalf("failed to listen: %v", err) - } - s := grpc.NewServer() - healthCheck := health.NewServer() - - healthpb.RegisterHealthServer(s, healthCheck) - pb.RegisterKmsTalkerServer(s, &kmsTalkerServer{ - keyNegotiationMap: make(map[uuid.UUID]*kmsKSElement), - eKMS: eKMS, - }) - - go func() { - // set status to serving - healthCheck.SetServingStatus(pb.KmsTalker_ServiceDesc.ServiceName, healthpb.HealthCheckResponse_SERVING) - // TODO: add logic for adjusting health status based on operating status of - // the services - // for{} - }() - - log.Infof("server listening at %v", lis.Addr()) - if err := s.Serve(lis); err != nil { - log.Fatalf("failed to serve: %v", err) - } -} diff --git a/kms/module.go b/kms/module.go index 14fff0f02f7fb548091cfb2b652dc81a464d9e37..e19d32df16235637ca52537687ee3004291a412d 100644 --- a/kms/module.go +++ b/kms/module.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "io" - "net" "net/url" "sync" "time" @@ -13,7 +12,7 @@ import ( etsi14 "code.fbi.h-da.de/danet/ekms/api/go/rest/etsi/client" restclient "code.fbi.h-da.de/danet/ekms/restclient" pbIC "code.fbi.h-da.de/danet/proto-kms/api/gen/proto/go/kmsintercom" - "code.fbi.h-da.de/danet/proto-kms/quantumlayer" + "code.fbi.h-da.de/danet/quantumlayer" "github.com/google/uuid" "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus" @@ -29,31 +28,33 @@ type QuantumModule interface { Sync() error Peer() *kmsPeer SetPeer(*kmsPeer) - Address() net.Addr + Address() string } type EmulatedQuantumModule struct { - QlID uuid.UUID - QuantumElementLink *quantumlayer.QuantumlayerEmuPRNG // contains information about the quantum links + QlID uuid.UUID + //QuantumElementLink *quantumlayer.QuantumlayerEmuPRNG // contains information about the quantum links //key stores of unchopped bulk keys go here + addr string rawBulkKeysMutex sync.Mutex rawBulkKeys map[int64]*quantumlayer.QuantumLayerBulkKey keyStore *kmsKeyStore // the keys used between two peers. peer *kmsPeer } -func NewEmulatedQuantumModule(kmsUDPAddr string, generateKeys bool, logOutput io.Writer, logLevel log.Level, logInJson bool) *EmulatedQuantumModule { +func NewEmulatedQuantumModule(kmsUDPAddr string, logOutput io.Writer, logLevel log.Level, logInJson bool) *EmulatedQuantumModule { // create an emulated quantum layer - ql := quantumlayer.NewQuantumlayerEmuPRNG(logOutput, logLevel, logInJson) - ql.Configure(kmsUDPAddr) - ql.PowerOn(generateKeys) + // ql := quantumlayer.NewQuantumlayerEmuPRNG(logOutput, logLevel, logInJson) + // ql.Configure(kmsUDPAddr) + // ql.PowerOn(generateKeys) return &EmulatedQuantumModule{ - QlID: uuid.New(), - QuantumElementLink: ql, - rawBulkKeys: make(map[int64]*quantumlayer.QuantumLayerBulkKey), - keyStore: NewKmsKeyStore(256), - peer: nil, + QlID: uuid.New(), + //QuantumElementLink: ql, + addr: kmsUDPAddr, + rawBulkKeys: make(map[int64]*quantumlayer.QuantumLayerBulkKey), + keyStore: NewKmsKeyStore(256), + peer: nil, } } @@ -63,12 +64,12 @@ func (eqe *EmulatedQuantumModule) ID() uuid.UUID { func (eqe *EmulatedQuantumModule) Initialize() error { // TODO: error handling - go eqe.keyHandler() + //go eqe.keyHandler() return nil } -func (eqe *EmulatedQuantumModule) Address() net.Addr { - return eqe.QuantumElementLink.GetLocalQLPort() +func (eqe *EmulatedQuantumModule) Address() string { + return eqe.addr } func (eqe *EmulatedQuantumModule) Sync() error { @@ -141,24 +142,24 @@ func (eqe *EmulatedQuantumModule) SetPeer(peer *kmsPeer) { eqe.peer = peer } -func (eqe *EmulatedQuantumModule) keyHandler() { - // periodically walk through quantum element and retrieve the key bulk buffer - for { - log.Debugf("%s: KeyHandler reading...\n", eqe.ID()) - bulkKeys, err := eqe.QuantumElementLink.GetKeyBulkPeer() - if err != nil { - log.Errorf("%s: failed to retrieve bulkkeys with error %s", eqe.ID(), err) - } else { - // Add to the slice, but not process yet. - log.Debugf("%s: produced %d bytes of key", eqe.ID(), bulkKeys.BulkKeyLength) - eqe.rawBulkKeysMutex.Lock() - eqe.rawBulkKeys[bulkKeys.BulkKeyId] = &bulkKeys - eqe.rawBulkKeysMutex.Unlock() - } - // TODO: hardcoded - time.Sleep(5 * time.Second) - } -} +//func (eqe *EmulatedQuantumModule) keyHandler() { +// // periodically walk through quantum element and retrieve the key bulk buffer +// for { +// log.Debugf("%s: KeyHandler reading...\n", eqe.ID()) +// bulkKeys, err := eqe.QuantumElementLink.GetKeyBulkPeer() +// if err != nil { +// log.Errorf("%s: failed to retrieve bulkkeys with error %s", eqe.ID(), err) +// } else { +// // Add to the slice, but not process yet. +// log.Debugf("%s: produced %d bytes of key", eqe.ID(), bulkKeys.BulkKeyLength) +// eqe.rawBulkKeysMutex.Lock() +// eqe.rawBulkKeys[bulkKeys.BulkKeyId] = &bulkKeys +// eqe.rawBulkKeysMutex.Unlock() +// } +// // TODO: hardcoded +// time.Sleep(5 * time.Second) +// } +//} // Takes a bulk of keys and chops them in chopFactor keys each // Any remainder is discarded @@ -204,14 +205,16 @@ func (eqe *EmulatedQuantumModule) KeyChopper(bulkKey *quantumlayer.QuantumLayerB type ETSI014HTTPQuantumModule struct { id uuid.UUID + addr string keyStore *kmsKeyStore peer *kmsPeer client *restclient.ClientImpl slaveSAEID string masterSAEID string + master bool } -func NewETSI014HTTPQuantumModule(addr, slaveSAEID, masterSAEID string) (*ETSI014HTTPQuantumModule, error) { +func NewETSI014HTTPQuantumModule(addr, slaveSAEID, masterSAEID string, master bool) (*ETSI014HTTPQuantumModule, error) { parsedUrl, err := url.Parse("http://" + addr) if err != nil { return nil, err @@ -241,11 +244,13 @@ func NewETSI014HTTPQuantumModule(addr, slaveSAEID, masterSAEID string) (*ETSI014 return &ETSI014HTTPQuantumModule{ id: uuid.New(), + addr: addr, keyStore: NewKmsKeyStore(256), peer: nil, client: client, slaveSAEID: slaveSAEID, masterSAEID: masterSAEID, + master: master, }, nil } @@ -255,48 +260,50 @@ func (eqe *ETSI014HTTPQuantumModule) ID() uuid.UUID { func (eqe *ETSI014HTTPQuantumModule) Initialize() error { // start polling - go func() { - ticker := time.NewTicker(2 * time.Second) - defer ticker.Stop() - - // TODO: add context/channel to stop - for { - select { - case <-ticker.C: - container, _, err := eqe.client.GetKey() - if err != nil { - log.Error(err) - break - } - - keyIds := make([]string, len(container.GetKeys())) - for i, keyItem := range container.GetKeys() { - keyIds[i] = keyItem.GetKeyID() - } - - _, err = eqe.peer.peerClient.KeyIdNotification(context.Background(), - &pbIC.KeyIdNotificationRequest{ - Timestamp: time.Now().Unix(), - InterComAddr: eqe.peer.interComAddr, - KeyIds: keyIds, - }) - if err != nil { - log.Error(err) - break - } - - if err := addETSIKeysToKeystore(eqe.keyStore, container.GetKeys()); err != nil { - log.Error(err) - break + if eqe.master { + go func() { + ticker := time.NewTicker(2 * time.Second) + defer ticker.Stop() + + // TODO: add context/channel to stop + for { + select { + case <-ticker.C: + container, _, err := eqe.client.GetKey() + if err != nil { + log.Error(err) + break + } + + keyIds := make([]string, len(container.GetKeys())) + for i, keyItem := range container.GetKeys() { + keyIds[i] = keyItem.GetKeyID() + } + + _, err = eqe.peer.peerClient.KeyIdNotification(context.Background(), + &pbIC.KeyIdNotificationRequest{ + Timestamp: time.Now().Unix(), + InterComAddr: eqe.peer.interComAddr, + KeyIds: keyIds, + }) + if err != nil { + log.Error(err) + break + } + + if err := addETSIKeysToKeystore(eqe.keyStore, container.GetKeys()); err != nil { + log.Error(err) + break + } } } - } - }() + }() + } return nil } -func (eqe *ETSI014HTTPQuantumModule) Address() net.Addr { - return nil +func (eqe *ETSI014HTTPQuantumModule) Address() string { + return eqe.addr } func (eqe *ETSI014HTTPQuantumModule) KeyStore() *kmsKeyStore { diff --git a/kms/quipsec.go b/kms/quipsec.go new file mode 100644 index 0000000000000000000000000000000000000000..afc82aecf78e2f72191b5f90ecbacfbd4220c7bf --- /dev/null +++ b/kms/quipsec.go @@ -0,0 +1,53 @@ +package kms + +import ( + "context" + "net" + "strconv" + "time" + + "code.fbi.h-da.de/danet/quantumlayer" + pb "code.fbi.h-da.de/danet/quipsec/gen/go/quipsec" + "github.com/sirupsen/logrus" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/peer" + "google.golang.org/grpc/status" +) + +type quipSecServer struct { + pb.UnimplementedKmsQkdmCommunicationServiceServer + eKMS *EKMS +} + +func (qs *quipSecServer) PushKeys(ctx context.Context, req *pb.PushKeysRequest) (*pb.PushKeysResponse, error) { + p, _ := peer.FromContext(ctx) + host, _, err := net.SplitHostPort(p.Addr.String()) + if err != nil { + } + + for _, qm := range qs.eKMS.quantumModules { + if qm.Address() == host { + eqm, ok := qm.(*EmulatedQuantumModule) + if !ok { + return nil, status.Errorf(codes.Internal, "quantum module is of wrong type") + } + + bulkKeyId, err := strconv.ParseInt(req.GetKeyBulk().GetKeyId(), 10, 64) + if err != nil { + return nil, status.Errorf(codes.Internal, "could not get bulkkeyid") + } + req.GetKeyBulk().GetKeyId() + req.GetKeyBulk().GetKeys() + eqm.rawBulkKeysMutex.Lock() + eqm.rawBulkKeys[bulkKeyId] = &quantumlayer.QuantumLayerBulkKey{ + BulkKeyId: bulkKeyId, + BulkKeyLength: int(req.GetKeyBulk().GetKeyLength()), + BulkKey: &req.GetKeyBulk().Keys, + } + eqm.rawBulkKeysMutex.Unlock() + logrus.Infof("%s received a new bulk with id: %s and a length of: %d", qs.eKMS.kmsName, req.GetKeyBulk().GetKeyId(), req.GetKeyBulk().GetKeyLength()) + return &pb.PushKeysResponse{Timestamp: time.Now().Unix()}, nil + } + } + return nil, status.Errorf(codes.Internal, "could not find a quantum module for host address: %s", host) +} diff --git a/main_test.go b/main_test.go index 1ce88b4aa61f521bc8d2af59029be237121ef4de..65e3b727c5ab57772cb9b2e8e05e3389f0e476d0 100644 --- a/main_test.go +++ b/main_test.go @@ -1,14 +1,9 @@ package main -// go generate protoc --proto_path=kmsintercomproto --go_out=kmsintercomproto --go_opt=paths=source_relative --go-grpc_out=kmsintercomproto --go-grpc_opt=paths=source_relative kmsintercom.proto -// go generate protoc --proto_path=kmsetsiproto --go_out=kmsetsiproto --go_opt=paths=source_relative --go-grpc_out=kmsetsiproto --go-grpc_opt=paths=source_relative kmsetsiproto.proto - import ( "flag" - "net" "os" "testing" - "time" log "github.com/sirupsen/logrus" @@ -51,36 +46,28 @@ func TestMain(m *testing.M) { if selfTesting == true { log.Infof("%s in self-testing mode", ql1Name) - go emulatedKMS("leftKMS", "[::1]:50900", "[::1]:50930", "[::1]:50910", "[::1]:50932") - go emulatedKMS("rightKMS", "[::1]:50901", "[::1]:50931", "[::1]:50911", "[::1]:50932") - middleKMS("middleKMS", "[::1]:50902", "[::1]:50932", "[::1]:50900", "[::1]:50930", "[::1]:50901", "[::1]:50931") + go emulatedKMS("leftKMS", "[::1]:50900", "[::1]:50930", "[::1]:50931", true) + emulatedKMS("rightKMS", "[::1]:50901", "[::1]:50931", "[::1]:50930", false) + } else { // log.Infof("%s in regular mode of operation", ql1Name) // emulatedKMS(ql1Name, udpQL1AddrString, udpQL2AddrString) } } -func emulatedKMS(myName, myUDPAddr, myInterComAddr, peerUDPAddr, peerInterComAddr string) { +func emulatedKMS(myName, myUDPAddr, myInterComAddr, peerInterComAddr string, master bool) { // Attach to eKMS emuKMS := kms.NewEKMS(myName, uuid.New(), os.Stdout, log.TraceLevel, false, myInterComAddr) - eqm := kms.NewEmulatedQuantumModule(myUDPAddr, false, os.Stdout, log.TraceLevel, false) + eqm := kms.NewEmulatedQuantumModule("::1", os.Stdout, log.TraceLevel, false) // Fire up Quantum LinK err := emuKMS.AddQuantumElement(eqm) if err != nil { - log.Println("failed to create emulated quantum module") - return - } - - udpQL2Addr, err := net.ResolveUDPAddr("udp", peerUDPAddr) - if err != nil { - log.Fatalf("%s: QuantumlayerEmuPRNG UDP failure: %s", myName, err) + log.Println("failed to add emulated quantum module") return } - eqm.QuantumElementLink.AddPeer(udpQL2Addr) - _, err = emuKMS.AddPeer(myName, peerInterComAddr, eqm) if err != nil { log.Println("PEERERROR: ", err) @@ -88,64 +75,6 @@ func emulatedKMS(myName, myUDPAddr, myInterComAddr, peerUDPAddr, peerInterComAdd // Start the SDN/management and key retrieval interface go kms.StartETSI(myUDPAddr, emuKMS) -} - -func middleKMS(myName, myUDPAddr, myInterComAddr, leftUDPAddr, leftInterComAddr, rightUDPAddr, rightInterComAddr string) { - // Attach to eKMS - emuKMS := kms.NewEKMS(myName, uuid.New(), os.Stdout, log.TraceLevel, false, myInterComAddr) - - // create two quantum modules that generate keys - qlForLeft := kms.NewEmulatedQuantumModule("[::1]:50910", true, os.Stdout, log.TraceLevel, false) - qlForRight := kms.NewEmulatedQuantumModule("[::1]:50911", true, os.Stdout, log.TraceLevel, false) - - netLeftUDPAddr, err := net.ResolveUDPAddr("udp", leftUDPAddr) - if err != nil { - log.Fatalf("%s: QuantumlayerEmuPRNG UDP failure: %s", myName, err) - return - } - - netRightUDPAddr, err := net.ResolveUDPAddr("udp", rightUDPAddr) - if err != nil { - log.Fatalf("%s: QuantumlayerEmuPRNG UDP failure: %s", myName, err) - return - } - - // Fire up Quantum LinK - err = emuKMS.AddQuantumElement(qlForLeft) - if err != nil { - log.Println("failed to create emulated quantum module") - return - } - - err = emuKMS.AddQuantumElement(qlForRight) - if err != nil { - log.Println("failed to create emulated quantum module") - return - } - - qlForLeft.QuantumElementLink.AddPeer(netLeftUDPAddr) - qlForRight.QuantumElementLink.AddPeer(netRightUDPAddr) - - peerLeft, err := emuKMS.AddPeer("leftKMS", leftInterComAddr, qlForLeft) - if err != nil { - log.Println(err) - } - - peerRight, err := emuKMS.AddPeer("rightKMS", rightInterComAddr, qlForRight) - if err != nil { - log.Println(err) - } - - // Start the SDN/management and key retrieval interface - go kms.StartETSI(myUDPAddr, emuKMS) - - time.Sleep(time.Second * 15) - if err := peerLeft.SyncBulkKeys(); err != nil { - log.Println("SYNC ERROR: ", err) - } - if err := peerRight.SyncBulkKeys(); err != nil { - log.Println("SYNC ERROR: ", err) - } for { } diff --git a/quantumlayer/quantumlayer-emu-prng.go b/quantumlayer/quantumlayer-emu-prng.go deleted file mode 100644 index 76dcd1dfb268c61a2039e2011dd7eac747ad24c6..0000000000000000000000000000000000000000 --- a/quantumlayer/quantumlayer-emu-prng.go +++ /dev/null @@ -1,357 +0,0 @@ -package quantumlayer - -/* - * - * This packages "implements", actually it only emulates, the output of a - * quantum link, i.e., the transmitted random numbers from one quantum - * sender to a quantum receiver. - * This relies on crypto/rand to generate the random numbers that will be - * transmitted to the other end. - * - */ -import ( - "context" - "crypto/rand" - "encoding/json" - "errors" - "io" - "math/big" - "net" - "sync" - "time" - - "github.com/sirupsen/logrus" - logi "github.com/sirupsen/logrus" -) - -type QuantumPayloadElement struct { - BulkKeyId int64 `json:"bulk-key-id"` // the unique ID of this bulk of keys - BulkKeyLength int `json:"bulk-key-length"` // the length, counted in bytes, of bulkKey - BulkKey *[]byte `json:"bulk-key"` // the bulk key -} - -type QuantumlayerEmuPRNG struct { - configured bool - poweron bool // set to yes if operation, i.e., generating keys - generateKeys bool // set to yes, if this qle should generate random number. - incomingRandNums chan QuantumPayloadElement - peerNumbers *NumberStore - myNumbers *NumberStore - localQLAddress string - udpSrvConn *net.UDPConn - qlPeer string - qlPeerCancel context.CancelFunc - qlLocalPort *net.UDPAddr - qlPeerMutex sync.Mutex -} - -// We use our own logrus instance, as we would like to have different log levels for different parts. -var log = logrus.New() - -func NewQuantumlayerEmuPRNG(logOutput io.Writer, logLevel logi.Level, logInJson bool) (newql *QuantumlayerEmuPRNG) { - /* - * Setup logging - */ - - //What level - log.SetLevel(logLevel) - // Where to send log out put - log.SetOutput(logOutput) - // and plain-text (standard) or json - if !logInJson { - log.SetFormatter(&logi.TextFormatter{}) - } else { - log.SetFormatter(&logi.JSONFormatter{}) - } - // print code function if level is set to Trace - if logLevel == logi.TraceLevel { - log.SetReportCaller(true) - } else { - log.SetReportCaller(false) - } - - // Return PRNG Quantum Layer - return &QuantumlayerEmuPRNG{ - configured: false, - poweron: false, - generateKeys: false, - incomingRandNums: make(chan QuantumPayloadElement), - peerNumbers: NewNumberStore(40000), - myNumbers: NewNumberStore(40000), - qlPeer: "", - } -} - -// Configure the quantum emulation, but do not start if yet -func (qlemuprng *QuantumlayerEmuPRNG) Configure(localQLAddress ...string) { - - // Start receiving numberstores - go qlemuprng.peerNumbers.receiveNumbers(qlemuprng.incomingRandNums) - - // Determine if a local UDP address should be used or not - if len(localQLAddress) == 0 { - // No input - qlemuprng.localQLAddress = ":0" - } else { - qlemuprng.localQLAddress = localQLAddress[0] - } - qlemuprng.configured = true -} - -// Power on the quantum layer, i.e., open up the communication ports for the -// other quantum module -func (qlemuprng *QuantumlayerEmuPRNG) PowerOn(enableKeyGeneration bool) { - if !qlemuprng.configured { - // nothing do here move on - log.Errorf("QuantumlayerEmuPRNG: Sorry, the quantum layer is not configured for action. You've missed Configure()") - return - } - //qlemuprng.poweron = false - log.Infof("QuantumlayerEmuPRNG: is powering on...charging.") - - if enableKeyGeneration { - log.Infof("QuantumlayerEmuPRNG: will GENERATE random keys") - } - qlemuprng.generateKeys = enableKeyGeneration - - // serve UDP incoming - if qlemuprng.udpSrvConn == nil { - go func() { - // Get UDP server part going... - log.Debugf("QuantumlayerEmuPRNG: localQLAddress is %s", qlemuprng.localQLAddress) - - // This reads random numbers from other Quantum end - udpSrvPort, err := net.ResolveUDPAddr("udp", qlemuprng.localQLAddress) - if err != nil { - log.Fatalf("QuantumlayerEmuPRNG: UDP failure: %s", err) - return - } - - qlemuprng.udpSrvConn, err = net.ListenUDP("udp", udpSrvPort) - if err != nil { - log.Fatalf("QuantumlayerEmuPRNG: UDP failure: %s", err) - return - } - defer qlemuprng.udpSrvConn.Close() - - // Retrieve local UDP address and store it for further actions. - qlemuprng.qlLocalPort = qlemuprng.udpSrvConn.LocalAddr().(*net.UDPAddr) - - // TODO: This does not seem to be necessary if the gle is not generating rands - log.Infof("QuantumlayerEmuPRNG: started server, waiting for incoming rands on port %s \n", qlemuprng.udpSrvConn.LocalAddr().(*net.UDPAddr).String()) - inBuffer := make([]byte, 1500) - for { - // Buffer for reading from "Quantum link" - n, addr, err := qlemuprng.udpSrvConn.ReadFromUDP(inBuffer) - if err != nil { - log.Errorf("QuantumlayerEmuPRNG: Could not read from UDP: %s", err) - } else { - log.Debugf("QuantumlayerEmuPRNG: read %d bytes from %s\n", n, addr) - - // Check if sender of datagram is qlPeer - // Warning this is not checking the validity of the sender, i.e., spoofing is possible - if addr.String() == qlemuprng.qlPeer { - log.Debugf("QuantumlayerEmuPRNG: Peer %s listed", addr) - //dumb the received data into the channel and carry on - // TODO/XXX: no vetting for anything - // Unmarshall out of JSON - var inQBuffer QuantumPayloadElement - unmarshallErr := json.Unmarshal(inBuffer[0:n], &inQBuffer) - if unmarshallErr == nil { - qlemuprng.incomingRandNums <- inQBuffer - } - } else { - log.Infof("QuantumlayerEmuPRNG: Peer %s NOT listed", addr) - } - } - } - }() - } - - // Wait for listening UDP socket in the above go-routine to get ready - for qlemuprng.udpSrvConn == nil { - } - - // Ready, set, go! - qlemuprng.poweron = true - - log.Infof("QuantumlayerEmuPRNG: is charged and powered on.") -} - -// Power off the quantum layer, i.e., close the communication ports for the -// other quantum module -func (qlemuprng *QuantumlayerEmuPRNG) PowerOff() { - qlemuprng.poweron = false - log.Println("QuantumlayerEmuPRNG: is powered off...discharging.") -} - -func (qlemuprng *QuantumlayerEmuPRNG) AddPeer(addr *net.UDPAddr) { - if !qlemuprng.poweron { - return - } - //TODO/XXX check the incoming addr - - // Add peer to the .... - qlemuprng.qlPeerMutex.Lock() - qlemuprng.qlPeer = addr.String() - qlemuprng.qlPeerMutex.Unlock() - - // generate only keys if requested to do so. - if qlemuprng.generateKeys { - ctx, cancel := context.WithCancel(context.Background()) - qlemuprng.qlPeerCancel = cancel - - // Start the generation and shipping of random numbers - go func(ctx context.Context) { - for { - select { - case <-ctx.Done(): - return - default: - if qlemuprng.poweron { - // retrieve a new back of random numbers - newNumberBatch := qlemuprng.GenerateRandomNumbers() - // TODO: Replace this by some generic encapsulation reader and not just JSON - //Get JSON for transmission ready - qpe := QuantumPayloadElement{time.Now().UnixNano(), len(newNumberBatch), &newNumberBatch} - - // XXX/TODO: error must be handled - jsonPayload, err := json.Marshal(qpe) - if err != nil { - log.Errorf("QuantumlayerEmuPRNG: json.Marshal error %s", err) - } - - _, _, err = qlemuprng.udpSrvConn.WriteMsgUDP(jsonPayload, nil, addr) - if err != nil { - log.Fatalf("QuantumlayerEmuPRNG: WriteMsgUDPAddrPort failed: %s", err) - } - qlemuprng.incomingRandNums <- qpe - } - // TODO: This sleep timer has to replaced by something for clever. - time.Sleep(5 * time.Second) - } - } - }(ctx) - } -} - -func (qlemuprng *QuantumlayerEmuPRNG) RemovePeer() { - if !qlemuprng.poweron { - return - } - - // Stop the generation and shipping of random numbers - qlemuprng.qlPeerCancel() - - // delete peer - qlemuprng.qlPeerMutex.Lock() - qlemuprng.qlPeer = "" - qlemuprng.qlPeerMutex.Unlock() -} - -func (qlemuprng *QuantumlayerEmuPRNG) GetLocalQLPort() (myAddr *net.UDPAddr) { - return qlemuprng.qlLocalPort -} - -func (qlemuprng *QuantumlayerEmuPRNG) GenerateRandomNumbers() (randNums []byte) { - numRands, randError := rand.Int(rand.Reader, big.NewInt(1000)) - if randError != nil { - log.Fatalf("QuantumlayerEmuPRNG: %s", randError) - return - } - - b := make([]byte, numRands.Uint64()) - _, randError = rand.Read(b) - if randError != nil { - log.Fatalf("QuantumlayerEmuPRNG: %s", randError) - return - } - return b -} - -func (qlemuprng *QuantumlayerEmuPRNG) GetKeyBulkPeer() (QuantumLayerBulkKey, error) { - return qlemuprng.peerNumbers.GetBulk() -} - -// GetStatus returns the current status of the QuantumLayerEmuPRNG. This -// includes the information if the QLE is powered, aswell as if the QLE is -// enabled for key generation. -func (qlemuprng *QuantumlayerEmuPRNG) GetStatus() (poweredOn, enabled bool) { - return qlemuprng.poweron, qlemuprng.generateKeys -} - -type NumberStore struct { - mu sync.Mutex - maxBytes int - storage []byte - bulkKeyStorage []QuantumLayerBulkKey - topOfStorage int -} - -// Generates a new store with given maximum number of bytes -func NewNumberStore(maxBytes int) (newNS *NumberStore) { - return &NumberStore{ - maxBytes: maxBytes, - storage: make([]byte, maxBytes), - topOfStorage: 0, - } -} - -func (store *NumberStore) GetBulk() (bulk QuantumLayerBulkKey, err error) { - store.mu.Lock() - defer store.mu.Unlock() - - for nextID := range store.bulkKeyStorage { - next := store.bulkKeyStorage[nextID] - // Preprare to return - a := QuantumLayerBulkKey{ - BulkKeyId: next.BulkKeyId, - BulkKeyLength: next.BulkKeyLength, - BulkKey: nil, - } - - bulkKey := make([]byte, next.BulkKeyLength) - copy(bulkKey, *next.BulkKey) - a.BulkKey = &bulkKey - - // Delete from key store - store.bulkKeyStorage = store.bulkKeyStorage[1:] - // and return - return a, nil - } - returnErr := errors.New("no bulk key to retrieve") - b := QuantumLayerBulkKey{} - return b, returnErr -} - -func (store *NumberStore) GetBatch() (batch []byte) { - store.mu.Lock() - defer store.mu.Unlock() - - if store.topOfStorage != 0 { - log.Debugf("QuantumlayerEmuPRNG: Have Storage in my belly") - } - // prepare to return full batch of numbers - batchReturn := make([]byte, store.topOfStorage) - copy(batchReturn, store.storage) - store.topOfStorage = 0 - - return batchReturn -} - -func (store *NumberStore) receiveNumbers(incoming chan QuantumPayloadElement) { - for { - receivedNumbers := <-incoming - // add received to our buffer, if buffer still last - store.mu.Lock() - mem := QuantumLayerBulkKey{ - BulkKeyId: receivedNumbers.BulkKeyId, - BulkKeyLength: receivedNumbers.BulkKeyLength, - BulkKey: receivedNumbers.BulkKey, - } - //store.bulkKeyStorage[receivedNumbers.BulkKeyId] = mem - store.bulkKeyStorage = append(store.bulkKeyStorage, mem) - - store.mu.Unlock() - } -} diff --git a/quantumlayer/quantumlayer-emu-prng_test.go b/quantumlayer/quantumlayer-emu-prng_test.go deleted file mode 100644 index d13131d28bc84538bcc86d5896686efac7f78f5c..0000000000000000000000000000000000000000 --- a/quantumlayer/quantumlayer-emu-prng_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package quantumlayer - -// Some tests - -import ( - "fmt" - "net" - "os" - "testing" - "time" - - logrus "github.com/sirupsen/logrus" -) - -func TestQuantumLayer(t *testing.T) { - - // Generate UDPAddr for ql1 peer - udpQL2AddrString := fmt.Sprintf("127.0.0.1:%d", 5002) - udpQL2Addr, err := net.ResolveUDPAddr("udp", udpQL2AddrString) - if err != nil { - t.Fatalf("QuantumlayerEmuPRNG UDP failure: %s", err) - return - } - - // Generate UDPAddr for ql2 peer - udpQL1AddrString := fmt.Sprintf("127.0.0.1:%d", 5001) - udpQL1Addr, err := net.ResolveUDPAddr("udp", udpQL1AddrString) - if err != nil { - t.Fatalf("QuantumlayerEmuPRNG UDP failure: %s", err) - return - } - - ql1 := NewQuantumlayerEmuPRNG(os.Stdout, logrus.DebugLevel, false) - ql1.Configure(udpQL1AddrString) - ql1.PowerOn(true) // this one generates keys - defer ql1.PowerOff() - - ql2 := NewQuantumlayerEmuPRNG(os.Stdout, logrus.DebugLevel, false) - ql2.Configure(udpQL2AddrString) - ql2.PowerOn(false) // this one does NOT generate keys - defer ql2.PowerOff() - - ql1.AddPeer(udpQL2Addr) - ql2.AddPeer(udpQL1Addr) - - // Wait for key gen to get up and running - time.Sleep(5 * time.Second) - - for n := 0; n < 2; n++ { - resultQl1, err := ql1.GetKeyBulkPeer() - if err == nil { - t.Logf("run %d, *ql1* keyid %d \t keylen %d", n, resultQl1.BulkKeyId, resultQl1.BulkKeyLength) - } else { - t.Fatalf("Couldn't read local ql1 batch with error %s", err) - } - - // TODO: Calculate checksum of BulkKey and double-check - - time.Sleep(5 * time.Second) - - } -} diff --git a/quantumlayer/quantumlayer.go b/quantumlayer/quantumlayer.go deleted file mode 100644 index 3399b6b956d942e4a71592819dad4a0f1b91af4b..0000000000000000000000000000000000000000 --- a/quantumlayer/quantumlayer.go +++ /dev/null @@ -1,31 +0,0 @@ -// This package aims at emulating a quantum link and is extendable to different models -// One can use most of the sourc code of emu-prng and reuse it. -// To add a different quantum module one should only modify the GenerateRandomNumbers function - -package quantumlayer - -type QuantumLayerBulkKey struct { - BulkKeyId int64 // the unique ID of this bulk of keys - BulkKeyLength int // the length, counted in bytes, of bulkKey - // TODO: Pointer of slice should have a well thought reason; - // ask Martin if this is really necessary here - BulkKey *[]byte // the bulk key -} - -type QuantumLayer interface { - Configure(...string) // configure the interface, e.g., used IP/Port config if emulated - PowerOn(enableKeyGeneration bool) // switch on the quantum layer element - PowerOff() // switch off the quantum layer element - GetStatus() (poweredOn bool) // returns true if quantum layer element is powered on - AddPeer() // Adds a Quantum Layer Peer to the peer list - RemovePeer() // Remmoves a Quantum Layer Peer to the peer list - GetLocalQLPort() // Returns the information about the local quantum layer IP and port - GetKeyBulkPeer() (QuantumLayerBulkKey, error) // retrieve the bulk key received from peer - GenerateRandomNumbers() []byte // generate a number of random numbers -} - -type NumberLayer interface { - GetBatch() []byte // allows to retrieve the current available batch of numbers - GetBulk() (QuantumLayerBulkKey, error) - receiveNumbers(chan []byte) -}