@@ -300,87 +300,147 @@ def etsi_qkd(self):
300300 """
301301 ETSI QKD operations.
302302 """
303- master_node = self .find_kme_node_for_sae (self ._args .master_sae_id )
304- slave_node = self .find_kme_node_for_sae (self ._args .slave_sae_id )
303+ # ETSI QKD 014 uses different terminology than DSKE:
304+ #
305+ # ETSI QKD 014 term DSKE term
306+ # ---------------------------------- ----------------------------------
307+ # SAE (Secure Application Entity) Encryptor
308+ # SAE ID Encryptor name
309+ # KME (Key Management Entity) Client
310+ # KME ID Client name
311+ # N/A Hub
312+ # N/A Hub name
313+ #
314+ # In the code related to ETSI QKD 014, we use the ETSI terminology.
315+
316+ master_sae_id = self ._args .master_sae_id
317+ slave_sae_id = self ._args .slave_sae_id
318+ master_kme_node = self .find_kme_node_for_sae_id (master_sae_id )
319+ slave_kme_node = self .find_kme_node_for_sae_id (slave_sae_id )
305320 match self ._args .etsi_qkd_command :
306321 case "get-status" :
307- self .etsi_qkd_get_status (master_node , slave_node )
322+ self .etsi_qkd_get_status (master_kme_node , master_sae_id , slave_sae_id )
308323 case "get-key" :
309324 size = self ._args .size
310- self .etsi_qkd_get_key (master_node , slave_node , size )
325+ self .etsi_qkd_get_key (
326+ master_kme_node , master_sae_id , slave_sae_id , size
327+ )
311328 case "get-key-with-key-ids" :
312329 key_id = self ._args .key_id
313- self .etsi_qkd_get_key_with_key_ids (master_node , slave_node , key_id )
330+ self .etsi_qkd_get_key_with_key_ids (
331+ slave_kme_node , master_sae_id , slave_sae_id , key_id
332+ )
314333 case "get-key-pair" :
315334 size = self ._args .size
316- self .etsi_qkd_get_key_pair (master_node , slave_node , size )
335+ self .etsi_qkd_get_key_pair (
336+ master_kme_node , slave_kme_node , master_sae_id , slave_sae_id , size
337+ )
317338
318- def find_kme_node_for_sae (self , sae_id : str ) -> Node :
339+ def find_kme_node_for_sae_id (self , sae_id : str ) -> Node :
319340 """
320- Given an SAE ID, find the KME node that is associated with it.
341+ Given an encryptor name ( SAE ID) , find the client node (KME) that is associated with it.
321342 """
322- # $$$
323343 for node in self ._nodes :
324- if node .type == NodeType .CLIENT and node . name == sae_id :
344+ if node .type == NodeType .CLIENT and sae_id in node . encryptor_names :
325345 return node
326- self .fatal_error (f"Could not find KME client node for SAE ID { sae_id } " )
346+ self .fatal_error (
347+ f"There is no encryptor (SAE) in the topology with name (SAE ID) { sae_id } "
348+ )
349+
350+ # In the following ETSI QKD 014 API calls, the master SAE ID neither passed in a request query
351+ # parameter nor passed as a JSON attribute in the request body. In real life, the KME would
352+ # determine the SAE ID from the TLS authentication. However, we only have a simplified
353+ # implementation of ETSI QKD 014 without HTTPS (TLS). For that reason, we pass the master SAE ID
354+ # in cleartext in an HTTP "Authorization" header. This is, of course, not secure, but it is
355+ # sufficient for our simplified implementation and testing purposes.
327356
328- def etsi_qkd_get_status (self , master_node : Node , slave_node : Node ):
357+ def etsi_qkd_get_status (
358+ self ,
359+ master_kme_node : Node ,
360+ master_sae_id : str ,
361+ slave_sae_id : str ,
362+ ):
329363 """
330364 Invoke the ETSI QKD Status API.
331365 """
332366 print (
333- f"Invoke ETSI QKD Status API for client { master_node .name } on port { master_node .port } "
367+ f"Invoke ETSI QKD Status API on client { master_kme_node .name } "
368+ f"on port { master_kme_node .port } "
369+ )
370+ url = f"{ master_kme_node .base_url } /etsi/api/v1/keys/{ slave_sae_id } /status"
371+ self .http_request (
372+ "GET" ,
373+ url ,
374+ "ETSI QKD Get status" ,
375+ headers = {"Authorization" : master_sae_id },
334376 )
335- url = f"{ master_node .base_url } /etsi/api/v1/keys/{ slave_node .name } /status"
336- self .http_request ("GET" , url , "ETSI QKD Get status" )
337377
338378 def etsi_qkd_get_key (
339379 self ,
340- master_node : Node ,
341- slave_node : Node ,
380+ master_kme_node : Node ,
381+ master_sae_id : str ,
382+ slave_sae_id : str ,
342383 size : int | None ,
343384 ) -> None | dict :
344385 """
345386 Invoke the ETSI QKD Get Key API.
346387 """
347388 print (
348- f"Invoke ETSI QKD Get Key API for client { master_node .name } on port { master_node .port } "
389+ f"Invoke ETSI QKD Get Key API on client { master_kme_node .name } "
390+ f"on port { master_kme_node .port } "
349391 )
350- url = f"{ master_node .base_url } /etsi/api/v1/keys/{ slave_node . name } /enc_keys"
392+ url = f"{ master_kme_node .base_url } /etsi/api/v1/keys/{ slave_sae_id } /enc_keys"
351393 params = {}
352394 if size is not None :
353395 params ["size" ] = size
354- response = self .http_request ("GET" , url , "ETSI QKD Get key" , params = params )
396+ response = self .http_request (
397+ "GET" ,
398+ url ,
399+ "ETSI QKD Get key" ,
400+ params = params ,
401+ headers = {"Authorization" : master_sae_id },
402+ )
355403 return response
356404
357405 def etsi_qkd_get_key_with_key_ids (
358- self , master_node : Node , slave_node : Node , key_id : str
406+ self ,
407+ slave_kme_node : Node ,
408+ master_sae_id : str ,
409+ slave_sae_id : str ,
410+ key_id : str ,
359411 ) -> None | dict :
360412 """
361413 Invoke the ETSI QKD Get Key with Key IDs API.
362414 """
363415 print (
364- f"Invoke ETSI QKD Get Key with Key IDs API for client { slave_node .name } "
365- f"on port { slave_node .port } "
416+ f"Invoke ETSI QKD Get Key with Key IDs API on client { slave_kme_node .name } "
417+ f"on port { slave_kme_node .port } "
366418 )
367- url = f"{ slave_node .base_url } /etsi/api/v1/keys/{ master_node . name } /dec_keys"
419+ url = f"{ slave_kme_node .base_url } /etsi/api/v1/keys/{ master_sae_id } /dec_keys"
368420 params = {"key_ID" : key_id }
369421 response = self .http_request (
370- "GET" , url , "ETSI QKD Get key with key IDs" , params = params
422+ "GET" ,
423+ url ,
424+ "ETSI QKD Get key with key IDs" ,
425+ params = params ,
426+ headers = {"Authorization" : slave_sae_id },
371427 )
372428 return response
373429
374430 def etsi_qkd_get_key_pair (
375431 self ,
376- master_node : Node ,
377- slave_node : Node ,
432+ master_kme_node : Node ,
433+ slave_kme_node : None ,
434+ master_sae_id : str ,
435+ slave_sae_id : str ,
378436 size : int | None ,
379437 ):
380438 """
381439 Invoke the ETSI QKD Get Key API on master, followed by Get Key with Key IDs API on slave.
382440 """
383- master_response = self .etsi_qkd_get_key (master_node , slave_node , size )
441+ master_response = self .etsi_qkd_get_key (
442+ master_kme_node , master_sae_id , slave_sae_id , size
443+ )
384444 if master_response is None :
385445 return
386446 if master_response .status_code != 200 :
@@ -389,7 +449,7 @@ def etsi_qkd_get_key_pair(
389449 key_id = master_response_json ["keys" ]["key_ID" ]
390450 master_key_value = master_response_json ["keys" ]["key" ]
391451 slave_response = self .etsi_qkd_get_key_with_key_ids (
392- master_node , slave_node , key_id
452+ slave_kme_node , master_sae_id , slave_sae_id , key_id
393453 )
394454 if slave_response is None :
395455 return
@@ -408,13 +468,20 @@ def http_request(
408468 url : str ,
409469 action : str | None ,
410470 params : dict | None = None ,
471+ headers : dict | None = None ,
411472 quiet_success : bool = False ,
412473 ) -> httpx .Response :
413474 """
414475 Make an HTTP request.
415476 """
416477 try :
417- response = httpx .request (method = method , url = url , params = params , timeout = 1.0 )
478+ response = httpx .request (
479+ method = method ,
480+ url = url ,
481+ params = params ,
482+ headers = headers ,
483+ timeout = 1.0 ,
484+ )
418485 except httpx .HTTPError as exc :
419486 if action is not None :
420487 print (f"Failed to { action } : { method } { url } raised exception { exc } " )
0 commit comments