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ом ресурсов, но я делаю это, чтобы заставить его работать.)
- Возможно ли иметь сертификат SSL для IP-адреса, а не доменное имя?
- Присвоение имени домена локальному хосту для среды разработки
- Не удалось создать путь PKIX: не удалось найти допустимый путь сертификации для запрошенной цели
- Java: sun.security.provider.certpath.SunCertPathBuilderException: невозможно найти допустимый путь сертификации для запрошенной цели
- Самостоятельный SSL-сертификат Tomcat Server / Client
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 в node.js с https.request?
- Избегайте ввода пароля для ключей и подсказок для информации о DN
- Безопасное исправление: javax.net.ssl.SSLPeerUnverifiedException: нет однорангового сертификата
- Самоподписанный SSL-прием на Android
- Сертификаты SSL привязаны к IP-адресу серверов?
- Сертификат клиента SSL в Maven
- Цифровой знак электронной почты Gmail с S / MIME
- Trust Anchor не найден для подключения SSL для Android
Я должен был сделать что-то подобное некоторое время назад. У меня был файл сертификата, и мне пришлось выяснить, как его загрузить и использовать для подключения 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")
Это намного проще в использовании 🙂