Select Git revision
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
kms.go 6.44 KiB
// This package kms implements a simplistic key managment 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/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"
)
//type Qkdnkms interface {
// //AddExternalNotifierGeneral(chan bool) // used to indicate unspecific changes
// AddExternalNotifierQLE(chan uint32) // used to indicate changes to specific Quantum Link Element (QLE)
// AddExternalNotifierKMSPeer(chan string) // used to indicate changes to specific KMSPeer
// AddQuantumElement() *EmulatedQuantumModule
// GlobalKeyHandler(time.Duration) error
// AddPeer(kmsPeerSocket string, servingQLE *EmulatedQuantumModule)
// RemovePeer(kmsPeerSocket string)
// FindPeerUuid(uuid.UUID) *kmsPeer
//}
type Route struct {
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
qleMapMutex sync.Mutex
quantumModules map[string]QuantumModule
quantumModulesMutex sync.RWMutex
externalNotifierQLE chan uint32
kmsPeersMutex sync.Mutex
// TODO(maba): find a better name for this
// TODO: add mutex
keysForPathId map[uuid.UUID]string
routingTable map[uuid.UUID]*Route
KmsPeers map[string]*kmsPeer
externalNotifierKMSPeer chan string
pbETSI.UnimplementedKmsETSIServer
pbIC.UnimplementedKmsTalkerServer
supportedKeyLengths map[BitKeyLength]bool
}
// 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),
externalNotifierQLE: nil, // just be surely set to nil!
externalNotifierKMSPeer: nil, // just be surely set to nil!
supportedKeyLengths: make(map[BitKeyLength]bool),
}
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.externalNotifierKMSPeer)
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 = ", 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)
}
}
// set the route within routing table
kms.routingTable[pathId] = &Route{
Previous: previousHop,
Next: nextHop,
}
return nil
}
// 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)
return
}
func (kms *EKMS) AddExternalNotifierQLE(in chan uint32) {
kms.externalNotifierQLE = in
}
func (kms *EKMS) AddExternalNotifierKMSPeer(in chan string) {
kms.externalNotifierKMSPeer = in
}
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
}