Java:通过资源加载 SSL 密钥库

发布于 2024-09-10 00:26:59 字数 901 浏览 3 评论 0原文

如果我有:

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:收到致命警报:handshake_failure

If I have:

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

I'm able to open a secure connection without a problem.

However, I'd like to have the certificates stored directly in the war, so I use: (The file input stream will eventually become a resource stream, but I'm doing this to get it to work.)

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

Now, if I open the same connection, I get: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

黑凤梨 2024-09-17 00:26:59

不久前我不得不做类似的事情。我有一个证书文件,我必须找到一种方法来加载它并将其用于 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();
    }
}

然后我使用该套接字工厂发送我的帖子:

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

我唯一不明白的是如何简单地添加证书文件到常规密钥库。我在研究过程中发现的所有示例源代码都指向创建一个套接字因子,然后向该套接字工厂注册一个协议。也许有一种方法可以简单地使用套接字工厂来建立连接,而无需注册协议;我还没有调查得很彻底。在我的特殊情况下,创建一个特定的协议是必要的。希望这能让您走得更远。我承认这似乎有点迂回;当我最初这样做时,我也有同样的感觉。但这是我让它发挥作用的唯一方法。也许其他人有更好的解决方案。

I had to do something similar a while back. I had a certificate file and I had to figure out a way to load it in and use it for an SSL connection. Hopefully what I did will help you out.

First I had to create a trust manager:

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();
    }
}

After that I had to create a socket factory that used my trust manager:

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();
    }
}

Then I used that socket factory to send my 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);

The only thing I couldn't figure out was how to simply add the certificate file to the regular keystore. All the example source code I found during my research pointed to creating a socket factor and then registering a protocol with that socket factory. Perhaps there is a way to simply use the socket factory to make a connection without registering a protocol; I haven't investigated that thoroughly. In my particular situation, creating a specific protocol was necessary. Hopefully this will get your further along the way. I admit it seems a bit roundabout; I felt the same way when I did it initially. But this was the only way I got it to work. Maybe other people have a better solution.

迷离° 2024-09-17 00:26:59

为了后代的缘故,所有这些都太复杂了,我们几乎只是在静态块中进行了检查:

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

For posterity's sake, all of this was far too complicated, and we pretty much just had a check in the static block:

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");
}
许久 2024-09-17 00:26:59

对于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 获取的套接字工厂创建套接字。

With Axis, I think you need to configure its SSLSocketFactory via:

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

where com.example.MySSLSocketFactory is your class that implements org.apache.axis.components.net.SecureSocketFactory (you could extend org.apache.axis.components.net.JSSESocketFactory perhaps).

In the create method, create a socket using the socket factory obtained from the SSLContext you've configured.

北方的巷 2024-09-17 00:26:59

如果您愿意,这里有一个可以轻松创建 SSLSocket 和 SSLServerSocket 的 API:

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

这更容易使用:)

If you want, here's an API to create SSLSocket and SSLServerSocket easily:

https://github.com/gpotter2/SSLKeystoreFactories

It does not require any other jars.... just get the files and use them like:

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

Or:

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

That's much easier to use :)

彩扇题诗 2024-09-17 00:26:59

我遇到了类似的问题,我解决了创建一个使用来自输入流的密钥库返回 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;
}

希望这有帮助。

I had similar problem, I solved creating a function that returns an SSL context using a keystore coming from and input stream.

   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;
}

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文