在JAVA中如何在SSL握手期间获取ClientHello信息

在JAVA中如何在SSL握手期间获取ClientHello信息,java,ssl,handshake,jsse,Java,Ssl,Handshake,Jsse,我想从ssl握手中获得一些类似于客户端压缩方法或客户端支持的密码套件的东西 我试过使用 public static void main(String[] args) throws Exception { String serverKeyStoreFile = "D:\\tomcat.keystore"; String serverKeyStorePwd = "logiscn"; String catServerKeyPwd = "logiscn"; String

我想从ssl握手中获得一些类似于客户端压缩方法或客户端支持的密码套件的东西 我试过使用

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已经更新了一个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;
        }
    }
}
void processMessage(byte-paramByte,int-paramInt)引发IOException{
如果((this.state>=paramByte)&&&(this.state!=16)&&(paramByte!=15)){
抛出新的SSLProtocolException(“握手消息序列冲突,state=“+this.state+”,type=“+paramByte”);
}
开关(参数字节){
案例1:
HandshakeMessage.ClientHello localClientHello=新建HandshakeMessage.ClientHello(this.input,paramInt);
clientHello(本地clientHello);
打破
案例11:
if(this.doclientutututh==0){
fatalSE((字节)10,“客户端发送的未经请求的证书链”);
}
clientCertificate(新的握手消息.CertificateMsg(this.input));
打破
案例16:
SecretKey localSecretKey;
开关(此.keyExchange){
案例K_RSA:
案例K_RSA_导出:
RSAClientKeyExchange localRSAClientKeyExchange=新的RSAClientKeyExchange(this.protocolVersion,this.clientRequestedVersion,
this.sslContext.getSecureRandom()、this.input、paramInt、this.privateKey);
localSecretKey=clientKeyExchange(localRSAClientKeyExchange);
打破
案例K_KRB5:
案例K_KRB5_出口:
localSecretKey=clientKeyExchange(新KerberosClientKeyExchange(this.protocolVersion,this.clientRequestedVersion,
这个.sslContext
.getSecureRandom(),
这个输入,
getAccSE(),this.serviceCreds));
打破
案例K_DHE_RSA:
案例K_DHE_DSS:
案例K_DH_ANON:
localSecretKey=clientKeyExchange(新的DHClientKeyExchange(this.input));
打破
案例K_ECDH_RSA:
案例K_ECDH_ECDSA:
案例K_ECDHE_RSA:
案例K_ECDHE_ECDSA:
案例K_ECDH_ANON:
localSecretKey=clientKeyExchange(新的ECDHClientKeyExchange(this.input));
打破
违约:
抛出新的SSLProtocolException(“未识别的密钥交换:“+this.keyExchange”);
}
calculateKeys(localSecretKey,this.clientRequestedVersion);
打破
案例15:
clientCertificateVerify(新的HandshakeMessage.CertificateVerify(this.input,getLocalSupportedSignAlgs(),this.protocolVersion));
打破
案例20:
如果(!receivedChangeCipherSpec()){
fatalSE((字节)40,“在ChangeCipherSpec之前收到完成的消息”);
}
clientFinished(新的握手消息.Finished(this.protocolVersion,this.input,this.cipherSuite));
打破
违约:
抛出新的SSLProtocolException(“非法服务器握手消息,”+paramByte);
}
if(this.state

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

从理论上看这是可能的,但我还没有看到任何现成的Java代码。请看一下“准备ClientHello解析器”部分,它为您的问题提供了解决方案的开始

为什么??在JSSE协商后,您可以从
SSLSession
获取实际的密码套件。为什么您认为需要了解客户端支持的密码套件?事实上,您似乎正在尝试实现SSL密钥协商nnhasephase。为什么?已经为你做了。不清楚你在问什么。@EJP我正在尝试创建一个网站,它可以检测浏览器支持的密码套件和压缩模式,我不确定它是否能在java中成功,我知道apache mod可以做到这一点,但我很难编写c代码。设置代理套接字服务器是一个好主意,我会尝试,非常感谢,阿德尔