diff --git a/README.md b/README.md index 1715e68b55d4d7570d51c75418b96d689a84692a..ce189ceee6830e44a839df07f9cc522bb05002a6 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ V1.1.1 did not include an OpenAPI description. ## Visualise View draft API in -[Swagger Editor](https://forge.etsi.org/swagger/editor-versions/v3.8.0/?url=https://forge.etsi.org/rep/qkd/gs014-key-deliv/raw/edition2/key-deliv.yaml). +[Swagger Editor](https://forge.etsi.org/swagger/editor-versions/v3.8.0/?url=https://forge.etsi.org/rep/qkd/gs014-key-deliv/raw/wrk-initial-openapi/key-deliv.yaml). ## Related ISG QKD Repositories diff --git a/key-deliv.yaml b/key-deliv.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fae667dbc9a6fa74c12d12bd23ddd1aa3f686c84 --- /dev/null +++ b/key-deliv.yaml @@ -0,0 +1,701 @@ +# Copyright 2024 ETSI +# Licensed under the BSD-3 Clause (https://forge.etsi.org/legal-matters) +openapi: '3.0.3' +info: + title: Draft ETSI GS QKD 014 - Protocol and data format of REST-based key delivery for QKD + description: | + The present document describes a communication protocol and data + format for a quantum key distribution (QKD) network to supply + cryptographic keys to an application. It is intended to allow + interoperability of equipment from different vendors. A REST + (REpresentational State Transfer) API is specified as a simple, + scalable, widely deployed approach that is familiar to a large + developer community. The REST-based API specifies the format of + the URIs, the communication protocols (HTTPS), and the JSON + (JavaScript Object Notation) data format encoding of posted + parameters and responses, including key material. + contact: + name: ETSI ISG QKD + email: 'isgsupport@etsi.org' + version: '1.2.2' + license: + name: BSD 3-Clause + url: https://opensource.org/licenses/BSD-3-Clause +servers: +- url: http://{kme_hostname} + description: Local KME server + variables: + kme_hostname: + default: '127.0.0.1:443' +externalDocs: + description: 'Work Item description' + url: 'https://portal.etsi.org/webapp/WorkProgram/Report_WorkItem.asp?WKI_ID=69542' + +tags: + - name: Introduction + description: | + Quantum key distribution (QKD) networks connect nodes using QKD + links for the generation of cryptographic keys. Applications need + to be able to request key material from QKD Systems and their + associated Key Management Systems (KMSs). This document defines a + key delivery specification to ensure interoperability between QKD + networks, equipment, and applications offered by different vendors. + + The Application Programming Interface (API) defined in this + document utilizes a REST-based approach. This API operates over + the HTTPS protocol and encodes data in the JSON format, allowing + the secure delivery of block keys with key IDs to applications. + + REST-based APIs are popular across various application domains as + a result of their simplicity. Indeed, various software libraries + are available off-the-shelf to implement REST-based API + interactions, and for parsing JSON data. + + - name: Connection Specification + description: | + The common specifications for the Key Delivery API are as follows: + + | Name | Description | + |---------------------|--------------------------------------------------| + | Communication Protocol | HTTPS | + | Character code | UTF-8 | + | HTTP Content-type | application/json | + + SAEs shall connect to KMEs using HTTPS protocols with Transport + Layer Security (TLS) version 1.3 (or higher). At the connection + establishment, mutual authentication between the SAE and KME + shall be performed. + + The SAE shall verify the validity of the certificate possessed + by the KME and confirm the KME ID based on the certificate. If the + KME certificate is not valid, the SAE will not proceed to use the + API with the KME. + + Similarly, the KME shall verify the validity of the certificate + possessed by the SAE and confirm its SAE ID based on the + certificate. Practically, X.509 certificates should be used where + the identifying information is specified as a Distinguished Name (DN). + Specifically, the SAE's ID should be included as the UID field of + the DN or if that is not possible, as the Common Name (CN). If the + certificate is invalid, or if the SAE ID in the certificate does not + match the SAE ID for which the API call refers to, the KME will + reject the API call. + + - name: Protocol Specification + description: | + The list of available API methods shall be as follows. + +paths: + + /kdapi/versions: + get: + summary: 'Get supported API versions' + operationId: get-versions + tags: + - 'Protocol Specification' + description: | + Returns list of supported ETSI GS QKD 014 API versions. + + When an SAE makes a request to a KME, it should always use the most + recent version of the API that the KME and SAE support. The SAE can + use this end-point to determine which API versions the KME supports. + Note that this endpoint was introduced in v2 (ADD ETSI VERSION + NUMBER HERE ONCE FINALISED). Thus, if an SAE does not receive a + response from a KME using this call, it should use v1 (i.e. + ETSI GS QKD 014 V1.1.1). + responses: + '200': + description: Supported versions + content: + application/json: + schema: + $ref: '#/components/schemas/version_container' + '401': + $ref: '#/components/responses/401-unauthorized' + '503': + $ref: '#/components/responses/503-error' + + /kdapi/v2/status: + post: + summary: Get status of KME + operationId: post-v2-status + tags: + - 'Protocol Specification' + description: Returns KME status. Status contains information about the KME. + responses: + '200': + description: KME status + content: + application/json: + schema: + $ref: '#/components/schemas/kme_status' + '401': + $ref: '#/components/responses/401-unauthorized' + '503': + $ref: '#/components/responses/503-error' + + /kdapi/v2/status/link: + post: + summary: Get link status + operationId: post-v2-status-link + tags: + - 'Protocol Specification' + description: | + Returns status for one or more QKD links between Initiator and + Target SAEs. + + If both `initiator_sae_id` and `target_sae_id` are specified in the + request body, a single status container is returned containing + information on keys available to be requested by the initiator SAE + for the specified target SAE. + + If only `initiator_sae_id` is specified in the request body, a + status container will be returned for each link where the calling + SAE is the specified initiator SAE. + + If only `target_sae_id` is specified in the request body, a status + container will be returned for each link where the target SAE is + the specified target SAE. + + If neither `initiator_sae_id` nor `target_sae_id` are specified, + an Error Code 400 is returned. + requestBody: + description: Link status request. + content: + application/json: + schema: + $ref: '#/components/schemas/link_status_request' + responses: + '200': + description: Array of link statuses + content: + application/json: + schema: + $ref: '#/components/schemas/array_link_status' + '400': + $ref: '#/components/responses/400-badrequest' + '401': + $ref: '#/components/responses/401-unauthorized' + '503': + $ref: '#/components/responses/503-error' + + /kdapi/v2/keys: + post: + summary: 'Get key' + operationId: post-v2-keys + tags: + - 'Protocol Specification' + description: | + Returns Key container data from the KME to the calling initiator SAE. + + Key container data contains one or more keys. The calling initiator + SAE may supply Key request data to specify the requirement on Key + container data. The target SAE specified by the target_sae_id parameter + may subsequently request matching keys from a remote KME using key_id + identifiers from the returned Key container. + requestBody: + description: Key request. + content: + application/json: + schema: + $ref: '#/components/schemas/key_request' + responses: + '200': + $ref: '#/components/responses/200-getkey' + '400': + $ref: '#/components/responses/400-badrequest' + '401': + $ref: '#/components/responses/401-unauthorized' + '503': + $ref: '#/components/responses/503-error' + + /kdapi/v2/keys_with_id: + post: + summary: 'Get key with key ID' + operationId: post-v2-keys_with_id + tags: + - 'Protocol Specification' + description: | + Returns "Key container" from the KME to the calling target SAE. + + Key container contains keys matching those previously delivered to + a remote initiator SAE based on the Key IDs supplied from the remote + initiator SAE in response to its call to Get key. The KME shall + reject the request with a 401 HTTP status code if the SAE ID of the + requestor was not an SAE ID supplied to the "Get key" method each + time it was called resulting in the return of any of the Key IDs + being requested. + requestBody: + description: Key ID request. + content: + application/json: + schema: + $ref: '#/components/schemas/key_id_container' + responses: + '200': + $ref: '#/components/responses/200-getkey' + '400': + $ref: '#/components/responses/400-badrequest' + '401': + $ref: '#/components/responses/401-unauthorized' + '503': + $ref: '#/components/responses/401-unauthorized' + +components: + responses: + 200-getkey: + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/key_container' + + 400-badrequest: + description: Bad request format response + content: + application/json: + schema: + $ref: '#/components/schemas/message_data' + examples: + missing_parameters: + value: + message: 'missing parameters' + details: + - 'missing_parameters': 'required parameters are missing from the API call' + + 401-unauthorized: + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/message_data' + example: + message: 'unauthorized' + details: + - 'unauthorized': 'User-supplied certificate is invalid.' + + 503-error: + description: Error of server side response + content: + application/json: + schema: + $ref: '#/components/schemas/message_data' + example: + message: 'server side general error' + details: + - 'server_side_general_error': 'The server encountered a general failure and cannot respond.' + + schemas: + kme_id: + type: string + example: kme1 + description: KME ID of the KME + + initiator_kme_id: + type: string + example: kme1 + description: KME ID of the KME + + target_kme_id: + type: string + example: kme2 + description: KME ID of the target KME + + initiator_sae_id: + type: string + description: ID of the SAE that initiated the request to share the key(s) relevant to the request. + example: encryptor1 + + target_sae_id: + type: string + description: ID of target SAE that the initiator SAE wishes to share keys with. + example: encryptor2 + + target_sae_ids: + type: array + description: >- + Array of IDs of target SAEs that the initiator SAE wishes to share keys with. + A single target or multiple targets can be specified. Specified target SAEs + will each be allowed to retrieve an identical key, as returned to the + initiator SAE. The maximum number of IDs is defined as `max_sae_id_count` + in Status data format. Support of more than one `target_sae_ids` (multicast) + is optional and not widely implemented at the time of writing. + items: + $ref: '#/components/schemas/target_sae_id' + + size: + type: integer + description: >- + Size of key(s) requested in bits. If the requested size not supported the + request will be rejected. A client can query `status/link` and consider + `fractional_byte_support`, `min_key_size` and `max_key_size` in order to make + a valid request. + example: 256 + + number: + description: 'Number of keys requested (default value is 1).' + type: integer + default: 1 + example: 20 + + key_size: + type: integer + description: >- + Where a KME wishes to indicate a preferred or recommended size of key for + SAEs to request it can return a `key_size` in bits within the Link status + data format. Note that support for non-integer-byte-sizes is optional + (such support is available when `fractional_byte_support` is set in the + Link status data format with a value of `true`). + example: 256 + + stored_key_count: + type: integer + description: Number of stored keys KME can deliver to the SAE + example: 25000 + + max_key_count: + type: integer + description: Maximum number of stored_key_count + example: 100000 + + max_key_per_request: + type: integer + description: Maximum number of keys per request + example: 128 + + max_key_size: + type: integer + description: Maximum size of key the KME can deliver to the SAE (in bits) + example: 1024 + + min_key_size: + type: integer + description: Minimum size of key the KME can deliver to the SAE (in bits) + example: 64 + + max_sae_id_count: + type: integer + description: >- + Maximum number of additional target_sae_ids the KME allows. + `0` when the KME does not support key multicast. + example: 0 + + delivered_key_count: + type: integer + description: Total number of keys delivered by KME to the calling initiator SAE + example: 10 + + delivered_key_bits: + type: integer + description: Total number of bits delivered by KME to the calling initiator SAE + example: 2560 + + uptime: + type: string + description: Uptime of KME (ISO8601 time duration format) + example: 'P1Y2M10DT2H30M59S' + + fractional_byte_support: + type: boolean + description: >- + Non-integer-byte-size keys are supported for relevant keys when true. + When absent or false non-integer-byte-size keys are not supported. + example: true + + time_to_fetch: + type: integer + minimum: 1 + maximum: 2147483647 + description: >- + How many seconds to expect relevant keys to be available for requests + using `keys_with_id` from the queried KME after being requested on a + remote KME using the `keys` method. + example: 90 + + extension_mandatory: + type: object + additionalProperties: + type: object + additionalProperties: true + description: >- + Dictionary of objects representing extension parameters that KME shall + handle or return an error. Objects may be of any type. + example: + abc_route_type: 'direct' + abc_method: + hybrid_keys: true + primary: 'qkd' + secondary: 'pqc' + + extension_optional: + type: object + additionalProperties: + type: object + additionalProperties: true + description: >- + Dictionary of objects representing extension parameters that KME may + ignore. Objects may be of any type. + example: + abc_module_type: + vendor: 'Company ABC' + protocol: 'BB84' + min_version: 2.5 + abc_qos_session: 'e73d9abe' + + key_id: + description: 'ID of the key: UUID format.' + type: string + format: uuid + example: '550e8400-e29b-41d4-a716-446655440000' + + value: + description: | + Key data encoded by the base64 data encoding scheme specified in IETF + RFC 4648 (October 2006): "The Base16, Base32, and Base64 Data Encodings" + [7] using the alphabet in Table 1 of the RFC. + + Implementations shall ensure that padding used in the base64 data + encoding scheme is never used as key material. This includes the + zero, two, or one `=` padding characters at the end of the final + encoded unit of output where the final quantum of encoding input + is exactly 24 bits, 8 bits, or 16 bits, respectively. + + When non-integer-byte-size keys are used it is essential to + strip any padding bits with value zero that were added (on the + right) when decoding. It is not safe to strip all bits with + value zero from the end of the decoded key since this can bias + keys. Decoding needs to make use of independent knowledge of + the requested key size to correctly strip such padding in order to + recover a valid key. (The base64 data encoding scheme and the `=` + padding character rules it includes can only indicate the size of + the encoding input in integer byte sizes. The final character + of the encoded output or the final character before the first + `=` padding character can include information from padding bits + with value zero that were added when during encoding in the case + of non-integer-byte-size keys.) + + Note that support for non-integer-byte-size keys is optional and + many vendors choose to support only integer byte sizes. + + The key size is always specified by the "size" parameter to "Get key" + and an application needs to ensure that all SAEs know the requested + key size when non-integer-byte-size keys are used. + + type: string + example: 'wHHVxRwDJs3/bXd38GHP3oe4svTuRpZS0yCC7x4Ly+s=' + + extension: + type: object + additionalProperties: + type: object + additionalProperties: true + description: 'Reserved for future use. Dictionary of objects.' + example: + abc_extension1: 'Some string' + abc_extension2: + property1: 10111 + property2: 'Some text' + property3: + subprop1: 21 + subprop2: true + keys: + type: array + description: >- + Array of keys. The number of keys is specified by the "number" parameter + in "Get key". If not specified, the default number of keys is 1. + items: + type: object + required: + - key_id + - value + properties: + key_id: + $ref: '#/components/schemas/key_id' + value: + $ref: '#/components/schemas/value' + extension: + $ref: '#/components/schemas/extension' + + key_ids: + type: array + description: 'Array of key IDs.' + items: + $ref: '#/components/schemas/key_id' + + version: + type: string + description: 'Supported API version.' + example: 'v1' + + versions: + type: array + description: 'Array of supported API versions.' + items: + $ref: '#/components/schemas/version' + example: ['v1', 'v2'] + + version_container: + title: 'Version container' + type: object + required: + - versions + properties: + versions: + $ref: '#/components/schemas/versions' + extension: + $ref: '#/components/schemas/extension' + + link_status_request: + title: 'Link status request' + type: object + properties: + initiator_sae_id: + $ref: '#/components/schemas/initiator_sae_id' + target_sae_id: + $ref: '#/components/schemas/target_sae_id' + extension: + $ref: '#/components/schemas/extension' + + link_status: + title: 'Link status' + type: object + required: + - initiator_kme_id + - target_kme_id + - initiator_sae_id + - target_sae_id + - key_size + - stored_key_count + - max_key_count + - max_key_per_request + - max_key_size + - min_key_size + - max_sae_id_count + properties: + initiator_kme_id: + $ref: '#/components/schemas/initiator_kme_id' + target_kme_id: + $ref: '#/components/schemas/target_kme_id' + initiator_sae_id: + $ref: '#/components/schemas/initiator_sae_id' + target_sae_id: + $ref: '#/components/schemas/target_sae_id' + key_size: + $ref: '#/components/schemas/key_size' + stored_key_count: + $ref: '#/components/schemas/stored_key_count' + max_key_count: + $ref: '#/components/schemas/max_key_count' + max_key_per_request: + $ref: '#/components/schemas/max_key_per_request' + max_key_size: + $ref: '#/components/schemas/max_key_size' + min_key_size: + $ref: '#/components/schemas/min_key_size' + max_sae_id_count: + $ref: '#/components/schemas/max_sae_id_count' + delivered_key_count: + $ref: '#/components/schemas/delivered_key_count' + delivered_key_bits: + $ref: '#/components/schemas/delivered_key_bits' + fractional_byte_support: + $ref: '#/components/schemas/fractional_byte_support' + time_to_fetch: + $ref: '#/components/schemas/time_to_fetch' + extension: + $ref: '#/components/schemas/extension' + + array_link_status: + title: 'Array of link statuses' + type: array + items: + $ref: '#/components/schemas/link_status' + + kme_status: + title: 'KME status' + type: object + required: + - kme_id + - uptime + properties: + kme_id: + $ref: '#/components/schemas/kme_id' + uptime: + $ref: '#/components/schemas/uptime' + extension: + $ref: '#/components/schemas/extension' + + key_request: + title: 'Key request container' + type: object + required: + - initiator_sae_id + - target_sae_ids + - size + properties: + initiator_sae_id: + $ref: '#/components/schemas/initiator_sae_id' + target_sae_ids: + $ref: '#/components/schemas/target_sae_ids' + number: + $ref: '#/components/schemas/number' + size: + $ref: '#/components/schemas/size' + extension_mandatory: + $ref: '#/components/schemas/extension_mandatory' + extension_optional: + $ref: '#/components/schemas/extension_optional' + + key_container: + title: 'Key container' + type: object + required: + - keys + properties: + keys: + $ref: '#/components/schemas/keys' + extension: + $ref: '#/components/schemas/extension' + + key_id_container: + title: 'Key IDs container' + type: object + required: + - initiator_sae_id + - target_sae_id + properties: + initiator_sae_id: + $ref: '#/components/schemas/initiator_sae_id' + target_sae_id: + $ref: '#/components/schemas/target_sae_id' + key_ids: + $ref: '#/components/schemas/key_ids' + extension: + $ref: '#/components/schemas/extension' + + message_data: + title: 'Message data format' + type: object + required: + - message + properties: + message: + description: 'Response message' + type: string + example: 'success' + details: + description: 'Array of objects containing details' + type: array + items: + type: object + + securitySchemes: + mutualTLS: + type: http + scheme: mutual + description: >- + Mutual TLS authentication using certificates, TLSv1.3 (or later). + NOTE - OpenAPI 3.1.0 introduces better support for describing mTLS. + +security: + - mutualTLS: []