Php 这段代码如何提取签名?

Php 这段代码如何提取签名?,php,certificate,x509certificate,x509,Php,Certificate,X509certificate,X509,我必须调试一个离开公司的开发人员的旧PHP脚本。我理解代码的大部分,除了下面的函数。我的问题:什么是 如果($seq==0x03 | |$seq==0x30) …是指从X.509证书中提取签名 public function extractSignature($certPemString) { $bin = $this->ConvertPemToBinary($certPemString); if(empty($certPemString) || empty($bin)

我必须调试一个离开公司的开发人员的旧PHP脚本。我理解代码的大部分,除了下面的函数。我的问题:什么是

如果($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;
}
公共函数提取签名($certPemString){
$bin=$this->ConvertPemToBinary($certPemString);
if(空($certPemString)| |空($bin))
{
返回false;
}    
$bin=substr($bin,4);
而(strlen($bin)>1)
{            
$seq=ord($bin[0]);
如果($seq==0x03 | |$seq==0x30)
{            
$len=ord($bin[1]);
$bytes=0;
如果($len&0x80)
{
$bytes=($len&0x0f);
$len=0;
对于($i=0;$i<$bytes;$i++)
{

$len=($len0x03和0x30是十六进制值。向上看,你会得到$seq与之匹配的内容,正如帕特曼上面所说,你只需要一个逻辑if,我们只是检查
$seq
是0x30还是0x03

我有一种感觉,您已经知道了这一点,接下来就是。
$seq
是证书的第一个字节,它可能是证书的版本或表示文件是证书的幻数(也称为“我猜这是因为10:45没有时间开始读RFC”)

在本例中,我们将与0x30和0x03进行比较。这些数字以十六进制表示(每一个以0x开头的数字都以16为基数)。这实际上是一个非常方便的二进制简写,因为每个十六进制数字正好对应四个二进制位。快速表格如下:

0 = 0000
1 = 0001
2 = 0010
3 = 0011
...
...
E = 1110
F = 1111

同样好的,我们可以说
如果($seq==3 | |$seq==48)
,但是十六进制在这种情况下更容易阅读和理解。

获取您传递给它的ASCII字符的值。在这种情况下,它检查ASCII字符是0还是文本结尾(根据此).

我猜这是对x.509证书中版本标识符“3”的字节顺序独立检查。请参阅,第7页。其余部分逐字节提取签名。

x.509证书包含多个部分的数据(称为标记长度值三元组)。每个节都以标记字节开头,表示节的数据格式。您可以看到这些数据类型的列表

0x03是数据类型的标记字节,0x30是数据类型的标记字节

因此,此代码旨在处理位字符串和序列数据类型。如果您查看此部分:

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。)

下一个问题:长度字段。当值的长度小于128字节时,只需使用单个字节指定长度(最高有效位为0)。如果长度为128或更大,则第一个长度字节设置了位7,剩余的7位表示后面有多少字节包含长度(以大端顺序)。更多说明。长度字段的解析发生在代码的这一部分:

$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]);
    }
}

当然,此错误只适用于非常长的消息:只要长度值在0x0f=15字节之内,它就可以正常工作,这意味着数据必须小于256^15字节。这大约是一万亿字节,对任何人来说都足够了。

有什么问题吗?在这种情况下,您有一个简单的逻辑和。可以吗有人澄清一下
的内容吗?你理解脚本其余部分中发生的按位操作,但你不理解相等性?stackoverflow.com现在似乎有一些问题,我无法更新这个问题。我的意思是:条件意味着什么(两个值)在提取签名的上下文中?@Josh-“…除了0x03和0x30之间的差异不是字节顺序外,它是字节内的半字节顺序。@Roland-半字节是4位的,所以它是字节中半字节的顺序。这是非常罕见的,应该永远不需要检查。Endian ness可能是这里的问题,但我不能“我不能不看完整的文件类型规范。@tcovo-准确地说。在PEM格式证书的二进制表示形式中,字节存储的是big-endian还是little-endian?无论哪种方式,该代码都会找到“3”。@Roland不同的硬件类型可能以不同的方式存储位。big-endian硬件存储字节的高阶部分(最重要的四位)首先,而“little endian”硬件存储最不重要的四位。从历史上看,Intel(Windows)一直是little endian,Motorola(Apple)一直是big endian。哇!多好的答案!你一定是个天才,你的真名是阿尔伯特·爱因斯坦吗?:-)非常感谢,非常感谢你的帮助!
$bytes = ($len & 0x7f);