¿Por qué el protocolo de enlace SSL da la excepción "No se pudo generar el par de claves DH"?

Resuelto sam asked hace 13 años • 22 respuestas

Cuando hago una conexión SSL con algunos servidores IRC (pero no con otros, presumiblemente debido al método de cifrado preferido del servidor), aparece la siguiente excepción:

Caused by: java.lang.RuntimeException: Could not generate DH keypair
    at com.sun.net.ssl.internal.ssl.DHCrypt.<init>(DHCrypt.java:106)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverKeyExchange(ClientHandshaker.java:556)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:183)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
    at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:893)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165)
    ... 3 more

Causa final:

Caused by: java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)
    at com.sun.crypto.provider.DHKeyPairGenerator.initialize(DashoA13*..)
    at java.security.KeyPairGenerator$Delegate.initialize(KeyPairGenerator.java:627)
    at com.sun.net.ssl.internal.ssl.DHCrypt.<init>(DHCrypt.java:100)
    ... 10 more

Un ejemplo de un servidor que demuestra este problema es Opening.esper.net:6697 (este es un servidor IRC). Un ejemplo de un servidor que no demuestra el problema es kornbluth.freenode.net:6697. [No sorprende que todos los servidores de cada red compartan el mismo comportamiento respectivo.]

Mi código (que, como se señaló, funciona cuando me conecto a algunos servidores SSL) es:

    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, trustAllCerts, new SecureRandom());
    s = (SSLSocket)sslContext.getSocketFactory().createSocket();
    s.connect(new InetSocketAddress(host, port), timeout);
    s.setSoTimeout(0);
    ((SSLSocket)s).startHandshake();

Es ese último startHandshake el que genera la excepción. Y sí, hay algo de magia con los 'trustAllCerts'; ese código obliga al sistema SSL a no validar los certificados. (Entonces... no es un problema de certificado).

Obviamente, una posibilidad es que el servidor de Esper esté mal configurado, pero busqué y no encontré ninguna otra referencia a personas que tuvieran problemas con los puertos SSL de Esper y 'openssl' se conecta a él (ver más abajo). Entonces me pregunto si esto es una limitación del soporte SSL predeterminado de Java, o algo así. ¿Alguna sugerencia?

Esto es lo que sucede cuando me conecto a apertura.esper.net 6697 usando 'openssl' desde la línea de comandos:

~ $ openssl s_client -connect aperture.esper.net:6697
CONNECTED(00000003)
depth=0 /C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
verify error:num=18:self signed certificate
verify return:1
depth=0 /C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
verify return:1
---
Certificate chain
 0 s:/C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
   i:/C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
---
Server certificate
-----BEGIN CERTIFICATE-----
[There was a certificate here, but I deleted it to save space]
-----END CERTIFICATE-----
subject=/C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
issuer=/C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
---
No client certificate CA names sent
---
SSL handshake has read 2178 bytes and written 468 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : DHE-RSA-AES256-SHA
    Session-ID: 51F1D40A1B044700365D3BD1C61ABC745FB0C347A334E1410946DCB5EFE37AFD
    Session-ID-ctx: 
    Master-Key: DF8194F6A60B073E049C87284856B5561476315145B55E35811028C4D97F77696F676DB019BB6E271E9965F289A99083
    Key-Arg   : None
    Start Time: 1311801833
    Timeout   : 300 (sec)
    Verify return code: 18 (self signed certificate)
---

Como se señaló, después de todo eso, se conecta correctamente, que es más de lo que se puede decir de mi aplicación Java.

Si fuera relevante, estoy usando OS X 10.6.8, versión Java 1.6.0_26.

sam avatar Jul 28 '11 04:07 sam
Aceptado

El problema es el tamaño principal. El tamaño máximo aceptable que acepta Java es 1024 bits. Este es un problema conocido (consulte JDK-6521495 ).

El informe de error al que me vinculé menciona una solución alternativa que utiliza la implementación JCE de BouncyCastle. Con suerte, eso debería funcionar para ti.

ACTUALIZAR

Esto se informó como error JDK-7044060 y se solucionó recientemente.

Sin embargo, tenga en cuenta que el límite sólo se elevó a 2048 bits. Para tamaños > 2048 bits, existe JDK-8072452: eliminar el tamaño principal máximo de las claves DH ; la solución parece ser para 9.

Vivin Paliath avatar Jul 27 '2011 22:07 Vivin Paliath

La respuesta "Archivos de política de jurisdicción de fuerza ilimitada de Java Cryptography Extension (JCE)" no funcionó para mí, pero la sugerencia del proveedor JCE de The BouncyCastle sí.

Estos son los pasos que seguí usando Java 1.6.0_65-b14-462 en Mac OSC 10.7.5

1) Descarga estos frascos:

  • bcprov-jdk15on-154.jar

  • bcprov-ext-jdk15on-154.jar

2) mueve estos frascos a $JAVA_HOME/lib/ext

3) edite $JAVA_HOME/lib/security/java.security de la siguiente manera: security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider

reinicie la aplicación usando JRE y pruébelo

mjj1409 avatar Mar 20 '2015 22:03 mjj1409