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.

12voto

angelcorral Points 121

Vous pouvez installer le fournisseur de manière dynamique :

1) Télécharger ces jarres :

  • bcprov-jdk15on-152.jar
  • bcprov-ext-jdk15on-152.jar

2) Copier les pots dans WEB-INF/lib (ou votre chemin d'accès)

3) Ajouter un fournisseur de manière dynamique :

import org.bouncycastle.jce.provider.BouncyCastleProvider;

...

Security.addProvider(new BouncyCastleProvider());

8voto

Bertl Points 108

Il s'agit d'un article assez ancien, mais si vous utilisez Apache HTTPD, vous pouvez limiter la taille du DH. Voir http://httpd.apache.org/docs/current/ssl/ssl_faq.html#javadh

7voto

Il est possible que les dépendances Maven soient incorrectes. Vous devez trouver ces bibliothèques dans la hiérarchie des dépendances Maven :

bcprov-jdk14, bcpkix-jdk14, bcmail-jdk14

Si vous avez ces dépendances, c'est l'erreur, et vous devriez faire ceci :

Ajouter la dépendance :

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcmail-jdk15on</artifactId>
    <version>1.59</version>
</dependency>

Exclure ces dépendances de l'artefact qui a inclus les mauvaises dépendances, dans mon cas c'est :

<dependency>
    <groupId>com.lowagie</groupId>
    <artifactId>itext</artifactId>
    <version>2.1.7</version>
    <exclusions>
        <exclusion>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bctsp-jdk14</artifactId>                
        </exclusion>
        <exclusion>
            <groupId>bouncycastle</groupId>
            <artifactId>bcprov-jdk14</artifactId>               
        </exclusion>
        <exclusion>
            <groupId>bouncycastle</groupId>
            <artifactId>bcmail-jdk14</artifactId>               
        </exclusion>
    </exclusions>       
</dependency>

6voto

Lekkie Points 105

Si vous utilisez jdk1.7.0_04, mettez à jour vers jdk1.7.0_21. Le problème a été corrigé dans cette mise à jour.

5voto

mjomble Points 99

Essayez de télécharger "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files" à partir de l'adresse suivante Site de téléchargement Java et en remplaçant les fichiers dans votre JRE.

Cela a fonctionné pour moi et je n'ai même pas eu besoin d'utiliser BouncyCastle - le JCE standard de Sun a pu se connecter au serveur.

PS. J'ai obtenu la même erreur (ArrayIndexOutOfBoundsException : 64) lorsque j'ai essayé d'utiliser BouncyCastle avant de modifier les fichiers de politique, il semble donc que notre situation soit très similaire.

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