是否有可能以编程方式生成仅使用C#的X509证书?

我们正尝试使用C#和BouncyCastle库以编程方式生成X509证书(包括私钥)。 我们已经尝试使用Felix Kollmann的这个示例中的一些代码,但是证书的私钥部分返回null。 代码和unit testing如下:

using System; using System.Collections; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Prng; using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; using Org.BouncyCastle.X509; namespace MyApp { public class CertificateGenerator { /// <summary> /// /// </summary> /// <remarks>Based on <see cref="http://www.fkollmann.de/v2/post/Creating-certificates-using-BouncyCastle.aspx"/></remarks> /// <param name="subjectName"></param> /// <returns></returns> public static byte[] GenerateCertificate(string subjectName) { var kpgen = new RsaKeyPairGenerator(); kpgen.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 1024)); var kp = kpgen.GenerateKeyPair(); var gen = new X509V3CertificateGenerator(); var certName = new X509Name("CN=" + subjectName); var serialNo = BigInteger.ProbablePrime(120, new Random()); gen.SetSerialNumber(serialNo); gen.SetSubjectDN(certName); gen.SetIssuerDN(certName); gen.SetNotAfter(DateTime.Now.AddYears(100)); gen.SetNotBefore(DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0))); gen.SetSignatureAlgorithm("MD5WithRSA"); gen.SetPublicKey(kp.Public); gen.AddExtension( X509Extensions.AuthorityKeyIdentifier.Id, false, new AuthorityKeyIdentifier( SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(kp.Public), new GeneralNames(new GeneralName(certName)), serialNo)); gen.AddExtension( X509Extensions.ExtendedKeyUsage.Id, false, new ExtendedKeyUsage(new ArrayList() { new DerObjectIdentifier("1.3.6.1.5.5.7.3.1") })); var newCert = gen.Generate(kp.Private); return DotNetUtilities.ToX509Certificate(newCert).Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs12, "password"); } } } 

unit testing:

 using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace MyApp { [TestClass] public class CertificateGeneratorTests { [TestMethod] public void GenerateCertificate_Test_ValidCertificate() { // Arrange string subjectName = "test"; // Act byte[] actual = CertificateGenerator.GenerateCertificate(subjectName); // Assert var cert = new X509Certificate2(actual, "password"); Assert.AreEqual("CN=" + subjectName, cert.Subject); Assert.IsInstanceOfType(cert.PrivateKey, typeof(RSACryptoServiceProvider)); } } } 

只是为了澄清,一个X.509证书不包含私钥。 单词证书有时被误用来表示证书和私钥的组合,但它们是两个不同的实体。 使用证书的重点是或多或less地公开发送,而不必发送必须保密的私钥。 一个X509Certificate2对象可能有一个私钥(通过它的PrivateKey属性),但这只是这个类的devise的一部分。

在您的第一个BouncyCastle代码示例中, newCert实际上只是证书,而DotNetUtilities.ToX509Certificate(newCert)仅由证书构build。

考虑到PKCS#12格式需要一个私钥存在,我很惊讶,以下部分甚至可以工作(考虑到你在一个不可能知道私钥的证书上调用它):

 .Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs12, "password"); 

gen.Generate(kp.Private)使用私钥签名证书,但不将私钥放在证书中,这是没有意义的。)

如果你想要你的方法返回证书和私钥,你可以:

  • 返回已经初始化PrivateKey属性的X509Certificate2对象
  • 构buildPKCS#12存储并返回其byte[]内容(就像它是一个文件一样)。 您发送的链接 ( 镜像 ) 中的第3步介绍了如何构buildPKCS#12存储。

返回X.509证书的byte[] (DER)结构本身将不包含私钥。

如果您的主要担心(根据您的testing案例)是检查证书是从RSA密钥对构build的,则可以检查其公钥的types。

我意识到这是一个旧的post,但我发现这些过程中的优秀文章:

使用.NET中的Bouncy Castle