Caffeinated Petručeņa Quantum Key Distribution • Software Architecture • Confidential Computing

Problems with ETSI GS QKD 014 v1.1.1

TL;DR: ETSI GS QKD 014 v1 is a good start, but every interesting decision is left to the vendor.

Why should you care about a QKD API

Quantum key distribution (QKD) lets two parties detect eavesdropping on a channel while agreeing on shared secret bits. Neat property; limited adoption. The hardware is expensive, and the benefit over shipping a large HDD full of pre-shared keys is genuinely debatable. ANSSI’s position paper puts it dryly: “QKD may find some use in a few niche applications, for instance as a defense-in-depth measure on point-to-point links” 1. Academia is more romantic about it and treats these boxes as stepping stones to a quantum internet 2.

Commercial products have existed since MagiQ unveiled Navajo in 2003 3, and roughly 16 vendors sell devices today 4. Typical secret key rates are a few kbit/s, which rules out one-time-pad encryption of any serious traffic. In practice, QKD keys are used to rekey AES, continuously.

Then there is EuroQCI 5: an EU-wide quantum communication infrastructure involving all 27 Member States and ESA, with terrestrial fibre and a satellite segment. A network like that needs common interfaces, or every deployment becomes a custom adapter project and cross-border federation becomes fragile and expensive. ETSI saw this early: its QKD application-interface work started in 2008, GS QKD 004 came out in 2010, and the REST-based GS QKD 014 followed in 2019. GS QKD 014 defines a simple JSON key-delivery API so that an encryptor or VPN gateway does not need to know whose QKD boxes sit underneath.

That is the right goal. The problem is that the document leaves so much under-specified that, per Hyrum’s Law, every vendor’s accidental choices become the de facto contract 6. And once implementations diverge, the usual fix is a new standard — and we all know how that goes 7. The gaps below are the ones I keep tripping over.

One framing note before we start. ETSI 014 assumes the SAE and KME sit together inside a trusted site. In a semi-trusted QKD network, the more realistic adversary is not someone building a million-dollar quantum computer, but the site admin with local network access — the $5-wrench end of the threat spectrum 8. Even an admin who cannot open the KME box can record encrypted traffic between KME and SAE and wait. Also, nothing in this API is actually QKD-specific: the same key-delivery model would work fine for classical symmetric-key networks, which might see more real use in military and finance settings than the quantum hardware does.

How the API works

ETSI 014 is not an abstract QKD protocol; it is a REST API between two roles.

The SAE (Secure Application Entity) is the client: an encryptor, VPN gateway, or any software that wants key material. The KME (Key Management Entity) is the server: it manages keys in cooperation with other KMEs and serves them over HTTPS. Below the KME sit QKDEs (QKD Entities), the actual quantum endpoints, and everything lives inside a Trusted Node, a site whose equipment the standard simply assumes is secure.

The two-party flow:

  1. The Master SAE calls Get key at /api/v1/keys/{slave_SAE_ID}/enc_keys.
  2. Its KME returns fresh key material plus one or more key_ID values.
  3. The Master SAE sends the key_ID values to the Slave SAE over some channel the standard refuses to talk about.
  4. The Slave SAE calls Get key with key IDs at /api/v1/keys/{master_SAE_ID}/dec_keys on its own KME.
  5. That KME returns the matching key material.

ETSI 014 key delivery across KMEs

In the diagram, U_1 gets key material from KME A, sends the key_ID to U_2, and U_2 redeems it at KME C. Behind the API, the key has to be forwarded or reconstructed from A through B to C, and C has to learn that U_2 may redeem it. There is also Get status, a preliminary query for what key material is available for a given peer.

A quick terminology gripe: “master SAE” and “slave SAE” describe nothing more than who called first, yet carry needless historical baggage. GitHub renamed its default branch from master to main back in 2020 for exactly this reason 9. requesting_SAE_ID and peer_SAE_ID would say what the parties actually do. ETSI should make the swap in the next incompatible revision.

Who are you, exactly?

Clause 5.1 requires the KME to verify the SAE’s TLS client certificate and confirm the SAE ID based on the certificate. Based on which field? The standard never says. Not which field carries the ID, not how to parse it, not how to compare it, not what to do when several identity-bearing fields are present. For a mandatory processing path, that is not an editorial gap; it is an interoperability defect.

Divergence is already visible in the wild. The public reference implementation generates certificates with a Subject CN like sae_123456 and a SAN IP of 127.0.0.1, without saying which is authoritative 10. Palo Alto’s PAN-OS guide sidesteps the question entirely and has the operator type the SAE ID into a separate config field next to the certificate 11. Two conformant products, two different answers to “who is calling me”.

