如何在 PDF 中对证书撤销列表 (CRL) 流字节进行编码?
How do you encode the Certificate Revocation List (CRL) stream bytes in PDF?
我签署了一个 PDF 并添加了更新版本,我在其中编写了 DSS 及其 CRL、证书、VRI。
19 0 obj
[15 0 R 16 0 R]
endobj
20 0 obj
[13 0 R 14 0 R]
endobj
11 0 obj
[15 0 R 16 0 R]
endobj
12 0 obj
[13 0 R 14 0 R]
endobj
17 0 obj
<<
/CRL 11 0 R
/Cert 12 0 R
>>
endobj
18 0 obj
<<
/5F44CF6F351DFD45FB62F3D0ED046408BC892797 17 0 R
>>
endobj
21 0 obj
<<
/VRI 18 0 R
/CRLs 19 0 R
/Certs 20 0 R
>>
我对如何编写证书和 CRL 流感到困惑。
15 0 obj
<<
/Length 1454
/Filter /FlateDecode
>>
stream
xÚ3hb0hb{ÅÄÈhÀÉƪÍÇÌ$ÅÊ`àcÈä2‡²° 3…Šˆ€8\¼®y%E¥Å%:žyÉz†ªÊ
ZbXd{0%KW÷ýY¯’ó‚-ØÂÛ„OÏó½z•î ‰`®•® K-›2}tÖ§^_8;xÉì¥Ó®~›.g9A'Õüê½—
ZbXd{0%KW÷ýY¯’ó‚-ØÂÛ„OÏó½z•î ‰`®•® K-›2}tÖ§^_8;xÉì¥Ó®~›.g9A'Õüê½—
endstream
endobj
16 0 obj
<<
/Length 1477
/Filter /FlateDecode
>>
stream
„kâR7Å41*!‡#8Íñ3 Ź˜@‰o=«‡çƒ#yë:X]r\~}¼)/Ñmç×£¦³äsËê]ÓÕ_+µ¥$Ô¿}¾ÜÏiÁÝT!¹ôi–Í9üÀ}Š¸|
ìŒH¿GÓø^ú¿ÔVÜK–qõ†µ®“¸»Ý*Žh¾JzåU7c~÷•ÔêýK*îú®¹¸DcÁ³·NtV~Vóåíé5\‚&½|¶NäïŽ[K
î›NRZbXd{0%KW÷ýY¯’ó‚-ØÂÛ„OÏó½z•î ‰`®•® K-›2}tÖ§^_8;xÉì¥Ó®~›.g9A'Õüê½—›oÇ:ç-¶?
endstream
endobj
13 0 obj
<<
/Length 1240
/Filter /FlateDecode
>>
stream
%ŸwC[í2×¾Iej©úkŽ-:ݳÔ<¼a£ƒô/5›‡~zÒ•7ü9uãcfk?ËÅ`ßÃ:Èb—’‚Ÿõ{ÏÅ—¢{]HçQ”9w(ÂB#í×g¥ìþè
^–F«š/r§š¿ì=#,^pëO€{äú=}RÎêð¦ÉŠ7or¼±Ëtë–x·˜§LÌŒŒ‹› Cd0€eùÿ³°03±>0P ñUY$
endstream
endobj
14 0 obj
<<
/Length 1159
/Filter /FlateDecode
>>
stream
4!>T‚êPpÎI,.V0Ò™@ûœºƒ=LÍš•ãˆ‘•¹‰‘Ÿ(ÎÅÔÄÈÈplŽ÷A¯¹7k/[‡O\}
öe™¨îö£œ¶ä'¶ÌpžªweÞª[¡$¼ØÍþþtó[½xÉO4ÞZ¥ØŸ^g ø,mu„_Rz™_PÏê.||º¶*þîÝxv½"»êôó»ø%Ü%ý
endstream
endobj
请忽略以上流的长度和内容。我截断了它们,所以长度不再对应。溪流比那个大。
问题是我的 PDF 没有启用 LTV 我测试了一些场景,从中我得出结论
我的流没有以正确的方式写入。
我使用 WinCrypt.h 中的以下结构:
typedef struct _CERT_CONTEXT {
DWORD dwCertEncodingType;
BYTE *pbCertEncoded;
DWORD cbCertEncoded;
PCERT_INFO pCertInfo;
HCERTSTORE hCertStore;
} CERT_CONTEXT, *PCERT_CONTEXT;
typedef const CERT_CONTEXT *PCCERT_CONTEXT;
我通过它们并以这种方式获取字节:
PCCERT_CONTEXT cngContext = (PCCERT_CONTEXT)(*itChain);
ByteArray certBytes(cngContext->pbCertEncoded, (size_t)cngContext->cbCertEncoded);
然后我只对获得的字节应用 FlateDecode,并将它们像流一样写入 PDF,如您在第二个代码块中所见。
我漏掉了什么步骤吗?比如转换之类的?我看到流应该是 BER 编码的。那么我应该将字节转换为 BER 编码然后应用 FlateDecode 吗?
编辑:
您可以在此处找到 My File
解决方案
问题出在我在 PDF 文件中编写的 流 CRL。
从每个证书中获得 CRL_CONTEXT 结构,我只是将 pbCrlEncoded 变量直接写入 CRL 的流中。
这似乎是正确的,但我注意到我在这个结构的 CRL_INFO 中没有任何 CRL_ENTRY,因此编码的 BYTE 不包含任何已撤销证书的列表。
因此,发现证书有一个 URL,您可以从那里下载更新的 CRL。您可以通过在 Windows 中打开 管理计算机证书 -> 找到您的证书并 打开证书 -> 详细信息 -> CRL 分发点 -> URL = ".."。通过访问此 url,浏览器会自动下载 CRL 信息。您可以访问它并查看一些信息,例如 Next Update 这是该列表有效的最后一天。在那之后,我假设您需要再次下载它以获得更新版本。您还可以看到已撤销证书的列表本身。
这是我需要以 PDF 格式放入 CRL 流中的列表。
所以我找到了一种通过代码完成下载过程的方法。这是使用的代码片段:
PCERT_CHAIN_ELEMENT chainElement; // this is the certification in the chain
pExtension = CertFindExtension(szOID_CRL_DIST_POINTS, chainElement->pCertContext->pCertInfo->cExtension, chainElement->pCertContext->pCertInfo->rgExtension);
if (!pExtension)
return ByteArray();
if (!CryptDecodeObject(X509_ASN_ENCODING, szOID_CRL_DIST_POINTS, pExtension->Value.pbData, pExtension->Value.cbData, 0, 0, &cbStructInfo))
return ByteArray();
if (!(pvStructInfo = LocalAlloc(LMEM_FIXED, cbStructInfo)))
return ByteArray();
CryptDecodeObject(X509_ASN_ENCODING, szOID_CRL_DIST_POINTS, pExtension->Value.pbData, pExtension->Value.cbData, 0, pvStructInfo, &cbStructInfo);
pInfo = (CRL_DIST_POINTS_INFO*)pvStructInfo;
Net::HttpRequest req;
Net::HttpRequestOptions ops;
ops.verb = Net::GET;
crllist = req.send(pInfo->rgDistPoint->DistPointName.FullName.rgAltEntry->pwszURL);
通过这种方式,我获得了可以在应用 FlateDecode 后粘贴到 PDF 中的字节。
现在 PDF 已启用 LTV。
我签署了一个 PDF 并添加了更新版本,我在其中编写了 DSS 及其 CRL、证书、VRI。
19 0 obj
[15 0 R 16 0 R]
endobj
20 0 obj
[13 0 R 14 0 R]
endobj
11 0 obj
[15 0 R 16 0 R]
endobj
12 0 obj
[13 0 R 14 0 R]
endobj
17 0 obj
<<
/CRL 11 0 R
/Cert 12 0 R
>>
endobj
18 0 obj
<<
/5F44CF6F351DFD45FB62F3D0ED046408BC892797 17 0 R
>>
endobj
21 0 obj
<<
/VRI 18 0 R
/CRLs 19 0 R
/Certs 20 0 R
>>
我对如何编写证书和 CRL 流感到困惑。
15 0 obj
<<
/Length 1454
/Filter /FlateDecode
>>
stream
xÚ3hb0hb{ÅÄÈhÀÉƪÍÇÌ$ÅÊ`àcÈä2‡²° 3…Šˆ€8\¼®y%E¥Å%:žyÉz†ªÊ
ZbXd{0%KW÷ýY¯’ó‚-ØÂÛ„OÏó½z•î ‰`®•® K-›2}tÖ§^_8;xÉì¥Ó®~›.g9A'Õüê½—
ZbXd{0%KW÷ýY¯’ó‚-ØÂÛ„OÏó½z•î ‰`®•® K-›2}tÖ§^_8;xÉì¥Ó®~›.g9A'Õüê½—
endstream
endobj
16 0 obj
<<
/Length 1477
/Filter /FlateDecode
>>
stream
„kâR7Å41*!‡#8Íñ3 Ź˜@‰o=«‡çƒ#yë:X]r\~}¼)/Ñmç×£¦³äsËê]ÓÕ_+µ¥$Ô¿}¾ÜÏiÁÝT!¹ôi–Í9üÀ}Š¸|
ìŒH¿GÓø^ú¿ÔVÜK–qõ†µ®“¸»Ý*Žh¾JzåU7c~÷•ÔêýK*îú®¹¸DcÁ³·NtV~Vóåíé5\‚&½|¶NäïŽ[K
î›NRZbXd{0%KW÷ýY¯’ó‚-ØÂÛ„OÏó½z•î ‰`®•® K-›2}tÖ§^_8;xÉì¥Ó®~›.g9A'Õüê½—›oÇ:ç-¶?
endstream
endobj
13 0 obj
<<
/Length 1240
/Filter /FlateDecode
>>
stream
%ŸwC[í2×¾Iej©úkŽ-:ݳÔ<¼a£ƒô/5›‡~zÒ•7ü9uãcfk?ËÅ`ßÃ:Èb—’‚Ÿõ{ÏÅ—¢{]HçQ”9w(ÂB#í×g¥ìþè
^–F«š/r§š¿ì=#,^pëO€{äú=}RÎêð¦ÉŠ7or¼±Ëtë–x·˜§LÌŒŒ‹› Cd0€eùÿ³°03±>0P ñUY$
endstream
endobj
14 0 obj
<<
/Length 1159
/Filter /FlateDecode
>>
stream
4!>T‚êPpÎI,.V0Ò™@ûœºƒ=LÍš•ãˆ‘•¹‰‘Ÿ(ÎÅÔÄÈÈplŽ÷A¯¹7k/[‡O\}
öe™¨îö£œ¶ä'¶ÌpžªweÞª[¡$¼ØÍþþtó[½xÉO4ÞZ¥ØŸ^g ø,mu„_Rz™_PÏê.||º¶*þîÝxv½"»êôó»ø%Ü%ý
endstream
endobj
请忽略以上流的长度和内容。我截断了它们,所以长度不再对应。溪流比那个大。
问题是我的 PDF 没有启用 LTV 我测试了一些场景,从中我得出结论 我的流没有以正确的方式写入。
我使用 WinCrypt.h 中的以下结构:
typedef struct _CERT_CONTEXT {
DWORD dwCertEncodingType;
BYTE *pbCertEncoded;
DWORD cbCertEncoded;
PCERT_INFO pCertInfo;
HCERTSTORE hCertStore;
} CERT_CONTEXT, *PCERT_CONTEXT;
typedef const CERT_CONTEXT *PCCERT_CONTEXT;
我通过它们并以这种方式获取字节:
PCCERT_CONTEXT cngContext = (PCCERT_CONTEXT)(*itChain);
ByteArray certBytes(cngContext->pbCertEncoded, (size_t)cngContext->cbCertEncoded);
然后我只对获得的字节应用 FlateDecode,并将它们像流一样写入 PDF,如您在第二个代码块中所见。
我漏掉了什么步骤吗?比如转换之类的?我看到流应该是 BER 编码的。那么我应该将字节转换为 BER 编码然后应用 FlateDecode 吗?
编辑:
您可以在此处找到 My File
解决方案
问题出在我在 PDF 文件中编写的 流 CRL。
从每个证书中获得 CRL_CONTEXT 结构,我只是将 pbCrlEncoded 变量直接写入 CRL 的流中。
这似乎是正确的,但我注意到我在这个结构的 CRL_INFO 中没有任何 CRL_ENTRY,因此编码的 BYTE 不包含任何已撤销证书的列表。 因此,发现证书有一个 URL,您可以从那里下载更新的 CRL。您可以通过在 Windows 中打开 管理计算机证书 -> 找到您的证书并 打开证书 -> 详细信息 -> CRL 分发点 -> URL = ".."。通过访问此 url,浏览器会自动下载 CRL 信息。您可以访问它并查看一些信息,例如 Next Update 这是该列表有效的最后一天。在那之后,我假设您需要再次下载它以获得更新版本。您还可以看到已撤销证书的列表本身。
这是我需要以 PDF 格式放入 CRL 流中的列表。 所以我找到了一种通过代码完成下载过程的方法。这是使用的代码片段:
PCERT_CHAIN_ELEMENT chainElement; // this is the certification in the chain
pExtension = CertFindExtension(szOID_CRL_DIST_POINTS, chainElement->pCertContext->pCertInfo->cExtension, chainElement->pCertContext->pCertInfo->rgExtension);
if (!pExtension)
return ByteArray();
if (!CryptDecodeObject(X509_ASN_ENCODING, szOID_CRL_DIST_POINTS, pExtension->Value.pbData, pExtension->Value.cbData, 0, 0, &cbStructInfo))
return ByteArray();
if (!(pvStructInfo = LocalAlloc(LMEM_FIXED, cbStructInfo)))
return ByteArray();
CryptDecodeObject(X509_ASN_ENCODING, szOID_CRL_DIST_POINTS, pExtension->Value.pbData, pExtension->Value.cbData, 0, pvStructInfo, &cbStructInfo);
pInfo = (CRL_DIST_POINTS_INFO*)pvStructInfo;
Net::HttpRequest req;
Net::HttpRequestOptions ops;
ops.verb = Net::GET;
crllist = req.send(pInfo->rgDistPoint->DistPointName.FullName.rgAltEntry->pwszURL);
通过这种方式,我获得了可以在应用 FlateDecode 后粘贴到 PDF 中的字节。 现在 PDF 已启用 LTV。