问题描述
我收到了一个字节数据包,它是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:
- 格式
- 您的问题标题提到证书;客户端证书不目前
ClientHello
消息;它们仅在握手过程中稍后发送,以响应消息。
- 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 aCertificateRequest
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;
}
请参阅文件剩下的代码。
See this SslClientHelloDecoder.java file for the rest of the code.
希望这会有所帮助!
这篇关于Java中是否有Java x509certificate ClientHello解析器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!