The tempting candidates all have problems. Subject CN comparison is brittle because DN strings are not canonical. SAN URI, DNS, and email names drag in normalization rules that make no sense for an opaque identifier. DN serialNumber gets confused with the certificate serial number. Issuer-plus-serial lookup tables work as local policy but make certificate renewal a database migration.

My proposal: pick exactly one place and forbid the rest. Put the SAE ID in a single subjectAltName otherName under an ETSI-assigned OID (the GS QKD 014 subtree 0.4.0.14 is sitting right there), encoded as a bounded UTF8String. The KME extracts only that value, compares it byte-for-byte — no case folding, no trimming, no Unicode normalization — and rejects the connection if the field is absent, duplicated, or malformed. The CA must populate it from verified enrollment data, not copy it from the CSR. And do it symmetrically: the SAE has the same problem confirming the KME’s identity, and fixing identity only halfway keeps half the problem. ETSI has an active GS QKD 014 revision in draft; this is the moment for one field, one parser, one comparison rule, one failure mode.

Authorization that loses a race with itself

ETSI 014 handles retrieval rights implicitly: the original Get key creates state in the KME layer, and the slave SAE’s later dec_keys call succeeds only if that state says it may 12. There is no authorization object that can travel with the key IDs.

Now consider the timing. U_1 gets a key_ID and immediately sends it to U_2 over its own fast application channel. The authorization state, meanwhile, may crawl hop-by-hop from KME to KME — a reasonable design, since it avoids requiring full mesh reachability between KMEs. If U_2 is quicker than the KME gossip, its dec_keys call fails or blocks for no good reason. The standard declares the key-ID notification channel out of scope, but the authorization semantics of that notification are very much in scope.

The fix is an optional delegated retrieval token that the master side hands over together with the key IDs. A JWS-signed, JWT-shaped token works: issuer, audience, both KME IDs, both SAE IDs, the permitted operation, the key IDs, an expiry, and a unique token ID for replay detection 13. OAuth token exchange already worked out the delegation-versus-impersonation semantics, including the act claim 14. The token carries no key material and supplements — never replaces — mutual TLS and local policy. Delegated retrieval becomes explicit, auditable, and interoperable instead of a race condition.

What is a 7-bit key for?

A SAE may request any key size in bits between a KME-advertised minimum and maximum 12. Any size. Seven bits, if the KME’s limits allow it. Even byte-aligned oddities like a 24-bit key have no portable cryptographic meaning.

The deeper issue is that this quietly moves a cryptographic profile decision into vendor policy. One KME accepts only 128, 192, and 256 bits; another accepts arbitrary byte lengths; a third accepts gigabit values for OTP-style consumption. All three look identical at the status endpoint and behave like three different products.

ETSI should define mandatory key-size profiles instead: a base profile with the small symmetric sizes everyone must support (the AES-class sizes), and — if OTP use is meant to be supported — a separate profile with large mandatory sizes, streaming retrieval, and reservation semantics. Without that, min_key_size and max_key_size are implementation trivia, not an interoperability contract.

“It depends” is not a fulfilment semantic

Suppose the SAE asks for one 1024-bit key and the KMEs have buffered 256-bit keys. Does the KME fail immediately? Wait? Kick off reactive routing through the QKD network, turning a pool lookup into a network-dependent latency lottery? The standard exposes stored_key_count and friends but says nothing about what happens on a miss 12, so a conforming SAE cannot plan for any of these.

The default should be immediate-only: buffered material now, or a clear failure. Waiting should be explicit opt-in (fulfilment_mode = wait plus max_wait_ms), and reactive routing another explicit opt-in. ETSI’s own GS QKD 004 already has reservation and QoS timeout semantics 15, and gRPC has been telling everyone for years that requests without explicit deadlines wait forever 16.

Retries that eat your keys

Get key is not a harmless read: on success, the delivered keys are removed from the pool 12. If the client times out after the KME committed the operation, a naive retry silently burns fresh key material. For a technology whose entire product is expensive random bits, that is an unfortunate failure mode.

Two ingredients fix this. First, replay-safe request identifiers: retrying with the same ID and parameters returns the same result; same ID with different parameters fails loudly. This is the standard idempotency-key pattern from AWS and Stripe, and the same lesson RIFL formalized for exactly-once semantics in distributed systems 17 18 19. Second, for anything slow, return 202 Accepted with a request resource that moves through pending, ready, claimed, expired, failed — rather than holding the HTTP connection open and hoping. KMIP does async work this way, with correlation values, polling, and cancellation 20; the OAuth device flow shows how to do polling discipline, including a server-side “slow down” 21.

