2012-05-21 19 views
14

Przeczytałem poprzedni wpis dotyczący błędu "Nie można wygenerować keypair DH", gdy serwer wysłał klucz dłuższy niż 1024 bity. Pobieranie słoików JCE bez ograniczeń powinno rozwiązać ten problem. W środowisku testowym napotkałem następujące, dla tego samego serwera WWW, jeśli używam Java 6, nie dostaję żadnych błędów podczas wykonywania zapytania https, ale jeśli używam Java 7, otrzymuję komunikat "Nie mogę wygenerować DH keypair".Java 7 i nie można wygenerować keypair DH

Próbowałem zastąpić pliki JAR dla JCE bez ograniczeń, ale nadal otrzymuję ten sam błąd. Błąd jest zgłaszany od 2007 roku, ale dlaczego działa na Java 6, a nie na Java 7? Czy pliki do pobrania nie są prawidłowe? Mam link z poprzedniego posta Java: Why does SSL handshake give 'Could not generate DH keypair' exception?.

W tym momencie nie wiem, co robić. Jeśli spróbuję załadować dostawcę BouncyCastle, otrzymam wyjątek ArrayOutOfIndex. Mój serwer zezwala tylko na algorytm DH, więc nie mogę użyć innego algorytmu, jak sugerowano w powyższym poście.

Odpowiedz

8

Natknąłem się na ten sam problem z SSLScokets i myślę, że zidentyfikowałem przyczynę tej regresji przy pomocy Javy 7. Powodem są szyfry negocjowane między klientem a serwerem.

Domyślnie Java 6 umożliwia tych szyfrów dla połączenia TLS (w kolejności priorytetu):

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 

i Java 7 pozwala na osiągnięcie tych szyfrów:

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 

Szyfry wykorzystujące DiffieHellman przyjść wyższe pierwszeństwo w Java 7, ale wydaje się, że nie obsługują kluczy dłuższych niż 1024 bity, chyba że zainstalowany jest silny pakiet kryptograficzny.

Obejście Kiedyś było określenie szyfrów włączone przez Java 6 na SSLSocket:

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

Thanks a lot natknąłem się na dziwny * java.security.ProviderException: słońce .security.pkcs11.wrapper.PKCS11Exception: Błąd CKR_DOMAIN_PARAMS_INVALID * podczas korzystania z Webscarab (SSL MITM proxy). Jawne określenie tych pakietów szyfrów sprawia, że ​​działa on ponownie. – Lekensteyn

+1

Jestem nowy w papierach wartościowych Java. Gdzie powinienem napisać ten fragment kodu? – Shashank

0

Jeśli używasz jdk1.7.0_04, upgrade do jdk1.7.0_21. Problem został rozwiązany w tej aktualizacji.

+0

Cool. Zostało to naprawione w nowszych wersjach Javy. Ale moje pytanie dotyczy używania starszej wersji. Kiedy używam starszej wersji, czasami działa i czasami daje powyżej wyjątek. Dlaczego więc przypadkowe zachowanie? Jeśli jest to błąd w java, to myślę, że to nigdy nie powinno działać? –

+2

Niestety nadal otrzymuję ten błąd w '7u21-2.3.9-1ubuntu1'. – expert

+0

Nadal dostaję ten błąd w kompilacji 1.7.0_45-b18 – duffymo

10

Niektóre uzupełnienia lub wyjaśnienia:

(Suncle) Java 7 od 7u09 używa bardziej sensownego spójnego kolejność szyfrowaniem domyślnie, w odróżnieniu od pozornie przypadkowej kolejności w 7u04. (Nie mam testów między 04 i 09.) To zamówienie stawia ECDHE i zwykły RSA (akaAAAA) przed DHE, a tym samym unika problemu, jeśli I TYLKO JEŻELI serwer obsługuje ECDHE lub RSA i zgadza się na preferencje klienta. (Lub ECDH-fixed, ale praktycznie nikt tego nie używa). Jeśli serwer nalega na DHE (z jakiegokolwiek powodu) I używa DH> 1024 bitów, wciąż masz problem.

Jeśli osoba pytająca (lub ktokolwiek inny) łączy się z serwerem naprawdę wymagającym liczby całkowitej-DH (a nie z ECDH lub RSA), jedynym sposobem pracy z Javą przed 8 jest uzyskanie serwera do użycia DH 1024-bitowego . Który AFAWK jest technicznie bezpieczny przez kilka kolejnych lat, ale z niewielkim marginesem jest zabroniony przez ważne autorytety, takie jak NIST (patrz Specjalny Pub 800-57 na csrc.nist.gov). (Nawet RSA 1024 jeszcze się nie zepsuł, ale prawdopodobnie niedługo to się stanie, a więc jest zabronione.)

"Polityka nieograniczonej siły" nie ma związku z tym problemem, a przynajmniej nie bezpośrednio, a dobre odpowiedzi do # 6851461 nie powiedziałem, że jest. Nie zmienia to ograniczenia parametrów DH w SunJCE, który jest (błędnie) traktowany jako standardowy problem, a nie jako siła. (W szczególności zajmuje ograniczenia, które były prawidłowe dla DSA, i stosuje je do DH.) Włącza pakiety AES-256 i SHA-2 (tylko dla TLSv1.2), i otrzymuje wystarczająco dziwną listę preferencji, która może zmienić wynik wyboru z DHE (fail) na non-DHE (works).

Nie musisz wracać całkowicie do listy Java 6, wystarczy nadać priorytet innym kluczowym wymianom w stosunku do DHE lub całkowicie upośledzony serwer DHE. Zdecydowanie NIE powinieneś wracać do włączania jakichkolwiek EXPORT lub pojedynczych pakietów DES, chyba że jest to absolutnie konieczne dla starego serwera; NIE były BEZPIECZNE od kilku lat i pozostawały włączone domyślnie w 6 o wiele dłużej niż powinny.

1

Występowaliśmy również w tym problemie z Java7 i Java8. Zastosowaliśmy również obejście podobne do sugestii Emanual Borg. Ale naszym celem było uniknięcie hardcoding stałej listy CipherSuites. Więc próbowaliśmy usunąć wpisy, które spowodowały problem (metodą prób i błędów ...).

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

Pytanie: Czy ktoś widzi problem z tym podejściem?

Btw: jeśli używasz Apache httpclient, następnie https://issues.apache.org/jira/browse/HTTPCLIENT-1111 jest interesująca, który pokazuje, jak ustawić szyfrowaniem (począwszy HTTPClient v4.2) metodą

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

Aktualizacja 31.10.2015 : aby pomóc lepiej zrozumieć kontekst gdzie używać tego tutaj jako przykład pełnej pseudo-kodu, gdzie można zobaczyć, jak podłączyć się by zastąpić prepareSocket() metoda:

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

Należy zachować ostrożność. Używamy tego fragmentu kodu tylko w kontekście, w którym użytkownik wyraźnie pozwala zaufać certyfikatom z podpisem własnym (np. do środowisk testowych itp.). Jeśli nie chcesz tego robić, lepiej nie zadzieraj z SSL.

+0

Używam apache httpclient, ale nie mogłem zrozumieć jak używać prepareSocket –

6

Biorąc pod uwagę, że używasz najnowszej wersji Java i nadal pojawia się błąd, można zmienić ustawienia w java.security (na przykład w folderze C: \ Program Files \ Java \ jre1.8.0_xx \ lib \ security

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

Dodaj DH algorytmu niepełnosprawnych w jdk.tls.disabledAlgorithms

jdk.tls.disabledAlgorithms=SSLv3, RC4, DH 

Restart Tomcat lub uruchom program