兩串指紋,一串 64 個字元一串 95 個字元
起因是一則群組訊息:一份憑證指紋是冒號分組、串尾還多一個冒號,另一份從本地檔案讀出來是連續 64 個十六進位字元。兩串擺在一起肉眼對不出結果。指紋上疊著三層變數:算哪個物件、用哪種摘要、以哪種寫法顯示。
摘要物件是整張憑證的 DER
指紋是對整張憑證的 DER 編碼做摘要,不是公開金鑰,也不是 PEM 文字。樣本憑證解出的 DER 是 1159 位元組,包成 Base64 的 PEM 是 1627 位元組,兩個檔案進來的三條指紋逐字元相同;加 BOM(1630 位元組)、換 CRLF(1654 位元組)、補尾隨空白(1635 位元組)、把 Base64 擠成一行,四種變形的指紋一個字元都不動。
會動指紋的只有 DER 內部的位元組:另一張只差 1 個位元組的樣本,公開金鑰段 Base64 完全相同、都是 392 個字元,SHA-256 卻有 62/64 個字元不同,SHA-1 有 39/40 個不同。單獨對那 294 位元組的公開金鑰資訊求 SHA-256,得到第四個字串,和三條指紋都不等。
三種摘要、四種寫法
結果區的指紋固定三行,MD5、SHA-1、SHA-256,長度是摘要位元組數的兩倍:32、40、64 個十六進位字元。四種寫法可切換:小寫無冒號(預設)、大寫無冒號,以及對應的冒號分隔版。冒號分組按 1 個位元組也就是 2 個十六進位字元一組,串尾不帶冒號,所以冒號比組數少 1。
| 摘要 | 十六進位字元 | 摘要位元組數 | 冒號寫法總字元 | 位元組組數 |
|---|---|---|---|---|
| MD5 | 32 | 16 | 47 | 16 |
| SHA-1 | 40 | 20 | 59 | 20 |
| SHA-256 | 64 | 32 | 95 | 32 |
95 等於 64 個十六進位字元加 31 個冒號,是同一條 SHA-256 摘要的兩種顯示,比對前先切成同一種寫法再逐字元比。
圖 1:綠段是十六進位字元,灰段是插進去的冒號。
一個檔案裡可能不止一張
指紋對上之前還得確認對方給的是哪一張。實測 1683 位元組的 .p7b 和 2322 位元組的 PEM 包 PKCS#7 各給出 2 張,同一張憑證重複 50 次寫成 81350 位元組的檔案一次給出 50 張,每張 DER 都是 1159 位元組、三條指紋相同。編號只反映排列順序,不代表角色:那條 2 張的鏈裡第 1 張是 1159 位元組,第 2 張只有 462 位元組,誰葉子誰根不由位置決定,別拿最後一條當實體憑證。
剩餘天數那一列,只看到期日
這列只用到期時間減目前時刻,按天四捨五入,於是已過期但不足 12 小時的憑證仍然顯示「剩餘 0 天」;生效時間不參與計算,notBefore 寫在 2027-06-01 的憑證照樣顯示「剩餘 587 天」,沒有尚未生效的提示。時間列跟機器時區:同一張憑證在 TZ 為 UTC 給出 2026-09-01 00:00,在 UTC+8 給出 2026-09-01 08:00,後綴都寫著「本地時區」,而兩種時區算出的剩餘天數都是 144 天。
公開金鑰匯出的三種寫法
結果區還有獨立的公開金鑰區塊,和指紋塊是兩碼事。樣本那張 RSA-2048 憑證的公開金鑰資訊段 294 位元組,三種寫法實測:含 -----BEGIN PUBLIC KEY----- 頭尾的 PEM 450 個字元 9 行、每 64 個字元換行的 Base64 398 個字元 7 行、單行無頭尾 392 個字元 1 行。這段內容求出的 SHA-256 不涵蓋主體、有效期、簽發者和簽章,跟憑證指紋混用會一直對不上。
位數與序號兩處口徑
金鑰位數那列,RSA 走模數實際位元長度,2048 位和 1024 位樣本都對得上;橢圓曲線是估算,位串長度減一再乘八取整,於是 P-521 那張顯示成「528 位」,真實位元長度是 521 位,名稱仍按 132 位元組查表給出 P-521 (secp521r1)。序號那列的顯示寬度等於 INTEGER 內容位元組數的兩倍,最長那條 42 個字元(內容 21 位元組),前導 0 會保留(00BFFF 是三個位元組)。
能核對到什麼,核對不到什麼
金鑰庫那四類後綴 .p12 / .pfx / .jks / .keystore 是命中後綴就拒,跟內容無關——1159 位元組的合法 DER 改名成 .p12 一樣被擋回來。只有 PRIVATE KEY 或 PUBLIC KEY 的 PEM 會給明確說法,不硬算指紋;憑證和私鑰寫在同一個檔案裡(3331 位元組那份)只出 1 張,私鑰區塊被安靜地忽略掉。辨識只看內容不看後綴,同一份 PEM 改叫 cert.txt 也照樣解析出 1 張。壞輸入也給尺寸資訊,DER 截掉一半做成 579 位元組,報的是「這張憑證宣告有 1159 位元組,但檔案只有 579 位元組」。
但它不驗簽章:那張只改了 1 個位元組的憑證照樣解析,指紋照算,17 行欄位全部可讀,一條警告都沒有。「兩條指紋一致」只等於「這兩份檔案是同一張憑證」,判斷不了鏈完整不完整,也回答不了這張憑證能不能用。
批次是只進不出
一次丟 3 個檔案,其中 1 個是 65 位元組純文字,結果區顯示 2 張,錯誤列只貼第 1 個失敗原因;再丟 1 個檔案,同一次工作階段裡累計到 3 張而不是替換前面的,想從頭開始只能按清空全部。輸出端只有指紋三行和公開金鑰各一個複製按鈕,一次只顯示選中的那一張,沒有並排比對也沒有匯出入口。
圖 2:摘要只吃綠色的 1159 位元組,三層容器不影響指紋。
Q:一條 64 個字元、一條 95 個字元,怎麼判斷是不是同一張憑證?
95 個字元那條是冒號分組,等於 64 個十六進位字元加 31 個冒號,刪掉冒號就還原成同一長度,逐位一樣就是同一張憑證、同一種摘要。
Q:對方貼來的字串末尾多了一個冒號,要緊嗎?
冒號分組寫法串尾不帶冒號,多出來那個不是工具產生的,多半是複製時手動補的;比對前刪掉,或兩邊都切成無冒號寫法重新複製一次。
Q:三條指紋都對上了,能不能說這條鏈路是安全的?
不能。指紋一致只證明兩份檔案是同一張憑證且用了同一種摘要;被改過 1 個位元組的憑證,解析、三條指紋和 17 行欄位照常給出,沒有任何警告,它不做簽章驗證。
Q:同一張憑證,PEM 和 DER 交出來的指紋會不一樣嗎?
不會。1159 位元組的 DER 和 1627 位元組的 PEM 給出逐字元相同的三條指紋,加 BOM、換 CRLF、把 Base64 擠成一行也都相同,摘要物件始終是剝開外衣後那段 DER。
這場爭論最後是這麼收的:兩串都切成無冒號小寫,長度都是 64,逐字元一致,多出來的尾冒號是維運人員手動補的。樣本檔案我都丟進本地解析的 憑證指紋 頁跑過一輪,檔案不離開瀏覽器,四種寫法和 openssl 那幾條命令逐字元對得上;要先確認對方給的是不是憑證檔案本身,可以先用 資訊檔讀取 看一眼魔數與真實類型。