net_io.core.ssl.SSLClientHello Maven / Gradle / Ivy
The newest version!
package net_io.core.ssl;
import net_io.core.ByteArray;
import net_io.core.ByteBufferPool;
import net_io.utils.EncodeUtils;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class SSLClientHello {
/** HELLO数据库最大限长 **/
private static final int MAX_HELLO_PACKET_LENGTH = 8192;
/** 扩展属性:服务器名称 **/
public static final int EXTENSION_SERVER_NAME = 0x00;
/** 扩展属性:填充 **/
public static final int EXTENSION_PADDING = 0x15;
/** 扩展属性:key share **/
public static final int EXTENSION_KEY_SHARE = 0x33;
/** 扩展属性:supported groups **/
public static final int EXTENSION_SUPPORTED_GROUPS = 0x0A;
/** 扩展属性:supported versions **/
public static final int EXTENSION_SUPPORTED_VERSIONS = 0x2B;
/** 取指纹,忽略的扩展 **/
private static HashMap fingerprintIgnoreExtension = new HashMap();
/** 保留ID **/
private static HashMap reservedIdMap = new HashMap();
static {
//忽略的扩展
fingerprintIgnoreExtension.put(EXTENSION_PADDING, new Boolean(true));
fingerprintIgnoreExtension.put(EXTENSION_KEY_SHARE, new Boolean(true));
//保留ID
reservedIdMap.put(0x0a0a, new Boolean(true));
reservedIdMap.put(0x1a1a, new Boolean(true));
reservedIdMap.put(0x2a2a, new Boolean(true));
reservedIdMap.put(0x3a3a, new Boolean(true));
reservedIdMap.put(0x4a4a, new Boolean(true));
reservedIdMap.put(0x5a5a, new Boolean(true));
reservedIdMap.put(0x6a6a, new Boolean(true));
reservedIdMap.put(0x7a7a, new Boolean(true));
reservedIdMap.put(0x8a8a, new Boolean(true));
reservedIdMap.put(0x9a9a, new Boolean(true));
reservedIdMap.put(0xaaaa, new Boolean(true));
reservedIdMap.put(0xbaba, new Boolean(true));
reservedIdMap.put(0xcaca, new Boolean(true));
reservedIdMap.put(0xdada, new Boolean(true));
reservedIdMap.put(0xeaea, new Boolean(true));
reservedIdMap.put(0xfafa, new Boolean(true));
}
private short contentType;
private int helloVersion;
private int helloLength;
private short handshakeType;
private int handshakeLength;
private int handshakeVersion;
private byte[] random;
private byte[] sessionId;
private int[] cipherSuites = null;
private short[] compressionMethods = null;
private List extensions = null;
public SSLClientHello(ByteArray data) {
ByteOrder order = data.getOrder();
if(order != ByteOrder.BIG_ENDIAN) {
data.setOrder(ByteOrder.BIG_ENDIAN);
}
parseHello(data);
if(order != ByteOrder.BIG_ENDIAN) {
data.setOrder(order);
}
data.rewind();
}
private void parseHello(ByteArray data) {
this.contentType = data.readUInt8();
this.helloVersion = data.readUInt16();
this.helloLength = data.readUInt16();
this.handshakeType = data.readUInt8();
data.readUInt8(); //长度字节:总长2字节,握手长度3字节,忽略多余的1个字节
this.handshakeLength = data.readUInt16();
this.handshakeVersion = data.readUInt16();
//创建动态数组之前,检查是否超长
if(this.helloLength > MAX_HELLO_PACKET_LENGTH) {
throw new HelloFormatException("ClientHello packet length error: " + this.helloLength);
}
if(this.handshakeLength > this.helloLength) {
throw new HelloFormatException("ClientHello handshake packet length error: " + this.handshakeLength);
}
this.random = new byte[32]; //随机数组,固定32字节
data.readBytesTo(this.random);
int sessionIdLength = data.readUInt8();
if(sessionIdLength > 0) {
if(sessionIdLength > this.handshakeLength) {
throw new HelloFormatException("ClientHello session id length error: " + sessionIdLength);
}
this.sessionId = new byte[sessionIdLength];
data.readBytesTo(this.sessionId);
}
int cipherSuiteLenth = data.readUInt16();
if(cipherSuiteLenth > this.handshakeLength) {
throw new HelloFormatException("ClientHello cipher suites length error: " + cipherSuiteLenth);
}
cipherSuiteLenth /= 2; //每个加密套件占用2个字节
this.cipherSuites = new int[cipherSuiteLenth];
for(int i=0; i this.handshakeLength) {
throw new HelloFormatException("ClientHello compression length error: " + compressionLength);
}
this.compressionMethods = new short[compressionLength]; //一个压缩方法,占用1个字节
for(int i=0; i this.handshakeLength) {
throw new HelloFormatException("ClientHello extension total length error: " + extensionsLength);
}
this.extensions = new ArrayList();
for(int i=0; i extensionsLength) {
throw new HelloFormatException("ClientHello extension length error: " + extensionsLength);
}
byte[] bts = new byte[len];
if(len > 0) {
data.readBytesTo(bts);
}
this.extensions.add(new Extension(type, bts));
}
}
/** 获取主机名 **/
public String getHostName() {
if(this.extensions == null) {
return null;
}
for(Extension extension : this.extensions) {
if(extension.type != EXTENSION_SERVER_NAME) {
continue;
}
for(Extension.ServerName serverName : extension.getServerNames()) {
if(serverName.type == Extension.ServerName.TYPE_HOST_NAME) {
return new String(serverName.name, EncodeUtils.Charsets.UTF_8);
}
}
}
return null;
}
public String getFingerprint() {
ByteBuffer buff = ByteBufferPool.mallocMiddle();
try {
buff.order(ByteOrder.BIG_ENDIAN); //网络字节序
buff.putShort((short)this.handshakeVersion);
if(this.cipherSuites != null) {
for(int i=0; i getServerNames() {
if(type != EXTENSION_SERVER_NAME) {
throw new HelloFormatException("ClientHello extension type is not server name: " + type);
}
ByteBuffer buff = ByteBuffer.wrap(data);
buff.order(ByteOrder.BIG_ENDIAN);
int total = buff.getShort() & 0xFFFF;
if(total > data.length) {
throw new HelloFormatException("ClientHello server name total length error: " + total);
}
ArrayList names = new ArrayList();
for(int i=0; i total) {
throw new HelloFormatException("ClientHello server name length error: " + len);
}
byte[] name = new byte[len];
buff.get(name);
names.add(new ServerName(nameType, name));
}
return names;
}
private int[] getSupportedGroups() {
if(type != EXTENSION_SUPPORTED_GROUPS) {
throw new HelloFormatException("ClientHello extension type is not supported groups: " + type);
}
ByteBuffer buff = ByteBuffer.wrap(data);
buff.order(ByteOrder.BIG_ENDIAN);
int total = buff.getShort() & 0xFFFF;
if(total != data.length - 2) {
throw new HelloFormatException("ClientHello supported groups length error: " + total);
}
total /= 2;
int[] res = new int[total];
for(int i=0; i