Java отклоняет сертификат, который принимает браузер

У меня проблемы с настройкой действующего сертификата (не самоподписанного!) В Wildfly 9. Я настроил коннектор HTTPS в Wildfly:

            <https-listener name="https" socket-binding="https" security-realm="UndertowRealm" />

Область безопасности:

        <security-realm name="UndertowRealm">
          <server-identities>
            <ssl>
              <keystore path="domain.p12" relative-to="jboss.server.config.dir" keystore-password="password"
                alias="appcert"  />
            </ssl>
          </server-identities>
        </security-realm>

И сгенерировал хранилище ключей с помощью этой команды:

openssl pkcs12 -export -in domain.crt -inkey domain.key -out domain.p12 -name appcert -CAfile cafile.crt -caname root

Теперь, когда я открываю приложение в браузере, все работает нормально. Браузер распознает сертификат как действующий сертификат без запроса исключения, как это было бы в случае самозаверяющего сертификата.

Однако, когда я пытаюсь подключиться к тому же URL через SSLPoke.java, я получаю следующее исключение:

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
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:747)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:138)
    at SSLPoke.main(SSLPoke.java:26)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
    at sun.security.validator.Validator.validate(Validator.java:260)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491)
    ... 9 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
    ... 15 more

Если я импортирую сертификат в клиент, эта ошибка исчезнет, ​​но я думаю, что мне не нужно этого делать, поскольку это действующий сертификат.

Код теста следующий:

import java.io.InputStream;
import java.io.OutputStream;

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

/** Establish a SSL connection to a host and port, writes a byte and
 * prints the response. See
 * http://confluence.atlassian.com/display/JIRA/Connecting+to+SSL+services
 */
public class SSLPoke {
    public static void main(String[] args) {

                if (args.length != 2) {
                        System.out.println("Usage: "+SSLPoke.class.getName()+"  ");
                        System.exit(1);
                }
                try {
                        SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
                        SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(args[0], Integer.parseInt(args[1]));

                        InputStream in = sslsocket.getInputStream();
                        OutputStream out = sslsocket.getOutputStream();

                        // Write a test byte to get a reaction :)
                        out.write(1);

                        while (in.available() > 0) {
                                System.out.print(in.read());
                        }
                        System.out.println("Successfully connected");

                } catch (Exception exception) {
                        exception.printStackTrace();
                }
        }
}

Почему это происходит и как правильно настроить сертификат SSL?


person Thiago    schedule 19.05.2016    source источник


Ответы (2)


Это происходит потому, что хранилище доверенных сертификатов Java не доверяет ни одному из сертификатов в цепочке.

Самым общим решением было бы импортировать сертификат top (последний в цепочке, самая верхняя подписывающая сторона) в lib/security/cacerts файл JRE.

person user207421    schedule 19.05.2016

Проблема здесь в том, что Java по умолчанию поставляется с очень ограниченным набором сертификатов корневого ЦС. Он «принимает» гораздо меньше центров сертификации, чем обычный браузер. Самый простой способ решить проблему - экспортировать набор сертификатов ЦС из браузера, такого как Chrome или Firefox, и импортировать их в хранилище ключей Java с помощью _ 1_.

person Jim Garrison    schedule 19.05.2016
comment
Для меня он работает с сертификатом SSL от Comodo, а не с GlobalSign - person Sandeep540; 08.01.2019