web-dev-qa-db-ja.com

Java:リソースを介したSSLキーストアのロード

私が持っている場合:

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

後世のために、これはすべて非常に複雑であり、静的ブロックをチェックしただけです。

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");
}
4
Reverend Gonzo

私はしばらく前に同じようなことをしなければなりませんでした。証明書ファイルがあり、それをロードして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
Vivin Paliath

Axisでは、次の方法でSSLSocketFactoryを構成する必要があると思います。

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

ここで、com.example.MySSLSocketFactoryorg.Apache.axis.components.net.SecureSocketFactoryを実装するクラスです(おそらくorg.Apache.axis.components.net.JSSESocketFactoryを拡張できます)。

createメソッドで、構成したSSLContextから取得したソケットファクトリを使用してソケットを作成します。

3
Bruno

必要に応じて、SSLSocketとSSLServerSocketを簡単に作成するためのAPIを次に示します。

https://github.com/gpotter2/SSLKeystoreFactories

他のjarファイルは必要ありません。ファイルを取得して次のように使用するだけです。

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

または:

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

それははるかに使いやすいです:)

2
mike345

同様の問題があり、入力ストリームからのキーストアを使用して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;
}

お役に立てれば。

0
Ramon