Troubleshooting PQC

Common issues and solutions for PQC TLS and SSH connections.

TLS Verification Fails

Symptom: openssl s_client does not show X25519MLKEM768 in Server Temp Key.

Solution:

  1. Verify DEFAULT:PQ crypto policy is active by running:
    update-crypto-policies --show
  2. Restart AAP services after enabling the crypto policy.
  3. Check Envoy gateway-proxy logs for TLS negotiation errors.

Certificate Not Recognized

Symptom: Browsers or clients reject ML-DSA certificates.

Solution:

1. Ensure clients support ML-DSA algorithm (may require client updates)

Client support depends on the client type:

  • RHEL-based CLI and Python clients: Verify the client host runs OpenSSL 3.5 or later (openssl version) and has the DEFAULT:PQ crypto policy active (update-crypto-policies --show). Update with sudo dnf update openssl && sudo update-crypto-policies --set DEFAULT:PQ if needed. Confirm validation with openssl s_client -connect <gateway>:443 -CAfile /path/to/ca-cert.pem, look for Verify return code: 0 (ok).
  • Browsers: ML-DSA certificate signing support varies by browser version and is still emerging. If broad browser compatibility is required, use an installer-generated RSA certificate with PQC key exchange instead of a self-supplied ML-DSA certificate. This provides quantum-resistant key exchange without requiring the browser to validate an ML-DSA signature. For more information on certificate signing and key exchange, see Post-quantum cryptography in Red Hat Enterprise Linux 10
  • Other clients (Java, Go, Node.js): Check vendor documentation for ML-DSA / FIPS 204 certificate support. Clients not on a RHEL 9.7+ host with OpenSSL 3.5 may require vendor-specific updates.

2. Verify certificate chain includes all intermediate CAs

Run the following to inspect the chain the gateway is serving:

openssl s_client -connect <gateway-hostname>:443 -showcerts 2>/dev/null

Count the -----BEGIN CERTIFICATE----- blocks in the output. If only one is present, the gateway is not serving intermediate CA certificates and clients cannot build a complete trust chain.

To validate the chain against your CA bundle:

openssl verify -CAfile /path/to/ca-cert.pem -untrusted /path/to/intermediate.pem /path/to/leaf-cert.pem

Expected output: leaf-cert.pem: OK. Any other output indicates a missing or misordered certificate in the chain.

If intermediates are missing, concatenate them with the root CA into a single PEM file and set custom_ca_cert to that file in the installer inventory, then re-run the installer:

cat intermediate-ca.pem root-ca.pem > full-chain-ca.pem

3. Check that custom_ca_cert is properly configured in installer inventory

  1. Confirm the variable is present in your inventory file:
    grep -n "custom_ca_cert" /path/to/inventory
  2. Confirm the referenced file exists, is readable, and contains valid PEM content:
    openssl crl2pkcs7 -nocrl -certfile /path/to/full-chain-ca.pem \
     | openssl pkcs7 -print_certs -noout

    This prints the subject and issuer of every certificate in the bundle. Any error here indicates a malformed or incorrect file path.

  3. Confirm the bundle covers your ML-DSA certificate's issuer by comparing the leaf certificate's issuer field against the subject values printed in step 2. If there is no match, the wrong CA file is being referenced.
  4. If any of the above are incorrect, fix the inventory and re-run the installer, then verify with:
    openssl s_client -connect <gateway-hostname>:443 -CAfile /path/to/full-chain-ca.pem

    Expected: Verify return code: 0 (ok)

Known issue

DE/EE container images usage from Private Automation Hub when using a TLS certificate based on ML-DSA. The containerized installer will not push container images to Private Automation Hub and Automation Controller jobs or Automation EDA activation jobs will not be able to consume them due to podman limitation (golang 1.26). Using DE/EE container images from registry.redhat.io still work (or any other container registries not using ML-DSA based TLS certificates)