为什么 OpenSSL 的 PKCS7_verify() 需要 "smimesign" 证书用途?

Why OpenSSL's PKCS7_verify() requires "smimesign" certificate purpose?

PKCS7_verify() 的手册页指出

...Each signer's certificate is chain verified using the smimesign purpose...

为什么总是需要这个目的?我理解它,因此签名的 PKCS7 结构可以用于很多事情,S/MIME 只是其中之一。

如果我的签名证书在其 extendedKeyUsage 扩展名中没有 smimeSignPKCS7_verify() 将失败。我需要手动调整 purpose 才能进行验证。我在这里遗漏了什么吗?

仅仅验证签名、检查签名者的证书是否真实以及通往可信根的链是不够的。任何验证码还必须确保证书持有者有权为特定目的执行签名。获得具有 smimeSign 特权的证书的审查比代码签名证书的审查要宽松得多。

想象一家软件开发公司,每个员工都获得了用于电子邮件签名和加密的证书。该公司还发布了一款软件产品,并提供了其产品的 PKCS#7 签名分发包。如果 PKCS#7 验证函数没有检查签名证书的目的(在这种情况下我们想要 codesign),公司雇佣的不良行为者可能会创建软件产品的受损版本,并且用他们的电子邮件证书签名(只有 smimesign 的用途)

对于 OpenSSL 的 pkcs7_verify(),API 旨在暗示一个目的,而不是明确要求传入一个目的,并且 smimeSign 被选为默认值。我猜想因为 S/MIME 是 PKCS#7 最常见的用法,所以它是有道理的,并且它允许某人在大多数用例中验证 PKCS#7 而无需了解 extendedKeyUsage

[在我的原始答案下方,解决您的预编辑问题'我可以指定我想针对其他目的验证 PKCS7 中的签名':]

证书可以包含一个名为 "Extended Key Usage" 的(可选)属性。此属性用于指示允许使用证书的用途。一些可能的 X509.v3 用法是:

  • 服务器身份验证
  • 客户端身份验证
  • codeSigning
  • 电子邮件保护
  • ipSecEndSystem
  • ipSecTunnel
  • 时间戳
  • ocspSigning
  • 智能卡登录
  • pkiPeerAuth

您可以查看 x509v3_config 手册页以了解 openssl 知道的密钥使用标志。

PKCS#7 是一种通用容器格式,允许对容器内容进行签名和/或加密。 S/MIME 使用 PKCS#7 签署 and/or 加密电子邮件消息,在这种情况下,所使用的证书应该具有 emailProtection 用法。

如果你想分发一些代码,并且你想确保接收者可以验证分发是你的,并且没有改变,你可以使用 PKCS#7 来分发,在这种情况下你的证书应该具有 codeSigning 增强型密钥使用属性。 一个证书可以有多个密钥用途,但一般来说,为不同的使用类型使用单独的密钥(以及证书)是个好主意。

Openssl,在命令行上,支持在使用"openssl smime"命令时指定证书的预期用途。例如,

    openssl smime -verify -in myfile.p7b -inform DER -out my-p7-content -purpose any

将验证文件 'my file.p7p' 中的签名,它将 PKCS#7 容器的内容写入文件 'my-p7-content' 并且它将接受任何有效的证书,无论其指示的目的是什么是。 (-目的任何)。请注意,smime 的 openssl 手册页没有将 -purpose 开关列为选项,但它确实受支持。

由于您以编程方式引用了 PKCS7_verify API 文档,因此您可以在设置 X509_STORE 对象时通过 X509_VERIFY_PARAM_set_purpose 方法指定用途。以下片段应该让您了解该过程:

X509_STORE store;
int purpose;

store = X509_STORE_new();
verify_params = X509_Store_get0_param(store);
purpose = X509_PURPOSE_get_by_sname("sslclient");
X509_VERIFY_PARAM_set_purpose(verify_params, purpose)
...
PKCS7_verify(..., store, ...);

这将在验证时将目的设置为 SSL 客户端。