-
Neil-Jocelyn Schark authoredNeil-Jocelyn Schark authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
kms.go 6.38 KiB
// This package kms implements a simplistic key management system (kms) for
// Quantum Key Distribution Networks (QKDN) which is a simple emulated KMS. x
// It relies on the emulated quantum link out of the quantumlayer package
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/quant/ekms/internal/api/gen/proto/go/kmsetsi"
pbIC "code.fbi.h-da.de/danet/quant/ekms/internal/api/gen/proto/go/kmsintercom"
"code.fbi.h-da.de/danet/quant/ekms/internal/kms/event"
pbQS "code.fbi.h-da.de/danet/quipsec/gen/go/quipsec"
"github.com/google/uuid"
)
type Route struct {
PathId uuid.UUID
Previous *kmsPeer
Next *kmsPeer
}
type BitKeyLength string
const (
BitKeyLen128 BitKeyLength = "128"
BitKeyLen256 BitKeyLength = "256"
BitKeyLen512 BitKeyLength = "512"
)
// The general emulated KMS.
type EKMS struct {
kmsName string
kmsUUID uuid.UUID
interComAddr string
// TODO create a mapping between ids and address
quantumModules map[string]QuantumModule
quantumModulesMutex sync.RWMutex
kmsPeersMutex sync.Mutex
// TODO(maba): find a better name for this
// TODO: add mutex
keysForPathId map[uuid.UUID]string
routingTable map[uuid.UUID]*Route
routingTableMutex sync.RWMutex
KmsPeers map[string]*kmsPeer
pbETSI.UnimplementedKmsETSIServer
pbIC.UnimplementedKmsTalkerServer
supportedKeyLengths map[BitKeyLength]bool
eventBus *event.EventBus
}
// Will keep information about the quantum elements that this EKMS is talking to
// This actually constitutes a quantum element with only a single link
/*
type QuantumElementInterface interface {
GetQlID() qlElementId
}*/
func NewEKMS(kmsName string, kmsUUID uuid.UUID, logOutput io.Writer, logLevel log.Level, logInJson bool, interComAddr string) (newEKMS *EKMS) {
/*
* 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(&log.TextFormatter{})
} else {
log.SetFormatter(&log.JSONFormatter{})
}
// print code function if level is set to Trace
if logLevel == log.TraceLevel {
log.SetReportCaller(true)
} else {
log.SetReportCaller(false)
}
createdEKMS := &EKMS{
kmsName: kmsName,
kmsUUID: kmsUUID,
interComAddr: interComAddr,
quantumModules: make(map[string]QuantumModule),
routingTable: make(map[uuid.UUID]*Route),
KmsPeers: make(map[string]*kmsPeer),
supportedKeyLengths: make(map[BitKeyLength]bool),
eventBus: event.NewEventBus(),
}
createdEKMS.supportedKeyLengths[BitKeyLen256] = true
// start the inter communication gRPC server
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()
log.Info(qm.Address())
kms.quantumModules[qm.Address()] = qm
kms.quantumModulesMutex.Unlock()
return nil
}
func (kms *EKMS) AddPeer(peerKmsId string, kmsPeerSocket string, servingQLE QuantumModule) (*kmsPeer, error) {
// check if peer exists
if _, there := kms.KmsPeers[kmsPeerSocket]; there {
log.Errorf("Trying to add existing peer %s", kmsPeerSocket)
return nil, fmt.Errorf("Trying to add existing peer %s", kmsPeerSocket)
}
peer, err := NewKmsPeer(peerKmsId, servingQLE, kmsPeerSocket, kms.interComAddr, kms.eventBus)
if err != nil {
return nil, err
}
peer.tcpSocketStr = kmsPeerSocket
kms.kmsPeersMutex.Lock()
kms.KmsPeers[kmsPeerSocket] = peer
kms.kmsPeersMutex.Unlock()
// go peer.PeerHandler(kms.kmsName)
return peer, nil
}
func (kms *EKMS) AssignForwardingRoute(pId, pHop, nHop string) error {
pathId, err := uuid.Parse(pId)
if err != nil {
return fmt.Errorf("The given path id %s is no uuid; err = %w", pathId, err)
}
var previousHop *kmsPeer
var nextHop *kmsPeer
var ok bool
if pHop != "" {
previousHop, ok = kms.KmsPeers[pHop]
if !ok {
return fmt.Errorf("No peer found for %s", pHop)
}
}
if nHop != "" {
nextHop, ok = kms.KmsPeers[nHop]
if !ok {
return fmt.Errorf("No peer found for %s", nHop)
}
}
kms.routingTableMutex.Lock()
// set the route within routing table
kms.routingTable[pathId] = &Route{
PathId: pathId,
Previous: previousHop,
Next: nextHop,
}
kms.routingTableMutex.Unlock()
err = kms.eventBus.Publish(event.NewRouteEvent())
if err != nil {
log.Error(err)
}
return nil
}
func (kms *EKMS) EventBus() *event.EventBus {
return kms.eventBus
}
// TODO/XXX error handling.
func (kms *EKMS) RemovePeer(kmsPeerSocket string) {
if _, there := kms.KmsPeers[kmsPeerSocket]; there {
// peer.quit <- true
delete(kms.KmsPeers, kmsPeerSocket)
return
}
log.Errorf("%s: Can not find a peer with socket: %s", kms.kmsName, kmsPeerSocket)
}
func (kms *EKMS) FindPeerUuid(lookup uuid.UUID) (peer *kmsPeer) {
if kms.KmsPeers != nil {
for _, peer = range kms.KmsPeers {
if peer.id == lookup {
return peer
}
}
}
return nil
}
func (kms *EKMS) RoutingTableDeepCopy() map[uuid.UUID]*Route {
copy := make(map[uuid.UUID]*Route, len(kms.KmsPeers))
kms.routingTableMutex.Lock()
for k, v := range kms.routingTable {
copy[k] = v
}
kms.routingTableMutex.Unlock()
return copy
}
func (kms *EKMS) PeersDeepCopy() map[string]*kmsPeer {
copy := make(map[string]*kmsPeer, len(kms.KmsPeers))
kms.kmsPeersMutex.Lock()
for k, v := range kms.KmsPeers {
copy[k] = v
}
kms.kmsPeersMutex.Unlock()
return copy
}