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

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

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

 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

Я должен был сделать что-то подобное некоторое время назад. У меня был файл сертификата, и мне пришлось выяснить, как его загрузить и использовать для подключения 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); 

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

Для потомков все это было слишком сложно, и мы почти просто проверили статический блок:

 if( environment == 'production') { System.setProperty("javax.net.ssl.keyStore", '/etc/certificates/prod/keystore.ks'); System.setProperty("javax.net.ssl.keyStorePassword", 'password'); System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true"); } else { System.setProperty("javax.net.ssl.keyStore", '/etc/certificates/test/keystore.ks'); System.setProperty("javax.net.ssl.keyStorePassword", 'password'); System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true"); } 

С Axis я думаю, вам нужно настроить SSLSocketFactory помощью:

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

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

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

Если вы хотите, вот API для создания SSLSocket и SSLServerSocket легко:

https://github.com/gpotter2/SSLKeystoreFactories

Он не требует никаких других банок … просто получите файлы и используйте их как:

 SSLSocket s = SSLSocketKeystoreFactory.getSocketWithCert(ip, port, Main.class.getResourceAsStream("/mykey.jks"), "password") 

Или:

 SSLServerSocket s = SSLServerSocketKeystoreFactory.getSocketWithCert(port, Main.class.getResourceAsStream("/mykey.jks"), "password") 

Это намного проще в использовании 🙂

  • Возможно ли преобразовать SSL-сертификат из файла .key в .pfx?
  • curl: (60) SSL-сертификат: не удалось получить сертификат локального эмитента
  • Подписанный SSL-сертификат третьей стороны для localhost или 127.0.0.1?
  • Как установить разрешение на чтение файла закрытого ключа сертификата X.509 из .NET.
  • Что мне нужно сделать, чтобы заставить Internet Explorer 8 принять самоподписанный сертификат?
  • Получено фатальное предупреждение: handshake_failure через SSLHandshakeException
  • Как исправить ошибку «java.security.cert.CertificateException: нет альтернативных имен объектов»?
  • Как правильно импортировать самоподписанный сертификат в хранилище ключей Java, доступное для всех приложений Java по умолчанию?
  • Почему локальное хранилище сертификатов отсутствует в Windows 8.1?
  • Постоянное получение ошибок сертификата https во всех браузерах
  • Java7 Отказ от доверия сертификату в хранилище доверия
  • Давайте будем гением компьютера.