150 votes

Pourquoi le handshake SSL génère-t-il une exception "Could not generate DH keypair" (Impossible de générer une paire de clés DH) ?

Lorsque j'établis une connexion SSL avec certains serveurs IRC (mais pas avec d'autres - probablement en raison de la méthode de cryptage préférée du serveur), j'obtiens l'exception suivante :

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

Cause finale :

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 exemple de serveur qui démontre ce problème est aperture.esper.net:6697 (il s'agit d'un serveur IRC). Un exemple de serveur ne présentant pas ce problème est kornbluth.freenode.net:6697. [Il n'est pas surprenant de constater que tous les serveurs de chaque réseau ont le même comportement].

Mon code (qui, comme indiqué, fonctionne lors de la connexion à certains serveurs SSL) est le suivant :

    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();

C'est la dernière poignée de main de démarrage qui provoque l'exception. Et oui, il y a un peu de magie avec le code "trustAllCerts" ; ce code force le système SSL à ne pas valider les certificats. (Ce n'est donc pas un problème de certificat).

Évidemment, une possibilité est que le serveur d'esper soit mal configuré, mais j'ai cherché et je n'ai pas trouvé d'autres références à des personnes ayant des problèmes avec les ports SSL d'esper, et 'openssl' s'y connecte (voir ci-dessous). Je me demande donc s'il ne s'agit pas d'une limitation du support SSL par défaut de Java, ou quelque chose comme ça. Des suggestions ?

Voici ce qui se passe lorsque je me connecte à aperture.esper.net 6697 en utilisant 'openssl' depuis la ligne de commande :

~ $ 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)
---

Comme indiqué, après tout cela, il se connecte avec succès, ce qui est plus que ce que l'on peut dire de mon application Java.

Si cela s'avère pertinent, j'utilise OS X 10.6.8, Java version 1.6.0_26.

5voto

pka Points 173

Si vous êtes toujours mordu par cette question ET vous utilisez Apache httpd v> 2.4.7, essayez ceci : http://httpd.apache.org/docs/current/ssl/ssl_faq.html#javadh

copié de l'url :

À partir de la version 2.4.7, mod_ssl utilisera les paramètres DH qui incluent des nombres premiers d'une longueur supérieure à 1024 bits. Java 7 et les versions antérieures limitent toutefois leur prise en charge des tailles de nombres premiers DH à un maximum de 1024 bits.

Si votre client basé sur Java est interrompu par des exceptions telles que java.lang.RuntimeException : Impossible de générer une paire de clés DH et java.security.InvalidAlgorithmParameterException : Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive), and httpd logs tlsv1 alert internal error (SSL alert number 80) (at LogLevel info or higher), vous pouvez soit réarranger la liste de chiffrement de mod_ssl avec SSLCipherSuite (éventuellement en conjonction avec SSLHonorCipherOrder), soit utiliser des paramètres DH personnalisés avec un prime de 1024 bits, qui aura toujours la priorité sur n'importe lequel des paramètres DH intégrés.

Pour générer des paramètres DH personnalisés, utilisez la fonction

openssl dhparam 1024

commande. Vous pouvez également utiliser les paramètres DH 1024 bits standard suivants, tirés de la RFC 2409, section 6.2 :

-----BEGIN DH PARAMETERS-----
MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR
Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL
/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC
-----END DH PARAMETERS-----

Ajoutez les paramètres personnalisés, y compris les lignes "BEGIN DH PARAMETERS" et "END DH PARAMETERS", à la fin du premier fichier de certificat que vous avez configuré à l'aide de la directive SSLCertificateFile.


J'utilise Java 1.6 côté client, et cela a résolu mon problème. Je n'ai pas abaissé les suites de chiffrement ou autres, mais j'ai ajouté un paramètre DH généré sur mesure au fichier cert

3voto

v.ladynev Points 10855

J'ai le même problème avec le serveur Yandex Maps, JDK 1.6 et Apache HttpClient 4.2.1. L'erreur était

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

avec débogage activé par -Djavax.net.debug=all il y avait un message dans un journal

Could not generate DH keypair

J'ai résolu ce problème en ajoutant la bibliothèque BouncyCastle bcprov-jdk16-1.46.jar et l'enregistrement d'un fournisseur dans une classe de services cartographiques

public class MapService {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public GeocodeResult geocode() {

    }

}

Un fournisseur est enregistré lors de la première utilisation de MapService .

2voto

Saheed Points 440

J'ai rencontré l'erreur SSL sur un serveur CentOS utilisant le JDK 6.

J'avais l'intention d'installer une version plus récente du JDK (JDK 7) pour coexister avec le JDK 6, mais il s'avère que le simple fait d'installer le JDK le plus récent avec la commande rpm -i n'a pas suffi.

