简体   繁体   English

使用根CA从.NET中的证书文件进行数字签名

[英]Digitally sign using root CA from certificate file in .NET

I have to digitally sign some data in C# using a certificate and private key. 我必须使用证书和私钥在C#中对某些数据进行数字签名。 The certificate that I'm using has a custom root CA as well as a custom intermediate CA. 我使用的证书具有自定义的根CA和自定义的中间CA。

I can use code like this to do the signing without any problem, if the root and intermediate CAs are installed into the Windows certificate stores: 如果将根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();

Unfortunately, howeber, I am not able to install the root and intermediate CAs into the server's certificate store (I'm using Azure Web Apps). 不幸的是,但是,我无法将根CA和中间CA安装到服务器的证书存储中(我正在使用Azure Web Apps)。 I'm trying to work out a way to sign by using the root and intermediate CA certificates if they are stored on disk instead. 我正在尝试找到一种方法,通过使用根CA证书和中间CA证书(如果它们存储在磁盘上)来进行签名。 I thought I might be able to do something like this before calling cms.Encode() : 我以为我可以在调用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);

But when I execute this I get a CryptographicException thrown "A certificate chain could not be built to a trusted root authority." 但是,当我执行此操作时,会引发CryptographicException "A certificate chain could not be built to a trusted root authority." .

Is it possible to digitally sign using non-standard CAs without installing them into the Windows certificate store? 是否可以在不将非标准CA安装到Windows证书存储区的情况下进行数字签名?

It is possible. 有可能的。

Basically, the BLOB that comes back from the SignedCms class has the capability to include any number of arbitrary certificates in addition to the signature itself. 基本上,从SignedCms类返回的BLOB可以包含除签名本身之外的任意数量的任意证书。 This is typically done to include at least the certificate that the message was signed with and possibly any other intermediate certificates so that the receiving entity can verify the signature up to a root certificate that it trusts. 通常这样做是为了至少包括与消息进行签名的证书,并可能包括任何其他中间证书,以便接收实体可以验证签名,直到它信任的根证书为止。

When you are making calls to signer.Certificates.Add() call above, you're adding certificates to be encoded in the output signature BLOB. 在调用上面的signer.Certificates.Add()调用时,您正在添加要在输出签名BLOB中编码的证书。 However, adding certificates to this collection does nothing to imply any sort of "trust" of them. 但是,将证书添加到此集合并不能暗示对它们的任何形式的“信任”。

The problem in your case is the fact that by default the .NET SignedCms class tries to help you by automatically including the certificates that would be included for a typical scenario. 您遇到的问题是这样的事实:默认情况下,.NET SignedCms类尝试通过自动包含典型情况下将包含的证书来帮助您。 By default, it includes every certificate in the chain except for the root. 默认情况下,它包括链中除根以外的所有证书。 It does this by attempting to build a chain with certificates it finds in the server's certificate store, which, as you've noticed, fails when the root/intermediate CA's certificates aren't installed. 它通过尝试使用在服务器的证书存储中找到的证书构建证书链来实现此目的,如您所注意到的,当未安装根/中间CA的证书时,证书链将失败。

The certificate chain building is controlled by the CmsSigner.IncludeOption property. 证书链的构建由CmsSigner.IncludeOption属性控制。 The default value for this is X509IncludeOption.ExcludeRoot . 缺省值为X509IncludeOption.ExcludeRoot Both this value and X509IncludeOption.WholeChain will fail on your system since the class will be unable to build a chain based on what's in the certificate store. 此值和X509IncludeOption.WholeChain都将在您的系统上失败,因为该类将无法基于证书存储中的内容构建链。

Likely, what you'll want to do is as follows: 您可能想要做的如下:

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

This will include the certificate you are signing with (which is included when you specify EndCertOnly ) and the intermediate and root certificates which are explicitly added. 这将包括您用来签名的证书(当您指定EndCertOnly时将包括该证书)以及显式添加的中间证书和根证书。 SignedCms won't attempt to build a certificate chain since it only needs to include a certificate it has already been provided, so it won't throw any exceptions. SignedCms不会尝试构建证书链,因为它只需要包括已经提供的证书,因此不会引发任何异常。

Incidentally, you could get the same result as above like this: 顺便说一句,您可能会得到与上述相同的结果:

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

In this case, the signature certificate isn't automatically included, but the next line explicitly adds it to the collection. 在这种情况下,不会自动包括签名证书,但是下一行将其显式添加到集合中。

Depending upon which CAs your receiver trusts, it's possible that you don't need to include all the certificates in the chain as above and you may be able to get away with including just the signature certificate. 根据您的接收者信任的CA,有可能您不需要像上面那样在链中包含所有证书,并且可能仅包含签名证书就可以逃脱。 However, I'd suggest manually including at least up to but not including the root, as this is the .NET default behavior. 但是,我建议手动至少包括但不包括根目录,因为这是.NET的默认行为。 Indeed, there is no real harm in including the entire chain either, but for all intents and purposes the receiver should already trust the root CA or else the whole concept of PKI breaks down. 确实,包括整个链条也没有真正的危害,但是对于所有意图和目的,接收者应该已经信任根CA,否则PKI的整个概念就会崩溃。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM