java - getLocalCertificates() 返回 null

标签 java ssl certificate serversocket sslsocketfactory

我正在尝试编写一个简单的 ssl 服务器套接字和客户端套接字程序。首先我得到一些真正的证书,然后我使用第一个代码为它生成 keystore 。然后我编写了服务器和客户端代码,所以我的服务器使用该 keystore 作为服务器证书,但在连接期间没有发送证书,并且 session.getLocalCertificates() 只返回 null 我的 keystore 生成代码:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.security.KeyStore;
import java.security.cert.CertPath;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

public class MainClass {
    public static void main(String args[]) throws Exception {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        List mylist = new ArrayList();

            FileInputStream in = new FileInputStream("C:\\Users\\nima\\Downloads\\72315359_example.com.cert");
            Certificate cr = cf.generateCertificate(in);
            mylist.add(cr);

        CertPath cp = cf.generateCertPath(mylist);
        System.out.println(cp);

        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(null, null);
        List cplist = cp.getCertificates();
        Object[] o = cplist.toArray();
        for (int i = 0; i < o.length; i++) {
            X509Certificate c = (X509Certificate) o[i];
            ks.setCertificateEntry("my" + i, c);
        }
        FileOutputStream output = new FileOutputStream("C:\\Users\\nima\\Downloads\\test.dat");
        ks.store(output, "mypass".toCharArray());
        output.close();

    }
}

我的服务器代码:

import java.io.PrintStream;
import java.math.BigInteger;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;

public class MainClass {
    public static void main(String args[]) throws Exception {
        System.setProperty("javax.net.ssl.keyStore", "C:\\Users\\nima\\Downloads\\test.dat");
        System.setProperty("javax.net.ssl.keyStorePassword", "mypass");

        SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
        ServerSocket ss = ssf.createServerSocket(5432);
        while (true) {
            Socket s = ss.accept();
            SSLSession session = ((SSLSocket) s).getSession();
            Certificate[] cchain2 = session.getLocalCertificates();
            for (int i = 0; i < cchain2.length; i++) {
                System.out.println(((X509Certificate) cchain2[i]).getSubjectDN());
            }
            System.out.println("Peer host is " + session.getPeerHost());
            System.out.println("Cipher is " + session.getCipherSuite());
            System.out.println("Protocol is " + session.getProtocol());
            System.out.println("ID is " + new BigInteger(session.getId()));
            System.out.println("Session created in " + session.getCreationTime());
            System.out.println("Session accessed in " + session.getLastAccessedTime());

            PrintStream out = new PrintStream(s.getOutputStream());
            out.println("Hi");
            out.close();
            s.close();
        }

    }
}

我的客户端代码:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.net.Socket;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class MainClass {
    public static void main(String args[]) throws Exception {
        System.setProperty("javax.net.ssl.trustStore", "C:\\Users\\nima\\Downloads\\test.dat");

        SSLSocketFactory ssf = (SSLSocketFactory) SSLSocketFactory.getDefault();
        Socket s = ssf.createSocket("127.0.0.1", 5432);

        SSLSession session = ((SSLSocket) s).getSession();
        Certificate[] cchain = session.getPeerCertificates();
        System.out.println("The Certificates used by peer");
        for (int i = 0; i < cchain.length; i++) {
            System.out.println(((X509Certificate) cchain[i]).getSubjectDN());
        }
        System.out.println("Peer host is " + session.getPeerHost());
        System.out.println("Cipher is " + session.getCipherSuite());
        System.out.println("Protocol is " + session.getProtocol());
        System.out.println("ID is " + new BigInteger(session.getId()));
        System.out.println("Session created in " + session.getCreationTime());
        System.out.println("Session accessed in " + session.getLastAccessedTime());

        BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String x = in.readLine();
        System.out.println(x);
        in.close();

    }
}

我的服务器代码来自here在服务器端和客户端,我都从 getLocalCertificates 中得到 null。也有可能我的所有代码都是错误的。

最佳答案

(来自评论,略有扩展)

如果 SSLSocket.getSession() 在握手完成之前被调用,它会尝试这样做,但是如果握手失败 getSession() 吞下异常并且只是返回一个“nullSession”对象,它没有真实 session 对象所具有的数据。要么 (1) 设置 sysprop javax.net.debug=ssl(在启动时,通常在命令行上使用 -D)并查看它记录的内容以查看问题所在您的握手或 (2) 显式调用 ((SSLSocket)s).startHandshake()(尽管名称实际运行握手完成,成功与否)并查看它抛出的内容。

特别是如果您使用由显示的第一个代码创建的 keystore 文件,该文件仅包含证书 (trustedCertEntry) 而不是 privateKeyEntry(具有私钥和证书/链),这是 SSL/TLS 服务器必需和需要的使用任何通用和默认启用的套件;这个错误通常会有点令人困惑地表现为“没有共同的密码[套件]”或“没有密码[套件]重叠”的握手失败。

第二部分(没有私钥的 SSL/TLS 服务器不起作用)已被多次询问和回答,但我不记得有任何欺骗也包括“getSession masks the error”部分。

关于java - getLocalCertificates() 返回 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52457767/

相关文章:

java - JAXB 编码 Java 以输出 XML 文件

新 mac 机器上的 iPhone 证书和配置...等?

c# - 在 C# 中将 asn1 转换为 base64

java - 如何在 Play Framework 2.3 中反转从我的表单到操作的路由

java - 订阅远程 rospy 发布者

java - ./gradlew 因 NoSuchAlgorithmException 失败

c# - 使用 POP3 连接到 SSL

asp.net - 不同端口的 SSL 证书

java - eToken java key 工具证书

java - Mockito - 创建嵌套模拟对象