Java: Загрузка SSL Keystore через ресурс

Если я имею:

System.setProperty("javax.net.ssl.keyStore", '/etc/certificates/fdms/WS1001237590._.1.ks');
System.setProperty("javax.net.ssl.keyStorePassword", 'DV8u4xRVDq');
System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");

Я могу открыть безопасное соединение без проблемы.

Однако я хотел бы сохранить сертификаты непосредственно в войне, таким образом, я использую: (Входной поток файла в конечном счете станет потоком ресурса, но я делаю это, чтобы заставить его работать.)

System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("/etc/certificates/fdms/WS1001237590._.1.ks"), "DV8u4xRVDq".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "DV8u4xRVDq".toCharArray());
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), null, null);

Теперь, если я открываю то же соединение, я добираюсь: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

11
задан Reverend Gonzo 21 May 2012 в 15:27
поделиться

2 ответа

Некоторое время назад мне пришлось делать нечто подобное. У меня был файл сертификата, и мне нужно было придумать, как загрузить его и использовать для SSL-соединения. Надеюсь, то, что я сделал, поможет вам.

Сначала мне нужно было создать доверительный менеджер:

public class MyX509TrustManager implements X509TrustManager {

    X509TrustManager pkixTrustManager;

    MyX509TrustManager() throws Exception {

        String certFile = "/certificates/MyCertFile.cer";

        Certificate myCert = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(valicertFile));

        KeyStore keyStore = KeyStore.getInstance("JKS");
        keyStore.load(null, "".toCharArray());
        keyStore.setCertificateEntry("myCert", myCert);

        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX");
        trustManagerFactory.init(keyStore);

        TrustManager trustManagers[] = trustManagerFactory.getTrustManagers();

        for(TrustManager trustManager : trustManagers) {
            if(trustManager instanceof X509TrustManager) {
                pkixTrustManager = (X509TrustManager) trustManager;
                return;
            }
        }

        throw new Exception("Couldn't initialize");
    }

    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        pkixTrustManager.checkServerTrusted(chain, authType);
    }

    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        pkixTrustManager.checkServerTrusted(chain, authType);
    }

    public X509Certificate[] getAcceptedIssuers() {
        return pkixTrustManager.getAcceptedIssuers();
    }
}

После этого мне нужно было создать фабрику сокетов, которая использовала мой доверительный менеджер:

public class MySSLProtocolSocketFactory implements SecureProtocolSocketFactory {

    private SSLContext sslContext = null;

    public MySSLProtocolSocketFactory() {
        super();
    }

    private static SSLContext createMySSLContext() {
        try {
            MyX509TrustManager myX509TrustManager = new MyX509TrustManager();
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, new MyX509TrustManager[] { myX509TrustManager}, null);
            return context;
        }

        catch(Exception e) {
            Log.error(Log.Context.Net, e);
            return null;
        }
    }

    private SSLContext getSSLContext() {
        if(this.sslContext == null) {
            this.sslContext = createMySSLContext();
        }

        return this.sslContext;
    }

    public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException {
        return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort);
    }

    public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort, final HttpConnectionParams params) throws IOException {
        if(params == null) {
            throw new IllegalArgumentException("Parameters may not be null");
        }

        int timeout = params.getConnectionTimeout();
        SocketFactory socketFactory = getSSLContext().getSocketFactory();

        if(timeout == 0) {
            return socketFactory.createSocket(host, port, localAddress, localPort);
        }

        else {
            Socket socket = socketFactory.createSocket();
            SocketAddress localAddr = new InetSocketAddress(localAddress, localPort);
            SocketAddress remoteAddr = new InetSocketAddress(host, port);
            socket.bind(localAddr);
            socket.connect(remoteAddr, timeout);
            return socket;
        }
    }

    public Socket createSocket(String host, int port) throws IOException {
        return getSSLContext().getSocketFactory().createSocket(host, port);
    }

    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
        return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    public boolean equals(Object obj) {
        return ((obj != null) && obj.getClass().equals(MySSLProtocolSocketFactory.class));
    }

    public int hashCode() {
        return MySSLProtocolSocketFactory.class.hashCode();
    }
}

Затем я использовал эту фабрику сокетов для отправки POST:

Protocol.registerProtocol("myhttps", new Protocol("myhttps", new MySSLProtocolSocketFactory(), 443));

PostMethod postMethod = new PostMethod("myhttps://some.url.here");

HttpClient client = new HttpClient();
int status = client.executeMethod(postMethod);

Единственное, чего я не мог понять, это как просто добавить файл сертификата в обычное хранилище ключей. Все примеры исходного кода, которые я нашел во время своего исследования, указывали на создание сокет-фактора и последующую регистрацию протокола в этом сокет-факторе. Возможно, существует способ просто использовать фабрику сокетов для создания соединения без регистрации протокола; я не изучал этот вопрос досконально. В моей конкретной ситуации создание конкретного протокола было необходимо. Надеюсь, это поможет вам продвинуться дальше по этому пути. Я признаю, что это кажется немного окольным путем; я чувствовал то же самое, когда делал это вначале. Но только так я смог заставить его работать. Возможно, у других людей есть лучшее решение.

9
ответ дан 3 December 2019 в 06:44
поделиться

В Axis, я думаю, вам нужно настроить его SSLSocketFactory через:

AxisProperties.setProperty("axis.socketSecureFactory",
    "com.example.MySSLSocketFactory");

где com.example.MySSLSocketFactory - ваш класс, реализующий org. apache.axis.components.net.SecureSocketFactory (вы могли бы расширить org.apache.axis.components.net.JSSESocketFactory, возможно).

В методе create создайте сокет, используя фабрику сокетов, полученную из SSLContext, который вы настроили.

3
ответ дан 3 December 2019 в 06:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: