在上一篇《SOD 安全文件概論》中,我直接使用工具 openssl 解讀 SOD 的內容。但它只是按照各項資料的結構順序,用粗略的格式顯示資料內容。本文則是直接用 OpenSSL C 函數庫解讀 SOD 內容。
由於本文案例中的 SOD 採用 ASN.1 格式儲存,所以解讀 SOD 的工作實際上就是 ASN.1 文件的解讀工作,需要利用 OpenSSL C 函數庫中與 ASN.1 相關的函數。不幸的是,在已經很貧乏的 OpenSSL C 函數庫文件中, ASN.1 函數更是連份說明文件都沒有。如果不直接去讀 OpenSSL 的 C 源碼,可能根本寫不出 ASN.1 解讀程式。在此提供大家一個指引方向,想要進行這項挑戰的人,只需要去讀 OpenSSL C 源碼的 crypto/asn1/asn1_par.c 這份源碼文件。本文也沒有足夠的資訊仔細說明那些 C 函數的用法。
本文案例規劃的 SOD 是加上 X.509 金鑰蠟封的 ASN.1 文件,所以 SOD 的解讀工作分成兩部份,第一部份是檢查蠟封是否完好,第二部份才是解讀 ASN.1 文件內容。
解讀程式有些複雜,所以我保留了除錯用工具程式碼。定義於 sod-info.h 。
檢查文件蠟封
第一動要利用 PKCS7 函數載入 SOD 文件。PKCS7 有三個載入函數,根據你規劃的 SOD 文件儲存格式使用。分別是:
- 若儲存格式為 SMIME,則以
SMIME_read_PKCS7()
載入。
- 若儲存格式為 PEM,則以
PEM_read_bio_PKCS7()
載入。
- 若儲存格式為 DER,則以
d2i_PKCS7_bio()
載入。
本文案例規劃的 SOD 儲存格式為 SMIME ,所以會用 SMIME_read_PKCS7() 載入。
第二動則是檢查 X.509 的憑證資訊,這部份的程式碼在《讀取 X509 certificate 的資訊》中就已經說明。在此就直接引用。
第三動就是用 X.509 公鑰查驗 SOD 文件的完好性,調用 PKCS7_verify()
為之。
綜合以上三動,設計了 sod_verify()
,程式碼存為 sod-verify.c 。
解讀文件內容
調用 PKCS7_verify()
之後,如果蠟封完好,它就會一併傳回拆封後的 ASN.1 文件內容。
我們需要解讀這份 ASN.1 文件,得到其他文件的摘要資訊。
本文案例將 ASN.1 文件記載的資訊分成三節。第一節記載 SOD 版本號碼。如果你們的案子可能隨著版本更迭而變更 ASN.1 文件記載的結構,那麼你們就可利用版本號碼判斷後續解讀動作要採用哪一套流程。第二節記載摘要資訊所用的演算器。第三節則是一組記載檔案號碼與摘要內容的序列。
按照上述結構,我的解讀流程也設計成兩個函數。一、sod_dump()
讀出 SOD 版本號碼與摘要演算器。二、dump_digests()
印出檔案號碼與摘要內容。程式碼存為 sod-dump.c 。
ASN.1 文件是一種隨機記錄檔,其中儲存的每一筆記錄都屬於 ASN1_object 類。一律先用 ASN1_get_object()
取得該記錄的資料位址與標籤(tag)。再根據標籤判斷記錄型態,調用對應的轉換函數取得資料內容。
依本文案例的規劃,只用了四種標籤,即: SEQUENCE, OID, INTEGER, OCTETSTRING。
SEQUENCE 是一個包含其他項目的序列,它使 ASN.1 文件的內容形成巢狀結構。解讀 SEQUENCE 最簡單的方法就是用遞迴。不過本文選擇按照節區劃分。前兩節的 SEQUENCE 屬於 SOD 基本資訊,交由 get_sod_information()
解讀。第三節的 SEQUENCE 則是檔案號碼與摘要內容序列,交由 dump_digests()
解讀。
INTEGER 的項目則以 c2i_ASN1_INTEGER()
讀取轉換為 C 語言的整數項,以 M_ASN1_INTEGER_free()
釋放。
OID 則是儲存個體ID的項目,在本文中儲放的是演算器ID。應以 d2i_ASN1_OBJECT()
讀取後,再以 OBJ_obj2nid()
取得其 NID。
sod-info.c 是調用前面說明的解讀函數,查驗並解讀 SOD 的示範程式。它解讀的對象,是我在前一篇《SOD 安全文件概論》中,以 sod_generate.php 產生的 SOD 。
下列為執行結果。
$ gcc -lssl -o sod-info sod-info.c sod-verify.c sod-dump.c show-x509-info.c
error: 0, ok: 1
Issuer name: /CN=rocksaying/O=Rock's blog./C=TW/ST=Some-State
Subject name: /CN=rocksaying/O=Rock's blog./C=TW/ST=Some-State
Validity from: 111011075144Z
Validity till: 111110075144Z
PKCS7 SOD ok.
SOD Verification successful
SOD Version: 1
Algorithm NID: 672; SN: SHA256; LN: sha256.
DG: 1
Digest: 3315B46DC11FEBFF188C8A4BEC95C7CAB800E7F52848AAFEFDB6CB6550CD3EC5
DG: 2
Digest: BD231484C813F1C78F6497B7ACF3B9B28F534A5B7C61D4BBA3AFB580336ACF2E
DG: 13
Digest: 5D35444622F70AB896A01C8D2B4904BECFFD30BD81AE9C4AA45B489A3164F0EB
本文僅將演算器與各檔案的摘要內容傾印於畫面上,並未進行摘要查核動作。請參考《OpenSSL Library - EVP, Digest and Cipher》了解如何透過 NID 調用演算器,以查核晶片內其他文件的完整性。
本文是針對 OpenSSL 應用於文件保全工作的最後一篇文章。下列為已完成的其他四篇:
樂多舊網址: http://blog.roodo.com/rocksaying/archives/17760845.html