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
Ответы
Ответ 1
Для потомства все это было слишком сложно, и мы почти просто проверили статический блок:
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");
}
Ответ 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();
}
}
После этого мне пришлось создать сокет factory, который использовал мой менеджер доверия:
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();
}
}
Затем я использовал этот сокет factory для отправки моего 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);
Единственное, что я не мог понять, это просто добавить файл сертификата в обычное хранилище ключей. Весь исходный код примера, который я нашел во время моего исследования, указал на создание фактора сокета, а затем регистрацию протокола с этим сокетом factory. Возможно, есть способ просто использовать сокет factory для создания соединения без регистрации протокола; Я не исследовал это тщательно. В моей конкретной ситуации необходимо было создать конкретный протокол. Надеюсь, это поможет вам продвинуться дальше. Я признаю, что это немного круто; Я чувствовал то же самое, когда сначала делал это. Но это был единственный способ заставить меня работать. Возможно, у других людей есть лучшее решение.
Ответ 3
С 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
создайте сокет, используя сокет factory, полученный из SSLContext
, который вы настроили.
Ответ 4
Если вы хотите, здесь 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")
Это гораздо проще в использовании:)
Ответ 5
У меня была похожая проблема, я решил создать функцию, которая возвращает контекст SSL, используя хранилище ключей из потока ввода.
protected SSLContext getSslCtx(InputStream is, String password) {
try {
// Load keystore
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(is, password.toCharArray());
// Load trust manager
TrustManagerFactory trustMgrFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustMgrFactory.init(keystore);
// Load key manager
KeyManagerFactory keyMgrFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyMgrFactory.init(keystore, password.toCharArray());
// Create SSL context
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
ctx.init(keyMgrFactory.getKeyManagers(), trustMgrFactory.getTrustManagers(), null);
return ctx;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Надеюсь, это поможет.