Java le ofrece los componentes poscuánticos antes que un handshake TLS poscuántico. Para una aplicación Java de servidor situada detrás de un proxy inverso, la vía más rápida hacia el intercambio de claves híbrido con ML-KEM (Module-Lattice-Based Key Encapsulation Mechanism, estandarizado como NIST FIPS 203) consiste en actualizar el proxy, no la JVM. Cuando Java actúa como cliente TLS, el intercambio de claves híbrido depende de la versión del JDK y del proveedor JSSE utilizado, por lo que la única respuesta fiable procede de las notas de versión de la compilación que realmente despliega, confirmada mediante una prueba de handshake.
Determine primero qué lado del handshake controla
El intercambio de claves TLS lo negocian las dos pilas que realizan el handshake, no el código de la aplicación. Tres casos cubren casi todos los despliegues Java, y cada uno tiene una respuesta distinta.
- Tráfico entrante terminado en un proxy. Un controlador de ingress, un balanceador de carga, una CDN o una instancia de nginx, Apache, HAProxy o Caddy realiza el handshake. La JVM nunca ve el intercambio de claves. Basta con actualizar el proxy para ofrecer grupos híbridos a navegadores y clientes de API.
- Tráfico entrante terminado en la JVM. Un listener embebido de Tomcat, Jetty, Undertow o Netty con un almacén de claves Java. En este caso, la lista de grupos procede de la implementación TLS del JDK (JSSE), o de la biblioteca TLS nativa que hay detrás del conector.
- Tráfico saliente, Java como cliente. Clientes HTTP que llaman a API de socios, controladores JDBC y de brókeres de mensajería, SDK de almacenamiento de objetos, TLS mutuo entre servicios internos. El lado Java propone la lista
supported_groupsy el servidor remoto elige uno.
Priorice el trabajo según el riesgo de «recolectar ahora, descifrar después» (HNDL, harvest now, decrypt later): a un atacante que graba el tráfico hoy y lo descifra años más tarde lo frena el intercambio de claves, no el certificado. Por eso el establecimiento de claves con ML-KEM va primero y la migración de firmas puede venir después. El registro TLS de IANA recoge los grupos híbridos en uso, entre ellos X25519MLKEM768 (codepoint 0x11EC), SecP256r1MLKEM768 y SecP384r1MLKEM1024 (parámetros TLS de IANA), y RFC 10024 especifica el acuerdo de claves híbrido poscuántico y tradicional para TLS 1.3 (RFC 10024).
Situación actual del JDK
Conviene distinguir dos capas: las primitivas criptográficas expuestas a través de la Java Cryptography Architecture (JCA) y el soporte de grupos híbridos dentro de JSSE.
Primitivas: disponibles en las versiones actuales
JEP 452 añadió en JDK 21 una API de mecanismo de encapsulación de claves (KEM), javax.crypto.KEM. JDK 24 añadió implementaciones de ML-KEM (JEP 496) y de ML-DSA (Module-Lattice-Based Digital Signature Algorithm, NIST FIPS 204) en JEP 497, accesibles mediante las API habituales KeyPairGenerator, KEM y Signature con nombres de algoritmo para cada conjunto de parámetros. Como las funcionalidades del JDK se mantienen de una versión a otra, las versiones posteriores las incluyen. Esto es lo que necesita para sus propios protocolos, el envoltorio de claves, los formatos de token y los entornos de prueba. Por sí solo, no es TLS.
Grupos TLS híbridos: consulte las notas de versión de su JDK
Ofrecer un grupo híbrido en un handshake TLS 1.3 es un trabajo independiente dentro de JSSE: hay que registrar el grupo, generar y analizar los key shares y derivar el secreto compartido a partir de ambos componentes. Que el JDK que ejecuta lo haga, con qué nombres de grupo y si está activado por defecto varía según la versión y la compilación del proveedor, ya que las distribuciones aplican backports de forma selectiva. No deduzca el soporte TLS de la presencia de ML-KEM en la JCA, ni se base en un artículo escrito sobre otra compilación. Consulte las notas de versión de su versión exacta del JDK y verifíquelo después de forma empírica con la prueba de handshake que se describe más abajo.
| Capa | Qué verificar | Dónde consultar |
|---|---|---|
| Primitivas JCA | Generación de pares de claves ML-KEM y ML-DSA, encapsulación, verificación de firmas | Notas de versión del JDK, documentación de nombres de algoritmos estándar |
| Grupos híbridos JSSE | Si el grupo híbrido aparece en el ClientHello o el ServerHello | Notas de versión del JDK, junto con un handshake real con registro de depuración |
| TLS nativo detrás de un conector | Versión de la biblioteca nativa que usa el conector (los grupos ML-KEM requieren OpenSSL 3.5 o posterior en compilaciones basadas en OpenSSL) | Árbol de dependencias, versión de la biblioteca nativa en tiempo de ejecución |
| Proxy o ingress | Lista y orden de grupos, presencia del respaldo clásico | Configuración del proxy y sus propias notas de versión |
Sus opciones, por orden de esfuerzo
Terminar el TLS entrante en un proxy
Es la opción pragmática por defecto para Java de servidor. El proxy necesita una biblioteca TLS que implemente los grupos ML-KEM: en compilaciones basadas en OpenSSL, eso significa OpenSSL 3.5 o posterior. Configure el grupo híbrido en primer lugar y mantenga los grupos clásicos detrás, para que los clientes sin soporte híbrido sigan conectándose, y valide en preproducción antes de pasar a producción. Las directivas paso a paso para los servidores habituales están en nuestra guía para activar ML-KEM en nginx, Apache, HAProxy y Caddy. Una precaución práctica: un key share híbrido es bastante más grande que un key share X25519, lo que puede hacer que el ClientHello supere los límites de un paquete. Algunos middleboxes antiguos y equipos de red con un comportamiento deficiente lo gestionan mal, así que pruebe desde las redes que sus clientes utilizan realmente.
Actualizar el JDK allí donde la JVM termina el TLS
Si un listener Java atiende directamente a los clientes, o si Java es el cliente en una conexión que le importa, la solución limpia es ejecutar una versión del JDK cuyo JSSE ofrezca el grupo híbrido y confirmarlo después en la red. JSSE expone la propiedad de sistema documentada jdk.tls.namedGroups para restringir y ordenar los grupos que ofrece. Los nombres que acepta dependen de la versión, así que tómelos de sus notas de versión en lugar de copiar un ejemplo, y deje siempre en la lista un grupo clásico como X25519. No fije un único grupo poscuántico en producción.
Añadir una biblioteca proveedora o enrutar el tráfico saliente a través de una pasarela
Un proveedor JCA o JSSE de terceros puede aportar algoritmos y, en algunos casos, una pila TLS independiente del JDK. Valórelo con cuidado: instalar un proveedor modifica el comportamiento de seguridad de toda la JVM, interactúa con el modo FIPS y con la validación de la ruta de certificación, y se convierte en una dependencia que debe mantener parcheada. Limite el cambio al SSLContext del cliente concreto cuando la biblioteca lo permita, en lugar de reordenar los proveedores globales. Para las llamadas salientes desde JVM heredadas que no pueden actualizarse, un proxy de salida que realice el handshake suele ser más sencillo y fácil de auditar que modificar cada aplicación. Tenga en cuenta también que los conectores que usan una biblioteca TLS nativa (por ejemplo, Netty con netty-tcnative) dependen de la versión de esa biblioteca, no del JDK.
Inventariar el uso criptográfico en Java antes de cambiar nada
Todos los calendarios oficiales empiezan por el descubrimiento, y los auditores piden el inventario antes que la migración. Estos comandos de solo lectura le ofrecen una primera pasada; adapte las rutas a la estructura de su proyecto.
# TLS and crypto entry points in application code
grep -rnE "SSLContext|SSLSocketFactory|HttpsURLConnection|TrustManager|KeyManagerFactory" --include="*.java" src/
# algorithm names and keystore formats hard coded in source or configuration
grep -rnE "RSA|ECDSA|SHA1|MD5|PKCS12|JKS" --include="*.java" --include="*.properties" --include="*.yml" .
# which TLS stack each service really uses
mvn -q dependency:tree | grep -Ei "netty|tcnative|conscrypt|bouncycastle|okhttp|httpclient"
./gradlew dependencies --configuration runtimeClasspath | grep -Ei "netty|tcnative|okhttp|httpclient"
# keys and certificates in a keystore, with their algorithms
keytool -list -v -keystore keystore.p12 -storetype PKCS12 | grep -E "Alias name|Signature algorithm name|Subject Public Key Algorithm"
Registre algo más que TLS. Las aplicaciones Java también firman JSON Web Tokens y aserciones SAML, verifican JAR firmados, cifran columnas de bases de datos y fijan anclas de confianza. Anote los algoritmos de clave pública vulnerables a la computación cuántica (RSA, ECDSA, EdDSA, ECDH, Diffie-Hellman de campo finito y DSA se ven todos afectados por el algoritmo de Shor, sea cual sea el tamaño de clave), dónde se utiliza cada uno, quién es su responsable y si el algoritmo puede configurarse sin modificar el código. Un inventario criptográfico legible por máquina es una forma práctica de mantener esa lista actualizada: consulte qué es un CBOM y cómo generarlo. Vigile también los archivos de política de seguridad del JDK, ya que jdk.tls.disabledAlgorithms y jdk.certpath.disabledAlgorithms en java.security ya determinan lo que sus JVM aceptarán.
Comprobar lo que el handshake negocia realmente
Las afirmaciones sobre el soporte no valen nada sin un grupo negociado. Realice tres comprobaciones, en este orden.
# 1. external view of the listener (OpenSSL 3.5 or later on the client side)
openssl s_client -connect api.example.com:443 -groups X25519MLKEM768 </dev/null 2>&1 | grep -i "Negotiated TLS1.3 group"
# 2. the classical fallback must still work
openssl s_client -connect api.example.com:443 -groups X25519 </dev/null 2>&1 | grep -i "Negotiated TLS1.3 group"
# 3. what the Java client offers, and what the peer selects
java -Djavax.net.debug=ssl:handshake -jar client.jar 2>&1 | grep -iE "supported_groups|named group|key_share"
El paso 3 es el decisivo cuando Java actúa como cliente: la salida de depuración muestra los grupos del ClientHello y el grupo elegido para el intercambio de claves. Si el grupo híbrido no aparece nunca, la compilación del JDK no lo ofrece, diga lo que diga la documentación. Conserve la salida como evidencia, junto con la cadena de versión del JDK y la fecha. Nuestro escáner gratuito cubre el paso 1 desde el exterior, incluidas las versiones de TLS, los conjuntos de cifrado y la cadena de certificados; lo que un resultado significa y lo que no se describe en nuestra página de metodología.
Cómo se refleja esto en las auditorías
El inventario que acaba de elaborar es el artefacto que piden la mayoría de los marcos, y lo que sigue es información, no asesoramiento jurídico. El requisito 12.3.3 de PCI DSS v4.0.1, obligatorio desde el 31 de marzo de 2025, exige un inventario documentado de los conjuntos de cifrado y protocolos en uso, revisado al menos cada 12 meses, con una estrategia ante los cambios previstos en las vulnerabilidades criptográficas: consulte nuestra página sobre el requisito 12.3.3 de PCI DSS. En el marco de DORA, el Art. 6 del Reglamento Delegado (UE) 2024/1774 de la Comisión exige una política de cifrado y controles criptográficos con disposiciones para actualizar o cambiar la tecnología criptográfica en función de la evolución del criptoanálisis, y el Art. 7 exige la gestión de claves y un registro de certificados para los activos de TIC que respaldan funciones críticas o importantes (EUR-Lex). Interpretación, no texto: en un parque Java, la prueba práctica del Art. 6 es que sus servicios puedan cambiar de grupos y algoritmos mediante configuración y una actualización del JDK o del proxy, no mediante una reescritura. En cuanto al estado de los algoritmos, NIST publicó FIPS 203, 204 y 205 como estándares definitivos el 13 de agosto de 2024 (FIPS 203), mientras que NIST IR 8547, que propone declarar obsoletos los algoritmos de clave pública con seguridad de 112 bits después de 2030 y prohibir los algoritmos de clave pública vulnerables a la computación cuántica después de 2035, sigue siendo un borrador público inicial (NIST IR 8547 ipd).
El siguiente paso concreto
Elija un servicio Java accesible desde el exterior y analice su dominio con PQC Status para ver qué grupo negocia hoy. Si la respuesta es solo clásico y un proxy termina el TLS, actualice ese proxy a una compilación con OpenSSL 3.5 o posterior y sitúe el grupo híbrido por delante de X25519 en preproducción. Si la JVM termina el TLS, o si Java es el cliente en una conexión que transporta secretos de larga duración, registre la versión del JDK en su inventario, consulte sus notas de versión sobre el intercambio de claves híbrido y capture en cualquier caso un registro del handshake como evidencia. Vuelva a analizar tras cada cambio y mantenga el respaldo clásico hasta que sus clientes ya no lo necesiten.