Java i problemy z połączeniem SSL

Niedawno napotkałem problem z podłączeniem serwera WildFly do serwera poczty przy użyciu połączenia szyfrowanego. Próba takiego połączenia kończyła się zgłoszeniem wyjątku:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

Szybko okazało się, że źródłem problemu jest fakt, iż certyfikat zamieszczony na serwerze pocztowym jest niewiarygodny (self-signed). Mechanizmy bezpieczeństwa JRE nie są w stanie potwierdzić autentyczności certyfikatu i dlatego zgłaszają wyjątek.

Oczywiście da się ten problem obejść, choć jest to nieco uciążliwe. Żeby JRE uznało certyfikat za wiarygodny, trzeba go zaimportować do tzw. magazynu JRE. W tym celu najpierw trzeba pozyskać plik certyfikatu. W moim przypadku najprościej było go pobrać z programu pocztowego (Postbox, komercyjny klon Thunderbirda). Plik certyfikatu zapisałem na dysku w formacie DER, a następnie użyłem narzędzia keytool, standardowo rozprowadzanego w ramach pakietu JRE.

Oto przykładowe polecenie importujące plik certyfikat.cer znajdujący się w katalogu domowym użytkownika. Pierwszy przykład dotyczy systemu OS X. Należy je wykonać z uprawnieniami administratora.

keytool -import -alias myprivateroot \
    -keystore $(/usr/libexec/java_home)/bin\lib\security\cacerts \
    -file ~/certyfikat.cer

A tutaj wersja dla linuksa:

keytool -import -alias myprivateroot \
    -keystore /usr/java/default/jre/lib/security/cacerts \
    -file ~/certyfikat.cer

Po takim zabiegu następna próba połączenia z serwerem pocztowym po SSL powinna się udać bez problemu. Dodam jeszcze tylko, że powyższa recepta rozwiązuje nie tylko problem w przypadku połączeń z serwerem pocztowym. Zadziała również w przypadku serwera HTTP oraz innych połączeń SSL wykorzystujących certyfikaty, których autentyczności JRE nie jest w stanie zweryfikować.

Uciążliwość tego rozwiązania polega na tym, że po każdej aktualizacji JRE trzeba pamiętać o ponownym zaimportowaniu certyfikatu do magazynu.