The*_*Dr. 2 java networking ssl-certificate x509certificate
我得到了一个字节数据包,它们是ClientHelloSSL 协议数据包。
在我开始自己编写代码之前,代码会遍历所有字节来获取每个字段值,我想知道是否有任何 Java 对象(来自 java.security)用于获取这些字节并解析数据以便我能够获取 SSL 协议字段并使用它们?
据我所知,java.securityJava 中的包不提供任何您正在寻找的功能。GitHub 上可能还有其他示例/库。
如果您最终自己这样做,需要注意的关键事项是:
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:
//
// https://datatracker.ietf.org/doc/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;
}
Run Code Online (Sandbox Code Playgroud)
有关其余代码,请参阅此SslClientHelloDecoder.java文件。
希望这可以帮助!
| 归档时间: |
|
| 查看次数: |
1002 次 |
| 最近记录: |