Certificate 格式與雜記

在稍微了解 RSA 演算法原理以及 ASN.1 DER 編碼方法
對 certificate 這個東西又多了解了一些,這邊記錄一下目前的理解以及一些連結,方便查詢






ASN.1 定義

Certificate 用 ASN.1 表示,編碼成DER格式,或是再由DER格式轉成PEM格式,PEM格式可以用printable string來表示binary file。
這裡列出 Certificate 會用到的 ASN.1 定義

Certificate  ::=  SEQUENCE  {
 tbsCertificate       TBSCertificate,
 signatureAlgorithm   AlgorithmIdentifier,
 signatureValue       BIT STRING  }

AlgorithmIdentifier  ::=  SEQUENCE  {
   algorithm               OBJECT IDENTIFIER,
   parameters              ANY DEFINED BY algorithm OPTIONAL  }

TBSCertificate  ::=  SEQUENCE  {
 version         [0]  EXPLICIT Version DEFAULT v1,
 serialNumber         CertificateSerialNumber,
 signature            AlgorithmIdentifier,
 issuer               Name,
 validity             Validity,
 subject              Name,
 subjectPublicKeyInfo SubjectPublicKeyInfo,
 issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
       -- If present, version MUST be v2 or v3
 subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
       -- If present, version MUST be v2 or v3
 extensions      [3]  EXPLICIT Extensions OPTIONAL
       -- If present, version MUST be v3
 }

Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }

CertificateSerialNumber  ::=  INTEGER

Validity ::= SEQUENCE {
 notBefore      Time,
 notAfter       Time }

Time ::= CHOICE {
 utcTime        UTCTime,
 generalTime    GeneralizedTime }

UniqueIdentifier  ::=  BIT STRING

SubjectPublicKeyInfo  ::=  SEQUENCE  {
 algorithm            AlgorithmIdentifier,
 subjectPublicKey     BIT STRING  }

Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension

Extension  ::=  SEQUENCE  {
 extnID      OBJECT IDENTIFIER,
 critical    BOOLEAN DEFAULT FALSE,
 extnValue   OCTET STRING
    -- contains the DER encoding of an ASN.1 value
    -- corresponding to the extension type identified
    -- by extnID
 }
 

Name ::= CHOICE { -- only one possibility for now --
 rdnSequence  RDNSequence }

RDNSequence ::= SEQUENCE OF RelativeDistinguishedName

RelativeDistinguishedName ::=
 SET SIZE (1..MAX) OF AttributeTypeAndValue

AttributeTypeAndValue ::= SEQUENCE {
 type     AttributeType,
 value    AttributeValue }

AttributeType ::= OBJECT IDENTIFIER

AttributeValue ::= ANY -- DEFINED BY AttributeType


 
DigestInfo ::= SEQUENCE {
  digestAlgorithm DigestAlgorithmIdentifier,
  digest Digest }

DigestAlgorithmIdentifier ::= AlgorithmIdentifier

Digest ::= OCTET STRING



Example file

使用 DOCSIS 的 Test certificate 來當範例
Test DOCSIS ROOT Cert
Test DOCSIS ROOT Private Key
Test DOCSIS ROOT Public Key
Test CVC



Certificate format


直接拿範例(Test_CVC.der)來了解certificate
一張 certificate 從最外層分可以切成 3 塊
tbsCertificate: tbs (to be sign 縮寫 ?), 這部分是 certificate 的主體,包含最重要的 public key, 以及這隻key的各種屬性,例如:版本,序號,有效日期,...等
signatureAlgorithm : 簽發者(issuer) 用的演算法
signatureValue : 用簽發者的 private key 搭配 signatureAlgorithm 計算 tbsCertificate 的結果, 收到 certificate 的人則是利用簽發者的 public key 去驗證簽名是否正確

signature

先看 sign certificate這件事做了什麼

tbsCertificate 就是要被拿來計算的資料,要如何計算則是記在 signatureAlgorithm 裡

先把 Test_CVC.der 拆開,
package require asn
set fd [open mfgcvc.der r]
fconfigure $fd -translation binary
set cvc [read $fd]
close $fd

::asn::asnGetSequence cvc cert

#取出 tbsCertificate,tbsCertificate的 tag 是 Sequence
::asn::asnGetSequence  cert tbs

#匯出時要把 tag,length補回去
set fd [open tbsCertificate w]
fconfigure $fd -translation binary
puts -nonewline $fd [::asn::asnSequence $tbs]
close $fd

