如何检查 SignedCms 信封的签名?

How can I check signature of a SignedCms envelope?

我不太明白如何使用 PKCS#7 消息。

我用我拥有的 X509Certificate2 对一些字节数组进行了签名,并且还得到了一个字节数组。

byte[] data = new byte[5] { 110, 111, 112, 113, 114 }, signedData;

X509Certificate2 cert = new X509Certificate2(certPath, password);

ContentInfo content = new ContentInfo(data);
SignedCms envelope = new SignedCms(content);
CmsSigner cmsSigner = new CmsSigner(cert);
envelope.ComputeSignature(cmsSigner);
signedData = envelope.Encode();

signedData 被传输给某个远程收件人,他得到 SignedCms 信封。

SignedCms envelope = new SignedCms();
envelope.Decode(signedData);

他怎么破译信封?他没有将我的 public 键作为参数传递。信封中有我的 public 密钥,在 SignerInfo 属性 中,但有什么原因吗,因为任何人都可以用整个签名替换它?

收件人可以使用他拥有的我的 public 密钥确定信封的实际发件人是我吗?

有方法envelope.CheckSignature(new X509Certificate2Collection(certificate), true);但我尝试使用错误的证书并且没有抛出异常。

PKCS#7 本身就是一个签名,它可以被替换吗?当然。 envelope.CheckSiganture 只是验证 pkcs#7 具有正确的格式和长度,换句话说检查 pkcs#7 是否构造良好。

概括地说,您需要实施 PKI(私钥基础设施)。一方面,您使用 public 密钥构建 pkcs#7,而另一方面,您必须验证您拥有的 pkcs#7 实际上具有您认为是您自己的有效证书。您必须实施 OCSP 来验证这些证书,如果一切正常,您应该并且必须向第三方请求时间戳以担保您的 pkcs#7。此外,您还需要一个保险库(数据库)来跟踪所有内容:pkcs#7、数据哈希、时间戳、原始数据、ocsp 响应...

但是如果您只对知道如何识别 pkcs#7 感兴趣,可以使用各种工具来解码 PKCS#7,此操作返回其中包含的所有信息。或者您可以使用 c# 创建您自己的。

PKCS#7 / CMS / S/MIME 签名消息是一个数据容器,它具有(除了一些其他元数据之外):

EncapsulatedContentInfo
  ContentInfoType
  EncapsulatedContent (the message bytes)
Certificates (Optional)
CRLs (Optional)
SignerInfos
  DigestAlgorithm (e.g. SHA-1)
  SignedAttributes (Optional, allows other context information to be signed)
  SignatureAlgorithm (e.g. RSA, DSA, ECDSA)
  SignatureValue (the signature bytes)
  UnsignedAttributes (Optional, allows for after-signing information, like counter-signatures)

(这是RFC 2630 (Cryptographic Message Syntax) Section 5的总结)

SignedCms.Decode 读取编码消息并填充成员。可以从 SignedCms::SignerInfos 属性 中读取消息的每个直接签名者(可以从 SignerInfo::CounterSignerInfos 中读取会签人或已签名的实体,他们见证了原始签名)。 =14=]

当您调用 SignedCms.CheckSignature 时,它会检查每个 SigerInfo 并验证签名是否可以成功验证(或抛出异常),以及是否可以计算出每个会签人签名。

它不知道的是任何签名者都“说得通”。对于该检查,您需要遍历每个 SignerInfo 并查看(例如)证书 属性;然后执行适用性检查:

  • 可能是预注册的public密钥
  • 也许它链接到一个众所周知的根或中间 CA
  • 也许它有某种扩展表明它是合适的

SignedCms 这部分实际上不能为您完成,因为与 TLS 的主机名验证不同,消息没有“适合”的默认概念。

如果你想评估单个签名者的签名,你可以调用SignedInfo::CheckSignature,但如果你也调用了SignedCms::CheckSignature,那是多余的。

There's method envelope.CheckSignature(new X509Certificate2Collection(certificate), true); but I tried to use wrong certificate and there was no exception thrown.

extraCerts 重载提供 额外的 证书。拥有不嵌入签名者证书的 SignedCms 消息是有效的,让接收者提前知道有效证书(例如,使用预注册证书的每个用户数据库)。您没有遇到异常,因为在提供的证书集合中找到了正确的证书。

您可以通过 X509Certificate2Collection.Import 方法查看提供的证书集合中的内容;他们可以读取 PKCS#7 签名数据消息并使用可选的嵌入式证书填充集合。