CMS登录与证书链不.NET本地受信任的证书存储 [英] CMS signing in .NET with certificate chain not in local trusted certificate store

查看:1034
本文介绍了CMS登录与证书链不.NET本地受信任的证书存储的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我具有被存储在网络上X509证书。我可以读取远程Windows证书存储链。我需要签署一些数据,包括链的签名,以使人们有可能在以后对其进行验证。

I have X509 certificates that are stored on the network. I can read the chain from remote windows certificate store. I need to sign some data and include chain to the signature to make it possible to validate it later.

的问题是,我无法找到一个办法把证书链到CsmSigner。我已阅读,它从构造函数的参数证书,并试图建立与X509Chain.Build链。它忽略证书列表值和失败(显然),因为没有证书可以在本地Windows证书存储中找到。

The problem is that I can't find a way to put certificate chain to the CsmSigner. I have read that it takes certificate from constructor parameter and tries to build a chain with X509Chain.Build. It ignores Certificates list values and fails (obviously) because no certificate can be found in the local Windows cert store.

请在下面找到我的测试代码(即仅当证书在本地保存到Windows证书存储)

Please find below my test code (that works only if certificates were saved locally to the windows cert store)

protected byte[] SignWithSystem(byte[] data, X509Certificate2 cert, X509Certificate[] chain)
{
    ContentInfo contentInfo = new ContentInfo(data);

    SignedCms signedCms = new SignedCms(contentInfo, true);

    CmsSigner cmsSigner = new CmsSigner(cert);
    cmsSigner.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1"); //sha256
    cmsSigner.IncludeOption = X509IncludeOption.WholeChain;

    if (chain != null)
    {
        //adding cert chain to signer
        cmsSigner.Certificates.AddRange(chain);
        signedCms.Certificates.AddRange(chain);
    }

    signedCms.ComputeSignature(cmsSigner); //fails here with System.Security.Cryptography.CryptographicException : A certificate chain could not be built to a trusted root authority.


    byte[] signedPkcs = signedCms.Encode();
    return signedPkcs;
}



有没有什么办法让它不上传证书到当地商店工作?我应该使用任何替代签名?

Is there any way to make it work without uploading certificates to the local store? Should I use any alternative signer?

我可以尝试上传证书到店,但问题是,

I can try to upload certificates to the store but the problems are that


  • 我有添加和删除证书(权限都被授予)

  • I have to add and remove certificates (permissions have to be granted)

有几种工艺适用签名所以跨进程同步必须添加。

There are several processes that applies signature so cross-process synchronization have to be added.

这是不是我想要做的。

推荐答案

您可以使用 BouncyCastle的加密的.NET库,其中包含了自己的X509证书和CMS签名机械。很多在网络上的实例和文档的Java,作为BouncyCastle的是一个Java库第一。我用回答这个问题#1 作为起点证书和密钥加载,并添加CMS签名。您可能需要调整参数产生你想为你的用例的结果。

Example CMS Signing with BouncyCastle for .NET

You could use the BouncyCastle crypto library for .NET, which contains its own X509 certificate and CMS signing machinery. A lot of the examples and documentation on the web are for Java, as BouncyCastle was a Java library first. I've used the answer to this Stackoverflow question as a starting point for the certificate and key loading, and added the CMS signing. You may have to tweak parameters to produce the results you want for your use case.

我所做的签约功能看起来大约像你这样的,但要注意的私钥现在一个单独的参数

I've made the signing function look approximately like yours, but note the private key is a separate parameter now.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using Org.BouncyCastle.Cms;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509.Store;

class Program
{
  protected static byte[] SignWithSystem(byte[] data, AsymmetricKeyParameter key, X509Certificate cert, X509Certificate[] chain)
  {
    var generator = new CmsSignedDataGenerator();
    // Add signing key
    generator.AddSigner(
      key,
      cert,
      "2.16.840.1.101.3.4.2.1"); // SHA256 digest ID
    var storeCerts = new List<X509Certificate>();
    storeCerts.Add(cert); // NOTE: Adding end certificate too
    storeCerts.AddRange(chain); // I'm assuming the chain collection doesn't contain the end certificate already
    // Construct a store from the collection of certificates and add to generator
    var storeParams = new X509CollectionStoreParameters(storeCerts);
    var certStore = X509StoreFactory.Create("CERTIFICATE/COLLECTION", storeParams);
    generator.AddCertificates(certStore);

    // Generate the signature
    var signedData = generator.Generate(
      new CmsProcessableByteArray(data),
      false); // encapsulate = false for detached signature
    return signedData.GetEncoded();
  }

