<分区>
RFC6066在 server_name
类型的扩展中定义服务器名称指示。此扩展的 extension_data
字段应包含 ServerNameList
,其中:
struct {
NameType name_type;
select (name_type) {
case host_name: HostName;
} name;
} ServerName;
enum {
host_name(0), (255)
} NameType;
opaque HostName<1..2^16-1>;
struct {
ServerName server_name_list<1..2^16-1>
} ServerNameList;
最好能逐步解释这个数据结构。另外,这里是示例代码,可以找到here , 如何读取扩展数据:
private static List<SNIServerName> exploreSNIExt(ByteBuffer input,
int extLen) throws IOException {
Map<Integer, SNIServerName> sniMap = new LinkedHashMap<>();
int remains = extLen;
if (extLen >= 2) { // "server_name" extension in ClientHello
int listLen = getInt16(input); // length of server_name_list
if (listLen == 0 || listLen + 2 != extLen) {
throw new SSLProtocolException(
"Invalid server name indication extension");
}
remains -= 2; // 0x02: the length field of server_name_list
while (remains > 0) {
int code = getInt8(input); // name_type
int snLen = getInt16(input); // length field of server name
if (snLen > remains) {
throw new SSLProtocolException(
"Not enough data to fill declared vector size");
}
byte[] encoded = new byte[snLen];
input.get(encoded);
SNIServerName serverName;
switch (code) {
case StandardConstants.SNI_HOST_NAME: // 0x00
if (encoded.length == 0) {
throw new SSLProtocolException(
"Empty HostName in server name indication");
}
serverName = new SNIHostName(encoded);
break;
default:
serverName = new UnknownServerName(code, encoded);
}
// check for duplicated server name type
if (sniMap.put(serverName.getType(), serverName) != null) {
throw new SSLProtocolException(
"Duplicated server name of type "
+ serverName.getType());
}
remains -= encoded.length + 3; // NameType: 1 byte
// HostName length: 2 bytes
}
} else if (extLen == 0) { // "server_name" extension in ServerHello
throw new SSLProtocolException(
"Not server name indication extension in client");
}
if (remains != 0) {
throw new SSLProtocolException(
"Invalid server name indication extension");
}
return Collections.<SNIServerName>unmodifiableList(
new ArrayList<>(sniMap.values()));
}
字节读取器:
private static int getInt16(ByteBuffer input) {
return ((input.get() & 0xFF) << 8) | (input.get() & 0xFF);
}
Here是如何读取数据的好例子。例如,扩展类型是通过读取 2 个字节来定义的 - 那么另一个问题是 - 哪个 RFC 定义了它?
最佳答案
如果您已经有了实现它的源代码,还需要了解什么?
用于抽象模式的格式源自XDR但在每个 TLS 规范中都有具体定义,例如 3. Presentation Language 中的最后一个规范
所以如果我们一 block 一 block 地看:
struct {
NameType name_type;
select (name_type) {
case host_name: HostName;
} name;
} ServerName;
参见 https://www.rfc-editor.org/rfc/rfc8446#section-3.6 ,这定义了一个结构:
name_type
类型称为 NameType
(稍后定义)name
并且是一个变体(https://www.rfc-editor.org/rfc/rfc8446#section-3.8):它的值取决于
以前的 name_type
内容。如果name_type
具有的值(value)
host_name
, 那么第二个分量的值是类型
HostName
(稍后定义)下一步:
enum {
host_name(0), (255)
} NameType;
参见 https://www.rfc-editor.org/rfc/rfc8446#section-3.5 , 这定义了一个只有一个可能值 ( 0
) 的枚举,其别名是 host_name
(255)
仅用于强制宽度(因此 0 到 255,因为值适合一个字节,此结构使用一个字节的空间),如规范中所述:
One may optionally specify a value without its associated tag to force the width definition without defining a superfluous element.
所以这意味着你在网络上使用 0,但如果你有 0,它就是编码 host_name
在规范的其他部分。
opaque HostName<1..2^16-1>;
在https://www.rfc-editor.org/rfc/rfc8446#section-3.2我们有:
Single-byte entities containing uninterpreted data are of type opaque.
并且在 https://www.rfc-editor.org/rfc/rfc8446#section-3.4 , <>
用于定义可变长度向量(或一维数组,或列表)。
所以 HostName
是一个包含 1 到 216-1 个字节(不是元素)的向量,每个元素都是“不透明”类型,即一个字节。
请注意,在 RFC 中有关于 SNI 的进一步解释:
"HostName" contains the fully qualified DNS hostname of the server, as understood by the client. The hostname is represented as a byte string using ASCII encoding without a trailing dot.
struct {
ServerName server_name_list<1..2^16-1>
} ServerNameList;
与第一个情况相同,但使用像上面一样的可变长度数组
ServerNameList
是一个结构ServerName
类型的, 如前所述换句话说:
ServerNameList
structure 是一个元素列表,每个元素的类型都是 ServerName
ServerName
编码 name_type
(只能是“host_name”,也就是值 0)和类型为 HostName
的名称,这是一个最多 216-1 字节的非空列表,编码主机名,如 https://www.rfc-editor.org/rfc/rfc6066#section-3 中所述。 关于ssl - 解释由 RFC6066 服务器名称指示定义的 SSL ClientHello SNI 消息扩展语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57315940/