Post-Quantum Cryptography in Linux: ML-KEM, ML-DSA, TLS, and SSH

Learn how to check ML-KEM support in TLS, create ML-DSA signatures, and verify post-quantum SSH key exchange on Linux, with tested Rocky Linux examples.

Published

Updated

Read time 19 min read

Reviewed byDeepak Prasad

Post-quantum cryptography in Linux with hybrid ML-KEM key exchange, ML-DSA signatures, TLS 1.3, and OpenSSH

Post-quantum support on Linux depends on the OpenSSL and OpenSSH versions supplied by your distribution, along with any distro-specific crypto policies. This guide begins with capability checks that work across Linux distributions, then demonstrates ML-KEM, ML-DSA, TLS, and SSH on Rocky Linux 10.2. Sections that use RHEL-family system-wide crypto policies are labeled separately.

The capability checks and OpenSSL/OpenSSH labs can work on any Linux distribution that provides the required versions and algorithms. The commands involving update-crypto-policies, DEFAULT, FUTURE, NO-PQ, and TEST-PQ are specific to the RHEL family and related distributions.

I will show you how to check what your host already supports, then walk through small labs you can run on your own machines without leaning on a public website.

Tested on: Rocky Linux 10.2 (Red Quartz); OpenSSL 3.5.5; OpenSSH 9.9p1.

IMPORTANT
Just because an algorithm is available on your system does not mean a connection actually used it. Both ends have to support it and agree on it during the handshake. Check the negotiated TLS group or SSH key-exchange line instead of assuming post-quantum cryptography is in play.
Reader's goal Jump to
See the two-VM lab layout Lab environment
Check whether PQC is enabled Inspect PQC support on the current system
Test hybrid TLS key exchange Test hybrid ML-KEM key exchange with TLS 1.3
Generate and verify a PQ signature Generate and verify ML-DSA signatures
Check an SSH connection Verify post-quantum key exchange in SSH
Understand RHEL-family crypto policies RHEL-family crypto policies and PQC interoperability
Compare distro release history How PQC support differs across Linux distributions

Lab environment

Most labs need only one host. For the RHEL-family crypto-policy lab I used two disposable VMs on the same lab network. You can mirror that layout if you want to see client and server behaviour side by side.

Role Example address Used for
Client 192.168.56.108 OpenSSL TLS and ML-DSA labs; RHEL-family update-crypto-policies changes
Server 192.168.56.109 SSH peer, hybrid TLS server, classical-only sshd on port 2222

Both hosts began with the DEFAULT crypto policy for the policy lab. One section later switches only the client to FUTURE so you can see what that change does. I configured root SSH public-key trust between them. If firewalld is active on your server, open test ports temporarily. I used firewall-cmd --add-port=2222/tcp for the classical SSH demo and firewall-cmd --add-port=14433/tcp for cross-host TLS.

Swap in your own lab IPs. The hostnames here are disposable labels, not production DNS names.


What post-quantum cryptography changes

Today's public-key algorithms (RSA and elliptic-curve cryptography) could become vulnerable to a sufficiently capable quantum computer. No cryptographically relevant quantum computer is known today, but traffic can still be recorded now and attacked later. That harvest-now-decrypt-later risk is why vendors are adding NIST-standardized post-quantum algorithms next to the classical ones.

Symmetric ciphers such as AES are a separate story. Post-quantum work on Linux concentrates on key exchange and digital signatures, because that is where RSA and ECC carry the long-term risk.

Purpose Algorithm Protects
Establish a shared secret ML-KEM Key exchange and confidentiality
Sign and authenticate data ML-DSA or SLH-DSA Integrity and authenticity

Current TLS and SSH implementations commonly combine classical and post-quantum key exchange:

text
Classical ECDH/X25519 + ML-KEM

Combining both components provides a security hedge: the session remains protected unless both components are broken. Both peers must support the same hybrid method. TLS uses names such as X25519MLKEM768, while OpenSSH uses mlkem768x25519-sha256. Compatibility with classical-only peers comes from negotiating a separate classical method, not from the classical component inside the hybrid method.


How PQC support differs across Linux distributions

No two distributions ship post-quantum cryptography on the same schedule. Fedora, Debian, Ubuntu, SUSE, Arch, and the RHEL family each package OpenSSL and OpenSSH on their own timelines. Some backport PQC support into older upstream version numbers. Others wait for a newer upstream release. The portable checks in the next section tell you what your installed build actually supports, regardless of distribution name.

OpenSSL 3.5 provides native ML-KEM and ML-DSA support. Upstream OpenSSH added mlkem768x25519-sha256 in 9.9 and made it the default key-exchange method in OpenSSH 10.0. Your distribution may ship those capabilities earlier or later than the upstream version string suggests.

RHEL-family release timeline

The following timeline explains the RHEL-family implementation used for the tested labs. Other distributions may package upstream OpenSSL and OpenSSH support on a different schedule.

Many online instructions still describe the initial RHEL-family Technology Preview behaviour. If you are on a current release, you can skip the old workarounds. Glance at this table once when you plan an upgrade or when an older blog post mentions TEST-PQ or oqsprovider.

Release PQC status and important changes
10.0 Technology Preview; required crypto-policies-pq-preview, DEFAULT:TEST-PQ, and oqsprovider for OpenSSL
10.1 Standardized PQC fully supported; OpenSSL 3.5 provides ML-KEM, ML-DSA, and SLH-DSA; supported PQ algorithms enabled by predefined policies
10.2 Expanded OpenSSH and libssh hybrid ML-KEM support; NIST-curve SSH hybrids in FIPS mode; FUTURE permits only hybrid ML-KEM key exchange

Keep these migration points in mind when you read older blog posts:

  • RHEL 10.0 used oqsprovider for its Technology Preview implementation. Current RHEL-family releases with OpenSSL 3.5 provide native standardized algorithms and do not require it for these labs.
  • The 10.0 release used pre-standard private-key formats; existing ML-KEM and ML-DSA keys from that era may need conversion after an upgrade.
  • TEST-PQ is no longer required to enable normal hybrid PQC on current releases.
  • TEST-PQ today is mainly relevant when testing pure ML-KEM in OpenSSL.

If you still have keys from the Technology Preview era, Red Hat documents conversion to the standardized PKCS #8 form:

bash
openssl pkcs8 -in old-private-key.pem -nocrypt -topk8 -out standard-private-key.pem

Treat that command as an upgrade note, not a full migration procedure.


Supported algorithms and applications

Core algorithms

Algorithm Function Standard Available parameter sets
ML-KEM Key encapsulation NIST FIPS 203 512, 768, 1024
ML-DSA Digital signatures NIST FIPS 204 44, 65, 87
SLH-DSA Hash-based digital signatures NIST FIPS 205 SHA2 and SHAKE variants

The suffix identifies a parameter set, not a key size. Names cannot be compared directly across algorithm families, although ML-KEM-768 and ML-DSA-65 both target NIST security category 3 for different cryptographic functions.

Major components

Component Relevant PQC support
OpenSSL 3.5 ML-KEM, ML-DSA, SLH-DSA, and hybrid TLS 1.3 groups
GnuTLS Hybrid ML-KEM key exchange and ML-DSA signatures
NSS Hybrid ML-KEM TLS support and ML-DSA keys/signatures
OpenSSH Hybrid post-quantum key exchange
libssh Hybrid ML-KEM key exchange (expanded in recent releases)
Crypto policies (RHEL family) System-wide enablement and algorithm ordering on RHEL, Rocky Linux, AlmaLinux, Fedora, and related distributions

Library support is not the same as application support. OpenSSL may know about ML-KEM even when a service linked to an older library build never offers it.


Inspect PQC support on the current system

