【问题标题】:Digitally sign using root CA from certificate file in .NET使用 .NET 中证书文件中的根 CA 进行数字签名
【发布时间】:2016-02-27 12:21:00
【问题描述】:

我必须使用证书和私钥在 C# 中对一些数据进行数字签名。我使用的证书具有自定义根 CA 以及自定义中间 CA。

我可以使用这样的代码毫无问题地进行签名,如果根 CA 和中间 CA 已安装到 Windows 证书存储中:

var content = new ContentInfo(manifest);
var cms = new SignedCms(content, true);
var signer = new CmsSigner(SubjectIdentifierType.SubjectKeyIdentifier, myCertificate);

signer.SignedAttributes.Add(new Pkcs9SigningTime(DateTime.Now));
cms.ComputeSignature(signer);

return cms.Encode();

不幸的是,我无法将根 CA 和中间 CA 安装到服务器的证书存储中(我正在使用 Azure Web 应用程序)。如果它们存储在磁盘上,我正在尝试使用根证书和中间 CA 证书进行签名。我想在打电话给cms.Encode() 之前我可以做这样的事情:

// add CAs from disk
var intermediateCACertificate = new X509Certificate2(@"pathToIntermediateCertificate.cer");
signer.Certificates.Add(intermediateCACertificate);

var rootCACertificate = new X509Certificate2(@"pathToRootCertificate.cer");
signer.Certificates.Add(rootCACertificate);

但是当我执行这个时,我得到了一个 CryptographicException 抛出 "A certificate chain could not be built to a trusted root authority."。

是否可以使用非标准 CA 进行数字签名而不将它们安装到 Windows 证书存储中?

【问题讨论】:

  • 这不会破坏拥有 CA 的目的吗?您不能(不应该)能够在没有管理员权限的情况下添加受信任的证书颁发机构。签名与将证书添加为受信任的 CA 非常不同 - 但您可能不会被允许使用不受信任的 CA 链进行签名
  • 可能,是的——虽然我不能添加 CA,我也不想信任它,只需使用它生成的证书对某些东西进行数字签名。由于 CA 的架构,这可能是不可能的,但我想确定一下。
  • 我想基本上我想做的就是告诉系统“为了这个操作的目的,将此链视为受信任的”,如果这有意义的话。
  • 我认为 Windows 不会让你这样做,但我不经常使用它,你是否尝试过使用自签名证书而不是 CA 链?
  • 我在使用的证书中没有任何选择。

标签: c# cryptography certificate x509certificate


【解决方案1】:

有可能。

基本上,从SignedCms 类返回的 BLOB 除了签名本身之外还可以包含任意数量的任意证书。这通常至少包括签署消息的证书以及可能的任何其他中间证书,以便接收实体可以验证签名直至其信任的根证书。

当您调用上述signer.Certificates.Add() 调用时,您正在添加要在输出签名BLOB 中编码的证书。但是,将证书添加到此集合中并不意味着对它们有任何形式的“信任”。

您的问题是,默认情况下,.NET SignedCms 类会尝试通过自动包含典型场景中包含的证书来帮助您。默认情况下,它包括链中除根以外的所有证书。它通过尝试使用它在服务器的证书存储中找到的证书构建一个链来做到这一点,正如您所注意到的,当未安装根/中间 CA 的证书时,该链会失败。

证书链构建由CmsSigner.IncludeOption 属性控制。其默认值为X509IncludeOption.ExcludeRoot。此值和X509IncludeOption.WholeChain 在您的系统上都将失败,因为该类将无法根据证书存储中的内容构建链。

您可能想要做的事情如下:

signer.IncludeOption = X509IncludeOption.EndCertOnly;
signer.Certificates.Add(intermediateCACertificate);
signer.Certificates.Add(rootCACertificate);

这将包括您用来签名的证书(在您指定EndCertOnly 时包括)以及显式添加的中间证书和根证书。 SignedCms 不会尝试构建证书链,因为它只需要包含已经提供的证书,因此不会抛出任何异常。

顺便说一下,你可以得到和上面一样的结果:

signer.IncludeOption = X509IncludeOption.None;
signer.Certificates.Add(myCertificate);
signer.Certificates.Add(intermediateCACertificate);
signer.Certificates.Add(rootCACertificate);

在这种情况下,签名证书不会自动包含在内,但下一行会明确将其添加到集合中。

根据您的接收者信任的 CA,您可能不需要像上面那样在链中包含所有证书,并且您可以只包含签名证书而侥幸。但是,我建议手动至少包括但不包括根,因为这是 .NET 默认行为。事实上,包含整个链也没有真正的危害,但出于所有意图和目的,接收者应该已经信任根 CA,否则 PKI 的整个概念就会失效。

【讨论】:

  • 这种方法对我来说绝对可以解决 Azure 无服务器环境中 OP 提到的 certificate chain could not be built to a trusted root authority 异常。
  • 我正在使用 Azure Functions,最终使用 Key Vault Explorer 加载根证书和中间证书的公钥(.cer 文件)。然后,我使用该应用程序使用的半非标准格式从存储在 Key Vault 中的密钥中加载了这些证书(因为 Azure Key Vault 本身不支持 .cer 文件)。按照@ben 的描述添加这些证书后,问题就解决了!
猜你喜欢
  • 2019-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-30
  • 2020-07-30
  • 2017-05-23
  • 2022-12-17
  • 2012-08-29
相关资源
最近更新 更多