Skip to content
Snippets Groups Projects
kms.go 6.38 KiB
Newer Older
  • Learn to ignore specific revisions
  • // 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 (
    
    	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"
    
    type Route struct {
    
    	Previous *kmsPeer
    	Next     *kmsPeer
    }
    
    
    type BitKeyLength string
    
    const (
    	BitKeyLen128 BitKeyLength = "128"
    	BitKeyLen256 BitKeyLength = "256"
    	BitKeyLen512 BitKeyLength = "512"
    )
    
    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
    
    Malte Bauch's avatar
    Malte Bauch committed
    	// 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
    
    // 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
    
    Malte Bauch's avatar
    Malte Bauch committed
    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
    
    	// 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)
    		}
    	}
    
    
    	kms.routingTableMutex.Lock()
    
    	// set the route within routing table
    	kms.routingTable[pathId] = &Route{
    
    		Previous: previousHop,
    		Next:     nextHop,
    	}
    
    	kms.routingTableMutex.Unlock()
    
    	err = kms.eventBus.Publish(event.NewRouteEvent())
    	if err != nil {
    		log.Error(err)
    	}
    
    func (kms *EKMS) EventBus() *event.EventBus {
    	return kms.eventBus
    }
    
    
    // TODO/XXX error handling
    
    func (kms *EKMS) RemovePeer(kmsPeerSocket string) {
    
    Malte Bauch's avatar
    Malte Bauch committed
    	if _, there := kms.KmsPeers[kmsPeerSocket]; there {
    
    		// peer.quit <- true
    
    Malte Bauch's avatar
    Malte Bauch committed
    		delete(kms.KmsPeers, kmsPeerSocket)
    		return
    	}
    
    	log.Errorf("%s: Can not find a peer with socket: %s", kms.kmsName, kmsPeerSocket)
    
    Malte Bauch's avatar
    Malte Bauch committed
    	return
    
    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
    }