首页 文章

Java上的SSL套接字连接

提问于
浏览
3

在阅读了关于这些主题的众多答案之后,我发现自己完全无法将拼图的各个部分拼凑在一起,我希望你能原谅我 .

我试图在Java中更改我的简单套接字连接以使用SSL . 如果可能的话,我希望服务器和客户端都自己进行身份验证,但只有服务器身份验证才是好的开始 .

目前,这是服务器端非常简单的代码:

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

这是客户端的代码:

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

这很好,但没有SSL .

我使用OpenSSL为服务器和客户端生成了SSL证书,最终得到:

  • 服务器证书(PEM格式)

  • 客户证书(PEM格式)

  • 服务器的私钥(PEM格式)

  • 客户端的私钥(PEM格式)

  • CA文件(PEM,CER和CRT格式)

由此我使用OpenSSL为客户端和服务器创建PKCS12(.p12)密钥库,如下所示

  • server.p12,通过执行openssl pkcs12 -export -in server-cert.pem -inkey server-private-key.pem -out server.p12

  • client.p12,通过执行openssl pkcs12 -export -in client-cert.pem -inkey client-private-key.pem -out client.p12

然后,我通过使用keytool将这些转换为JKS密钥库(例如,对于服务器,命令是keytool -importkeystore -srckeystore server.p12 -srcstoretype PKCS12 -destkeystore server.jks -deststoretype JKS),从而生成两个名为server的文件 . jks和client.jks .

然后,我使用以下代码替换以前的服务器代码段:

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

以下代码替换客户端代码段:

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) {}
    }

我现在仍然得到javax.net.ssl.SSLHandshakeException:服务器上没有共同的密码套件(和javax.net.ssl.SSLHandshakeException:收到致命警报:客户端上的handshake_failure) .

可能有什么不对?

1 回答

  • 1

    我找到了拼图的缺失部分(我相信) .

    而不是客户端上的行 SSLContext sslContext = SSLContext.getDefault(); ,我把:

    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是一个文件,使用openssl509 -outform der -in server-cert.pem -out server-cert.der创建 .

    我无法在StackOverflow上找到关于此问题的好教程或问题,所以这是我通过尝试理解参考指南而创建的 .

    本质上,我正在创建一个TrustManager,对于服务器,当其中一个提供的证书属于您自己的服务器时,它会信任它 .

    它似乎有用,如果这种方法有任何重大错误,请告诉我(我很遗憾地认为有) . 谢谢你读了这么多!

相关问题