While we are at it, the error vocabulary of 400, 401, and 503 is too small. A valid request that cannot be satisfied from current key state is a 409 Conflict, not a 503; 504 fits a peer-KME timeout; 410 Gone fits an expired request resource; and 429 with Retry-After fits an impatient poller 22 23. ETSI is already revising GS QKD 014 for OpenAPI and QoS improvements 24 — the right moment to standardize these names instead of leaving them as vendor extensions.

Shipping a gigabyte through one JSON string

Key material is returned as a single base64 string in a JSON object 12. Fine for 256 bits. For a 1 GiB one-time-pad key, base64 alone inflates it to about 1.34 GiB 25, and many stacks will transiently hold the raw HTTP body, the parsed JSON string, and the decoded bytes all at once. Whether that works depends on your HTTP client, your JSON parser, and whichever reverse proxy or logging middleware decides to buffer the whole thing for a closer look. That is not a bulk-transfer model; it is a stress test.

This matters because QKD is marketed on information-theoretic security, and information-theoretic security means OTP-scale keys. If the API is only comfortable with a few thousand bits, it has silently optimized for AES rekeying while the marketing says otherwise. (OTP alone is also not a secure channel — it is malleable without an information-theoretic MAC such as Wegman-Carter 26 — but that is an argument for specifying the profile properly, not for skipping it.)

The fix: keep the control plane in JSON, deliver key bytes as application/octet-stream. A request creates a reserved, immutable bundle with a bundle_ID, size, peer SAEs, expiry, and retrieval authorization; a streaming endpoint delivers the bytes with a known Content-Length, no compression, and integrity metadata. Resume support must reference the same immutable bundle — a failed download must never trigger key reuse or quietly consume a second fresh key.

TLS between friends

ETSI 014 requires HTTPS with “TLS 1.2 or higher” and mutual certificate authentication, and stops there 12. No cipher suites, no groups, no forbidden list. Understandable in 2019; too vague for a QKD API in particular.

Remember the threat model from the introduction: the SAE-KME link carries the very keys applications will use, and the realistic adversary is the semi-trusted site with packet capture, not the quantum computer. Recording that HTTPS traffic today and decrypting it after a cryptographically relevant quantum computer arrives — harvest now, decrypt later — is precisely the attack QKD is sold as preventing. It would be a nice bit of irony if the QKD delivery API were the weakest classical link in the chain.

The revision should mandate a profile: TLS 1.3, mutual authentication, AEAD suites, and explicit key-exchange groups — and note that in TLS 1.3 the group is negotiated via key shares, not the cipher suite, so both need constraining 27. Hybrid post-quantum key establishment should follow as soon as the specs are stable; ML-KEM is standardized in FIPS 203 28, and X25519MLKEM768 is on the IETF standards track, currently as a draft 29. Equally important is the forbidden list: static RSA key exchange, weak curves, non-AEAD ciphers, compression, unauthenticated fallback. Leaving this to vendor defaults is not interoperability; it is accidental security.

Closing

None of this is fatal. ETSI 014 did its main job: there is a common REST shape that most vendors implement, and that alone saved the ecosystem from N-squared adapter projects. But v1.1.1 standardized the easy 80% and left the 20% where interoperability actually lives — identity, authorization, sizing, retries, bulk transfer, channel security — to whoever writes the code. The revision currently in draft is the chance to fix that without spawning standard number fifteen 7. Whether it does, I cannot tell you: the work item page lists v1.3.1 as a stable draft, but the document itself is members-only 24. For a standard whose entire purpose is public interoperability, keeping the draft behind an ETSI membership is a curious way to collect feedback.

