Can';我不明白为什么我的PDF签名没有启用LTV

Can';我不明白为什么我的PDF签名没有启用LTV,pdf,certificate,digital-signature,signature,acrobat,Pdf,Certificate,Digital Signature,Signature,Acrobat,我正在生成带有签名的PDF文档,我希望它启用LTV。 为此,我在创建PDF时对其进行签名,然后添加包含DSS的第二个版本以及验证相关信息(VRI)。 正如我在一些文章中发现的,我需要添加证书链(没有根证书颁发机构)和证书吊销列表(CRL)。在我的例子中,两者都有2个元素。之后,我为VRI添加条目,它是签名内容的SHA-1散列(在/Contents中的第一个PDF版本中找到),其值引用上述证书和CRL 对于证书和吊销列表元素,我都使用内容的原始字节流 这是 编辑 我获取CRL信息的方式是使用W

我正在生成带有签名的PDF文档,我希望它启用LTV。 为此,我在创建PDF时对其进行签名,然后添加包含DSS的第二个版本以及验证相关信息(VRI)。 正如我在一些文章中发现的,我需要添加证书链(没有根证书颁发机构)和证书吊销列表(CRL)。在我的例子中,两者都有2个元素。之后,我为VRI添加条目,它是签名内容的SHA-1散列(在/Contents中的第一个PDF版本中找到),其值引用上述证书和CRL

对于证书和吊销列表元素,我都使用内容的原始字节流

这是

编辑

我获取CRL信息的方式是使用WynCrypt,如下所示:

//Retrieve chained certificate
if(!CertGetCertificateChain(hChainEngine, pSignerCert, pTime, hAdditionalStore, &chainPara, dwFlags, NULL, &ppChainContext))
    return NULL;

//first cert in chain is the end cert; last one is the root cert
for(int i = 0; i < ppChainContext->cChain; ++i)
{
    PCERT_SIMPLE_CHAIN simpleChain = ppChainContext->rgpChain[i];

    for(int j = 0; j < (int)simpleChain->cElement - 1; j++)//do not include root certificate
    {
        PCERT_CHAIN_ELEMENT chainElement = simpleChain->rgpElement[j];

        if(chainElement->pCertContext)
        {   
            //the certificate bytes
            byte* certBytes =chainElement->pCertContext->pbCertEncoded
        }

        if(chainElement->pRevocationInfo && chainElement->pRevocationInfo->pCrlInfo)
        {
            PCCRL_CONTEXT crlContext = chainElement->pRevocationInfo->pCrlInfo->pBaseCrlContext;//get revocation context

            //the bytes that will be written in PDF
            byte* crlBytes = crlContext->pbCrlEncoded;
        }
    }
}
//检索链接证书
if(!CertGetCertificateCain(HchaineEngine、pSignerCert、pTime、HadAdditionalStore和chainPara、dwFlags、NULL和ppChainContext))
返回NULL;
//链中的第一个证书是结束证书;最后一个是根证书
对于(int i=0;icChain;++i)
{
PCERT_SIMPLE_CHAIN simpleChain=ppChainContext->rgpChain[i];
对于(int j=0;j<(int)simpleChain->cElement-1;j++)//不包括根证书
{
PCERT_CHAIN_ELEMENT chainElement=simpleChain->rgpElement[j];
if(chaineelement->pCertContext)
{   
//证书长度为个字节
字节*certBytes=chainElement->pCertContext->pCertEncoded
}
if(chainElement->preocationInfo&&chainElement->preocationInfo->pCrlInfo)
{
PCCRL_CONTEXT crlContext=chaineelement->pRevocationInfo->pCrlInfo->pBaseCrlContext;//获取撤销上下文
//将以PDF格式写入的字节
字节*crlBytes=crlContext->pbCrlEncoded;
}
}
}

刚刚快速查看了一下,对象15和16是OCSP响应,但您将它们添加为CRL:

在我的源代码查看器中,DSS字典(对象21)是:

>
19点指向数组原子:
[15 0 R 16 0 R]


同样,对于LTV来说,VRI不是必需的,它目前基本上是一种优化(参见附录A1,其中基本上取自PDF 2.0规范)。如果使用它并添加时间戳(/TS条目),Adobe当前甚至无法正确显示它。在VRI中,TU/TS也是完全可选的,不会影响LTV的有效性(同上)。

只是快速查看了一下,对象15和16是OCSP响应,但您将它们添加为CRL:

在我的源代码查看器中,DSS字典(对象21)是:

>
19点指向数组原子:
[15 0 R 16 0 R]

同样,对于LTV来说,VRI不是必需的,它目前基本上是一种优化(参见附录A1,其中基本上取自PDF 2.0规范)。如果使用它并添加时间戳(/TS条目),Adobe当前甚至无法正确显示它。在VRI中,TU/TS也是完全可选的,不影响LTV的有效性(同上)。

术语“LTV启用” 据我所知,“启用LTV”一词的含义没有正式规范。其中有一些非规范性描述,尤其是:

  • Leonard Rosenthol(Adobe的PDF架构师兼首席科学家)曾将其描述为

    启用LTV意味着验证文件(减去根证书)所需的所有信息都包含在中

  • 另一位Adobe员工Steven.Madwin将实现描述为

    作为验证过程的一部分,[Acrobat]确定是否必须联机下载撤销信息,或者所有撤销信息是否都嵌入到PDF文件中。此时,它知道将在签名导航面板中显示什么。如果必须下载数据,则签名未启用LTV,但如果文件中包含所有撤销附属文件,则签名已启用LTV

因此,术语“启用LTV”的含义取决于Adobe Acrobat的签名验证算法的实现细节(这些算法是封闭源代码,不一定是固定的)和底层配置。你可以在多个旧的堆栈溢出答案中读到我对此的咆哮

尽管如此,这些实现细节下的机制并不是完全任意的,它们基本上形成了关于该主题的现有已发布规范的概要文件(尽管是专有的、封闭的,甚至可能是更改的),特别是RFC

特别是,为了让您的签名有机会被标记为“LTV enabled”,您应该做些什么?添加验证器在验证过程中可能需要的所有信息,尤其是

  • 将签名者证书中的所有中间证书添加到Adobe信任的证书中。如果不确定哪些证书受信任,请将所有证书添加到根证书。如果您知道这些证书中的任何一个将由另一个CA交叉签名,请添加所有这些可能链的证书
  • 对于所有这些证书(根证书除外),检索吊销信息(CRL或OCSP响应)并添加它们
  • 对于每个添加的CRL和OCSP响应,确定其各自的签名者证书,将该证书及其链中的证书添加到文档中,以检索和添加其吊销信息(除非它们是根证书,或者具有pkix ocsp nocheck扩展名的证书,或者您已经拥有它们的吊销信息)等等
然而,一个挑战仍然存在,那就是确定如何准确地将所有这些信息添加到您的PDF中

如果你知道签名者证书
<<
/CRLs 19 0 R
/Certs 20 0 R
/VRI 18 0 R
>>