Как получить информацию ClientHello во время рукопожатия SSL в JAVA

Я хочу получить что-то вроде клиентских Compression_methods или наборов шифров, поддерживаемых клиентом, из рукопожатия 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;
        }
    }
}

проблема в том, что я не могу получить HandshakeMessage.ClientHello из объекта sslsocket.


person kyrotiko    schedule 02.01.2018    source источник
comment
Почему? Вы можете получить фактический набор шифров от SSLSession, после согласования JSSE. Как вы думаете, зачем вам нужно знать наборы шифров, поддерживаемые клиентом?   -  person user207421    schedule 02.01.2018
comment
На самом деле вы, похоже, пытаетесь реализовать согласование ключей SSL nnhasephase. Почему? Это уже сделано за вас. Непонятно, что вы спрашиваете.   -  person user207421    schedule 02.01.2018
comment
@EJP Я пытаюсь создать веб-сайт, который может определять, какие наборы шифров и режим сжатия поддерживает браузер, например website1 и веб-сайт2   -  person kyrotiko    schedule 02.01.2018
comment
Я не уверен, что это может быть успешным в java, я узнал о том, что мод apache может это сделать, но мне сложно писать код C   -  person kyrotiko    schedule 02.01.2018


Ответы (1)


Теоретически это возможно, но я не видел готового Java-кода. Ознакомьтесь с Справочным руководством по JSSE. в части "Подготовка парсера ClientHello", которая дает начало решению вашей проблемы.

person Eugène Adell    schedule 02.01.2018
comment
Это хорошая идея настроить прокси-сервер сокетов, я попробую, большое спасибо, Adell - person kyrotiko; 03.01.2018