Java中是否有Java x509certificate ClientHello解析器? [英] Is there any Java x509certificate ClientHello parser in Java?

查看:195
本文介绍了Java中是否有Java x509certificate ClientHello解析器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我收到了一个字节数据包,它是SSL协议数据包的 ClientHello

I got a packet of bytes which are the ClientHello of SSL protocol packet.

在我之前开始自己编码,一个遍历整个字节的代码来获取每个字段值,我想知道是否有任何Java对象(来自java.security)用于获取这些字节并解析数据所以我会能够获取SSL协议字段并使用它们吗?

Before I'm starting to code by myself, a code which is going through all over the bytes to get each field value, I wonder if there is any Java Object (from java.security) which is used to get these bytes and parse the data so I would be able to take the SSL protocol fields and use them?

推荐答案

据我所知, java.security Java中的包不提供您所需要的任何功能。 GitHub上可能还有其他示例/库。

As far as I know, the java.security package in Java does not provide any functionality along the lines of what you're looking for. There may be other examples/libraries on GitHub.

如果你最终自己这样做,关键的事情是:

If you end up doing this yourself, key things to be aware of are:

  • SSLv2 vs SSLv3 vs TLSv1 ClientHello formats
  • Your question title mentions certificates; client certificates are not present ClientHello messages; they are only sent later in the handshake process, in response to a CertificateRequest message from the server.

解码SSL / TLS消息通常涉及阅读(并重新读取相关的RFC,并通过其在数据包中的位置确定每个字节值表示的含义。设计为二进制协议,为了提高效率,梳理您想要的字段可能比您认为必要的更复杂。但是,了解这些领域是非常值得的。

Decoding SSL/TLS messages usually involves reading (and re-reading) the relevant RFCs, and figuring out what each byte value signifies, by its position within the packet. Being designed as a binary protocol, for efficiency, it can be more complicated to tease out the fields you want than you might think necessary. But it's well-worth gaining an understanding of these fields.

这里有一些Java代码可能有助于您入门。 注意它在Java中使用字节缓冲区,因为在解码这样的二进制协议时必须处理 unsigned 数据类型。

Here's some Java code which might help to get you started. Note that it uses byte buffers in Java, as it is necessary to deal with unsigned data types when decoding binary protocols like this.

// These values are defined in the IETF TLS cipher suite registry; see:
//
//   http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-3
private static final int RC4_MD5_HEX = 0x0004;
private static final int RC4_SHA_HEX = 0x0005;

private static final short HANDSHAKE_CONTENT_TYPE = 22;
private static final short CLIENTHELLO_MESSAGE_TYPE = 1;

private static final short SSLV2_CLIENTHELLO = 128;
protected boolean doDecode(IoSession session,
                           IoBufferEx original,
                           ProtocolDecoderOutput out)
    throws Exception {

    // Need at least 2 bytes to differentiate between SSLv2 ClientHello
    // messages and SSLv3/TLSv1/+ messages.
    //
    // For SSLv2 ClientHello, we need:
    //
    //  length header (short)
    //  content type (byte)
    //
    // For more details, see:
    //
    //  http://tools.ietf.org/html/draft-hickman-netscape-ssl-00
    //
    // Otherwise, we need:
    //
    //  content type (byte)
    //  version (short)
    //  length (short)
    //
    // So wait for at least 5 bytes, to cover either case.

    if (original.remaining() < 5) {
        return false;
    }

    // Make a copy, so that we can read things non-destructively
    IoBufferEx dup = original.duplicate();

    // If not a Handshake record, be done.  Note that we have to
    // successfully handle SSLv2 ClientHello formats as well.

    short contentType = dup.getUnsigned();
    if (contentType == HANDSHAKE_CONTENT_TYPE) {
        // Skip the ProtocolVersion here; we will get it later
        dup.skip(2);

        int recordSize = dup.getUnsignedShort();

        // Now wait until we have the entire record
        if (original.remaining() < (5 + recordSize)) {
            // Keep buffering
            return false;
        }

    } else if (contentType == SSLV2_CLIENTHELLO) {
        short len = dup.getUnsigned();

        // Decode the length
        int recordSize = ((contentType & 0x7f) << 8 | len);

        // Now wait until we have the entire record
        if (original.remaining() < (2 + recordSize)) {
            // Keep buffering
            return false;
        }

    } else { 
        // We're only interested in Handshake records
        out.write(original.getSlice(original.remaining()));
        return true;
    }

    // For the format of the ClientHello message, see RFC 5246,
    // Section 7.4.1.2.

    short messageType = dup.getUnsigned();
    if (messageType != CLIENTHELLO_MESSAGE_TYPE) {
        // We're only interested in ClientHello messages
        out.write(original.getSlice(original.remaining()));
        return true;
    }

    if (contentType == HANDSHAKE_CONTENT_TYPE) {
        // If we're not an SSLv2 ClientHello, then skip the ClientHello
        // message size.
        dup.skip(3);

        // Use the ClientHello ProtocolVersion
        SslVersion version = SslVersion.decode(dup.getUnsignedShort());

        // Skip ClientRandom
        dup.skip(32);

        // Skip SessionID
        int sessionIDSize = dup.getUnsigned();
        dup.skip(sessionIDSize);

        // Now we get to what we're really after: the ciphersuites supported
        // by the client.
        int cipherSuiteSize = dup.getUnsignedShort();

        // cipherSuiteSize is the number of bytes; each cipher is specified
        // using a short (2 bytes).  Thus the cipher suite count is the half
        // the cipher suite size.
        int cipherSuiteCount = cipherSuiteSize / 2;

        // Iterate through each of the ciphersuites

        for (int i = 0; i < cipherSuiteCount; i++) {
            int cipher = dup.getUnsignedShort();

            if (cipher == RC4_SHA_HEX) {
                ciphers.add(SslCipherSelectionFilter.RC4_SHA);

            } else if (cipher == RC4_MD5_HEX) {
                ciphers.add(SslCipherSelectionFilter.RC4_MD5);
            }
        }

    } else {
        // SSLv2 ClientHello.
        // Use the ClientHello ProtocolVersion
        SslVersion version = SslVersion.decode(dup.getUnsignedShort());

        // Determine cipher specs size
        short msb = dup.getUnsigned();
        short lsb = dup.getUnsigned();
        int cipherSuiteSize = ((msb << 8) | lsb);

        // Skip the sessionID size
        dup.skip(2);

        // Skip the challenge size
        dup.skip(2);

        // Now we get to what we're really after: the ciphersuites supported
        // by the client.

        // cipherSuiteSize is the number of bytes; each cipher is specified
        // using a medium int (3 bytes).
        int cipherSuiteCount = cipherSuiteSize / 3;

        // Iterate through each of the ciphersuites, looking for 
        // SSL_RSA_WITH_RC4_128_MD5.  (It's the only one supported in
        // SSLv2 ClientHellos).

        for (int i = 0; i < cipherSuiteCount; i++) {
            int cipherKind = dup.getUnsignedMediumInt();

            if (cipherKind == SSLV2_RC4_MD5_HEX) {
                appletCiphers.add(SslCipherSelectionFilter.RC4_MD5);
            }
        }
    }

    out.write(original.getSlice(original.remaining()));
    return true;
}

请参阅 SslClientHelloDecoder.java 文件剩下的代码。

See this SslClientHelloDecoder.java file for the rest of the code.

希望这会有所帮助!

这篇关于Java中是否有Java x509certificate ClientHello解析器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