web-dev-qa-db-ja.com

C#のみを使用してプログラムでX509証明書を生成することは可能ですか?

C#と BouncyCastle ライブラリを使用して、プログラムでX509証明書(秘密キーを含む)を生成しようとしています。 Felix Kollmannによるこのサンプル のコードの一部を使用してみましたが、証明書の秘密キー部分はnullを返します。コードと単体テストは次のとおりです。

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

単体テスト:

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));
        }
    }
}
40
Tom Robinson

明確にするために、X.509証明書には秘密鍵が含まれていません。 Wordcertificateは、証明書と秘密キーの組み合わせを表すために誤用される場合がありますが、2つの別個のエンティティです。証明書を使用する全体のポイントは、秘密鍵を送信せずに多かれ少なかれオープンに送信することです。秘密鍵は秘密にしておく必要があります。 _X509Certificate2_オブジェクトには(PrivateKeyプロパティを介して)関連付けられた秘密キーがありますが、これはこのクラスの設計の一部としての利便性にすぎません。

最初のBouncyCastleコード例では、newCertは実際には単なる証明書であり、 DotNetUtilities.ToX509Certificate(newCert) は証明書のみから構築されます。

PKCS#12形式では秘密キーの存在が必要であることを考慮すると、次の部分が機能することにも驚かされます(秘密キーをおそらくは知らない証明書で呼び出していると考えてください)。

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

gen.Generate(kp.Private)は秘密鍵を使用して証明書に署名しますが、証明書に秘密鍵を入れません。これは意味がありません。)

メソッドが証明書と秘密キーの両方を返すようにする場合は、次のいずれかを実行できます。

  • PrivateKeyプロパティを初期化した_X509Certificate2_オブジェクトを返します
  • PKCS#12ストアを構築し、その_byte[]_コンテンツを(ファイルであるかのように)返します。 送信したリンクのステップミラー )は、PKCS#12ストアの構築方法を説明しています。

X.509証明書自体の_byte[]_(DER)構造を返すことには、秘密鍵は含まれません。

(テストケースによる)主な懸念事項が、証明書がRSAキーペアから作成されたことを確認することである場合は、代わりに公開キーの種類を確認できます。

31
Bruno

これは古い投稿であることに気づきましたが、プロセスを通過するこれらの優れた記事を見つけました。

。NETのBouncy Castleを使用

7
haymansfield