證書-雙證書請求檔案

羊37發表於2024-07-10

1.背景

關於數字證書、數字信封、OID等基本知識,此文不做贅述。

在傳統的數字信封體系中,我們的流程大概這樣的。

image-20240708163439802

這裡有個值得注意的點是:

節點1用於加密對稱金鑰的公鑰和節點3用於簽名的私鑰,它們是否可以是同一對。

基於這個思想,我們有了單證書體系和雙證書體系。

其原因之一就是,從功能角度隔離開我們的加密秘鑰對和簽名金鑰對。

根據“中國金融認證中心標準-SM2 雙證書申請及下載規範”,我們可以看到一個雙證書的基本流程。

  1. 產生簽名金鑰對和互動金鑰對。

  2. 生成 Base64 編碼的 SM2 雙證書請求。

  3. 向伺服器端提交 SM2 雙證書請求。

  4. 解析伺服器端返回的報文資料,並解密加密證書私鑰。

  5. 匯入簽名公鑰證書、加密公鑰證書、加密證書私鑰。

2.雙證書

以國密SM2為例

上面我們知道,所謂的雙證書,即。

  • 專門用於簽名驗籤
  • 專門用於加密解密

注意,在中國金融認證中心標準-SM2 雙證書申請及下載規範中,此處的加密秘鑰不是由我們的本地生成的,而是由CA生成。

整個邏輯大致互動邏輯如下:

  • 本地生成簽名公私鑰對
  • 本地生成臨時公私鑰對(注意,非加密秘鑰對,僅僅在生成請求證書階段使用)
  • 結合簽名公鑰、臨時公鑰,生成雙證書請求檔案。
  • CA簽發簽名證書
  • CA生成加密公私鑰對(並使用剛才我們的臨時公鑰加密加密秘鑰對中的私鑰)
  • 下載CA簽發的簽名證書、加密證書、加密私鑰
  • 使用臨時私鑰解密加密過的私鑰,得到最終的加密私鑰。

image-20240710004147113

3.雙證請求檔案

請求檔案、CSR、P10,不嚴格的場景下,你可以當做是同一個東西。

3.1 格式描述

3.1.1 整體格式

image-20240710010041063

SM2 雙證書請求的 ASN.1 資料格式。

CertificationRequest ::= SEQUENCE {
	certificationRequestInfo CertificationRequestInfo,
	signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
	signature BIT STRING
}
  • ccertificationRequestInfo: SM2 雙證書請求資訊。
  • signatureAlgorithm:簽名演算法 ID,文件中OID取值為:1.2.156.10197.1.501。
  • signature:使用簽名私鑰,對 certificationRequestInfo 節點的簽名結果。

這裡提到了oid,可以在這裡查詢。

國家OID註冊中心

GmSSL

然後,這裡的{{ SignatureAlgorithms }}是什麼意思呢?

  • AlgorithmIdentifier:這是一個ASN.1的標準型別,用於標識演算法。它通常包含兩個欄位:演算法OID(物件識別符號)和可選的引數。

  • {{ SignatureAlgorithms }}:表示AlgorithmIdentifier的值必須來自SignatureAlgorithms的集合。

嗯,就是下面這個。

image-20240710011413875

3.1.2 CertificationRequestInfo

image-20240710010353721

CertificationRequestInfo ::= SEQUENCE {
	version INTEGER,
	subject Name,
	subjectPKInfo SubjectPublicKeyInfo,
	attributes [0] Attributes
}
  • version:版本號,本文件中取值為 0x00。

  • subject:公鑰證書 DN。詳細介紹,請參考 PKCS#10。

  • subjectPKInfo:簽名公鑰資訊。

  • attributes:屬性資訊。

3.1.3 SubjectPublicKeyInfo

image-20240710011520142

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

AlgorithmIdentifer::= SEQUENCE {
	algorithm OBJECT IDENTIFIER,
	parameters ANY DEFINED BY algorithm OPTIONAL
}
  • algorithm:ECC 公鑰演算法 OID,在本文件中,取值為:1.2.840.10045.2.1。

  • parameters:SM2 公鑰演算法 OID,在本文件中,取值為:1.2.156.10197.1.301。

  • subjectPublicKey:SM2 公鑰資料,結構如下。

    0x04||簽名公鑰 X 分量||簽名公鑰 Y 分量。
    

3.1.4 attributes

