gpt4 book ai didi

java - 如何将第一个 hello SSL 消息转换为 jdk ClientHello.java 对象?

转载 作者:太空宇宙 更新时间:2023-11-03 15:13:54 25 4
gpt4 key购买 nike

在我创建 SSLEngine 之前,我需要在第一个 SSL 客户端问候的扩展中使用 SNI 服务器名称(当然如果它存在的话)。我在这里查看 ClientHello 类...(尽管我现在使用的是 jdk 8)。

http://hg.openjdk.java.net/jdk9/dev/jdk/file/6407a15e2274/src/share/classes/sun/security/ssl/HandshakeMessage.java

有谁知道如何更轻松地从 ByteBuffer 转到数据结构以获取 SNI 服务器名? (字节缓冲区将包含一个等于或大于所需大小的大小,因为我已经检查了 SSL 数据包的大小并等待我拥有完整的 ssl hello 数据包)。

此外,这篇文章对于让起始部分到位非常有效 Is there any Java x509certificate ClientHello parser in Java?

谢谢,院长

最佳答案

供其他人重复使用,但这是我的第一次尝试,它的工作原理使我可以在握手开始之前获取 sniServerName...

public class ClientHelloParser {
private static final short HANDSHAKE_CONTENT_TYPE = 22;
private static final short CLIENTHELLO_MESSAGE_TYPE = 1;
private static final short SSLV2_CLIENTHELLO = 128;

private static final int SERVER_NAME_EXTENSION_TYPE = 0;
private static final short HOST_NAME_TYPE = 0;

private ByteBuffer cachedBuffer;
private BufferPool pool;

public ClientHelloParser(BufferPool pool) {
this.pool = pool;
}

/**
* Returns null if we still need more data
*
* @param b
* @return
*/
ParseResult fetchServerNamesIfEntirePacketAvailable(ByteBuffer b) {
if(cachedBuffer != null) {
//prefix cachedBuffer in front of b and assign to b as the packet that is coming in
ByteBuffer newBuf = pool.nextBuffer(cachedBuffer.remaining()+b.remaining());
newBuf.put(cachedBuffer);
newBuf.put(b);
newBuf.flip();
pool.releaseBuffer(b); //release b that is now in the newBuf
pool.releaseBuffer(cachedBuffer); //release cached buffer that is now in newBuf
b = newBuf;
}

if(b.remaining() < 5) {
cachedBuffer = b;
return null; //wait for more data
}

int recordSize = 0;
ByteBuffer duplicate = b.duplicate();
short contentType = getUnsignedByte(duplicate);
if(contentType == HANDSHAKE_CONTENT_TYPE) {
getUnsignedByte(duplicate);
getUnsignedByte(duplicate);
recordSize = getUnsignedShort(duplicate);

// Now wait until we have the entire record
if (b.remaining() < (5 + recordSize)) {
// Keep buffering
return null;
}
} else if (contentType == SSLV2_CLIENTHELLO) {
short len = getUnsignedByte(duplicate);

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

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

} else {
throw new IllegalStateException("contentType="+contentType+" not supported in ssl hello handshake packet");
}

short messageType = getUnsignedByte(duplicate);
if (messageType != CLIENTHELLO_MESSAGE_TYPE) {
throw new IllegalStateException("something came before ClientHello :( messageType="+messageType);
}

if (contentType == HANDSHAKE_CONTENT_TYPE) {
// If we're not an SSLv2 ClientHello, then skip the ClientHello
// message size.
duplicate.get(new byte[3]);

// Use the ClientHello ProtocolVersion
getUnsignedShort(duplicate);

// Skip ClientRandom
duplicate.get(new byte[32]);

// Skip SessionID
int sessionIDSize = getUnsignedByte(duplicate);
duplicate.get(new byte[sessionIDSize]);

//read in and discard cipherSuite...
int cipherSuiteSize = getUnsignedShort(duplicate);
duplicate.get(new byte[cipherSuiteSize]);

//read in compression methods size and discard..
short compressionMethodsLen = getUnsignedByte(duplicate);
duplicate.get(new byte[compressionMethodsLen]);

int extensionLen = getUnsignedShort(duplicate);
List<String> names = readInExtensionServerNames(duplicate, extensionLen);

return new ParseResult(b, names);
} else {
// SSLv2 ClientHello.
// Use the ClientHello ProtocolVersion
//SslVersion version = SslVersion.decode(getUnsignedByte(duplicate));

throw new UnsupportedOperationException("not supported yet");
}
}

private List<String> readInExtensionServerNames(ByteBuffer duplicate, int len) {
List<String> serverNames = new ArrayList<>();
int byteCount = 0;
while(byteCount < len) {
byteCount += 4; //reading in 4 bytes so add them in
if(duplicate.remaining() < 4)
throw new IllegalStateException("Corrupt packet with incorrect format");
int type = getUnsignedShort(duplicate);
int extLen = getUnsignedShort(duplicate);

if(duplicate.remaining() < extLen)
throw new IllegalStateException("Corrupt packet with incorrect format as len didn't match");

if(type == SERVER_NAME_EXTENSION_TYPE) {
String name = readServerNames(duplicate, extLen);
serverNames.add(name);
} else
duplicate.get(new byte[extLen]);
byteCount += extLen;
}

return serverNames;
}

private String readServerNames(ByteBuffer duplicate, int extLen) {
int byteCount = 0;

byteCount += 2; //for listLen 2 bytes
int listLen = getUnsignedShort(duplicate);
if(listLen + 2 != extLen)
throw new RuntimeException("we have something we need to fix here as listLen is only two less bytes then extensionLength");

byteCount += 1; //for serverNameType
short serverNameType = getUnsignedByte(duplicate);
if(serverNameType != HOST_NAME_TYPE)
throw new IllegalStateException("Server name type="+serverNameType+" not supported yet");

byteCount += 2; //for serverNameLen
int serverNameLen = getUnsignedShort(duplicate);

byteCount += serverNameLen;
if(byteCount != extLen)
throw new UnsupportedOperationException("bytes read in servernames extension does not match extLen(we need to loop here then)");

byte[] data = new byte[serverNameLen];
duplicate.get(data);

String serverName = new String(data);
return serverName;
}

public short getUnsignedByte(ByteBuffer bb) {
return ((short)(bb.get() & 0xff));
}

public int getUnsignedShort (ByteBuffer bb)
{
return (bb.getShort() & 0xffff);
}
}

关于java - 如何将第一个 hello SSL 消息转换为 jdk ClientHello.java 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37290053/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com