简体   繁体   English

Java上的SSL套接字连接

[英]SSL socket connection over Java

After reading through numerous answers concerning these topics, I have found myself completely unable to string together the pieces of the puzzle, I hope you will excuse me for this. 在阅读了关于这些主题的众多答案之后,我发现自己完全无法将拼图的各个部分拼凑在一起,我希望你能原谅我。

I am trying to change my simple socket connection in Java to use SSL. 我试图在Java中更改我的简单套接字连接以使用SSL。 I would like both the server and client to authenticate themselves if possible, but only server authentication would be good start. 如果可能的话,我希望服务器和客户端都自己进行身份验证,但只有服务器身份验证才是好的开始。

Currently, this is the extremely simple code on the server side: 目前,这是服务器端非常简单的代码:

    ServerSocket serverSocket = new ServerSocket(port);
    Socket socket = serverSocket.accept();

And this is the code on the client side: 这是客户端的代码:

    Socket socket = null;
    while (true) {
        try {
            socket = new Socket(ipAddress, port);
            break;
        } catch (Exception e) {}
    }

This works fine, but without SSL. 这很好,但没有SSL。

I have generated SSL certificates for the server and client using OpenSSL, ending up with: 我使用OpenSSL为服务器和客户端生成了SSL证书,最终得到:

  • A certificate for the server (PEM format) 服务器证书(PEM格式)
  • A certificate for the client (PEM format) 客户证书(PEM格式)
  • A private key for the server (PEM format) 服务器的私钥(PEM格式)
  • A private key for the client (PEM format) 客户端的私钥(PEM格式)
  • A CA file (PEM, CER and CRT format) CA文件(PEM,CER和CRT格式)

From this I have used OpenSSL to create PKCS12 (.p12) keystores for both the client and the server, as follows 由此我使用OpenSSL为客户端和服务器创建PKCS12(.p12)密钥库,如下所示

  • server.p12, made by doing openssl pkcs12 -export -in server-cert.pem -inkey server-private-key.pem -out server.p12 server.p12,通过执行openssl pkcs12 -export -in server-cert.pem -inkey server-private-key.pem -out server.p12
  • client.p12, made by doing openssl pkcs12 -export -in client-cert.pem -inkey client-private-key.pem -out client.p12 client.p12,由openssl创建pkcs12 -export -in client-cert.pem -inkey client-private-key.pem -out client.p12

Then, I turned these into JKS keystores by using keytool (for the server, for example, the command was keytool -importkeystore -srckeystore server.p12 -srcstoretype PKCS12 -destkeystore server.jks -deststoretype JKS ), resulting in two files named server.jks and client.jks . 然后,我通过使用keytool将这些转换为JKS密钥库(例如,对于服务器,命令是keytool -importkeystore -srckeystore server.p12 -srcstoretype PKCS12 -destkeystore server.jks -deststoretype JKS ),从而生成两个名为server的文件。 jksclient.jks

I then use the following code as replacement for the previous server snippet: 然后,我使用以下代码替换以前的服务器代码段:

    char[] keyStorePassword =  "JKSPassword".toCharArray();
    FileInputStream keyStoreFile = new FileInputStream("somepath/server.jks");
    KeyStore keyStore = KeyStore.getInstance("JKS");
    keyStore.load(keyStoreFile, keyStorePassword);
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    keyManagerFactory.init(keyStore, "PKCS12Password".toCharArray());
    SSLContext sslContext = SSLContext.getDefault();
    ServerSocket serverSocket = sslContext.getServerSocketFactory().createServerSocket(port);
    Socket socket = serverSocket.accept();

And the following code as replacement for the client snippet: 以下代码替换客户端代码段:

    Socket socket = null;
    while (true) {
        try {
            char[] keyStorePassword =  "JKSPassword".toCharArray();
            FileInputStream keyStoreFile = new FileInputStream("somepath/client.jks");
            KeyStore keyStore = KeyStore.getInstance("JKS");
            keyStore.load(keyStoreFile, keyStorePassword);
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, "PKCS12Password".toCharArray());
            SSLContext sslContext = SSLContext.getDefault();
            socket = sslContext.getSocketFactory().createSocket(ipAddress, port);
            break;
        } catch (Exception e) {}
    }

I now still get javax.net.ssl.SSLHandshakeException: no cipher suites in common on the server (and javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure on the client). 我现在仍然得到javax.net.ssl.SSLHandshakeException:服务器上没有共同的密码套件 (和javax.net.ssl.SSLHandshakeException:收到致命警报:客户端上的handshake_failure )。

What could be wrong? 可能有什么不对?

I found the missing part of the puzzle (I believe). 我找到了拼图的缺失部分(我相信)。

Instead of the line SSLContext sslContext = SSLContext.getDefault(); 而不是行SSLContext sslContext = SSLContext.getDefault(); on the client, I put: 在客户端,我说:

    BufferedInputStream serverCertificateFile = new BufferedInputStream(new FileInputStream("somepath/server-cert.der"));
    X509Certificate serverCertificate = (X509Certificate)
              CertificateFactory.getInstance("X.509").generateCertificate(serverCertificateFile);
            sslContext.init(keyManagerFactory.getKeyManagers(), new TrustManager[] {
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] arg0,
                            String arg1) throws CertificateException {
                        throw new CertificateException();
                    }
                    @Override
                    public void checkServerTrusted(X509Certificate[] arg0,
                            String arg1) throws CertificateException {
                        boolean valid = false;
                        for (X509Certificate certificate : arg0) {
                            try {
                                certificate.verify(serverCertificate.getPublicKey());
                                valid = true;
                                break;
                            } catch (SignatureException e) {}
                        }
                        if (!valid) {
                            throw new CertificateException();
                        }
                    }
                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[0];
                    }
                }
            }, new SecureRandom());

server-cert.der is a file, created with openssl509 -outform der -in server-cert.pem -out server-cert.der . server-cert.der是一个文件,使用openssl509 -outform der -in server-cert.pem -out server-cert.der创建

I was not able to find good tutorials or question on this matter on StackOverflow, so this is what I created by attempting to understand the reference guide. 我无法在StackOverflow上找到关于此问题的好教程或问题,所以这是我通过尝试理解参考指南而创建的。

Essentially, I am creating a TrustManager that, for a server, trusts it when one of the provided certificates is the one that belongs to your own server. 本质上,我正在创建一个TrustManager,对于服务器,当其中一个提供的证书属于您自己的服务器时,它会信任它。

It appears to work, please let me know if there is anything principally wrong with this approach (I unfortunately assume there is). 它似乎有效,如果这种方法有任何重大错误,请告诉我(我很遗憾地认为有)。 Thanks for having read so much! 谢谢你读了这么多!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM