Cuando establezco una conexión SSL con algunos servidores IRC (pero no con otros, probablemente debido al método de cifrado preferido del servidor) obtengo 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 aperture.esper.net:6697 (este es un servidor IRC). Un ejemplo de un servidor que no demuestra el problema es kornbluth.freenode.net:6697. [No es sorprendente 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 comienzo, Handshake, lo que arroja la excepción. Y sí, hay algo de magia con el 'trustAllCerts'; ese código obliga al sistema SSL a no validar certs. (Entonces ... no es un problema de cert.)
Obviamente, una posibilidad es que el servidor de esper esté mal configurado, pero busqué y no encontré ninguna otra referencia a personas que tienen problemas con los puertos SSL de esper, y 'openssl' se conecta a él (ver más abajo). Así que 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 aperture.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 con éxito, lo que es más de lo que puedes decir para mi aplicación Java.
Si fuera relevante, estoy usando OS X 10.6.8, Java versión 1.6.0_26.
openssl
salida en la pregunta: "Cipher es DHE-RSA-AES256-SHA, la clave pública del servidor es 2048 bit". Y 2048> 1024 :-).
Server public key (size)
fue, y es, la clave en el certificado. s_client
en 2011 no mostró clave efímera en absoluto; 1.0.2 en 2015 y hasta hace Server Temp Key
varias líneas más arriba. Aunque un buen servidor generalmente debería hacer que el tamaño de DHE sea igual al tamaño de autenticación RSA.
Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)
. No tengo idea de qué tamaño envió el servidor aquí, y qué dice la especificación sobre esto.