Funding note. Some of the work behind these observations was carried out within the EU-funded project No. 101091559, Development of Experimental Quantum Communication Infrastructure in Latvia (LatQN). The comments and reflections in this post are my own and may not reflect technical position of the IMCS, UL or EU.


  1. ANSSI, “Technical Position Paper: QKD v2.1”. https://messervices.cyber.gouv.fr/documents-guides/anssi-technical_position_papers-qkd.pdf ↩︎

  2. Wehner, S.; Elkouss, D.; Hanson, R. “Quantum internet: A vision for the road ahead.” Science 362(6412), eaam9288 (2018). DOI: 10.1126/science.aam9288 ↩︎

  3. Light Reading, “MagiQ Demos Quantum Cryptography” (2003). https://www.lightreading.com/cable-technology/magiq-demos-quantum-cryptography ↩︎

  4. Bruno Rijsman, “Quantum Key Distribution (QKD) Companies | Quantum Networking Resource List”. https://brunorijsman.github.io/quantum-resource-list/companies-qkd.html ↩︎

  5. European Commission, “European Quantum Communication Infrastructure - EuroQCI”. https://digital-strategy.ec.europa.eu/en/policies/european-quantum-communication-infrastructure ↩︎

  6. Hyrum Wright, “Hyrum’s Law”: “With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody.” https://www.hyrumslaw.com/ ↩︎

  7. Randall Munroe, xkcd #927, “Standards”. https://xkcd.com/927/ ↩︎ ↩︎

  8. Randall Munroe, xkcd #538, “Security”. https://xkcd.com/538/ ↩︎

  9. GitHub Changelog, “The default branch for newly-created repositories is now main” (2020). https://github.blog/changelog/2020-10-01-the-default-branch-for-newly-created-repositories-is-now-main/ ↩︎

  10. cybermerqury, “ETSI GS QKD 014 v1.1.1 - Reference Implementation” (certificate generation). https://github.com/cybermerqury/etsi-gs-qkd-014-referenceimplementation/blob/develop/README.md#sae-certificate ↩︎

  11. Palo Alto Networks, “Configure Post-Quantum IKEv2 with QKD and ETSI-014” (QKD profile: Local SAE ID and Local Certificate). https://docs.paloaltonetworks.com/network-security/quantum-security/administration/configure-quantum-resistant-ikev2-vpns/configure-post-quantum-ikev2-with-qkd-and-etsi-014 ↩︎

  12. ETSI, “GS QKD 014 V1.1.1: Quantum Key Distribution (QKD); Protocol and data format of REST-based key delivery API”. https://www.etsi.org/deliver/etsi_gs/QKD/001_099/014/01.01.01_60/gs_qkd014v010101p.pdf ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  13. IETF RFC 7519, “JSON Web Token (JWT)”. https://datatracker.ietf.org/doc/html/rfc7519 ↩︎

  14. IETF RFC 8693, “OAuth 2.0 Token Exchange”. https://datatracker.ietf.org/doc/html/rfc8693 ↩︎

  15. ETSI, “GS QKD 004 V2.1.1: Quantum Key Distribution (QKD); Application Interface”. https://www.etsi.org/deliver/etsi_gs/QKD/001_099/004/02.01.01_60/gs_qkd004v020101p.pdf ↩︎

  16. gRPC, “Deadlines”. https://grpc.io/docs/guides/deadlines/ ↩︎

  17. Amazon Web Services, “Ensuring idempotency in Amazon EC2 API requests”. https://docs.aws.amazon.com/ec2/latest/devguide/ec2-api-idempotency.html ↩︎

  18. Stripe, “Idempotent requests”. https://docs.stripe.com/api/idempotent_requests ↩︎

  19. Lee, C. et al., “Implementing Linearizability at Large Scale and Low Latency”. https://web.stanford.edu/~ouster/cgi-bin/papers/rifl.pdf ↩︎

  20. OASIS, “Key Management Interoperability Protocol Specification Version 1.4”. https://docs.oasis-open.org/kmip/spec/v1.4/kmip-spec-v1.4.pdf ↩︎

  21. IETF RFC 8628, “OAuth 2.0 Device Authorization Grant”. https://datatracker.ietf.org/doc/html/rfc8628 ↩︎

  22. IETF RFC 9110, “HTTP Semantics”. https://httpwg.org/specs/rfc9110.html ↩︎

  23. IETF RFC 6585, “Additional HTTP Status Codes”. https://datatracker.ietf.org/doc/html/rfc6585 ↩︎

  24. ETSI Work Programme, “RGS/QKD-014ed2_KeyDeliv: QKD; Protocol and data format of REST-based key delivery API” (v1.3.1 stable draft, not publicly downloadable). https://portal.etsi.org/webapp/WorkProgram/Report_WorkItem.asp?WKI_ID=69542 ↩︎ ↩︎

  25. IETF RFC 4648, “The Base16, Base32, and Base64 Data Encodings”. https://datatracker.ietf.org/doc/html/rfc4648 ↩︎

  26. Wegman, M. N.; Carter, J. L. “New hash functions and their use in authentication and set equality.” Journal of Computer and System Sciences 22(3), 265-279 (1981). DOI: 10.1016/0022-0000(81)90033-7 ↩︎

  27. IETF RFC 8446, “The Transport Layer Security (TLS) Protocol Version 1.3”. https://datatracker.ietf.org/doc/html/rfc8446 ↩︎

  28. NIST, “FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard” (2024). DOI: 10.6028/NIST.FIPS.203 ↩︎

  29. IETF, “Post-quantum hybrid ECDHE-MLKEM Key Agreement for TLSv1.3”, draft-ietf-tls-ecdhe-mlkem (Standards Track, Internet-Draft). https://datatracker.ietf.org/doc/draft-ietf-tls-ecdhe-mlkem/ ↩︎