Attributes ::= Context[0] {
	chanllegPassword ChanllegPassword,
	tempPublicKeyInfo TempPulicKeyInfo
}
ChanllegPassword ::= SEQUENCE {
	chanllegPasswordOID OBJECTIDENTIFIER,
	password PrintableString
}
TempPulicKeyInfo ::= SEQUENCE {
	tempPublicKeyOID OBJECTIDENTIFIER,
	tempPublicKey OCTECT STRING
}
  • password:預設取值:111111。
  • tempPublicKeyOID:互動公鑰標識 OID,本文件中取值為:1.2.840.113549.1.9.63。
  • tempPublicKey:互動公鑰 TempPulicKey 的 OCTECT STRING 編碼。

image-20240710011645538

3.1.5 互動公鑰

image-20240710011658192

TempPulicKey ::= SEQUENCE {
	version INTEGER,
	tempPublicKeyData OCTET STRING
}
  • version:版本號,本文件中取值為:0x01。

  • tempPublicKeyData:互動公鑰資料,結構如下。

    0x00 0xB4 0x00 0x00||0x00 0x01 0x00 0x00 ||互動公鑰 X 分量||32 位元組 0x00 擴充套件空間||互動公鑰 Y 分 量||32 位元組 0x00 擴充套件空間
    

3.2 示例檔案

首先,給出文件中的demo雙證請求檔案。

MIIB0TCCAXUCAQAwWzENMAsGA1UEBh4EAEMATjEhMB8GA1UECh4YAEMARgBDAEEAIABUAEUAUwBU
ACAAQwBBMScwJQYDVQQDHh4AYwBlAHIAdABSAGUAcQB1AGkAcwBpAHQAaQBvAG4wWTATBgcqhkjO
PQIBBggqgRzPVQGCLQNCAAQv93JF1oROzBImU6Plgleu+HI659cECfKn+gajy7JWGAEoSyw+9rsB
WoRA+kqA7FmgO8NcNcm3fRBWS+yLBMLUoIG3MBMGCSqGSIb3DQEJBxMGMTExMTExMIGfBgkqhkiG
9w0BCT8EgZEwgY4CAQEEgYgAtAAAAAEAAGmQSyS20/zQ4tHJQKA5EYPgdLuPE568SYcKlqmwWGjW
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACokwM02BfEmqVM+qPPlx2I4v38pc1N4WgC
xVb2QmgSygAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAwGCCqBHM9VAYN1BQADSAAw
RQIgfm4txwd5pHMPPtsHEfN+4Y8iMKmKCxy1T3eIMwkYS0kCIQCu6nbbBxVF99qaX1h1/qksk9u9
fs6qkzlkrFbkPkvMjw==

我們使用ASN.1線上解析工具,可以看到大體結構,上文中對細節處已經做了框選,此處不贅述。

image-20240710005900697

看起來複雜,實際也很複雜,哈哈。

但是別慌,跟咱們前面的格式描述那裡對應上就好了。

就像咱們Java的實體類一樣,沒啥特別的,只不過走了ASN1編碼而已。

3.3 程式碼

本文基於Java構建

4.結果檔案解析

4.1 分析

根據規範,將會收到3個結果檔案。

image-20240710012307258

  • SignCert.cer:簽名對應的公鑰證書
  • EncCert.cer:加密對應的公鑰證書
  • PrivateKey.key:加密過的公私鑰檔案(使用我們的臨時公鑰加密)

由規範指引,我們可以得到解密的具體邏輯。

image-20240710012558519

image-20240710012539475

image-20240710012656444

  • 根據,分隔,提取密文資料。
  • 解析密文資料,得到實際密文。
  • 使用臨時公鑰解密密文,得到秘鑰值。

注意,直接移除,後得到的資料並不是直接的SM2解密源文,它是具有如下結構的(回顧3.1.5節)。

TempPulicKey ::= SEQUENCE {
	version INTEGER,
	tempPublicKeyData OCTET STRING
}

4.2 程式碼

注意點如下:

  • 返回的資料裡面會解析出version和encryptedKeyData兩個部分的資料,encryptedKeyData才是我們實際解密的源資料。
  • 使用BC庫解密的時候,私鑰前加00/密文前加04/公鑰前加04。
  • 經過驗證,模式使用C1C3C2

關於為啥咱們BC庫裡密文前要加04,你可以參考這個issue:hutool-SM2私鑰解密檔案報錯Invalid point encoding 0x30

當然,咱們此處沒有用hutool,不過原因你可以研究下。

具體程式碼參考:easy-cryptography

image-20240710022210297

相關文章