java - JAVA中SSL握手时如何获取ClientHello信息

标签 java ssl handshake jsse

我想从 ssl handshake 中获取诸如客户端压缩方法或客户端支持的密码套件之类的东西 我试过使用

public static void main(String[] args) throws Exception {
    String serverKeyStoreFile = "D:\\tomcat.keystore";
    String serverKeyStorePwd = "logiscn";
    String catServerKeyPwd = "logiscn";
    String serverTrustKeyStoreFile = "D:\\tomcat.keystore";
    String serverTrustKeyStorePwd = "logiscn";
    //System.setProperty("javax.net.debug", "ssl,handshake");
    KeyStore serverKeyStore = KeyStore.getInstance("JKS");
    serverKeyStore.load(new FileInputStream(serverKeyStoreFile), serverKeyStorePwd.toCharArray());
    KeyStore serverTrustKeyStore = KeyStore.getInstance("JKS");
    serverTrustKeyStore.load(new FileInputStream(serverTrustKeyStoreFile), serverTrustKeyStorePwd.toCharArray());

    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(serverKeyStore, catServerKeyPwd.toCharArray());

    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(serverTrustKeyStore);
    SSLContext sslContext = SSLContext.getInstance("TLSv1");
    // System.out.println(sslContext.getProvider());
    sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
    SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory();
    SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(SERVER_PORT);
    // sslServerSocket.setNeedClientAuth(true);

    while (true) {
        SSLSocket s = (SSLSocket) sslServerSocket.accept();
    //  System.out.println(s);
        //System.out.println(s.getClass());
        // s.getSupportedProtocols()
        CatServer cs = new CatServer(s);
        //s.addHandshakeCompletedListener(cs);
        s.startHandshake();
        // System.out.println(s.getHandshakeSession().getProtocol());
        new Thread(cs).start();
    }
}

但 SSLSocket 不包含获取此类信息的 api。 我阅读了关于 jsse.jar 的源代码,发现 在sslhandshake的过程中,SSLSocket使用sun.security.ssl.ServerHandshaker来完成整个过程,而ServerHandshaker又new了一个ClientHello来恢复这个东西

    void processMessage(byte paramByte, int paramInt) throws IOException {
    if ((this.state >= paramByte) && (this.state != 16) && (paramByte != 15)) {
        throw new SSLProtocolException("Handshake message sequence violation, state = " + this.state + ", type = " + paramByte);
    }
    switch (paramByte) {
    case 1:
        HandshakeMessage.ClientHello localClientHello = new HandshakeMessage.ClientHello(this.input, paramInt);
        clientHello(localClientHello);
        break;
    case 11:
        if (this.doClientAuth == 0) {
            fatalSE((byte) 10, "client sent unsolicited cert chain");
        }
        clientCertificate(new HandshakeMessage.CertificateMsg(this.input));
        break;
    case 16:
        SecretKey localSecretKey;
        switch (this.keyExchange) {
        case K_RSA:
        case K_RSA_EXPORT:
            RSAClientKeyExchange localRSAClientKeyExchange = new RSAClientKeyExchange(this.protocolVersion, this.clientRequestedVersion,
                    this.sslContext.getSecureRandom(), this.input, paramInt, this.privateKey);

            localSecretKey = clientKeyExchange(localRSAClientKeyExchange);
            break;
        case K_KRB5:
        case K_KRB5_EXPORT:
            localSecretKey = clientKeyExchange(new KerberosClientKeyExchange(this.protocolVersion, this.clientRequestedVersion,
                    this.sslContext

                            .getSecureRandom(),
                    this.input,

                    getAccSE(), this.serviceCreds));

            break;
        case K_DHE_RSA:
        case K_DHE_DSS:
        case K_DH_ANON:
            localSecretKey = clientKeyExchange(new DHClientKeyExchange(this.input));
            break;
        case K_ECDH_RSA:
        case K_ECDH_ECDSA:
        case K_ECDHE_RSA:
        case K_ECDHE_ECDSA:
        case K_ECDH_ANON:
            localSecretKey = clientKeyExchange(new ECDHClientKeyExchange(this.input));
            break;
        default:
            throw new SSLProtocolException("Unrecognized key exchange: " + this.keyExchange);
        }
        calculateKeys(localSecretKey, this.clientRequestedVersion);
        break;
    case 15:
        clientCertificateVerify(new HandshakeMessage.CertificateVerify(this.input, getLocalSupportedSignAlgs(), this.protocolVersion));
        break;
    case 20:
        if (!receivedChangeCipherSpec()) {
            fatalSE((byte) 40, "Received Finished message before ChangeCipherSpec");
        }
        clientFinished(new HandshakeMessage.Finished(this.protocolVersion, this.input, this.cipherSuite));
        break;
    default:
        throw new SSLProtocolException("Illegal server handshake msg, " + paramByte);
    }
    if (this.state < paramByte) {
        if (paramByte == 15) {
            this.state = (paramByte + 2);
        } else {
            this.state = paramByte;
        }
    }
}

问题是我无法从 sslsocket 对象获取 HandshakeMessage.ClientHello。

最佳答案

它在理论上看起来是可行的,但我还没有看到任何现成的 Java 代码。看看 JSSE Reference Guide在“准备 ClientHello 解析器”部分,它为您的问题提供了解决方案的开始。

关于java - JAVA中SSL握手时如何获取ClientHello信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48057825/

相关文章:

java - Maven编译时找不到sun.jvm.hotspot

java - 将数字提取到字符串数组中

python - pip install numpy 没有安装文件

python - 在 python 2.7.10、Mac OSX 下机械化的 SSLv3 握手失败

java - 充气城堡给出未知的 HashAlgorithm

java - com.fasterxml.jackson.databind.exc.MismatchedInputException :

java多线程面试 : sleep, wait, notify, yield - 哪个是回调?

node.js - 在特定端口上为 Nodejs 配置 NGINX (Engintron) HTTPS 到 HTTP

c - 如何在一个进程中接受 SSL 连接并在另一个进程中重用相同的 SSL 上下文

java - 在浏览器中工作的 RestTemplate GET 请求中的 handshake_failure