-
Malte Bauch authored
See merge request !229
Malte Bauch authoredSee merge request !229
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
etsi14Quantummodule.go 6.75 KiB
package peers
import (
"context"
"fmt"
"net/http"
"net/url"
"time"
etsi14ClientGenerated "code.fbi.h-da.de/danet/quant/etsi014/go/rest/etsi/client"
pbIC "code.fbi.h-da.de/danet/quant/goKMS/api/gen/proto/go/kmsintercom"
"code.fbi.h-da.de/danet/quant/goKMS/config"
etsi14ClientImpl "code.fbi.h-da.de/danet/quant/goKMS/kms/etsi/etsi14/client"
"code.fbi.h-da.de/danet/quant/goKMS/kms/event"
"code.fbi.h-da.de/danet/quant/goKMS/kms/store"
kmstls "code.fbi.h-da.de/danet/quant/goKMS/kms/tls"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
)
type ETSI014HTTPQuantumModule struct {
id uuid.UUID
kmsId string
addr string
keyStore *store.KmsKeyStore
kmsClient *GRPCClient
client *etsi14ClientImpl.ClientImpl
localSAEID string
targetSAEID string
master bool
keyFetchInterval int
keyFetchAmount int64
maxKeyFillLevel uint64
stopFetch context.CancelFunc
active bool
}
func NewETSI014HTTPQuantumModule(addr, kmsId, localSAEID, targetSAEID string, tlsConfig config.TLSConfig, master bool, keyFetchInterval int, keyFetchAmount int64, maxKeyFillLevel uint64) (*ETSI014HTTPQuantumModule, error) {
parsedUrl, err := url.Parse(addr)
if err != nil {
return nil, err
}
restClientConf := &etsi14ClientGenerated.Configuration{
Debug: true,
Servers: etsi14ClientGenerated.ServerConfigurations{
{
URL: parsedUrl.String(),
Description: "QKD Module with ETSI14 implemented as API.",
},
},
Scheme: parsedUrl.Scheme,
}
if tlsConfig.Active {
tlsConf, err := kmstls.GenerateTLSLibraryConfig(tlsConfig)
if err != nil {
return nil, fmt.Errorf("unable to generate TLS config: %w", err)
}
restClientConf.HTTPClient = &http.Client{
Transport: &http.Transport{
TLSClientConfig: tlsConf,
},
}
}
client, err := etsi14ClientImpl.NewClientImpl(restClientConf)
if err != nil {
return nil, err
}
// set defaults for key fetching if not defined in config
if keyFetchInterval == 0 {
keyFetchInterval = defaultKeyFetchInterval
}
if keyFetchAmount == 0 {
keyFetchAmount = defaultKeyFetchAmount
}
if maxKeyFillLevel == 0 {
maxKeyFillLevel = DefaultMaxKeyFillLevel
}
return &ETSI014HTTPQuantumModule{
id: uuid.New(),
kmsId: kmsId,
addr: addr,
keyStore: store.NewKmsKeyStore(256),
kmsClient: nil,
client: client,
localSAEID: localSAEID,
targetSAEID: targetSAEID,
master: master,
keyFetchInterval: keyFetchInterval,
keyFetchAmount: keyFetchAmount,
maxKeyFillLevel: maxKeyFillLevel,
active: false,
}, nil
}
func (qm *ETSI014HTTPQuantumModule) ID() uuid.UUID {
return qm.id
}
func (qm *ETSI014HTTPQuantumModule) Client() *etsi14ClientImpl.ClientImpl {
return qm.client
}
func (qm *ETSI014HTTPQuantumModule) Initialize() error {
if !qm.active {
var ctx context.Context
ctx, qm.stopFetch = context.WithCancel(context.Background())
qm.active = true
// start polling keys
if qm.master {
go func() {
restartWaitingTime := time.Duration(2) * time.Minute
ticker := time.NewTicker(restartWaitingTime)
defer ticker.Stop()
RestartFetchLoop:
for {
// immediately start with the ticker instead of waiting the defined amount
qm.doKeyFetching(ctx)
select {
case <-ticker.C:
continue
case <-ctx.Done():
break RestartFetchLoop
}
}
}()
}
}
return nil
}
func (qm *ETSI014HTTPQuantumModule) Reset() {
if qm.master && qm.stopFetch != nil {
qm.stopFetch()
}
qm.active = false
qm.KeyStore().Reset()
}
func (qm *ETSI014HTTPQuantumModule) MaxKeyFillLevel() uint64 {
return qm.maxKeyFillLevel
}
func (qm *ETSI014HTTPQuantumModule) SetActive(active bool) {
qm.active = active
}
func (qm *ETSI014HTTPQuantumModule) IsActive() bool {
return qm.active
}
func (qm *ETSI014HTTPQuantumModule) SetKmsPeerInformation(kmsClient *GRPCClient, kmsEventBus *event.EventBus, kmsTcpSocketStr string) error {
qm.kmsClient = kmsClient
return nil
}
func (qm *ETSI014HTTPQuantumModule) Address() string {
return qm.addr
}
func (qm *ETSI014HTTPQuantumModule) KeyStore() *store.KmsKeyStore {
return qm.keyStore
}
func (qm *ETSI014HTTPQuantumModule) SetKeyStore(newKeyStore *store.KmsKeyStore) {
qm.keyStore = newKeyStore
}
func (qm *ETSI014HTTPQuantumModule) Sync() error {
return nil
}
func (qm *ETSI014HTTPQuantumModule) KmsGrpcClient() *GRPCClient {
return nil
}
func (qm *ETSI014HTTPQuantumModule) SetKmsGrpcClient(peer *GRPCClient) {
}
func (qm *ETSI014HTTPQuantumModule) GetKeys(number int64, size int64, additionalTargetSAEIDs []string, extensionMandatory []map[string]string, extensionOptional []map[string]string) (*etsi14ClientGenerated.KeyContainer, error) {
container, _, err := qm.client.GetKeyPost(qm.targetSAEID, number, size, additionalTargetSAEIDs, extensionMandatory, extensionOptional)
if err != nil {
return nil, err
}
if len(container.GetKeys()) == 0 {
return nil, fmt.Errorf("no key received, length of key container was: %d", len(container.GetKeys()))
}
return container, nil
}
func (qm *ETSI014HTTPQuantumModule) GetKeyWithIds(keyIds []etsi14ClientGenerated.KeyIDsRequestKeyIDsInner) (*etsi14ClientGenerated.KeyContainer, error) {
container, _, err := qm.client.GetKeyWithIdPost(qm.targetSAEID, keyIds)
if err != nil {
return nil, err
}
if len(container.GetKeys()) == 0 {
return nil, fmt.Errorf("no key received, length of key container was: %d", len(container.GetKeys()))
}
return container, nil
}
func (qm *ETSI014HTTPQuantumModule) doKeyFetching(ctx context.Context) {
ticker := time.NewTicker(time.Duration(qm.keyFetchInterval) * time.Second)
defer ticker.Stop()
failedAttemps := 0
FetchLoop:
for {
select {
case <-ticker.C:
if failedAttemps == maxFailedKeyRequestAttempts {
log.Errorf("stopped trying to fetch keys from qkd module after %d tries", failedAttemps)
break FetchLoop
}
if qm.keyStore.Length() < int(qm.maxKeyFillLevel) {
container, err := qm.GetKeys(qm.keyFetchAmount, 256, nil, nil, nil)
if err != nil {
log.Error(err)
failedAttemps++
continue
}
keyIds := make([]string, len(container.GetKeys()))
for i, keyItem := range container.GetKeys() {
keyIds[i] = keyItem.GetKeyID()
}
_, err = qm.kmsClient.KeyIdNotification(context.Background(),
&pbIC.KeyIdNotificationRequest{
Timestamp: time.Now().Unix(),
KmsId: qm.kmsId,
KeyIds: keyIds,
})
if err != nil {
log.Error(err)
failedAttemps++
continue
}
err = store.AddETSIKeysToKeystore(qm.keyStore, container.GetKeys())
if err != nil {
log.Error(err)
failedAttemps++
continue
}
failedAttemps = 0
}
case <-ctx.Done():
break FetchLoop
}
}
}