Java中是否有Java x509certificate ClientHello解析器?

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

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

据我所知,Java中的java.security包没有提供任何你想要的function。 GitHub上可能还有其他示例/库。

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

  • SSLv2 SSLv3 对比 TLSv1 ClientHello格式
  • 你的问题标题提到了证书; 客户端证书存在ClientHello消息; 它们仅在握手过程中稍后发送,以响应来自服务器的CertificateRequest消息。

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

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

 // 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文件以获取其余代码。

希望这可以帮助!