使用 Adob​​e PKCS#7 证书在 Origami 中签名的 PDF 验证

Signed PDF verification in Origami with an Adobe PKCS#7 certificate

总结澄清:

使用折纸,从签名的 pdf 中提取证书(在例如 Adob​​e Reader 中签名)我无法验证签名:

origami = Origami::PDF.read(File.open('/path/to/file.pdf', 'r'))
pdf_signature = origami.signature[:Contents]
cert = OpenSSL::PKCS7.new(pdf_signature).certificates.first

origami.verify(trusted_certs: [cert]) #=> false

据我所知,这应该总是正确的。所以也许 Adob​​e 使用不同的字节范围,它在签署 PDF 时采用 SHA?我如何使该验证生效?

如果有任何帮助,在小心翼翼地完成 origami master 上的更改后,我能够从 storecontext 中获得确切的 OpenSSL 错误:V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY - 我认为它的意思是 X509::Store 它设置。


完整背景

我正在尝试验证 PDF 的数字签名。这是我得到的:

我使用 Adob​​e Acrobat 签名的 PDF(试用了 Pro 10 和 Reader DC)

密钥是在 Acrobat Pro 中生成的,我可以访问 .p12,或导出为 FDF、PKCS#7 或 "Certificate File"。还尝试通过 Apple 的 "Keychain Access" 加载此 "Certificate File" 并将其导出为 .pem 这给出与 OpenSSL::PKCS7.new(File.read('/path/to/exported.p7c')).certificates.first.to_pem 相同的结果,后者给出与以下相同的结果:

openssl pkcs7 -print_certs -inform der -in pkcs7file.p7c -out certificate.cer

所以,我很确定我已经正确提取了证书。

此外,我可以验证 PDF 中是否嵌入了完全相同的证书 -

pdf_signature = origami.signature[:Contents]
OpenSSL::PKCS7.new(pdf_signature).certificates.first.to_pem #=> Same as above

使用 Origami gem,我尝试加载证书并尝试验证:

cert = OpenSSL::X509::Certificate.new(File.read('/path/to/pem.cer'))
Origami::PDF.read(File.open('/path/to/file.pdf', 'r')).verify(trusted_certs: [cert])

Origami 的输出确认文档已签名,但 verify(..) 方法 returns 错误。

请注意,通过 this excellent answer 中的代码工作正常,但它似乎只有在使用 openssl 生成 X.509 密钥对时才有效(例如 ruby-land 绑定代码)。不幸的是,我需要使用用户机器上预先存在的 Adob​​e 支持的签名。

也就是说,除此之外,我几乎没有什么约束;我可以要求用户以任何其他对我们有用的方式导出他们的证书(如有必要,我什至可以在他们的机器上 运行 一些简单的代码),但我不能在过程中传输私钥。我不必使用 Origami 进行验证,但它必须是 ubuntu 服务器上的 ruby 可访问的命令。用户都运行使用最新软件的 Mac。

密码可能不同。可能是 Adob​​e 密码与 openssl 使用的密码不同,因此无法通过验证检查。看看这个。 Details on ciphers

这也可能有用openssl commands

我离原来的问题有点远了,但差距不大:

证书需要正确的扩展名

在原始代码中 from Harry Fairbanks' very useful answer, 扩展是最重要的:


extension_factory = OpenSSL::X509::ExtensionFactory.new
extension_factory.issuer_certificate = cert
extension_factory.subject_certificate = cert

cert.add_extension extension_factory.create_extension('basicConstraints', 'CA:TRUE', true)
cert.add_extension extension_factory.create_extension('keyUsage', 'digitalSignature,keyCertSign')
cert.add_extension extension_factory.create_extension('subjectKeyIdentifier', 'hash')

所以...按照该答案的其余部分,如果将​​证书保存到 pemfile,扩展名也不会保存

我能够创建一个 PDF,使用我从 Acrobat reader 导出的密钥在 Origami 上签名,然后执行以下操作:

cert = OpenSSL::PKCS7.new(pdf_signature).certificates.first

origami.verify(trusted_certs: [cert]) #=> false

## ... then run the extension factory snippet above

origami.verify(trusted_certs: [cert]) #=> true

成功!事实上,即使是 Adob​​e Acrobat Reader 也很高兴 - 我无法将其与 Origami 生成的自签名证书联系起来。

...但是,当我使用 Adob​​e Acrobat Reader 签署文档时,使用相同的密钥,对证书执行相同的魔法咒语,我仍然从验证调用中得到 false .


注意:有人告诉我这实际上对某些人有效。不知道为什么它对我来说失败了——当我有机会玩的时候,我会再试一次。暂时将此标记为已回答!