L'installation du JDK 7 n'a réussi qu'avec l'option rpm -U comme illustré ci-dessous.

1. Télécharger le JDK 7

wget -O /root/jdk-7u79-linux-x64.rpm --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; o raclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/7u79-b15/jdk-7u79-linux-x64.rpm"

2. Échec de l'installation du RPM

rpm -ivh jdk-7u79-linux-x64.rpm
Preparing...                ########################################### [100%]
        file /etc/init.d/jexec from install of jdk-2000:1.7.0_79-fcs.x86_64 conflicts with file from package jdk-2000:1.6.0_43-fcs.x86_64

3. La mise à jour du RPM réussit

rpm -Uvh jdk-7u79-linux-x64.rpm
Preparing...                ########################################### [100%]
   1:jdk                    ########################################### [100%]
Unpacking JAR files...
        rt.jar...
        jsse.jar...
        charsets.jar...
        tools.jar...
        localedata.jar...
        jfxrt.jar...

4. Confirmer la nouvelle version

java -version
java version "1.7.0_79"
Java(TM) SE Runtime Environment (build 1.7.0_79-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode)

1voto

anre Points 682

Le problème a été résolu par la mise à jour vers le JDK 8.

1voto

Raffael Meier Points 159

J'utilise coldfusion 8 sur JDK 1.6.45 et j'ai eu des problèmes avec <cfdocument ...> qui me donnait juste des croix rouges au lieu d'images, et aussi avec cfhttp qui n'était pas capable de se connecter au serveur web local avec ssl.

mon test script à reproduire avec coldfusion 8 était

<CFHTTP URL="https://www.onlineumfragen.com" METHOD="get" ></CFHTTP>
<CFDUMP VAR="#CFHTTP#">

Cela m'a donné l'erreur générique suivante : " I/O Exception : peer not authenticated " (Exception d'entrée/sortie : l'homologue n'est pas authentifié). J'ai ensuite essayé d'ajouter les certificats du serveur, y compris les certificats racine et intermédiaires, au keystore java et au keystore coldfusion, mais rien n'y a fait. J'ai ensuite débogué le problème avec

java SSLPoke www.onlineumfragen.com 443

et a obtenu

javax.net.ssl.SSLException: java.lang.RuntimeException: Could not generate DH keypair

y

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:107)
    ... 10 more

J'ai alors eu l'idée que le serveur web (apache dans mon cas) avait des algorithmes de chiffrement très modernes pour ssl et est assez restrictif (qualys score a+) et utilise des groupes Diffie-hellman forts avec plus de 1024 bits. Il est évident que ColdFusion et Java JDK 1.6.45 ne peuvent pas gérer cela. La prochaine étape de l'odyssée était de penser à installer un fournisseur de sécurité alternatif pour java, et j'ai opté pour bouncy castle. voir aussi http://www.itcsolutions.eu/2011/08/22/how-to-use-bouncy-castle-cryptographic-api-in-netbeans-or-eclipse-for-java-jse-projects/

J'ai ensuite téléchargé le

bcprov-ext-jdk15on-156.jar

de http://www.bouncycastle.org/latest_releases.html et l'a installé sous C:\jdk6_45\jre\lib\ext ou à l'endroit où se trouve votre jdk, dans l'installation originale de coldfusion 8, il se trouve sous C:\JRun4\jre\lib\ext mais j'utilise un jdk plus récent (1.6.45) situé en dehors du répertoire coldfusion. il est très important de mettre le fichier bcprov-ext-jdk15on-156.jar dans le répertoire \ext répertoire (cela m'a coûté environ deux heures et quelques cheveux ;-) puis j'ai édité le fichier C:\jdk6_45\jre\lib\security\java.security (avec wordpad et non avec editor.exe !) et ajouter une ligne pour le nouveau fournisseur. ensuite la liste ressemblait à

#
# List of providers and their preference orders (see above):
#
security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider
security.provider.2=sun.security.provider.Sun
security.provider.3=sun.security.rsa.SunRsaSign
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC
security.provider.10=sun.security.mscapi.SunMSCAPI

(voir le nouveau en position 1)

puis redémarrer complètement le service coldfusion. vous pouvez alors

java SSLPoke www.onlineumfragen.com 443 (or of course your url!)

et profiter de la sensation... et bien sûr <cfhttp et <cfdocument> ont fonctionné comme un charme et comme avant nous avons "durci" notre cryptage ssl dans apache !

Quelle nuit et quel jour ! Si vous avez des questions, écrivez-moi à info ... (domaine ci-dessus).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X