我必须从离开公司的开发人员那里调试旧的PHP脚本。我理解代码的大部分内容,除了以下函数。我的问题:什么......
if($ seq == 0x03 || $ seq == 0x30)
...表示从X.509证书中提取签名的上下文?
public function extractSignature($certPemString) {
$bin = $this->ConvertPemToBinary($certPemString);
if(empty($certPemString) || empty($bin))
{
return false;
}
$bin = substr($bin,4);
while(strlen($bin) > 1)
{
$seq = ord($bin[0]);
if($seq == 0x03 || $seq == 0x30)
{
$len = ord($bin[1]);
$bytes = 0;
if ($len & 0x80)
{
$bytes = ($len & 0x0f);
$len = 0;
for ($i = 0; $i < $bytes; $i++)
{
$len = ($len << 8) | ord($bin[$i + 2]);
}
}
if($seq == 0x03)
{
return substr($bin,3 + $bytes, $len);
}
else
{
$bin = substr($bin,2 + $bytes + $len);
}
}
else
{
return false;
}
}
return false;
}
答案 0 :(得分:5)
X.509证书包含多个部分的数据(称为Tag-Length-Value三元组)。每个部分都以Tag字节开头,表示该部分的数据格式。您可以看到这些数据类型的列表here。
0x03 是BIT STRING数据类型的标记字节, 0x30 是SEQUENCE数据类型的标记字节。
因此,此代码旨在处理BIT STRING和SEQUENCE数据类型。如果你看这个部分:
if($seq == 0x03)
{
return substr($bin,3 + $bytes, $len);
}
else // $seq == 0x30
{
$bin = substr($bin,2 + $bytes + $len);
}
你可以看到该函数被设计为跳过序列(0x30),直到它找到一个位串(0x03),此时它返回位串的值。
您可能想知道为什么位字符串的 3 和序列的 2 。这是因为在位串中,第一个值字节是一个特殊的额外字段,表示在数据的最后一个字节中未使用的位数。 (例如,如果要发送13位数据,则需要2个字节= 16位,“未使用位”字段将为3。)
下一期:长度字段。当Value的长度小于128个字节时,使用单个字节简单地指定长度(最高有效位将为0)。如果长度为128或更大,则第一个长度字节的位设置为7,其余7位表示后续字节包含的长度(以大端顺序排列)。更多说明here。长度字段的解析发生在代码的这一部分:
$len = ord($bin[1]);
$bytes = 0;
if ($len & 0x80)
{
// length is greater than 127!
$bytes = ($len & 0x0f);
$len = 0;
for ($i = 0; $i < $bytes; $i++)
{
$len = ($len << 8) | ord($bin[$i + 2]);
}
}
之后,$bytes
包含长度字段使用的额外字节数,$len
包含值字段的长度(以字节为单位)。
您是否发现了代码中的错误?请记住,
如果长度为128或更大,则第一个长度字节的位为7 设置,剩余的 7位表示后续字节数 包含长度。
但代码显示$bytes = ($len & 0x0f)
,只占用字节的低4位!它应该是:
$bytes = ($len & 0x7f);
当然,这个错误只是极长消息的问题:只要长度值适合0x0f = 15字节,它就能正常工作,这意味着数据必须小于256 ^ 15个字节。这大约是一万亿个字节,对任何人来说应该足够了。
答案 1 :(得分:2)
正如佩特曼上面所说,你只是有一个合乎逻辑的,我们只是检查$seq
是0x30还是0x03。
我有一种感觉你已经知道了,所以这里。 $seq
是证书的第一个字节,可能是证书的版本或幻数,表示该文件是证书(也称为“我猜这是因为10:45不是是时候开始阅读RFC了。)。
在这种情况下,我们将与0x30和0x03进行比较。这些数字以十六进制表示(以每个以0x开头的数字表示),即base-16。这实际上是二进制的一种非常方便的简写,因为每个十六进制数字恰好对应于四个二进制位。快速表是这样的:
0 = 0000
1 = 0001
2 = 0010
3 = 0011
...
...
E = 1110
F = 1111
同样,我们可以说if($seq == 3 || $seq == 48)
,但在这种情况下,十六进制只是更容易阅读和理解。
答案 2 :(得分:2)
我猜测它是x.509证书中版本标识符“3”的字节顺序无关的检查。见RFC 1422,第7页。其余的是逐字节拉取签名。
答案 3 :(得分:1)
ord()获取您传递的ASCII字符的值。在这种情况下,它会检查ASCII字符是0还是文本结尾(根据此ASCII table)。
答案 4 :(得分:-1)
0x03和0x30是十六进制值。看一下,你会得到$ seq与
相匹配的东西