#取出 signatureAlgorithm , 1.2.840.113549.1.1.5 - SHA-1 with RSA Encryption
::asn::asnGetSequence cert alg
::asn::asnGetObjectIdentifier alg oid
binary scan $alg H* parameters
puts oid=[join $oid .]
puts parameters=$parameters

# 取出 signature,只匯出 content
::asn::asnGetBitString cert sign
set fd [open signatureValue w]
fconfigure $fd -translation binary
puts -nonewline $fd [binary format B* $sign]
close $fd

解出 tbsCertificate 和 signatureValue 兩個檔案,並看一下 signatureAlgorithm
signatureAlgorithm 解出來的結果是
oid=1.2.840.113549.1.1.5 (SHA-1 with RSA Encryption)
parameters=0500 (這是Null,目前看過的這個參數都是Null)

簽發及驗證

分別看簽發者與接收者的動作

簽發者:
1.先算出sha1 hash
openssl sha1 tbsCertificate
SHA1(tbscert)= 1a8e55e7778defea444f7c88ca685b4ce6593cca

2.把 hash 編碼成 DigestInfo
package require asn
package require asn
# http://www.alvestrand.no/objectid/1.3.14.3.2.26.html
# 1.3.14.3.2.26 - SHA-1 hash algorithm

# DigestInfo ::= SEQUENCE {
  # digestAlgorithm DigestAlgorithmIdentifier,
  # digest Digest }

# DigestAlgorithmIdentifier ::= AlgorithmIdentifier

# Digest ::= OCTET STRING

# AlgorithmIdentifier  ::=  SEQUENCE  {
   # algorithm               OBJECT IDENTIFIER,
   # parameters              ANY DEFINED BY algorithm OPTIONAL  }
   

set digestAlgorithm ""
append digestAlgorithm [asn::asnObjectIdentifier [split 1.3.14.3.2.26 .]]
append digestAlgorithm [asn::asnNull]
set digestAlgorithm [asn::asnSequence $digestAlgorithm]

set digest [asn::asnOctetString [binary format H* 1a8e55e7778defea444f7c88ca685b4ce6593cca]]

set DigestInfo [asn::asnSequence $digestAlgorithm$digest]
# 輸出 DigestInfo 再用 openssl 加密
set fd [open DigestInfo w]
fconfigure $fd -translation binary
puts -nonewline $fd $DigestInfo
close $fd

3.再把結果 padding 後用 private key 加密就能算出 signatureValue
openssl rsautl -inkey TEST_DOCSIS_CABLE_MODEM_ROOT_CA_PRIVATEKEY.PEM -sign -in DigestInfo -out DigestInfo.der
算出來的DigestInfo.der 就是 signatureValue,可以拿算出來的 DigestInfo.der 和從 certificate 解出來的 signatureValue 來驗證有沒有算對

openssl 有指令可以一次完成 hash,padding,encrypt
openssl sha1 -sign TEST_DOCSIS_CABLE_MODEM_ROOT_CA_PRIVATEKEY.PEM tbscert > sign

實際用 openssl 在 sign certificate 時不需要這麼麻煩,有更方便的指令把這些動作一次做完,這個例子是用來了解 sign certificate 做了什麼事
知道怎麼 sign 之後就可以修改 tbsCertificate 的某些欄位,再手動更新 signatureValue 成正確的值
例如: 修改 certificate 的有效時間,openssl X509 指令不能設定精確的時間值,可以先用 x509 sign 出一張 certificate 後再手動修改 (當初就是很龜毛的想弄出0:0:0 ~ 23:59:59 才開始研究怎麼算出signatureValue,
後來是直接修改 openssl source code 把時間參數加上去)

接收端:
收到 certificate 後就要利用簽發者的 public key 驗證 certificate 的來源是否可靠
方法與 sign certificate 類似
1.同樣先算出sha1 hash
openssl sha1 tbsCertificate
SHA1(tbscert)= 1a8e55e7778defea444f7c88ca685b4ce6593cca

