是否有可能以编程方式生成仅使用C#X509证书? [英] Is it possible to programmatically generate an X509 certificate using only C#?

查看:499
本文介绍了是否有可能以编程方式生成仅使用C#X509证书?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在尝试以编程方式使用C#和 BouncyCastle的库生成X509证书(包括私钥)。我们已经使用了一些code的试图从这个样本由费利克斯·Kollmann ,但该证书的私钥部分返回null。 code和单元测试情况如下:

 使用系统;
System.Collections中使用;
使用Org.BouncyCastle.Asn1;
使用Org.BouncyCastle.Asn1.X509;
使用Org.BouncyCastle.Crypto;
使用Org.BouncyCastle.Crypto.Generators;
使用Org.BouncyCastle.Crypto.Prng;
使用Org.BouncyCastle.Math;
使用Org.BouncyCastle.Security;
使用Org.BouncyCastle.X509;命名空间的MyApp
{
    公共类CertificateGenerator
    {
        ///<总结>
        ///
        ///< /总结>
        ///&LT;&言论GT;基于&LT;见cref=\"http://www.fkollmann.de/v2/post/Creating-certificates-using-BouncyCastle.aspx\"/></remarks>
        ///&LT; PARAM NAME =主旨名称&GT;&LT; /参数&GT;
        ///&LT;&回报GT;&LT; /回报&GT;
        公共静态的byte [] generateCertificate所(字符串主旨名称)
        {
            VAR kpgen =新RsaKeyPairGenerator();            kpgen.Init(新KeyGenerationParameters(新的SecureRandom(新CryptoApiRandomGenerator()),1024));            变种KP = kpgen.GenerateKeyPair();            VAR根=新X509V3CertificateGenerator();            VAR certName =新X509Name(CN =+主旨名称);
            变种系列号= BigInteger.ProbablePrime(120,新的随机());            gen.SetSerialNumber(系列号);
            gen.SetSubjectDN(certName);
            gen.SetIssuerDN(certName);
            gen.SetNotAfter(DateTime.Now.AddYears(100));
            gen.SetNotBefore(DateTime.Now.Subtract(新时间跨度(7,0,0,0)));
            gen.SetSignatureAlgorithm(MD5WithRSA);
            gen.SetPublicKey(kp.Public);            gen.AddExtension(
                X509Extensions.AuthorityKeyIdentifier.Id,
                假,
                新的执行authorityKeyIdentifier(
                    SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(kp.Public)
                    新GeneralNames(新GeneralName(certName))
                    序列号));            gen.AddExtension(
                X509Extensions.ExtendedKeyUsage.Id,
                假,
                新执行extendedKeyUsage(新的ArrayList(){新DerObjectIdentifier(1.3.6.1.5.5.7.3.1)}));            VAR newCert = gen.Generate(kp.Private);
            返回DotNetUtilities.ToX509Certificate(newCert).Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs12, 密码);
        }
    }
}

单元测试:

 使用System.Security.Cryptography;
使用System.Security.Cryptography.X509Certificates;
使用Microsoft.VisualStudio.TestTools.UnitTesting;命名空间的MyApp
{
    [识别TestClass]
    公共类CertificateGeneratorTests
    {
        [测试方法]
        公共无效GenerateCertificate_Test_ValidCertificate()
        {
            //安排
            字符串主旨名称=测试;            //法案
            字节[] =实际CertificateGenerator.GenerateCertificate(主旨名称);            //断言
            VAR证书=新X509Certificate2(实际,密码);
            Assert.AreEqual(CN =+主旨名称,cert.Subject);
            Assert.IsInstanceOfType(cert.PrivateKey的typeof(的RSACryptoServiceProvider));
        }
    }
}


只是为了澄清,X.509证书不包含的私钥。这个词的证书的有时被误用来重新present证书和私钥的组合,但它们是两个不同的实体。使用证书的整点是给他们或多或少的公开,不发送私钥,必须保密。一个 X509Certificate2 对象可能有(通过其 PrivateKey 属性)与它相关的私钥,但这只是一个方便的作为这个类的设计的一部分。

在你的第一个BouncyCastle的code例如, newCert 其实只是证书和<一个href=\"http://www.bouncycastle.org/viewcvs/viewcvs.cgi/csharp/crypto/src/security/DotNetUtilities.cs?rev=1.14&content-type=text/vnd.viewcvs-markup\"><$c$c>DotNetUtilities.ToX509Certificate(newCert)仅从证书建

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

 。出口(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs12,
    密码);

gen.Generate(kp.Private)签署使用自己的私钥证书,但并没有把私有密钥与证书中,这会不会使感。)

如果你希望你的方法返回证书和私钥,你既可以:


  • 返回您已初始化 PrivateKey 属性的 X509Certificate2 对象

  • 构建PKCS#12店,并返回其字节[] 内容(好像它是一个文件)。 步骤3在您发送链接(<一个href=\"http://web.archive.org/web/20100504192226/http://www.fkollmann.de/v2/post/Creating-certificates-using-BouncyCastle.aspx\">mirror)解释了如何构建一个PKCS#12店。

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

如果(根据你的测试用例)您主要关注的是检查证书是从一个RSA密钥对建成,可以检查,而不是它的公共密钥的类型。

We're trying to generate an X509 certificate (including the private key) programmatically using C# and the BouncyCastle library. We've tried using some of the code from this sample by Felix Kollmann but the private key part of the certificate returns null. Code and unit test are as below:

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 test:

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));
        }
    }
}

解决方案

Just to clarify, an X.509 certificate does not contain the private key. The word certificate is sometimes misused to represent the combination of the certificate and the private key, but they are two distinct entities. The whole point of using certificates is to send them more or less openly, without sending the private key, which must be kept secret. An X509Certificate2 object may have a private key associated with it (via its PrivateKey property), but that's only a convenience as part of the design of this class.

In your first BouncyCastle code example, newCert is really just the certificate and DotNetUtilities.ToX509Certificate(newCert) is built from the certificate only.

Considering that the PKCS#12 format requires the presence of a private key, I'm quite surprised that the following part even works (considering you're calling it on a certificate which can't possibly know the private key):

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

(gen.Generate(kp.Private) signs the certificate using the private key, but doesn't put the private key in the certificate, which wouldn't make sense.)

If you want your method to return both the certificate and the private key you could either:

  • Return an X509Certificate2 object in which you've initialized the PrivateKey property
  • Build a PKCS#12 store and returns its byte[] content (as if it was a file). Step 3 in the link you've sent (mirror) explains how to build a PKCS#12 store.

Returning the byte[] (DER) structure for the X.509 certificate itself will not contain the private key.

If your main concern (according to your test case) is to check that the certificate was built from an RSA key-pair, you can check the type of its public key instead.

这篇关于是否有可能以编程方式生成仅使用C#X509证书?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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