2012-03-22 20 views
19

Mam program Java, który łączy się z serwerem internetowym przy użyciu protokołu SSL/TLS i wysyła różne żądania HTTP za pośrednictwem tego połączenia. Serwer to localhost i używa certyfikatu z podpisem własnym, ale mój kod używa niestandardowych TrustManagers i ignoruje nieważne certyfikaty. Do tej pory działało idealnie.Odbieranie wyjątku SSLHandshakeException: handshake_failure pomimo mojego klienta ignorującego wszystkie certyfikaty

Jedyną różnicą na serwerze jest to, że był używany do uruchamiania jboss 6 i teraz działa jboss 7. Nie jestem pewien, czy jest to problem z konfiguracją, czy też występuje problem z moim kodem, ale dostaję te same błędy, jeśli próbuję połączyć się przy użyciu innych programów opartych na Javie, takich jak WebScarab lub ZAP.

W każdym razie czy jest coś, co mogę zrobić, aby obejść ten problem? Tutaj jest błąd w całości:

Received fatal alert: handshake_failure 
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure 
     at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source) 
     at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(Unknown Source) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source) 
     at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source) 
     at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source) 
     at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(Unknown Source) 

Oto komunikaty debugowania przed awarią:

main, WRITE: TLSv1 Handshake, length = 75 
main, WRITE: SSLv2 client hello message, length = 101 
main, READ: TLSv1 Alert, length = 2 
main, RECV TLSv1 ALERT: fatal, handshake_failure 

Odpowiedz

24

Więc znalazłem problem. W Javie może być błąd, ale wydaje się, że klient zainicjował uścisk dłoni TLSv1, ale następnie wysyła komunikat powitalny klienta SSLv2, w którym to momencie serwer odrzuca połączenie.

Dzieje się tak nawet jeśli utworzyć SSLContext z instancją TLS:

SSLContext sslContext = SSLContext.getInstance("TLS"); 

rozwiązaniem jest ustawić właściwość systemu zanim jakiekolwiek próby połączenia są wykonane:

System.setProperty("https.protocols", "TLSv1"); 

Prawdopodobnie istnieje inne rozwiązania, ale ten działał dla mnie.

+1

Może Cię to zainteresować: http://stackoverflow.com/a/4686924/372643 – Bruno

+0

@Bruno Tak, widziałem to wcześniej podczas wyszukiwania w Google. Czy to błąd w Javie? Nie mogę zobaczyć, jak to może/powinno być domyślnym zachowaniem, gdy określę SSLContext jako TLS. – Rsaesha

+1

To nie jest błąd, jest to zgodne z projektem (protokół SSLv2 dotyczy kompresji wstecznej). Zobacz [JSSE Ref/SSLContext] (http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#SSLContext): "* Na przykład getInstance (" SSLv3 ") może zwrócić instancję implementującą "SSLv3" i "TLSv1" * [...] Możesz kontrolować, które protokoły są faktycznie włączone dla połączenia SSL, używając metody setEnabledProtocols (String [] protocol) ". W twoim przypadku 'https.protocols' zajmuje się' setEnabledProtocols' dla 'HttpsURLConnection'. – Bruno

0

Widzisz ten błąd najprawdopodobniej ponieważ kluczy, czy JBoss 6 miał dostęp nie jest dostępny do instancji JBoss 7.

Co mogę polecić jest następujące.

Twój certyfikat serwera z podpisem własnym musi być importowane do truststore

keytool -import -alias gridserver -file server.crt -storepass $YOUR_PASSWORD_HERE -keystore server.keystore 

dodać następujące właściwości do run.conf

-Djavax.net.ssl.keyStoreType=pkcs12 
-Djavax.net.ssl.trustStoreType=jks 
-Djavax.net.ssl.keyStore=clientcertificate.p12 
-Djavax.net.ssl.trustStore=server.keystore 
-Djavax.net.debug=ssl # very verbose debug. Turn this off after everything looks good. 
-Djavax.net.ssl.keyStorePassword=$YOUR_PASSWORD_HERE 
-Djavax.net.ssl.trustStorePassword=$YOUR_PASSWORD_HERE 
+0

Serwer działa poprawnie poprzez przeglądarkę internetową jak Chrome czy Firefox, więc kluczy na serwerze nie jest problemem. Certyfikacja nie powinna stanowić problemu, ponieważ po prostu ignoruję wszystkie certyfikaty. – Rsaesha

4

informacji podasz jest bardzo mały, jak również swoje Ślad stosu.
Zgaduję tutaj.
Podejrzewam, że na nowym serwerze protokół to TLSv1, podczas gdy Twoi klienci próbują połączyć się z SSLv3 (lub mniej), w wyniku czego uzgadnianie kończy się niepowodzeniem.

Zmień klientów, którzy będą używać wyższej wersji TLS lub
Spraw, aby Twój serwer sieciowy również obsługiwał protokół SSLv3. Wiem, jak to zrobić w Tomcat, ale nie w JBoss.

Jeśli to nie zadziała, zaktualizuj wpis, dodając więcej informacji (i pełne śledzenie stosu).
należy włączyć SSL debugowania -Djavax.net.debug=ssl

+0

Śledzenie całego stosu pokazuje po prostu metodę połączenia mojej klasy i dowolne metody, które ją wywołują. Jest to ta sama metoda, która działa z poprzednimi wersjami serwera. Zresztą, tutaj jest debug: http://pastebin.com/RJqcQwaP Co wydaje się nieco dziwne dla mnie jest to, że chociaż powiem mój program przewiduje stosowanie protokołu TLS, wydaje się chcesz wysłać wiadomości SSLv2 klienckich komentarzy . – Rsaesha

+0

@Rsaesha: Umieść kod klienta w poście – Cratylus

0

Ślad stosu jest od ciebie kodu klienta i klienta „Odebrane [a] krytyczny alert”. Innymi słowy, błąd SSL wystąpił w Jboss, a nie w kliencie.

Niestandardowe programy TrustManager po stronie klienta nie mają z tym nic wspólnego. Domyślam się, że twój nowy Jboss 7 jest skonfigurowany tak, aby wymagał certyfikatu klienta, a twój klient go nie przedstawił.

debugowania połączenia SSL, należy użyć OpenSSL i spróbuj tego:

openssl s_client -connect jboss.server.com:443

czy jest to serwer SSLv3

openssl s_client -connect jboss.server.com:443 -ssl3

To powinno wydrukować wiele interesujących informacji.

+0

Tutaj jest wyjście z pierwszego polecenia: http://pastebin.com/NvRqdu3f – Rsaesha

+0

Moje dzikie domysły były właśnie takie, dzikie. Twój serwer jest w porządku. user384706 ustawił cię na właściwej drodze. Jest to bardziej prawdopodobne niedopasowanie wersji protokołu. Widzę, że twój serwer jest TLSv1/SSLv3 i wydajesz się, że wysyłasz SSLv2. –

0

Myślę, że jest to związane z Java 7 bug. Trudno być pewnym, że nie ma więcej szczegółów.

4

Czy to się kiedykolwiek rozwiązało?

Miałem dokładnie ten sam problem, w zasadzie otrzymałem wyjątek handshake natychmiast po clientHello. Więc Łańcuch zdarzeń była

  1. chciałbym przedstawić mój certyfikat serwera
  2. Server będzie imediately reagować z niewydolnością uzgadniania. (Nie otrzymam nawet serwera Hello Hello).

Ostatecznie okazało się, że serwer został wymagające silniejszego algorytmu szyfrowania/deszyfrowania niż to, co dostarcza w początkowej fazie uzgadniania (Tj. Klient i serwer nie może zgodzić się na algorytm wzajemnego szyfrowania użyć do komunikacji SSL).

Potrzebuję zainstalować Unlimited Java JCE (Java Cryptography Extension Policy). Istnieją reguły eksportu dotyczące korzystania z tego, więc jeśli wysyłasz swój kod za granicę, co może mieć konsekwencje ... jednak to właśnie rozwiązało mój problem.

Ten link wyjaśnia jak zainstalować zaktualizowane zasady http://suhothayan.blogspot.com/2012/05/how-to-install-java-cryptography.html

To również świetny link, który pomógł mi zrozumieć dokładnie, co się dzieje https://support.f5.com/kb/en-us/solutions/public/15000/200/sol15292.html#id

To może lub nie może być problem, ale gdy uzgadnianie kończy się niepowodzeniem natychmiast po przywitaniu klienta, wygląda na to, że klient i serwer nie mogą się z czymś zgodzić (w wielu przypadkach są to algorytmy szyfrowania, które będą wzajemnie się komunikować).

0

Dla mnie rozwiązaniem było: System.setProperty("https.protocols", "TLSv1.1,TLSv1.2");

Powiązane problemy