2012-03-08 55 views
2

我必須從已離開公司的開發人員處調試舊的PHP腳本。我瞭解了大部分代碼,除了以下功能。我的問題:是什麼...這段代碼如何提取簽名?

如果($ SEQ == 0×03 || $ 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

什麼問題?你在條件中有一個簡單的邏輯和。 – Pateman 2012-03-08 22:37:47

+2

任何人都可以澄清一下'<<'比較運算符的作用嗎? – Josh 2012-03-08 22:39:40

+0

您瞭解腳本其餘部分發生的按位操作,但您不明白相等嗎? – Crashspeeder 2012-03-08 22:41:12

回答

5

X.509證書包含多個部分中的數據(稱爲標籤長度 - 值三元組)。每個部分都以Tag字節開始,表示該部分的數據格式。您可以看到這些數據類型的列表here

×03是用於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),直到它找到一個比特串(0×03),此時它返回位的值串。

你可能會奇怪,爲什麼一個神奇的數字是爲位串和爲序列。這是因爲在位串中,第一個值字節是一個特殊的額外字段,它表示在數據的最後一個字節中未使用多少位。 (例如,如果要發送13位數據,它將佔用2個字節= 16位,並且「未使用位」字段將爲3.)

下一個問題:長度字段。當值的長度小於128個字節時,長度只用一個字節指定(最高有效位爲0)。如果長度爲128或更大,則第一個長度字節具有第7位設置,其餘7位指示後面多少字節包含長度(以big-endian順序)。更多描述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字節。這大約有萬億字節,這對任何人都應該足夠了。

+2

哇!多麼好的答案!你一定是天才,你的真名是阿爾伯特愛因斯坦? :-)非常感謝,非常感謝您的幫助! – HomeCoder 2012-03-09 14:28:40

-1

0x03和的0x30的十六進制值。看看這個,你將有什麼$ seq匹配到

2

正如Pateman上面所說,你只是有一個邏輯if,我們只是檢查是否$seq是0x30或0x03。

我有一種感覺,你已經知道,儘管如此。 $seq是證書的第一個字節,可能是證書的版本或幻數,表示文件是證書(也稱爲「我猜這是因爲10:45沒有時間開始閱讀RFC文檔「)。

在這種情況下,我們正在比較0x30和0x03。這些數字以十六進制表示(每個以0x開頭的數字表示),以16爲基數。這對於二進制來說只是一個非常方便的簡寫,因爲每個十六進制數字恰好對應四個二進制位。一個快速的表是這樣的:

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

同樣出色,我們可能會說if($seq == 3 || $seq == 48),但六角只是更容易閱讀,並在這種情況下理解。

1

ord()獲取您傳遞給它的ASCII字符的值。在這種情況下,它將檢查ASCII字符是否爲0或文本結尾(根據此ASCII table)。

2

我猜測它是x.509證書中版本標識符爲'3'的字節順序無關檢查。見RFC 1422,第7頁。其餘的是逐字節地提取簽名。

+1

這非常有幫助,謝謝。 – HomeCoder 2012-03-08 22:55:44

+1

...除了0x03和0x30之間的差別不是字節順序,它在字節內是半字節順序。 – tcovo 2012-03-08 23:02:18

+2

好的,但是這是一個「蠶食訂單」? – Roland 2012-03-08 23:06:49