  static void Main(string[] args)
  {
    try
    {
      // Load end certificate and signing key
      AsymmetricKeyParameter key;
      var signerCert = ReadCertFromFile(@"C:\Temp\David.p12", "pin", out key);

      // Read CA cert
      var caCert = ReadCertFromFile(@"C:\Temp\CA.cer");
      var certChain = new X509Certificate[] { caCert };

      var result = SignWithSystem(
        Guid.NewGuid().ToByteArray(), // Any old data for sake of example
        key,
        signerCert,
        certChain);

      File.WriteAllBytes(@"C:\Temp\Signature.data", result);
    }
    catch (Exception ex)
    {
      Console.WriteLine("Failed : " + ex.ToString());
      Console.ReadKey();
    }
  }

  public static X509Certificate ReadCertFromFile(string strCertificatePath)
  {
    // Create file stream object to read certificate
    using (var keyStream = new FileStream(strCertificatePath, FileMode.Open, FileAccess.Read))
    {
      var parser = new X509CertificateParser();
      return parser.ReadCertificate(keyStream);
    }
  }

  // This reads a certificate from a file.
  // Thanks to: http://blog.softwarecodehelp.com/2009/06/23/CodeForRetrievePublicKeyFromCertificateAndEncryptUsingCertificatePublicKeyForBothJavaC.aspx
  public static X509Certificate ReadCertFromFile(string strCertificatePath, string strCertificatePassword, out AsymmetricKeyParameter key)
  {
    key = null;
    // Create file stream object to read certificate
    using (var keyStream = new FileStream(strCertificatePath, FileMode.Open, FileAccess.Read))
    {
      // Read certificate using BouncyCastle component
      var inputKeyStore = new Pkcs12Store();
      inputKeyStore.Load(keyStream, strCertificatePassword.ToCharArray());

      var keyAlias = inputKeyStore.Aliases.Cast<string>().FirstOrDefault(n => inputKeyStore.IsKeyEntry(n));

      // Read Key from Aliases  
      if (keyAlias == null)
        throw new NotImplementedException("Alias");
      key = inputKeyStore.GetKey(keyAlias).Key;
      //Read certificate into 509 format
      return (X509Certificate)inputKeyStore.GetCertificate(keyAlias).Certificate;
    }
  }
}



.NET CMS(的Quick与链的其余部分自签字省略)



解决我可以用其根不在受信任的证书存储中的证书重现你的问题,并确认将证书链在 cmsSigner / signedCms 证书收集不避 A证书链无法建立到受信任的根证书颁发机构错误。

.NET CMS (Quick-fix with rest of chain omitted from signature)

I can reproduce your problem with a certificate whose root is not in the trusted certificate store, and confirm that adding the certificate chain to the cmsSigner/signedCms Certificates collection does not avoid the A certificate chain could not be built to a trusted root authority error.

您可以通过设置<$ C成功登录$ C> cmsSigner.IncludeOption = X509IncludeOption.EndCertOnly;

不过,如果你这样做,你不会得到链在休息签名。这可能不是你想要的。

However, if you do this, you will not get the rest of the chain in the signature. This probably isn't what you want.

顺便说一句,在你的榜样,你正在使用 X509证书的阵列中的链的证书,但将它们传递给一个 X509Certificate2Collection (注意在那里2)。 X509Certificate2 X509证书派生的,但如果它并不是一个真正的 X509Certificate2 你把这些收藏品之一,你会得到一个错误投,如果事情遍历集合(可惜加错误类型的证书,当你没有得到一个错误,因为 X509Certificate2Collection 也由 X509CertificateCollection 并继承了它添加方法)。

As an aside, in your example you are using X509Certificate for the array of certificates in the chain, but passing them to an X509Certificate2Collection (note the "2" in there). X509Certificate2 derives from X509Certificate, but if its not actually an X509Certificate2 that you put in one of those collections, you'll get a cast error if something iterates over the collection (you don't get an error when adding a certificate of the wrong type unfortunately, because X509Certificate2Collection also derives from X509CertificateCollection and inherits its add methods).

这篇关于CMS登录与证书链不.NET本地受信任的证书存储的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