2012-05-21 4 views
14

Ich las einen früheren Beitrag bezüglich des Fehlers 'DH-Schlüsselpaar konnte nicht generiert' ausgelöst, wenn der Server einen Schlüssel länger als 1024 Bit sent. Das Herunterladen der unbegrenzten JCE-Jars sollte dieses Problem beheben. In der Testumgebung habe ich Folgendes festgestellt, für denselben Webserver, wenn ich Java 6 verwende, erhalte ich keine Fehler bei der Ausführung der https-Abfrage, aber wenn ich Java 7 verwende, dann bekomme ich 'konnte kein DH-Schlüsselpaar erzeugen'.Java 7 und DH-Schlüsselpaar konnte nicht erzeugt werden

Ich habe versucht, die Jar-Dateien für JCE unbegrenzt zu ersetzen, aber immer noch den gleichen Fehler. Der Fehler wird seit 2007 gemeldet, aber warum läuft er für Java 6 und nicht für Java 7? Sind die herunterzuladenden Dateien nicht die richtigen? Ich habe den Link von einem früheren Post Java: Why does SSL handshake give 'Could not generate DH keypair' exception?.

An diesem Punkt weiß ich nicht, was zu tun ist. Wenn ich versuche, den BouncyCastle-Provider zu laden, erhalte ich eine ArrayOutOfIndex-Ausnahme. Mein Server erlaubt nur den DH-Algorithmus, so dass ich keinen anderen Algorithmus wie im obigen Beitrag vorgeschlagen verwenden kann.

Antwort

8

Ich stolperte über das gleiche Problem mit SSLScokets und ich denke, ich habe den Grund für diese Regression mit Java 7 identifiziert. Der Grund kommt zu den Chiffren ausgehandelt zwischen dem Client und dem Server.

standardmäßig Java 6 ermöglicht diese Chiffren für eine Verbindung TLS (in Prioritätsreihenfolge):

SSL_RSA_WITH_RC4_128_MD5 
SSL_RSA_WITH_RC4_128_SHA 
TLS_RSA_WITH_AES_128_CBC_SHA 
TLS_DHE_RSA_WITH_AES_128_CBC_SHA 
TLS_DHE_DSS_WITH_AES_128_CBC_SHA 
SSL_RSA_WITH_3DES_EDE_CBC_SHA 
SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA 
SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA 
SSL_RSA_WITH_DES_CBC_SHA 
SSL_DHE_RSA_WITH_DES_CBC_SHA 
SSL_DHE_DSS_WITH_DES_CBC_SHA 
SSL_RSA_EXPORT_WITH_RC4_40_MD5 
SSL_RSA_EXPORT_WITH_DES40_CBC_SHA 
SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA 
SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA 
TLS_EMPTY_RENEGOTIATION_INFO_SCSV 

Und Java 7 ermöglicht es, diese Chiffren:

TLS_DHE_RSA_WITH_AES_128_CBC_SHA 
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 
SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA 
SSL_RSA_WITH_RC4_128_SHA 
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 
TLS_ECDHE_RSA_WITH_RC4_128_SHA 
TLS_ECDH_ECDSA_WITH_RC4_128_SHA 
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA 
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA 
TLS_ECDH_RSA_WITH_RC4_128_SHA 
TLS_EMPTY_RENEGOTIATION_INFO_SCSV 
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA 
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 
TLS_RSA_WITH_AES_128_CBC_SHA 
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 
SSL_RSA_WITH_RC4_128_MD5 
TLS_DHE_DSS_WITH_AES_128_CBC_SHA 
SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA 
SSL_RSA_WITH_3DES_EDE_CBC_SHA 

Chiffren mit Diffie-Hellman kommen in höheren Priorität auf Java 7, aber sie scheinen keine Schlüssel länger als 1024 Bit zu unterstützen, es sei denn, das starke Crypto-Paket ist installiert.

Die Abhilfe, die ich verwendet wurde, war die Chiffren von Java 6 auf der SSLSocket aktiviert angeben:

SSLSocketFactory socketFactory = SSLContext.getInstance("TLS").getSocketFactory(); 
SSLSocket socket = (SSLSocket) socketFactory.createSocket(InetAddress.getByName(hostname), port); 
socket.setEnabledCipherSuites(new String[] { 
     "SSL_RSA_WITH_RC4_128_MD5", 
     "SSL_RSA_WITH_RC4_128_SHA", 
     "TLS_RSA_WITH_AES_128_CBC_SHA", 
     "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", 
     "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", 
     "SSL_RSA_WITH_3DES_EDE_CBC_SHA", 
     "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", 
     "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", 
     "SSL_RSA_WITH_DES_CBC_SHA", 
     "SSL_DHE_RSA_WITH_DES_CBC_SHA", 
     "SSL_DHE_DSS_WITH_DES_CBC_SHA", 
     "SSL_RSA_EXPORT_WITH_RC4_40_MD5", 
     "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", 
     "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", 
     "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", 
     "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"}); 

socket.startHandshake(); 
+0

vielen Dank traf ich eine seltsame * java.security.ProviderException: Sonne .security.pkcs11.wrapper.PKCS11Exception: CKR_DOMAIN_PARAMS_INVALID * Fehler bei der Verwendung von Webscarab (SSL MITM Proxy). Wenn Sie diese Chiffre-Suites explizit angeben, funktioniert sie wieder. – Lekensteyn

+1

Ich bin neu in Java Wertpapiere. Wo soll ich diesen Code schreiben? – Shashank

0

Wenn Sie jdk1.7.0_04 verwenden, um jdk1.7.0_21 zu aktualisieren. Das Problem wurde in diesem Update behoben.

+0

Kühl. Dies wurde in neueren Versionen von Java behoben. Aber meine Frage ist über die Verwendung älterer Version .. Wenn ich ältere Version verwenden, manchmal funktioniert es und manchmal gibt es über Ausnahme .. Warum so zufälliges Verhalten? Wenn es ein Bug in Java ist, dann denke ich, es sollte nie funktionieren? –

+2

Leider bekomme ich diesen Fehler immer noch in '7u21-2.3.9-1ubuntu1'. – expert

+0

Ich bekomme immer noch diesen Fehler in Build 1.7.0_45-b18 – duffymo

10

Einige Ergänzungen oder Präzisierungen:

(Suncle) Java 7 seit 7u09 einer vernünftige konsistente Reihenfolge des ciphersuites standardmäßig verwendet, im Gegensatz zu der scheinbar zufälligen Reihenfolge in 7u04. (Ich habe keine Tests zwischen 04 und 09.) Diese Reihenfolge setzt ECDHE und plain-RSA (aka akRSA) vor DHE und vermeidet somit das Problem, wenn UND NUR WENN der Server ECDHE oder RSA unterstützt und der Kundenpräferenz zustimmt. (Oder ECDH-behoben, aber praktisch niemand benutzt das.) Wenn der Server auf DHE besteht (aus welchem ​​Grund auch immer) UND DH> 1024 Bits verwendet, haben Sie immer noch das Problem. Wenn der Fragesteller (oder jemand anders) eine Verbindung zu einem Server herstellt, der tatsächlich eine Ganzzahl-DH (und nicht ECDH oder RSA) benötigt, ist die einzige Möglichkeit mit Java vor 8 zu arbeiten, den Server dazu zu bringen, DH 1024-Bit zu verwenden . Welche AFAWK ist für ein paar Jahre technisch sicher, aber mit einem geringen Spielraum wird es von wichtigen Behörden wie NIST verboten (siehe Special Pub 800-57 bei csrc.nist.gov). (Sogar RSA 1024 ist noch nicht wirklich kaputt, aber es wird wahrscheinlich bald und so ist verboten.)

Die "unbegrenzte Stärke Politik" ist nicht relevant für dieses Problem, oder zumindest nicht direkt, und die guten Antworten zu # 6851461 habe ich nicht gesagt. Es ändert nicht die Einschränkung der DH-Parameter in SunJCE, die (fälschlicherweise) als Standardproblem und nicht als Stärkeproblem behandelt wird. (Insbesondere nimmt es die Einschränkungen, die für DSA korrekt waren, und wendet sie auf DH an.) Es aktiviert AES-256 und SHA-2 (nur für TLSv1.2) -Suiten und gibt eine ausreichend merkwürdige Präferenzliste, die das könnte Ändern Sie das Auswahlergebnis von DHE (fehlgeschlagen) in nicht-DHE (funktioniert).

Sie müssen nicht ganz zurück zur Java 6-Liste gehen, Sie müssen nur andere Schlüsselaustauschvorgänge über DHE priorisieren, oder für einen widerspenstigen Server DHE vollständig löschen. Sie sollten auf keinen Fall darauf verzichten, EXPORT- oder Single-DES-Suites zu aktivieren, es sei denn, sie werden für einen Legacy-Server unbedingt benötigt. Sie sind seit mehreren Jahren NICHT SICHER und blieben standardmäßig 6 länger aktiviert, als sie sollten.

1

Wir sind auch auf dieses Problem mit Java7 und Java8 gekommen. Wir haben auch einen Workaround verwendet, der den Empfehlungen von Emanual Borg ähnelt. Unser Ziel war es jedoch, eine feste Liste von CipherSuites nicht hart zu codieren. Also haben wir versucht, die Einträge zu entfernen, die das Problem verursacht haben (durch Versuch und Irrtum ...).

String[] enabledCipherSuites = socket.getEnabledCipherSuites(); 

// avoid hardcoding a new list, we just remove the entries 
// which cause the exception 
List<String> asList = new ArrayList(Arrays.asList(enabledCipherSuites)); 

// we identified the following entries causeing the problems 
// "Could not generate DH keypair" 
// and "Caused by: java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)" 
asList.remove("TLS_DHE_RSA_WITH_AES_128_CBC_SHA"); 
asList.remove("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"); 
asList.remove("TLS_DHE_RSA_WITH_AES_256_CBC_SHA"); 

String[] array = asList.toArray(new String[0]); 
socket.setEnabledCipherSuites(array); 

Frage: Sieht jemand ein Problem mit diesem Ansatz?

Btw: Falls Sie Apache Httpclient verwenden, dann ist https://issues.apache.org/jira/browse/HTTPCLIENT-1111 interessant, die zeigt, wie der CipherSuites setzen (beginnend mit Httpclient v4.2) über das Verfahren

SSLConnectionSocketFactory() {...}.prepareSocket(SSLSocket) 

aktualisieren 2015.10.31 : besser zu helfen, den Kontext zu verstehen, wo dies zu nutzen, hier als Voll Pseudo-Code Beispiel, wo Sie sehen, wie man in dem Haken prepareSocket() -Methode außer Kraft zu setzen:

HttpClientBuilder builder = HttpClients.custom(); 

SSLContextBuilder sslContextBuilder = SSLContexts.custom(); 
SSLContext sslContext = sslContextBuilder.build(); 

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostNameVerfier) 
{ 


    protected void prepareSocket(SSLSocket socket) throws IOException { 

    // Workaround to use different order of CipherSuites used by Java6 in order 
     // to avoid the the problem of java7 "Could not generate DH keypair" 
     String[] enabledCipherSuites = socket.getEnabledCipherSuites(); 

     // but to avoid hardcoding a new list, we just remove the entries 
     // which cause the exception (via TrialAndError) 
     List<String> asList = new ArrayList(Arrays.asList(enabledCipherSuites)); 

     // we identified the following entries causeing the problems 
     // "Could not generate DH keypair" 
     // and "Caused by: java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)" 
     asList.remove("TLS_DHE_RSA_WITH_AES_128_CBC_SHA"); 
     asList.remove("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"); 
     asList.remove("TLS_DHE_RSA_WITH_AES_256_CBC_SHA"); 

     String[] array = asList.toArray(new String[0]); 
     socket.setEnabledCipherSuites(array); 

    }; 
}; 

Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create().register("https", sslsf).build(); 

PoolingHttpClientConnectionManager conman = new PoolingHttpClientConnectionManager(socketFactoryRegistry); 
builder.setConnectionManager(conman); 

CloseableHttpClient httpClient = builder.build(); 

Seien Sie vorsichtig Wir verwenden diesen Code nur in einem Kontext, in dem der Benutzer ausdrücklich erlaubt, selbstsignierte Zertifikate (z. für Testumgebungen usw.). Wenn du das nicht willst, dann mach dich besser nicht mit dem SSL-Zeug herum.

+0

Ich benutze Apache httpclient, konnte aber nicht verstehen, wie PrepareSocket zu verwenden –

6

Gegeben Sie die neueste Java-Version verwenden und immer noch den Fehler erhalten, können Sie eine Einstellung in java.security ändern (zB im Ordner C: \ Programme \ Java \ jre1.8.0_xx \ lib \ security

.!
# Example: 
# jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048 
    jdk.tls.disabledAlgorithms=SSLv3, RC4 

hinzufügen DH als deaktiviert Algorithmus in jdk.tls.disabledAlgorithms

jdk.tls.disabledAlgorithms=SSLv3, RC4, DH 

Restart Kater oder erneut aus Ihrem Programm

Verwandte Themen