如何对 PDF 中的证书吊销列表 (CRL) 流字节进行编码?

Posted

技术标签:

【中文标题】如何对 PDF 中的证书吊销列表 (CRL) 流字节进行编码?【英文标题】:How do you encode the Certificate Revocation List (CRL) stream bytes in PDF? 【发布时间】:2020-06-11 10:24:56 【问题描述】:

我签署了一份 PDF 并添加了更新版本,我在其中编写了带有 CRL、证书、VRI 的 DSS。

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†ªÊ
ZbXd0%KW÷ýY¯’ó‚-ØÂÛ„OÏó½z•î    ‰`®•®   K-›2tÖ§^_8;xÉì¥Ó®~›.g9A'Õüê½—
ZbXd0%KW÷ýY¯’ó‚-ØÂÛ„OÏó½z•î    ‰`®•®   K-›2tÖ§^_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­
î›NRZbXd0%KW÷ýY¯’ó‚-ØÂÛ„OÏó½z•î    ‰`®•®   K-›2tÖ§^_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-Encoded 然后应用 FlateDecode 吗?

编辑:

你可以在这里找到My File

【问题讨论】:

您能否发布一个指向 PDF 文件的链接以供下载? 我在底部添加了 流已经被 DER 编码。问题是(可能)CRLs 数组中的流不是 CRL,而是 OCSP 响应。 Godaddy 的 CRL 列表(crl.godaddy.com/repository/mastergodaddy2issuing.crl,在 OCSP 响应之一中引用)为 118MB。 文档声明 CRL 流应进行 BER 编码。这会是个问题吗?作为记录,我看到 DER 是 BER 的一个子集。另外,为什么我会得到 OCSP 而不是 CRL .. 你能检查一下这篇文章吗?这也是我的,有人注意到与 OCSP 相同的事情。 ***.com/questions/60413766/… 在您的previous question 的两个答案中检查过,您的“CRL”根本不是 CRL。它们是包装在其他结构中的 OCSP 响应。因此,您可以随心所欲地使用编码,通过将这些结构 作为 CRLs 嵌入 DSS 中,您不会获得支持 LTV 的 PDF。而是提取实际的 OCSP 响应并将它们嵌入为 OCSP 【参考方案1】:

解决方案

问题在于我在 PDF 文件中写入的 CRL

拥有来自每个证书的 CRL_CONTEXT 结构,我只需获取 pbCrlEncoded 变量并将其直接写入 CRL 的流中。

这似乎是正确的,但我注意到我在此结构的 CRL_INFO 中没有任何 CRL_ENTRY,因此编码的 BYTE 不包含任何已撤销证书的列表。 因此,发现证书有一个 URL,您可以从该 URL 下载更新的 CRL。您可以通过在 Windows 中打开 管理计算机证书 -> 找到您的证书并 打开证书 -> 详细信息 -> CRL分发点 -> URL = ".."。通过访问此 url,浏览器会自动下载 CRL 信息。您可以访问它并查看诸如下一次更新之类的信息,这是此列表有效的最后一天。在那之后,我假设您需要再次下载它以获得更新版本。您还可以查看已撤销证书的列表本身。

这是我需要放入 PDF 中的 CRL 流中的列表。 所以我找到了一种通过代码完成下载过程的方法。这是使用的代码的sn-p:

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。

【讨论】:

虽然这当然可以做到,但并不是很好。正如在回答您之前的问题时已经讨论过的那样,CrlEncoded 缓冲区中实际上有一个包装的 OCSP 响应,因此您确实已经有了撤销信息,您只需正确提取并添加到 OCSP 部分。获取 CRL 会使用 PKI 基础架构创建额外的网络流量。此外,通常应该首选 OCSP 响应,因为它们通常比 CRL 更短(在某些 PKI 中非常短)并且更新。

以上是关于如何对 PDF 中的证书吊销列表 (CRL) 流字节进行编码?的主要内容,如果未能解决你的问题,请参考以下文章

Go-加密学 - 证书吊销列表(CRL)

Go-加密学 - 证书吊销列表(CRL)

将证书吊销列表 (CRL) 文件从 .crl 转换为 .pem 扩展名 - Python 3

MIMEKIT Multipart Signed.Verify 如何禁用证书吊销列表检查?

如何在使用本地 CRL 文件(C#)的验证过程中检查客户端证书吊销

Java SSL 证书吊销检查