Before you change anything, confirm what your host already has. These commands work on any Linux distribution and answer the core question: does this build actually know about post-quantum algorithms?

Start with the OpenSSL version:

bash
openssl version

Sample output:

output
OpenSSL 3.5.5 27 Jan 2026 (Library: OpenSSL 3.5.5 27 Jan 2026)

OpenSSL 3.5 is the release that brought native ML-KEM and ML-DSA into the default provider. Older builds may need a newer package or a distribution backport before these checks show PQ entries.

List ML-KEM key-encapsulation algorithms:

bash
openssl list -kem-algorithms | grep -i ml-kem

Sample output:

output
{ 2.16.840.1.101.3.4.4.1, id-alg-ml-kem-512, ML-KEM-512, MLKEM512 } @ default
  { 2.16.840.1.101.3.4.4.2, id-alg-ml-kem-768, ML-KEM-768, MLKEM768 } @ default
  { 2.16.840.1.101.3.4.4.3, id-alg-ml-kem-1024, ML-KEM-1024, MLKEM1024 } @ default

List TLS 1.3 hybrid groups:

bash
openssl list -tls1_3 -tls-groups | grep -i mlkem

Sample output:

output
MLKEM512
MLKEM768
MLKEM1024
SecP256r1MLKEM768
X25519MLKEM768
SecP384r1MLKEM1024

Check the OpenSSH build:

bash
ssh -V

Sample output:

output
OpenSSH_9.9p1, OpenSSL 3.5.5 27 Jan 2026

List post-quantum SSH key-exchange methods the client knows about:

bash
ssh -Q kex | grep -iE 'mlkem|sntrup'

Sample output:

output
sntrup761x25519-sha512
[email protected]
mlkem768x25519-sha256
mlkem768nistp256-sha256
mlkem1024nistp384-sha384

If those commands show ML-KEM entries, your installed OpenSSL and OpenSSH builds include post-quantum support. That still does not prove a live connection negotiated a PQ algorithm.

Identify the distribution with the portable OS metadata file:

bash
cat /etc/os-release

Abridged sample output on Rocky Linux:

output
NAME="Rocky Linux"
VERSION="10.2 (Red Quartz)"
ID="rocky"
ID_LIKE="rhel centos fedora"
VERSION_ID="10.2"

On RHEL-compatible systems you can also read /etc/redhat-release as a shortcut.

Check installed package versions with the command that matches your distribution family:

Distribution family Check the core packages
RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora rpm -q openssl openssh
Debian and Ubuntu dpkg-query -W openssl openssh-client openssh-server
SUSE and openSUSE rpm -q openssl openssh
Arch Linux pacman -Q openssl openssh

Sample output on Rocky Linux:

bash
rpm -q openssl openssh
output
openssl-3.5.5-4.el10_2.x86_64
openssh-9.9p1-23.el10_2.rocky.0.1.x86_64

Package names and backports differ between distributions, so version numbers alone are not conclusive. Use the OpenSSL and OpenSSH capability commands above to see what the installed build actually supports.

List loaded OpenSSL providers:

bash
openssl list -providers

Sample output:

output
Providers:
  default
    name: OpenSSL Default Provider
    version: 3.5.5
    status: active
  pkcs11
    name: PKCS#11 Provider
    version: 3.2.2
    status: active

The tested Rocky Linux system also loads pkcs11; other distributions may show only default.

With native OpenSSL 3.5, standardized ML-KEM and ML-DSA implementations appear under the default provider. Systems using an older OpenSSL release may expose PQ algorithms through a separately installed oqsprovider. The provider list is build-dependent, and seeing only the default provider is sufficient for these OpenSSL 3.5 labs.

List signature algorithms:

bash
openssl list -signature-algorithms | grep -iE 'ml-dsa|slh-dsa'

Sample output:

output
{ 2.16.840.1.101.3.4.3.17, id-ml-dsa-44, ML-DSA-44, MLDSA44 } @ default
  { 2.16.840.1.101.3.4.3.18, id-ml-dsa-65, ML-DSA-65, MLDSA65 } @ default
  { 2.16.840.1.101.3.4.3.19, id-ml-dsa-87, ML-DSA-87, MLDSA87 } @ default
  { 2.16.840.1.101.3.4.3.20, id-slh-dsa-sha2-128s, SLH-DSA-SHA2-128s } @ default
  { 2.16.840.1.101.3.4.3.21, id-slh-dsa-sha2-128f, SLH-DSA-SHA2-128f } @ default

Additional SLH-DSA SHA2 and SHAKE parameter sets appear in the full listing.

Four separate layers trip people up. Work out which one you are actually looking at before you draw a conclusion:

Layer Question it answers
Implemented by the library Does OpenSSL or OpenSSH know the algorithm?
Allowed by crypto policy On RHEL-family systems, may this host use it at all?
Offered by an application Does this particular server or client propose it?
Negotiated with the peer Did both sides agree on it for this session?

You need proof at the negotiated layer before you tell anyone the connection is post-quantum protected.


Test hybrid ML-KEM key exchange with TLS 1.3

I like using a local OpenSSL server and client for this test because you are not guessing whether a public website happens to support ML-KEM today. You also do not need a post-quantum certificate. A normal RSA or ECDSA server certificate is enough to prove the key exchange.

Create a short-lived classical test certificate:

bash
openssl req -x509 -newkey rsa:2048 -keyout tls-lab.key -out tls-lab.crt -days 1 -nodes -subj "/CN=pqc-lab.local"

The command creates tls-lab.key and tls-lab.crt. Key-generation progress may appear before the prompt returns.

Start a TLS 1.3 server that offers only the hybrid group X25519MLKEM768:

bash
openssl s_server -accept 14433 -cert tls-lab.crt -key tls-lab.key -tls1_3 -groups X25519MLKEM768 -www -naccept 1

In a second shell, connect with a matching client:

bash
echo | openssl s_client -connect 127.0.0.1:14433 -tls1_3 -groups X25519MLKEM768

Look for the negotiated group near the end of the client output:

output
Negotiated TLS1.3 group: X25519MLKEM768
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Protocol: TLSv1.3
Verify return code: 18 (self-signed certificate)

That line tells you TLS 1.3 picked a hybrid X25519 plus ML-KEM-768 key exchange. The session secret gets protection from both worlds. It does not tell you whether the server certificate used a post-quantum signature, whether every app on the host will make the same choice, or whether a remote peer even offers X25519MLKEM768.

Repeat the exercise with classical X25519 only. Start the server:

bash
openssl s_server -accept 14434 -cert tls-lab.crt -key tls-lab.key -tls1_3 -groups X25519 -www -naccept 1

Connect the client:

bash
echo | openssl s_client -connect 127.0.0.1:14434 -tls1_3 -groups X25519

Sample output:

output
Peer Temp Key: X25519, 253 bits
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Protocol: TLSv1.3
Verify return code: 18 (self-signed certificate)

OpenSSL prints Negotiated TLS1.3 group for hybrid groups and Peer Temp Key for classical-only exchanges. Comparing the two runs makes the difference visible in your own terminal.

You can run the same hybrid test across two lab hosts. Start openssl s_server on the server VM and connect with openssl s_client from the client VM using the server address instead of 127.0.0.1. On my two-VM lab I saw Negotiated TLS1.3 group: X25519MLKEM768 between 192.168.56.108 and 192.168.56.109.

For broader OpenSSL TLS work (renewals, chains, and CSR choices), keep certificate management separate from key-exchange testing.


Generate and verify ML-DSA signatures

ML-DSA does a different job from ML-KEM. ML-KEM helps two parties agree on a shared secret. ML-DSA signs and verifies files. The commands below use the OpenSSL 3.5 names you will see on a current release, not the lowercase oqsprovider spellings from older tutorials.

Generate an ML-DSA-65 private key:

bash
openssl genpkey -algorithm ML-DSA-65 -out mldsa65-lab.key

OpenSSL creates the key file with no terminal output on success.

Extract the public key:

bash
openssl pkey -in mldsa65-lab.key -pubout -out mldsa65-lab.pub

Create a sample file and sign it:

bash
echo 'Post-quantum signature lab file.' > sample.txt
openssl pkeyutl -sign -inkey mldsa65-lab.key -in sample.txt -out sample.sig

Public-key extraction and signing normally produce no terminal output on success. They create mldsa65-lab.pub and sample.sig.

Verify the signature:

bash
openssl pkeyutl -verify -pubin -inkey mldsa65-lab.pub -in sample.txt -sigfile sample.sig

Sample output:

output
Signature Verified Successfully

Change the file and confirm verification fails:

bash
echo 'tampered content' > sample-bad.txt
openssl pkeyutl -verify -pubin -inkey mldsa65-lab.pub -in sample-bad.txt -sigfile sample.sig

Sample output:

output
Signature Verification Failure
Algorithm NIST security category General trade-off
ML-DSA-44 2 Smaller and faster
ML-DSA-65 3 Middle parameter set
ML-DSA-87 5 Larger keys and signatures

ML-DSA-65 is a sensible choice for this lab. Pick a different parameter set if your security team has already settled on one.

Optional: create an ML-DSA test certificate

You can mint a short-lived self-signed certificate from the same key for inspection:

bash
openssl req -x509 -new -key mldsa65-lab.key -out mldsa65-lab.crt -days 1 -subj "/CN=pqc-mldsa-lab.local"

Inspect the certificate:

bash
openssl x509 -in mldsa65-lab.crt -text -noout

Sample output:

output
Signature Algorithm: ML-DSA-65
        Issuer: CN=pqc-mldsa-lab.local
        Subject: CN=pqc-mldsa-lab.local
        Subject Public Key Info:
            Public Key Algorithm: ML-DSA-65
    Signature Algorithm: ML-DSA-65

Public CAs may not issue ML-DSA certificates yet, and many older TLS clients will not understand them. During a long transition you might run traditional and ML-DSA certificates side by side. You can adopt hybrid TLS key exchange long before post-quantum certificates are common.


Verify post-quantum key exchange in SSH

SSH handles key exchange, host authentication, user authentication, and session encryption as separate steps. Post-quantum support shows up mainly in key exchange. Your session can negotiate hybrid ML-KEM there while the server still uses an Ed25519, ECDSA, or RSA host key.

List available SSH key-exchange algorithms:

bash
ssh -Q kex | grep -iE 'mlkem|sntrup'

Sample output:

output
sntrup761x25519-sha512
[email protected]
mlkem768x25519-sha256
mlkem768nistp256-sha256
mlkem1024nistp384-sha384

Upstream OpenSSH added mlkem768x25519-sha256 in version 9.9. OpenSSH 10.0 made it the default key-exchange method. Any recent Linux distribution that ships a current OpenSSH build can offer this algorithm.

The sample output above came from Rocky Linux 10.2. You may also see mlkem768nistp256-sha256 and mlkem1024nistp384-sha384 on RHEL-family builds.

Those NIST-curve hybrids were added for documented FIPS-mode SSH support on that platform and are not guaranteed on every Linux OpenSSH package. sntrup761x25519-sha512 is another hybrid post-quantum exchange, but its PQ component is not ML-KEM.

Connect from the client VM to the server VM with verbose logging:

bash
ssh -vv [email protected] exit

Sample output:

output
debug1: kex: algorithm: mlkem768x25519-sha256
Authenticated to 192.168.56.109 ([192.168.56.109]:22) using "publickey".

That kex line is the proof you want in your notes. Seeing ML-KEM in ssh -Q kex only tells you the client knows the name.