2.將 signatureValue 解密
這指令解密完順便解開 asn1 編碼
openssl rsautl -verify -inkey TEST_DOCSIS_CABLE_MODEM_ROOT_CA_PUBLICKEY.PEM -pubin -in signature -asn1parse
Loading 'screen' into random state - done
    0:d=0  hl=2 l=  33 cons: SEQUENCE
    2:d=1  hl=2 l=   9 cons:  SEQUENCE
    4:d=2  hl=2 l=   5 prim:   OBJECT            :sha1
   11:d=2  hl=2 l=   0 prim:   NULL
   13:d=1  hl=2 l=  20 prim:  OCTET STRING
      0000 - 1a 8e 55 e7 77 8d ef ea-44 4f 7c 88 ca 68 5b 4c   ..U.w...DO|..h[L
      0010 - e6 59 3c ca                                       .Y<.

比較後知道 hash 值是一樣的,可以知道這張certificate 確實是由 TEST_DOCSIS_CABLE_MODEM_ROOT_CA 所簽發的,剩下的就是查看 tbsCertificate 的各項屬性來決定這張certificate 是否合用


tbsCertificate

tbsCertificate 用 sequence 把以下內容包起來

version

是 [APPLICATION 0] 包一個 INTEGER,所以 TAG 是 A0, integer 有3種可能 v1(0), v2(1), v3(2),CVC 用的是 v3 所以是 a0 03 02 01 02

serialNumber

很單純的以 integer 表示

signature

簽發者使用的演算法,這個值和 signatureAlgorithm 必須是一樣的,CVC 用的是SHA-1 with RSA, null parameters 所以會編成 30 0d 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 oid=1.2.840.113549.1.1.5 value=Null

issuer,subject

簽發者,主體,這兩個格式相同,用 oid 和 value 表示,再一層一層包起來,直接看CVC這個範例 美規 CVC issuer 有這幾個值是固定的 countryName(2.5.4.6): US organizationName(2.5.4.10): Data Over Cable Service Interface Specifications organizationalUnitName(2.5.4.11): Cable Modems commonName(2.5.4.3): DOCSIS Cable Modem Root Certificate Authority 編成 DER format 如下,其中 AttributeValue 都用 printable string 表示 printable string 的tag為 0x13 30 81 97 31 0b 30 09 06 03 55 04 06 (2.5.4.6) 13 02 55 53 (US) 31 39 30 37 06 03 55 04 0a (2.5.4.10) 13 30 44 61 74 61 20 4f 76 65 72 20 43 61 62 6c 65 20 53 65 72 76 69 63 65 20 49 6e 74 65 72 66 61 63 65 20 53 70 65 63 69 66 69 63 61 74 69 6f 6e 73 (Data Over Cable Service Interface Specifications) 31 15 30 13 06 03 55 04 0b (2.5.4.11) 13 0c 43 61 62 6c 65 20 4d 6f 64 65 6d 73 (Cable Modems) 31 36 30 34 06 03 55 04 03 (2.5.4.3) 13 2d 44 4f 43 53 49 53 20 43 61 62 6c 65 20 4d 6f 64 65 6d 20 52 6f 6f 74 20 43 65 72 74 69 66 69 63 61 74 65 20 41 75 74 68 6f 72 69 74 79 (DOCSIS Cable Modem Root Certificate Authority) subject 內容為 countryName organizationName organizationalUnitName DOCSIS commonName Code Verification Certificate organizationalUnitName 與 commonName 的值是固定的,在此範例裡 countryName = US, organizationName=VendorA organizationName 的值對 CVC 非常重要,CM 做 secure upgrade 時會比對這個值與 CM 裡的設定是否相同 因為 type 和issuer 相同 DER 就不列出來了

validity

記錄 certificate 生效以及到期的時間 30 1e (sequence ) 17 0d 30 31 30 31 30 31 30 30 30 30 30 30 5a (010101000000Z) 17 0d 31 31 30 31 30 31 30 30 30 30 30 30 5a (110101000000Z)

SubjectPublicKeyInfo

certificate 最重要的內容: public key,certificate 就是用來發不公鑰的,這個欄位記錄公鑰的種類與值 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 (1.2.840.113549.1.1.1 - RSA encryption) 05 00 (Null) 03 82 01 0f (public key,以 bitstring 表示) 00 30 82 01 0a 02 82 01 01 00 a2 05 d2 10 02 f3 47 b4 dd 2e 2a 9b 05 b3 86 38 a4 91 6d ad 39 5a da 0b 48 55 9b 94 dd 4e 9d 8b 98 c6 18 6d e8 de 1e 81 db ce 8f 3c 6d 02 81 fa 1e 46 f1 93 30 c2 79 bb ba f6 50 b2 db 10 b2 13 c0 bd a5 4d 33 5f 43 0d 9f a0 de 9b 8b 71 b5 ff 1f 48 e1 06 38 71 b8 df 3c 93 c6 f8 eb 90 a6 d2 a4 aa 7b 4e f1 2e 5c 11 07 88 1d 13 f8 60 d8 e2 3b e5 c7 7b 30 39 74 75 94 e3 73 19 92 b6 81 2f b7 db 85 be 6a 8e 54 e9 dd 67 8f a7 a3 4c d6 22 50 a8 0d 69 41 98 d5 a3 af 51 8d 48 44 f4 35 9d 5d 7d a3 d1 62 e4 01 3f 62 05 e1 89 57 5e 5b 90 09 ff 83 7b b6 f2 0d 32 72 47 9e e2 d6 1a 15 c0 97 53 9a a8 9f 24 5c 88 cf bb 98 b4 da 01 73 33 31 ea aa 8d e2 01 9f 20 3e e1 67 dd 36 2e 3c 83 28 5d 28 bb 6a d9 30 94 37 e6 d8 86 42 32 c7 9b 36 68 65 3b 3f 40 f3 87 1a 31 92 90 93 a3 21 b1 02 03 01 00 01 而 RSA 的 public key 為以下格式 RSAPublicKey ::= SEQUENCE { modulus INTEGER, -- n publicExponent INTEGER, -- e – } CVC public key 有以下規定 The CM MUST be able to verify DOCSIS code file signatures that are signed using key modulus lengths of 1024, 1536 and 2048 bits. The public exponent is F4 (65537 decimal) 繼續把這個 bitstring 拆開 30 82 01 0a 02 82 01 01 00 a2 05 d2 10 02 f3 47 b4 dd 2e 2a 9b 05 b3 86 (modulus n,這個犯利用的 key 長度是 1024 bits) 38 a4 91 6d ad 39 5a da 0b 48 55 9b 94 dd 4e 9d 8b 98 c6 18 6d e8 de 1e 81 db ce 8f 3c 6d 02 81 fa 1e 46 f1 93 30 c2 79 bb ba f6 50 b2 db 10 b2 13 c0 bd a5 4d 33 5f 43 0d 9f a0 de 9b 8b 71 b5 ff 1f 48 e1 06 38 71 b8 df 3c 93 c6 f8 eb 90 a6 d2 a4 aa 7b 4e f1 2e 5c 11 07 88 1d 13 f8 60 d8 e2 3b e5 c7 7b 30 39 74 75 94 e3 73 19 92 b6 81 2f b7 db 85 be 6a 8e 54 e9 dd 67 8f a7 a3 4c d6 22 50 a8 0d 69 41 98 d5 a3 af 51 8d 48 44 f4 35 9d 5d 7d a3 d1 62 e4 01 3f 62 05 e1 89 57 5e 5b 90 09 ff 83 7b b6 f2 0d 32 72 47 9e e2 d6 1a 15 c0 97 53 9a a8 9f 24 5c 88 cf bb 98 b4 da 01 73 33 31 ea aa 8d e2 01 9f 20 3e e1 67 dd 36 2e 3c 83 28 5d 28 bb 6a d9 30 94 37 e6 d8 86 42 32 c7 9b 36 68 65 3b 3f 40 f3 87 1a 31 92 90 93 a3 21 b1 02 03 01 00 01 (publicExponent e, 0x010001 = 655337)

issuerUniqueID subjectUniqueID

所有 DOCSIS 的 certificate 都沒用到這兩個欄位,目前實際在用的 certificate 中也沒看過有這兩個欄位的 用 openssl x509 與windows7 也沒解出這兩個值 RFC - support for subjectUniqueID and issuerUniqueID How put issuerUniqueID into certificate?

extensions

這是v3才有的欄位,每個 extension 有三個值 extnID: 以 oid 表示 critical: BOOLEAN DEFAULT FALSE,可省略 當使用 certificate 的系統發現其中的 extension 是標示為 critical, 但系統無法辨識,處理這個 extension,系統必須拒絕使用這張 certificate 若 extension 是標示為 non-critical,系統就可以忽略這個 extension,但若系統可以辨識這個 extension,就必須處理這個 extension extnValue: OCTET STRING,根據各個 extnID 有不同的格式 以 CVC 為例,有一個 critical extension, 用來說明這隻金鑰的用途是codeSigning extnID=2.5.29.37 - Extended key usage critical= True extnValue 就要根據 Extended key usage 的格式去編碼 id-ce-extKeyUsage OBJECT IDENTIFIER ::= {id-ce 37} ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId KeyPurposeId ::= OBJECT IDENTIFIER CVC 的 KeyPurposeId 是 1.3.6.1.5.5.7.3.3 - id_kp_codeSigning 所以這一段的 DER 是 a3 1a ( extensions [3]) 30 18 30 16 ( extension ) 06 03 55 1d 25 (extnID 2.5.29.37 Extended key usage) 01 01 ff (critical true) 04 0c (extnValue) 30 0a 06 08 2b 06 01 05 05 07 03 03 (oid = 1.3.6.1.5.5.7.3.3 id_kp_codeSigning) 以下列幾個 DOCSIS certificate 有用到的 extension (有玩到其他 extension 再繼續補) Basic Constraints (基本限制) 用來標示這張 certificate 是否為 CA,以及深度(在這張 certificate 以下最多允許幾層 non-selg-sign CA) id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } BasicConstraints ::= SEQUENCE { cA BOOLEAN DEFAULT FALSE, pathLenConstraint INTEGER (0..MAX) OPTIONAL } DOCSIS Root CA Certificate 的 cA = True pathLenConstraint = 1 DER 為 30 12 06 03 55 1d 13 (2.5.29.19 - Basic Constraints) 01 01 ff (critical = True) 04 08 30 06 01 01 ff (cA = True) 02 01 01 (pathLenConstraint = 1 ) keyUsage (金鑰使用方法) 標示金鑰用途 id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } KeyUsage ::= BIT STRING { digitalSignature (0), nonRepudiation (1), -- recent editions of X.509 have -- renamed this bit to contentCommitment keyEncipherment (2), dataEncipherment (3), keyAgreement (4), keyCertSign (5), cRLSign (6), encipherOnly (7), decipherOnly (8) } DOCSIS Root CA Certificate 有用到這個 extension For the keyUsage extension, the keyCertSign bit is set, the cRLSign bit may be set, and all other bits should not be set. (CM-SP-SECv3.0-I15-130808 Appendix III.1.6.4 DOCSIS Root CA Certificate) 30 0e 06 03 55 1d 0f (2.5.29.15 - Key Usage) 01 01 ff (critical = True) 04 04 03 02 01 06 (bitstring 0000011, keyCertSign,cRLSign = 1) ^bit 0

