Question

Nous essayons de générer un certificat X509 (y compris la clé privée) par programmation C # et la BouncyCastle bibliothèque. Nous avons essayé d'utiliser une partie du code de cet échantillon par Felix Kollmann mais la partie clé privée du rendement de certificat nul. Code et test unitaire sont comme ci-dessous:

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

Test Unité:

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));
        }
    }
}
Était-ce utile?

La solution

Pour préciser, un certificat X.509 ne contient pas la clé privée. Le mot certificat est parfois mal utilisé pour représenter la combinaison du certificat et la clé privée, mais ils sont deux entités distinctes. Le point entier de l'utilisation de certificats est de les envoyer plus ou moins ouvertement, sans envoyer la clé privée, qui doit être gardé secret. Un objet X509Certificate2 peut avoir une clé privée qui lui est associée (via sa propriété PrivateKey), mais c'est seulement une commodité dans le cadre de la conception de cette classe.

Dans votre premier exemple de code BouncyCastle, newCert est vraiment juste le certificat et DotNetUtilities.ToX509Certificate(newCert) est construit à partir du seul certificat.

Considérant que le format PKCS # 12 nécessite la présence d'une clé privée, je suis très surpris que la partie suivante fonctionne même (étant donné que vous appelez sur un certificat qui ne peut pas savoir peut-être la clé privée):

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

(signes gen.Generate(kp.Private) le certificat avec la clé privée, mais ne met pas la clé privée dans le certificat, ce qui ne serait pas logique.)

Si vous voulez que votre méthode pour revenir à la fois le certificat et la clé privée vous pouvez soit:

De retour la byte[] (DER) structure du certificat X.509 lui-même ne contient pas la clé privée.

Si votre principale préoccupation (selon votre cas de test) est de vérifier que le certificat a été construit à partir d'une clé RSA paire, vous pouvez vérifier le type de sa clé publique à la place.

Autres conseils

Je sais que c'est un ancien poste mais je trouve ces excellents articles qui passent par le processus:

En utilisant Bouncy Castle de .NET

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top