Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
基于Java的SSL套接字连接_Java_Sockets_Ssl_Certificate_Handshake - Fatal编程技术网

基于Java的SSL套接字连接

基于Java的SSL套接字连接,java,sockets,ssl,certificate,handshake,Java,Sockets,Ssl,Certificate,Handshake,在阅读了大量关于这些主题的答案后,我发现自己完全无法将谜题的各个部分串连起来,我希望你能原谅我 我正在尝试将Java中的简单套接字连接更改为使用SSL。如果可能的话,我希望服务器和客户端都进行身份验证,但只有服务器身份验证才是一个好的开始 目前,服务器端的代码非常简单: ServerSocket serverSocket = new ServerSocket(port); Socket socket = serverSocket.accept(); 这是客户端的代码:

在阅读了大量关于这些主题的答案后,我发现自己完全无法将谜题的各个部分串连起来,我希望你能原谅我

我正在尝试将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(例如,对于服务器,命令为keytool-importkeystore-srckeystore server.p12-srcstoretypkkcs12-destkeystore server.JKS-deststoretype JKS)将它们转换为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:在客户端收到致命警报:握手失败)


有什么问题吗?

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

而不是行
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,对于服务器,当提供的证书之一属于您自己的服务器时,它将信任它


它似乎有效,请让我知道这种方法是否有任何主要错误(我不幸地认为有)。谢谢你读了这么多

您在客户端和服务器上使用哪个Java版本?在客户端和服务器上都使用Java 8u20(当然包括SDK)(它是同一台机器,对于ip,我目前使用的是localhost)。您的服务器和客户端代码都是无意义的。您初始化密钥库,但从未使用它。请仔细阅读JSSE参考指南。我不明白为什么您首先看的是StackOverflow而不是官方文档。一旦你找对了地方,你马上就找到了答案。这是一个教训。我确实先看了官方文件,但我还是要尝试各种方法才能奏效,所以我不确定我现在是否理解了。正如我之前所说,我无法连接拼图的各个部分……至少可以说,官方文件是一个迷宫。我希望有一个教程。