其他欄位

用 windows 檢視 certificate 時會出現一些不存在檔案本身的資訊 Thumbprint algorithm : hash 演算法 (目前只看過 sha1) Thumbprint : 利用 Thumbprint algorithm 計算 certificate 的結果,certificate 必須使用 DER 格式,如果是 PEM 要先轉成 DER 再計算

中英文對照表

有些中文翻譯看起來怪怪的,整理以下對照表,想到就更新一下
Windows 英文版 WinXP 中文版 Win7 中文版 註解
tbsCertificate Version 1 Fields Only 只有版本1的欄位 版本1的欄位指的就是tbsCertificate裡的內容
version Version 版本 版本
serialNumber Serial number 序號 序號
signature Signature algorithm 簽章演算法 簽章演算法
Signature hash algorithm - 簽章雜湊演算法 win7 新增的欄位(可參考
Difference between “Signature Algorithm” and “Signature Hash Algorithm” in X.509)
issuer Issuer 發行者 簽發者
notBefore Valid from 有效期自 有效期自
notAfter Valid to 有效到 有效期到
subject Subject 主體 主體
subjectPublicKeyInfo Public Key 公開金鑰 公開金鑰 subjectPublicKeyInfo 裡包含公鑰類型與內容,公開金鑰的值只有 subjectPublicKeyInfo 的 subjectPublicKey
extensions Extension Only
Critical Extensions Only
副檔名
關鍵副檔名
延伸
關鍵延伸
windows 顯示 certificate 的 extension 欄位時,"!" 表示critical ; "↓" 表示non-critical
Key Usage 金鑰使用方式 金鑰使用方式
Basic Constraints 基本限制 基本限制
Subject Key Identifier 主體金鑰識別元 主體金鑰識別元
Version 1 Fields Only 只有版本1的欄位 版本1的欄位指的就是tbsCertificate裡的內容














沒有留言:

張貼留言