Force the hybrid algorithm when you need an explicit test:

bash
ssh -o KexAlgorithms=mlkem768x25519-sha256 -vv [email protected] exit

When both machines support the hybrid method, you should still see mlkem768x25519-sha256 even if you force it explicitly.

You rarely need to force algorithms in daily use. If you want client-wide defaults, see SSH client configuration and the SSH command reference.

Ansible and other tools may use libssh instead of the OpenSSH client, so the algorithm list can differ even between machines on the same distribution.


RHEL-family crypto policies and PQC interoperability

This section applies to distributions that use the RHEL/Fedora system-wide crypto-policies framework, including RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, and Fedora. Debian, Ubuntu, Arch, and other distributions do not necessarily provide an equivalent DEFAULT, FUTURE, NO-PQ, or TEST-PQ policy interface.

There is no safe universal replacement for update-crypto-policies --show. On other distributions, configuration may be controlled separately by OpenSSL, OpenSSH, GnuTLS, or the application itself.

Crypto policies set the ceiling for what your applications are allowed to use on RHEL-family systems. Here I am only talking about the post-quantum side of that picture. Broader update-crypto-policies administration belongs in your normal hardening notes.

Policy What it means for post-quantum cryptography
DEFAULT Hybrid PQC is on and preferred, but classical algorithms remain available for older peers
LEGACY Hybrid PQC stays available, with more older algorithms still permitted
FIPS PQ availability is component-specific; only hybrid ML-KEM combinations supported by the release's FIPS configuration work, while ML-DSA availability depends on the library and provider
FUTURE On RHEL 10.2 and aligned builds, hybrid ML-KEM only; many connections to non-PQ services stop working
DEFAULT:NO-PQ Turns off PQ algorithms that the system policy would otherwise allow
TEST-PQ Helps you test pure ML-KEM in OpenSSL; not needed for everyday hybrid PQC

See which policy is active on your host:

bash
update-crypto-policies --show

Sample output:

output
DEFAULT

DEFAULT is the policy you will see on most fresh RHEL-family installs. It turns on supported hybrid post-quantum algorithms and still leaves room for classical fallbacks when the other side needs them.

Check which PQ algorithms the active policy allows:

bash
grep -E 'MLKEM|MLDSA|KEM-ECDH' /etc/crypto-policies/state/CURRENT.pol

Abridged sample output:

output
group = MLKEM768-X25519 P256-MLKEM768 P384-MLKEM1024 MLKEM1024-X448 X25519 SECP256R1 ...
key_exchange = KEM-ECDH ECDHE DHE ...
sign = MLDSA44 MLDSA65 MLDSA87 ECDSA-SHA3-256 ...

For the labs here and for most day-to-day RHEL-family systems, stay on DEFAULT. I would only move a machine to FUTURE on RHEL 10.2 or an aligned build when you have a deliberate test plan. That policy is strict: it can block public TLS sites without PQ key exchange, older SSH servers, some Java TLS clients, and package mirrors that still speak only classical algorithms.

DEFAULT:NO-PQ is useful when you need to compare behaviour or chase a compatibility problem. I would not leave it in place as routine hardening.

Keep these interoperability points in mind:

  • Both ends need a hybrid group they agree on.
  • Allowed in policy is not the same as negotiated on the wire.
  • Hybrid TLS groups need TLS 1.3.
  • PQ handshakes are larger than classical-only ones.
  • Post-quantum certificates are still rare compared with hybrid key exchange.
  • Keys from the Technology Preview era may not match today's on-disk formats.
WARNING
NIST publishing ML-KEM, ML-DSA, and SLH-DSA as standards does not make your deployment FIPS 140 validated by itself. Algorithm support, FIPS mode, CAVP testing, and CMVP validation are separate questions. Talk to your vendor or assessor instead of inferring compliance from algorithm names.

What breaks when you enable the FUTURE policy

The table above tells you what FUTURE is supposed to do on RHEL 10.2 and aligned builds. Policy contents can differ across Fedora and RHEL-family releases even when update-crypto-policies exists. The lab below shows you what that feels like on a real SSH client.

I used the two VMs from the lab environment. The client at 192.168.56.108 is where you change crypto policy. The server at 192.168.56.109 runs a second sshd that speaks only classical key exchange.

Take a snapshot or keep console access before you change policy. Red Hat recommends a reboot after policy changes so long-running services pick up the new rules. On my lab, opening a fresh ssh client was enough to reproduce the failure.

On the server VM, create the lab directory:

bash
mkdir -p /tmp/pqc-lab/sshd-classical

Save this minimal configuration as /tmp/pqc-lab/sshd-classical/sshd_config:

text
Port 2222
ListenAddress 192.168.56.109
PidFile /tmp/pqc-lab/sshd-classical/sshd.pid
HostKey /etc/ssh/ssh_host_ed25519_key
AuthorizedKeysFile .ssh/authorized_keys
PermitRootLogin yes
KexAlgorithms curve25519-sha256,ecdh-sha2-nistp256

Start that classical server:

bash
/usr/sbin/sshd -f /tmp/pqc-lab/sshd-classical/sshd_config

Confirm it is listening on port 2222 so a later failure can be traced to key exchange rather than a server-start problem:

bash
ss -ltn | grep ':2222'

Sample output:

output
LISTEN 0 128 192.168.56.109:2222 0.0.0.0:*

If sshd cannot bind to port 2222 on an SELinux-enforcing system, assign the port to the SSH label:

bash
semanage port -a -t ssh_port_t -p tcp 2222

If the port is already defined, use semanage port -m -t ssh_port_t -p tcp 2222 instead.

If semanage is unavailable, install the package that supplies it—for example, policycoreutils-python-utils on current RHEL-family systems.

If firewalld is running on the server, allow the test port:

bash
firewall-cmd --add-port=2222/tcp

On the client VM, check which policy is active:

bash
update-crypto-policies --show

While the client is still on DEFAULT, confirm that the classical server on port 2222 answers:

bash
ssh -p 2222 -o StrictHostKeyChecking=no [email protected] exit

A quiet exit means the classical handshake worked.

Now change only the client to the FUTURE policy:

bash
update-crypto-policies --set FUTURE

Try the same classical connection again:

bash
ssh -p 2222 -vv [email protected] exit

Sample output:

output
debug1: kex: algorithm: (no match)
Unable to negotiate with 192.168.56.109 port 2222: no matching key exchange method found. Their offer: curve25519-sha256,ecdh-sha2-nistp256,ext-info-s,[email protected]

The client now offers only hybrid ML-KEM methods. The lab server on port 2222 offers only classical methods. With no shared choice, ssh stops and prints the error above.

That does not mean SSH is broken everywhere on the client. Connect to the normal sshd on port 22 on the same server:

bash
ssh -vv [email protected] exit

Sample output:

output
debug1: kex: algorithm: mlkem768x25519-sha256

Port 22 still negotiates hybrid ML-KEM because both sides support it. FUTURE blocks peers that never learned post-quantum key exchange, not every SSH session.

Do not run this on a production server, a host without console access, a system that must reach non-PQ repositories, or a workstation you rely on for normal internet access.

Switch back to DEFAULT when you finish

On the client VM, return to DEFAULT:

bash
update-crypto-policies --set DEFAULT

Confirm the change:

bash
update-crypto-policies --show

Sample output:

output
DEFAULT

Try the classical lab server on port 2222 again:

bash
ssh -p 2222 -o StrictHostKeyChecking=no [email protected] exit

The connection should work again. Going back to DEFAULT does not strip out post-quantum support. It simply lets the client talk to classical peers again when the remote side has not caught up yet.

On the server VM, stop the lab sshd, remove the temporary firewall rule if you added one, and delete /tmp/pqc-lab when you are done.


Decide what administrators should do now

If you are planning a rollout, this checklist is a practical place to start. It is not a promise that every connection is already quantum-resistant.

  1. Inventory OpenSSL and OpenSSH versions on every tier, using the capability commands above rather than distribution labels alone.
  2. Stay on supported package versions so OpenSSL, OpenSSH, and (on RHEL-family systems) crypto-policy fixes arrive together.
  3. On RHEL-family systems, keep DEFAULT unless your environment documentation calls for something else.
  4. Verify which PQ algorithms are implemented and allowed, then capture negotiated TLS and SSH output.
  5. Test interoperability with older clients, proxies, load balancers, HSMs, and monitoring tools.
  6. Identify data that needs long-term confidentiality and prioritize those paths for hybrid protection.
  7. Exercise ML-DSA keys and certificates in isolated labs before production issuance.
  8. Avoid generating new long-lived keys in the old RHEL 10.0 oqsprovider formats.
  9. On RHEL-family systems, convert important Technology Preview-era PQ keys before depending on them after an upgrade.
  10. Track vendor, OpenSSL, OpenSSH, IETF, and NIST updates.
  11. Obtain compliance guidance from your vendor or assessor instead of inferring it from algorithm availability.

The immediate value of post-quantum cryptography on Linux is operational experience, interoperability testing, harvest-now-decrypt-later protection for selected TLS and SSH sessions, and preparation for a gradual migration across certificates, signing workflows, and application stacks.


References


Frequently Asked Questions

1. Is post-quantum cryptography enabled by default on Linux?

There is no single Linux-wide default. Availability depends on the OpenSSL and OpenSSH builds your distribution ships and any system-wide crypto policy it applies. Current RHEL-family releases enable supported PQC through predefined policies, while other distributions may rely on upstream OpenSSL, OpenSSH, or application-specific configuration. Verify the negotiated TLS group or SSH key exchange instead of assuming PQC is active.

2. What is the difference between ML-KEM and ML-DSA?

ML-KEM establishes a shared secret for key exchange and confidentiality. ML-DSA signs and verifies data for integrity and authenticity. TLS can adopt hybrid ML-KEM key exchange before you deploy ML-DSA certificates.

3. Why is post-quantum cryptography enabled but not negotiated?

Both endpoints must support and prefer the same algorithm, the application must offer it, TLS 1.3 is required for hybrid TLS groups, and middleboxes or older peers may block PQ methods. Inspect negotiated TLS groups with openssl s_client or SSH kex lines with ssh -vv instead of assuming PQC from policy alone.

4. What does the FUTURE crypto policy break on RHEL-family systems?

On RHEL 10.2 and aligned builds that ship the crypto-policies framework, FUTURE allows only hybrid ML-KEM key exchange. SSH to classical-only servers, many public TLS sites, older Java TLS stacks, and some repositories can fail until you return to DEFAULT or the remote side adds compatible hybrid support.

5. How do I disable post-quantum algorithms with NO-PQ on RHEL-family systems?

Run update-crypto-policies --set DEFAULT:NO-PQ on distributions that use the RHEL/Fedora crypto-policies framework. Treat it as a diagnostic or compatibility step, not routine hardening, because it removes harvest-now-decrypt-later protection on new sessions.

6. Are PQC algorithms FIPS validated?

NIST standardization of ML-KEM, ML-DSA, and SLH-DSA is not the same as FIPS 140 module validation for your deployment. Algorithm availability, FIPS mode, CAVP testing, and CMVP validation are separate; obtain compliance guidance from your vendor or assessor.

7. Do I still need oqsprovider or TEST-PQ on RHEL-family systems?

RHEL 10.0 used oqsprovider for its Technology Preview implementation. Current RHEL-family releases with OpenSSL 3.5 provide native ML-KEM and ML-DSA and do not require it for these labs. TEST-PQ remains mainly for pure ML-KEM OpenSSL testing on those systems.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …