雖然自訂網路協定常有重造輪子的習慣,但在描述新協定時,沿用既有設計有時更合理。二進位協定中一個常見的既有格式就是抽象語法記法一(Abstract Syntax Notation 1, ASN.1)

ASN.1 是簡單網路管理協定(Simple Network Management Protocol, SNMP)等協定的基礎,也是各種密碼學值(例如 X.509 憑證)的編碼機制。

ASN.1 與 DER#

ASN.1 由 ISO、IEC 與 ITU 在 X.680 系列中標準化。它定義了一套抽象語法來表示結構化資料;資料在協定中實際如何呈現,則取決於所採用的編碼規則(encoding rules),而編碼規則有很多種。

你最可能遇到的是可辨別編碼規則(Distinguished Encoding Rules, DER),它的設計目標是讓 ASN.1 結構的表示方式無法被誤讀——這對密碼學協定是很有用的性質。

DER 的表示法正是 TLV 協定的好例子。認得 TLV 模式,你就已經掌握了讀懂 DER 傾印的一半基礎。

範例:X.509 憑證#

以下是 X.509 憑證的 ASN.1 定義:

Certificate ::= SEQUENCE {
     version         [0] EXPLICIT Version DEFAULT v1,
     serialNumber         CertificateSerialNumber,
     signature            AlgorithmIdentifier,
     issuer               Name,
     validity             Validity,
     subject              Name,
     subjectPublicKeyInfo SubjectPublicKeyInfo,
     issuerUniqueID  [1] IMPLICIT UniqueIdentifier OPTIONAL,
     subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
     extensions      [3] EXPLICIT Extensions OPTIONAL
}

這份 X.509 憑證的抽象定義可以用 ASN.1 的任何一種編碼格式來表示。

實例:用 OpenSSL 傾印 DER 編碼形式

用 OpenSSL 工具把 DER 編碼形式以文字傾印出來:

$ openssl asn1parse -in example.cer
    0:d=0 hl=4 l= 539 cons: SEQUENCE
    4:d=1 hl=4 l= 388 cons: SEQUENCE
    8:d=2 hl=2 l=   3 cons: cont [ 0 ]
   10:d=3 hl=2 l=   1 prim: INTEGER         :02
   13:d=2 hl=2 l=  16 prim: INTEGER         :19BB8E9E2F7D60BE48BFE6840B50F7C3
   31:d=2 hl=2 l=  13 cons: SEQUENCE
   33:d=3 hl=2 l=   9 prim: OBJECT          :sha1WithRSAEncryption
   44:d=3 hl=2 l=   0 prim: NULL
   46:d=2 hl=2 l=  17 cons: SEQUENCE
   48:d=3 hl=2 l=  15 cons: SET
   50:d=4 hl=2 l=  13 cons: SEQUENCE
   52:d=5 hl=2 l=   3 prim: OBJECT          :commonName
   57:d=5 hl=2 l=   6 prim: PRINTABLESTRING :democa

ASN.1 的完整內容足以寫成一本書。實務上你不需要背下規格,只要能認出「這是 ASN.1/DER」,就可以直接把 openssl asn1parse 這類現成工具接上去解析。