Enabling Post-Quantum Key Agreements with Nginx

Both Google Chrome¹ and CloudFlare² have announced that they are going to spend effort migrating to quantum-resistant cryptography. As one of the first steps both have implemented Kyber768 + X25519 KEM support.

Thankfully these improvements are not only available to Google and CloudFlare customers. Basically everyone can enable X25519Kyber768(Draft00) support in their web server. If they are using relatively modern OpenSSL 3.x. People at OpenQuantumSafe have written a provider for OpenSSL 3.x that provides amongst many others, Kyber and its hybrid KEM schemes. You can find the provider from here: https://github.com/open-quantum-safe/oqs-provider

Building OQS provider

All you have to do is clone the repository, build and install it.

For example:

git clone https://github.com/open-quantum-safe/oqs-provider
cd oqs-provider
mkdir build && cd build
cmake -S ..
cmake --build .
sudo cmake --install .

Enabling OQS provider

Open your OpenSSL configuration (on Ubuntu it's located at /etc/ssl/openssl.cnf).

Just enable the provider by-default, this avoids the need to force software to specifically enable the OQS provider.

# List of providers to load
[provider_sect]
default = default_sect
oqsprovider = oqsprovider_sect
...

[default_sect]
activate = 1

[oqsprovider_sect]
activate = 1

You can check the results using openssl list -kem-algorithms, it should list at least x25519_kyber768 @ oqsprovider.

Allowing Kyber hybrid KEMs

Next step is to enable the KEM in nginx's TLS configuration. No other changes need to be made if your distribution and nginx uses OpenSSL 3.

Locate the line that says ssl_ecdh_curve auto; and replace it with:

ssl_ecdh_curve x25519_kyber768:p384_kyber768:x25519:secp384r1:x448:secp256r1:secp521r1;

The first preference now being X25519Kyber768, then P384Kyber768 for Edge, X25519 for regular clients and the usual for compatibility after that.

After this change, just restart nginx (sudo systemctl restart nginx).

Checking if your browser has PQ KEM support

X25519Kyber768 has been available in Chrome since Chrome 115 (dev trial) and behind a flag after 118 (chrome://flags#enable-tls13-kyber). It's also behind a flag in Edge (edge://flags#edge-post-quantum-kyber). Chrome has also started a gradual rollout and they're at 10% (as of 30.11.2023).

You can test if your browser has Kyber enabled by visiting CloudFlare's test page. You should see kex=X25519Kyber768Draft00.

Besides this site I'm not aware of any that would allow one to test both QUIC and PQ KEMs simultaneously.

Firefox does not yet support X25519Kyber768Draft00, there has been some effort.

Result

If you visit your website with an enabled browser you should be seeing Kyber786 being used.

A secure QUIC connection using X25519Kyber768Draft00 as the key exchange, ECDSA with SHA-384 as the server signature and AES_256_GCM as the cipher. (QUIC + X25519Kyber768Draft00)

Edge will display something like this:

A secure HTTP/TLSv1.3 connection using P384Kyber768 (P384KYBER) as the key exchange, ECDSA with SHA-384 as the server signature and AES_256_GCM as the cipher.

CloudFlare PQ origin pulls

If you use CloudFlare as a reverse proxy, then you can also enable X25519Kyber768 on the first attempt (to save a round trip) using their API:

curl --request PUT \
--url https://api.cloudflare.com/client/v4/zones/[ ZONE_ID ]/id/cache/origin_post_quantum_encryption \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer [ API_TOKEN ]' \
--data '{"value": "preferred"}'

External references